/* The /tools pages.
 *
 * One system with the rest of lumioguard. What used to live here was the
 * console's own world — ruled paper, a hand pen, Archivo and Architects
 * Daughter off Google Fonts — which made /tools look like a different product
 * to anyone who arrived from search and then clicked through to /pricing. The
 * tokens, the nav, the buttons and the footer below are the site's, lifted from
 * index.html so a visitor crossing that seam never sees one. Only the chrome
 * changed: every word between it is still the console's.
 *
 * Kept external rather than inlined the way the site's own pages are: three
 * pages share this sheet, so it caches once, and `style-src 'self'` covers it
 * without the 'unsafe-inline' the inlined pages need.
 *
 * Dark is forced for everyone — data-theme is hardcoded in the markup and there
 * is no toggle — exactly as it is on the site. The light tokens are kept whole,
 * so bringing a switcher back is the same one-line job here as it is there.
 */

/* ---- typeface: self-hosted, the same files the site preloads ---------- */

@font-face {
  font-family: 'Geist';
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url(/assets/fonts/geist-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Geist';
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url(/assets/fonts/geist-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Geist Mono';
  font-style: normal;
  font-weight: 400 500;
  font-display: swap;
  src: url(/assets/fonts/geist-mono-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Geist Mono';
  font-style: normal;
  font-weight: 400 500;
  font-display: swap;
  src: url(/assets/fonts/geist-mono-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ---- tokens, verbatim from index.html --------------------------------- */

:root {
  --bg: #fafaf7;
  --bg-elev: #ffffff;
  --bg-soft: #f3f1ea;
  --bg-sunken: #eceae2;
  --fg: #0f0f10;
  --fg-muted: #5e5e63;
  --fg-subtle: #6c6c71;
  --border: #e6e4dc;
  --border-strong: #d5d2c8;
  --accent: #e89b2b;
  --accent-deep: #b97515;
  --accent-soft: #fbf1dc;
  --safe: #6b8e5a;
  --reliable: #4f8c8c;
  --info: #4a6fa5;
  --danger: #b85450;

  /* One measure for the whole page, the site's own, so the headline starts on
     the same x as the brand above it and the footer below it. Nothing is
     stretched to fill it: the headline, the address bar and every column of
     prose carry their own cap. */
  --max: max(1440px, 66.667vw);
  --pad: 28px;

  --r-sm: 6px;
  --r-md: 10px;
  --r-lg: 16px;
  --r-xl: 22px;

  --shadow-sm: 0 1px 0 rgb(15 15 16 / 4%), 0 1px 2px rgb(15 15 16 / 4%);
  --shadow-md: 0 1px 0 rgb(15 15 16 / 4%), 0 8px 24px -8px rgb(15 15 16 / 10%);
  --shadow-lg: 0 1px 0 rgb(15 15 16 / 4%), 0 24px 60px -20px rgb(15 15 16 / 18%);
}

[data-theme='dark'] {
  --bg: #08080a;
  --bg-elev: #101013;
  --bg-soft: #15151a;
  --bg-sunken: #1b1b21;
  --fg: #f2f1ec;
  --fg-muted: #a6a5ab;
  --fg-subtle: #8a8990;
  --border: #1e1e24;
  --border-strong: #2a2a31;
  --accent: #f5a93e;
  --accent-deep: #e89b2b;
  --accent-soft: #2a1f0e;
  --safe: #88b26c;
  --reliable: #6ca5a5;
  --info: #6e92c8;
  --danger: #d77a76;

  --shadow-sm: 0 1px 0 rgb(0 0 0 / 40%), 0 1px 2px rgb(0 0 0 / 30%);
  --shadow-md: 0 1px 0 rgb(0 0 0 / 40%), 0 8px 24px -8px rgb(0 0 0 / 50%);
  --shadow-lg: 0 1px 0 rgb(0 0 0 / 40%), 0 24px 60px -20px rgb(0 0 0 / 60%);
}

[data-theme='dark'] body {
  color-scheme: dark;
}

/* ---- base -------------------------------------------------------------- */

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

html,
body {
  margin: 0;
  padding: 0;
}

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  /* the offset equals the 60px sticky nav exactly */
  scroll-behavior: smooth;
  scroll-padding-top: 60px;
}

body {
  background: var(--bg);
  color: var(--fg);
  font-family: Geist, ui-sans-serif, system-ui, sans-serif;
  font-size: 16px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  font-feature-settings: 'ss01', 'cv11';
  overflow-x: hidden;
}

a {
  color: inherit;
  text-decoration: none;
}

::selection {
  background: var(--accent);
  color: #fff;
}

.mono {
  font-family: 'Geist Mono', ui-monospace, monospace;
}

.wrap {
  max-width: var(--max);
  margin: 0 auto;
  padding: 0 var(--pad);
}

h1,
h2,
h3 {
  margin: 0;
  font-weight: 500;
  letter-spacing: -0.025em;
  line-height: 1.05;
}

h2 {
  font-size: clamp(28px, 3.4vw, 40px);
}

h3 {
  font-size: 18px;
  letter-spacing: -0.015em;
  line-height: 1.3;
}

p {
  margin: 0;
  color: var(--fg-muted);
}

/* the site's own device for the second half of a headline */
.italic {
  color: var(--fg-muted);
}

/* Author display beats the user agent's [hidden] rule, so anything this file
   gives a display value has to opt back out of it by hand. */
section[hidden],
.problem[hidden],
.scan-clear[hidden] {
  display: none;
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border-width: 0;
}

a:focus-visible,
button:focus-visible,
input:focus-visible,
summary:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--r-sm);
}

/* the bar draws the focus treatment for the field inside it */
.scan-input:focus-visible {
  outline: none;
}

.skip-link {
  position: absolute;
  left: 8px;
  top: -56px;
  z-index: 100;
  padding: 10px 16px;
  border-radius: var(--r-md);
  background: var(--fg);
  color: var(--bg);
  font-size: 14px;
  font-weight: 500;
  transition: top 0.15s ease;
}

.skip-link:focus {
  top: 8px;
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* ---- nav --------------------------------------------------------------- */

.nav {
  position: sticky;
  top: 0;
  z-index: 50;
  backdrop-filter: blur(14px) saturate(140%);
  -webkit-backdrop-filter: blur(14px) saturate(140%);
  background: rgb(250 250 247 / 78%);
  border-bottom: 1px solid transparent;
  transition: border-color 0.3s ease, background 0.3s ease;
}

.nav.scrolled {
  border-bottom-color: var(--border);
  background: rgb(250 250 247 / 92%);
}

[data-theme='dark'] .nav {
  background: rgb(8 8 10 / 70%);
}

[data-theme='dark'] .nav.scrolled {
  background: rgb(8 8 10 / 88%);
}

.nav-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 60px;
}

.brand {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 17px;
  font-weight: 600;
  letter-spacing: -0.01em;
}

.brand-mark {
  width: auto;
  height: 22px;
}

/* sized so the wordmark's cap height equals the 22px shield; the g's descender
   hangs below via the negative margin without growing the row */
.brand-word {
  display: block;
  align-self: center;
  width: auto;
  height: 28.6px;
  margin-bottom: -6.6px;
}

.nav-links {
  display: flex;
  gap: 28px;
  font-size: 14px;
  color: var(--fg-muted);
}

.nav-links a {
  transition: color 0.15s ease;
}

.nav-links a:hover,
.nav-links a[aria-current='page'] {
  color: var(--fg);
}

/* Tools opens the readings. :hover for a mouse and :focus-within for a
   keyboard, so the menu carries no JavaScript and no state to fall out of sync. */
.nav-dd {
  position: relative;
  display: flex;
  align-items: center;
}

.nav-dd-t {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: inherit;
  cursor: pointer;
  transition: color 0.15s ease;
}

.nav-dd-t:hover,
.nav-dd-t[data-here] {
  color: var(--fg);
}

.nav-dd-t svg {
  width: 11px;
  height: 11px;
  transition: transform 0.15s ease;
}

.nav-dd:hover .nav-dd-t svg,
.nav-dd:focus-within .nav-dd-t svg {
  transform: rotate(180deg);
}

/* bridges the gap under the trigger: without it the pointer leaves .nav-dd on
   the way down and the menu closes before it can be reached */
.nav-dd::after {
  content: '';
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  height: 12px;
}

.nav-dd-menu {
  position: absolute;
  top: 100%;
  left: 50%;
  display: flex;
  flex-direction: column;
  min-width: 210px;
  padding: 6px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--bg-elev);
  box-shadow: var(--shadow-md);
  opacity: 0;
  visibility: hidden;
  transform: translateX(-50%) translateY(2px);
  transition: opacity 0.15s ease, transform 0.15s ease, visibility 0.15s;
}

.nav-dd:hover .nav-dd-menu,
.nav-dd:focus-within .nav-dd-menu {
  opacity: 1;
  visibility: visible;
  transform: translateX(-50%) translateY(10px);
}

.nav-dd-menu a {
  padding: 9px 11px;
  border-radius: 8px;
  color: var(--fg-muted);
  white-space: nowrap;
}

.nav-dd-menu a:hover {
  background: var(--bg-soft);
  color: var(--fg);
}

.nav-dd-menu a[aria-current='page'] {
  background: var(--bg-soft);
  color: var(--fg);
}

.nav-cta {
  display: flex;
  align-items: center;
  gap: 16px;
  font-size: 14px;
}

.nav-cta .signin {
  color: var(--fg-muted);
  transition: color 0.15s ease;
}

.nav-cta .signin:hover {
  color: var(--fg);
}

.nav-toggle {
  display: none;
  place-items: center;
  width: 40px;
  height: 40px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: transparent;
  color: var(--fg-muted);
  cursor: pointer;
  transition: color 0.15s ease, background 0.15s ease, border-color 0.15s ease;
}

.nav-toggle:hover {
  background: var(--bg-soft);
  border-color: var(--border-strong);
  color: var(--fg);
}

.nav-toggle svg {
  width: 18px;
  height: 18px;
}

.nav-toggle .ham-close {
  display: none;
}

.nav-toggle[aria-expanded='true'] .ham {
  display: none;
}

.nav-toggle[aria-expanded='true'] .ham-close {
  display: block;
}

.mobile-menu {
  display: none;
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  flex-direction: column;
  padding: 6px var(--pad) 14px;
  background: var(--bg-elev);
  border-bottom: 1px solid var(--border);
  box-shadow: var(--shadow-md);
}

.mobile-menu a {
  padding: 13px 4px;
  border-bottom: 1px solid var(--border);
  font-size: 16px;
  color: var(--fg);
}

.mobile-menu a:last-child {
  border-bottom: none;
}

.mobile-menu .mm-sub {
  padding-left: 18px;
  font-size: 15px;
  color: var(--fg-muted);
}

.mobile-menu .mm-sub[aria-current='page'] {
  color: var(--fg);
}

.mobile-menu .mm-label {
  padding: 13px 4px 4px;
  font-size: 13px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--fg-muted);
}

.mobile-menu .btn {
  justify-content: center;
  min-height: 46px;
  margin-top: 14px;
  border-bottom: none;
  color: var(--bg);
}

.mobile-menu.open {
  display: flex;
}

@media (max-width: 820px) {
  .nav-links {
    display: none;
  }

  .nav-toggle {
    display: inline-grid;
  }
}

@media (min-width: 821px) {
  .mobile-menu {
    display: none !important;
  }
}

/* The nav row is brand + CTA + hamburger, and it has to fit without the
   wordmark being covered. Sign in goes first (it is in the menu below), then
   the CTA tightens, and only at the last step does the wordmark yield to the
   shield. The thresholds are the measured widths, not round numbers:
   brand 174 + CTA 125 + gap 10 + hamburger 40 + padding 56 = 405. */
@media (max-width: 620px) {
  .nav-cta {
    gap: 10px;
  }

  .nav-cta .signin {
    display: none;
  }

  .nav-cta .btn {
    min-height: 38px;
    padding: 6px 10px;
    font-size: 13px;
  }
}

@media (max-width: 480px) {
  .nav-inner {
    padding: 0 20px;
  }

  .mobile-menu {
    padding-left: 20px;
    padding-right: 20px;
  }

  .brand {
    gap: 8px;
    font-size: 16px;
  }
}

/* the nav row only — the footer's brand has the whole width to itself */
@media (max-width: 440px) {
  .nav .brand-word {
    display: none;
  }
}

/* ---- buttons ----------------------------------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 12px;
  border: 1px solid var(--fg);
  border-radius: var(--r-md);
  background: var(--fg);
  color: var(--bg);
  font: inherit;
  font-size: 14px;
  font-weight: 500;
  white-space: nowrap;
  cursor: pointer;
  box-shadow: var(--shadow-sm);
  transition: transform 0.15s ease, background 0.15s ease, box-shadow 0.15s ease;
}

.btn:hover {
  transform: translateY(-1px);
  box-shadow: var(--shadow-md);
}

.btn:active {
  transform: translateY(0);
}

.btn-lg {
  padding: 8px 14px;
  font-size: 15px;
}

[data-theme='dark'] .btn {
  border-color: var(--fg);
  background: var(--fg);
  color: #0a0a0b;
  box-shadow: 0 1px 0 rgb(255 255 255 / 8%) inset, 0 1px 2px rgb(0 0 0 / 50%);
}

/* CTA chevron: the brand double-angle. Drawn as a mask so one declaration
   colours it, and sized in em so it tracks .btn-lg on its own. The orange is
   pinned rather than var(--accent-deep): .btn inverts its surface between
   themes while --accent-deep lightens in dark, which would leave the chevron
   near 2:1 on the light button. #b97515 clears 3:1 against both surfaces. */
.btn[href*='app.lumioguard.dev']::after {
  content: '';
  flex: none;
  width: 1.15em;
  height: 1.15em;
  background: #b97515;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M19.1642 12L12.9571 5.79291L11.5429 7.20712L16.3358 12L11.5429 16.7929L12.9571 18.2071L19.1642 12ZM13.5143 12L7.30722 5.79291L5.89301 7.20712L10.6859 12L5.89301 16.7929L7.30722 18.2071L13.5143 12Z'/%3E%3C/svg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M19.1642 12L12.9571 5.79291L11.5429 7.20712L16.3358 12L11.5429 16.7929L12.9571 18.2071L19.1642 12ZM13.5143 12L7.30722 5.79291L5.89301 7.20712L10.6859 12L5.89301 16.7929L7.30722 18.2071L13.5143 12Z'/%3E%3C/svg%3E") center / contain no-repeat;
  transition: transform 0.2s ease;
}

.btn[href*='app.lumioguard.dev']:hover::after {
  transform: translateX(3px);
}

/* ---- section rhythm ---------------------------------------------------- */

section {
  position: relative;
  padding: 96px 0;
}

section + section {
  border-top: 1px solid var(--border);
}

@media (max-width: 720px) {
  section {
    padding: 64px 0;
  }
}

/* Head left, body right. It is the one skeleton all three readings share below
   the ask, so the pages stay siblings however different their content is. */
.section-split {
  display: grid;
  grid-template-columns: minmax(300px, 4fr) 7fr;
  gap: 56px;
}

.section-split > .head {
  position: sticky;
  top: 96px;
  align-self: start;
}

.section-split > .body {
  min-width: 0;
}

.section-split .head h2 {
  text-wrap: balance;
}

@media (max-width: 1000px) {
  .section-split {
    grid-template-columns: 1fr;
    gap: 32px;
  }

  .section-split > .head {
    position: static;
  }
}

/* ---- reveal ------------------------------------------------------------ */

.js .reveal {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 0.9s cubic-bezier(0.2, 0.7, 0.2, 1), transform 0.9s cubic-bezier(0.2, 0.7, 0.2, 1);
}

.reveal.in {
  opacity: 1;
  transform: none;
}

.reveal[data-delay='1'] {
  transition-delay: 0.08s;
}

.reveal[data-delay='2'] {
  transition-delay: 0.16s;
}

.reveal[data-delay='3'] {
  transition-delay: 0.24s;
}

/* ---- the ask ----------------------------------------------------------- *
 *
 * The address bar is the page. Everything above it is a question and
 * everything below it is an explanation, so it gets the elevation, the ambient
 * pool the site puts behind its product shot, and the only amber on the page.
 */

.ask {
  /* sits directly under the sticky nav, the same allowance /checks makes */
  padding: 132px 0 104px;
  /* the ambient pool below reaches 70px past the bar on each side; on a phone
     that is wider than the page, so it is clipped here rather than allowed to
     add a scrollable strip (the same guard index.html puts on its hero) */
  overflow-x: clip;
}

@media (max-width: 720px) {
  .ask {
    padding: 96px 0 72px;
  }
}

/* Two columns, the way the console had them: the question and the field lead,
   the three beats sit beside them rather than in a band underneath. Below
   1040px there is no room for a 340px aside next to a 38px+ headline, so the
   beats drop under the field and keep their order. */
.ask-grid {
  display: grid;
  /* the left column is capped at the address bar's own width rather than given
     the rest of the page: pushed to the far margin the beats stop reading as
     part of the field they describe */
  grid-template-columns: minmax(0, 780px) minmax(0, 420px);
  justify-content: start;
  /* the beats stand clear of the button rather than starting where it ends;
     the page has the room, and at 780 + 420 the pair still leaves a margin */
  gap: clamp(40px, 8vw, 128px);
  /* the beats run the whole height the question and the field occupy, rather
     than sitting as a compact block centred against them */
  align-items: stretch;
}

.ask-main {
  min-width: 0;
}

.ask-side {
  display: flex;
}

/* The pair only shares a row while there is room for both: under this the
   field is squeezed past the point an address is readable in it (297px at
   1060, where the beats still hold their full 420), so the beats drop under
   the field and it takes the width back. */
@media (max-width: 1180px) {
  .ask-grid {
    grid-template-columns: 1fr;
    gap: 52px;
  }

  .ask-side {
    max-width: 520px;
  }
}

.ask h1 {
  max-width: 17ch;
  font-size: clamp(38px, 5.4vw, 68px);
  font-weight: 500;
  letter-spacing: -0.04em;
  line-height: 1.06;
  text-wrap: balance;
}

.scan {
  position: relative;
  isolation: isolate;
  max-width: 780px;
  margin-top: clamp(30px, 3.6vw, 44px);
}

[data-theme='dark'] .scan::before {
  content: '';
  position: absolute;
  z-index: -1;
  inset: -56px -70px -60px;
  background:
    radial-gradient(ellipse 52% 62% at 34% 50%, rgb(255 255 255 / 7.5%), transparent 72%),
    radial-gradient(ellipse 90% 90% at 45% 55%, rgb(255 255 255 / 3.5%), transparent 78%);
  pointer-events: none;
}

/* The field and the example chips are a light island: white in both papers, so
   they carry the light palette's inks rather than the page's. The values are
   :root's own, restated because the dark block has already taken those names. */
.scan-bar,
.try {
  --ink: #0f0f10;
  --ink-soft: #5e5e63;
  --ink-faint: #6c6c71;
}

.scan-row {
  display: flex;
  align-items: stretch;
  gap: 12px;
}

.scan-bar {
  flex: 1;
  min-width: 0;
  display: flex;
  align-items: center;
  /* the address sits off the mark, and both sit off the edge: at 18/12 the
     text read as pinned to the left wall of the box */
  gap: 15px;
  padding: 0 14px 0 18px;
  border: 1px solid transparent;
  /* the site button's corner, so the pair matches the hero's CTA */
  border-radius: var(--r-md);
  background: #fff;
  color: var(--ink);
  box-shadow: var(--shadow-md);
  transition: border-color 0.18s ease, box-shadow 0.18s ease;
}

[data-theme='dark'] .scan-bar {
  box-shadow:
    0 1px 0 rgb(0 0 0 / 40%),
    0 24px 60px -22px rgb(0 0 0 / 70%),
    0 0 50px rgb(255 255 255 / 4.5%);
}

.scan-bar:focus-within {
  border-color: var(--accent);
  box-shadow: var(--shadow-md), 0 0 0 4px rgb(232 155 43 / 18%);
}

[data-theme='dark'] .scan-bar:focus-within {
  box-shadow:
    0 1px 0 rgb(0 0 0 / 40%),
    0 24px 60px -22px rgb(0 0 0 / 70%),
    0 0 0 4px rgb(245 169 62 / 16%);
}

/* the page's danger ink is mixed for a near-black ground; on white it is the
   light palette's, which clears 4.5:1 against the field it outlines */
.scan-bar.wrong,
.scan-bar.wrong:focus-within {
  border-color: #b85450;
  box-shadow: var(--shadow-md);
}

.scan-glyph {
  flex: none;
  width: 21px;
  height: 21px;
  color: var(--ink-faint);
}

.scan-input {
  flex: 1;
  min-width: 0;
  /* no vertical padding of its own: the row's height comes from the button
     beside it, and the text sits centred in whatever that is */
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  font-size: 19px;
  line-height: 1.3;
  letter-spacing: -0.01em;
  color: var(--ink);
}

.scan-input::placeholder {
  color: var(--ink-faint);
}

.scan-input:focus {
  outline: none;
}

.scan-clear {
  display: grid;
  place-items: center;
  flex: none;
  width: 30px;
  height: 30px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: none;
  color: var(--ink-faint);
  cursor: pointer;
  transition: color 0.15s ease, background 0.15s ease;
}

.scan-clear:hover {
  background: #f0eee7;
  color: var(--ink);
}

.scan-clear svg {
  width: 13px;
  height: 13px;
}

/* The deep half of the wordmark — #C83B01 is the "guard" in lumioguard, read
   straight off lumioguard-logo.svg. White on it is 5.17:1, so the label clears
   AA. Written past the themed .btn rules, which would otherwise paint it. */
/* Paint only. Every dimension is .btn and .btn-lg's own, so this wears the same
   15px/500 at 8px 14px that "Start for Free" wears in the site's hero — 41px
   tall — and follows it if that button ever changes. The field beside it
   stretches to the same height. */
.scan .scan-go {
  flex: none;
  border-color: #c83b01;
  background: #c83b01;
  color: #fff;
  box-shadow: 0 1px 0 rgb(255 255 255 / 12%) inset, 0 6px 18px -8px rgb(200 59 1 / 55%);
}

.scan .scan-go:hover {
  border-color: #b23501;
  background: #b23501;
}

/* the chevron the site puts on every app-bound button would land dark orange
   on dark orange here, and this button is not app-bound anyway */
.scan .scan-go::after {
  content: none;
}

.scan-go svg {
  width: 15px;
  height: 15px;
  transition: transform 0.2s ease;
}

.scan-go:hover svg {
  transform: translateX(3px);
}

/* Below 560px the label crowds the field, so the bar wraps and the button takes
   the full width — which is the easier thumb target anyway. */
/* Below 560px the pair will not share a row: the field would be too narrow to
   show an address and the button too narrow to hold its label. They stack, and
   the button takes the full width, which is the easier thumb target anyway. */
@media (max-width: 560px) {
  .scan-row {
    flex-direction: column;
    gap: 10px;
  }

  .scan-bar {
    padding: 0 16px 0 20px;
  }

  .scan-input {
    font-size: 17px;
  }

  .scan .scan-go {
    min-height: 46px;
    justify-content: center;
  }
}

.problem {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 14px;
  font-size: 14px;
  color: var(--danger);
}

.problem svg {
  flex: none;
  width: 15px;
  height: 15px;
}

.tries {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 20px;
}

.tries-label {
  margin-right: 4px;
  font-family: 'Geist Mono', monospace;
  font-size: 13px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  /* the muted ink, not the subtle one: at 8.19:1 it reads as the label it is
     rather than as a watermark under the chips */
  color: var(--fg-muted);
}

.try {
  display: inline-flex;
  align-items: center;
  padding: 6px 15px;
  border: 1px solid transparent;
  border-radius: 999px;
  /* a step below the light palette's sunken grey: the chips are examples under
     the field, not a second field beside it, and holding them off white keeps
     that order legible. Near-black on it is 13.64:1. */
  background: #dedbd0;
  font: inherit;
  font-size: 13.5px;
  color: var(--ink);
  cursor: pointer;
  transition: background 0.15s ease, transform 0.15s ease;
}

.try:hover {
  background: #cec9ba;
  transform: translateY(-1px);
}

/* The slimmer chip is 34px, under the 44px a finger wants. On a touch pointer
   the hit area is padded back out past the pill without moving it, so the row
   keeps the height it was asked for and stays thumbable. */
@media (pointer: coarse) {
  .try {
    position: relative;
  }

  .try::after {
    content: '';
    position: absolute;
    inset: -6px 0;
  }
}

/* ---- the three beats, beside the field -------------------------------- */

/* One number drives the mark, the trail's ends and the column the labels start
   from, so the three cannot drift apart when the size changes. */
.how {
  --mark: 46px;

  position: relative;
  display: grid;
  /* Centred in whatever height the question and the field leave, on a gap that
     is a share of that height rather than a number typed in. Spreading to the
     ends made the run read as three things pinned to the column; a share of it
     reads as one group beside the field, and it stays that way as the column
     grows. The length below is the stacked layout's, where the aside sizes to
     its own content and a percentage has no height to resolve against. */
  align-content: center;
  gap: 1.65rem;
  flex: 1;
  margin: 0;
  padding: 0;
  list-style: none;
}

/* A share of the column, not a length: at the desktop layout's 283px column
   this is ~42px, against the 70 that spreading to the ends produced, and it
   holds that proportion at any height. Only where there is a column to centre
   in. After .how rather than before it — a media query carries no extra
   specificity, so the base rule would otherwise win on order. */
@media (min-width: 1181px) {
  .how {
    row-gap: 15%;
  }
}

/* The console drew a trail between its steps. This is that trail, as one
   hairline down the whole column rather than a segment per gap: the marks
   centre against labels that wrap to two and three lines, so where each gap
   begins and ends is not a number this sheet can know. The marks are opaque and
   sit above it, so it only ever shows between them, and half a mark at each end
   puts its ends behind the first and the last. */
.how::before {
  content: '';
  position: absolute;
  left: calc(var(--mark) / 2);
  top: calc(var(--mark) / 2);
  bottom: calc(var(--mark) / 2);
  width: 1px;
  background: var(--border-strong);
}

.how-step {
  display: grid;
  grid-template-columns: var(--mark) minmax(0, 1fr);
  gap: 18px;
  /* the mark centres on its label, so a beat that wraps does not leave it
     hanging off the first line */
  align-items: center;
}

.how-ico {
  position: relative;
  z-index: 1;
  display: grid;
  place-items: center;
  width: var(--mark);
  height: var(--mark);
  border: 1px solid var(--border);
  border-radius: 13px;
  background: var(--bg-soft);
}

.how-ico svg {
  width: 23px;
  height: 23px;
  /* the label's ink, not the page's brightest: a beat is one thing, and the
     mark leading it in white made the words beside it look like an afterthought */
  color: var(--fg-muted);
}

.how-label {
  font-size: 17px;
  line-height: 1.5;
  /* the beats are read a phrase at a time rather than scanned, so the spaces
     are opened past Geist's default to let the words come apart */
  word-spacing: 0.14em;
  color: var(--fg-muted);
}

/* ---- leaderboard, on ai-slop-check ------------------------------------- */

.board {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1px;
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  background: var(--border);
  overflow: hidden;
}

@media (max-width: 700px) {
  .board {
    grid-template-columns: 1fr;
  }
}

.board-side {
  padding: 22px 24px 18px;
  background: var(--bg-elev);
}

/* the Worker's own tier name for the side — a heading, so it is set like one:
   the page's face at its heading weight, not the mono the meta labels wear */
.board-band {
  margin: 0 0 6px;
  font-size: 16px;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--fg);
}

.board-rows {
  display: grid;
}

.brow {
  display: grid;
  grid-template-columns: 22px minmax(0, 1fr) auto;
  gap: 14px;
  align-items: center;
  padding: 16px 2px;
  border-top: 1px solid var(--border);
  transition: background 0.12s ease;
}

.brow:hover {
  background: var(--bg-soft);
}

.brow-place {
  font-size: 12.5px;
  font-variant-numeric: tabular-nums;
  color: var(--fg-subtle);
}

.brow-host {
  font-size: 15.5px;
  color: var(--fg);
  overflow-wrap: anywhere;
}

.brow:hover .brow-host {
  color: var(--accent-deep);
}

[data-theme='dark'] .brow:hover .brow-host {
  color: var(--accent);
}

.brow-score {
  font-size: 15.5px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

/* A screen that is loading holds the height it is about to have: the same .brow
   grid, filled with bars instead of text, so nothing under the board moves when
   the rows arrive. A CSS sweep rather than a Lottie — a loading state is not
   worth a runtime dependency, and this one cannot fail to load. */
.brow-skel {
  cursor: default;
}

.brow-skel:hover {
  background: none;
}

.skel {
  display: block;
  /* 12 + 6 + 6 = the 24px line box a single-line row's text makes at 15.5px on
     the body's 1.55, so a placeholder row is exactly the height of a real one
     and the rows below it do not move when the answer lands */
  height: 12px;
  margin: 6px 0;
  border-radius: 999px;
  background:
    linear-gradient(90deg, var(--bg-soft) 0%, var(--bg-sunken) 45%, var(--bg-soft) 90%);
  background-size: 220% 100%;
  animation: skel-sweep 1.5s ease-in-out infinite;
}

.brow-skel .skel-score {
  width: 26px;
  margin-left: auto;
}

@keyframes skel-sweep {
  from {
    background-position: 220% 0;
  }

  to {
    background-position: -120% 0;
  }
}

@media (prefers-reduced-motion: reduce) {
  .skel {
    animation: none;
  }
}

.board-note {
  padding: 16px 2px 4px;
  border-top: 1px solid var(--border);
  font-size: 14px;
  color: var(--fg-muted);
}

/* a row of the board rather than something under it: it spans both columns and
   sits on the same elevated surface, so the 1px grid gap draws its rule */
.board-more {
  grid-column: 1 / -1;
  display: flex;
  justify-content: center;
  padding: 18px;
  background: var(--bg-elev);
}

/* walking the board on its own page */
.board-foot {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 14px 2px 2px;
  border-top: 1px solid var(--border);
}

.board-btn {
  padding: 6px 13px;
  border: 1px solid var(--border-strong);
  border-radius: 8px;
  background: transparent;
  font: inherit;
  font-size: 13px;
  color: var(--fg-muted);
  cursor: pointer;
  transition: color 0.15s ease, border-color 0.15s ease, background 0.15s ease;
}

.board-btn:hover:not(:disabled) {
  border-color: var(--fg-subtle);
  background: var(--bg-soft);
  color: var(--fg);
}

.board-btn:disabled {
  opacity: 0.4;
  cursor: default;
}

/* 33px is under the 44 a finger wants, so the hit area is padded back out
   without moving the control — the same treatment the example chips get */
@media (pointer: coarse) {
  .board-btn {
    position: relative;
  }

  .board-btn::after {
    content: '';
    position: absolute;
    inset: -6px 0;
  }
}

.board-page {
  margin-left: auto;
  font-size: 13px;
  font-variant-numeric: tabular-nums;
  color: var(--fg-subtle);
}

/* the controls dim while the next page is on its way */
.board-foot[aria-busy='true'] {
  opacity: 0.55;
}

@media (max-width: 380px) {
  .board-page {
    width: 100%;
    margin: 4px 0 0;
  }

  .board-foot {
    flex-wrap: wrap;
  }
}

/* the board's own page: one centred column, capped rather than run to the page
   measure — at the full width each side is nearly 700px and a host name ends up
   at the opposite end of the row from its score. Named for the page and not the
   board, because .board-page is already the "Page 2 of 18" label and a wrapper
   sharing that name hands its muted ink and 13px down to everything inside. */
.leaderboard {
  max-width: 1060px;
  margin: 0 auto;
}

/* the same size /checks sets "One scan to catch them all" at — a section
   heading, not the hero question .ask h1 is written for */
.leaderboard h1 {
  max-width: none;
  font-size: clamp(32px, 4.4vw, 48px);
  letter-spacing: -0.025em;
}

.board-wrap {
  margin-top: 34px;
}

/* ---- what goes wrong, on security-check -------------------------------- *
 *
 * Ordered by how many independent write-ups report it, so the rank is content,
 * not decoration: it stays visible and the list stays one column, top to bottom.
 */

.issues {
  margin: 0;
  padding: 0;
  list-style: none;
  counter-reset: issue;
}

.issues li {
  display: grid;
  grid-template-columns: 34px minmax(0, 1fr);
  column-gap: 14px;
  padding: 20px 0 22px;
  border-top: 1px solid var(--border);
}

.issues li:first-child {
  padding-top: 0;
  border-top: 0;
}

.issues li::before {
  counter-increment: issue;
  content: counter(issue, decimal-leading-zero);
  padding-top: 4px;
  font-family: 'Geist Mono', monospace;
  font-size: 11px;
  color: var(--fg-subtle);
}

.issues b {
  font-size: 16px;
  font-weight: 500;
  letter-spacing: -0.012em;
  color: var(--fg);
}

.issues span {
  grid-column: 2;
  max-width: 62ch;
  margin-top: 6px;
  font-size: 14.5px;
  line-height: 1.65;
  color: var(--fg-muted);
}

@media (max-width: 520px) {
  .issues li {
    grid-template-columns: 1fr;
    row-gap: 4px;
  }

  .issues li::before {
    padding-top: 0;
  }

  .issues span {
    grid-column: 1;
  }
}

/* ---- why it matters, on seo-ai-visibility-check ------------------------- */

.prose p {
  max-width: 64ch;
  font-size: 16.5px;
  line-height: 1.75;
  color: var(--fg-muted);
}

.prose p + p {
  margin-top: 20px;
}

/* ---- footer ------------------------------------------------------------ */

footer {
  padding: 96px 0 36px;
  border-top: 1px solid var(--border);
  background: var(--bg);
}

@media (max-width: 720px) {
  footer {
    padding-top: 64px;
  }
}

.foot-grid {
  display: grid;
  grid-template-columns: 2fr repeat(4, 1fr);
  gap: 40px;
}

@media (max-width: 820px) {
  .foot-grid {
    grid-template-columns: 1fr 1fr;
  }

  .foot-brand {
    grid-column: span 2;
  }
}

.foot-brand .brand {
  font-size: 18px;
}

.foot-brand p {
  max-width: 280px;
  margin-top: 12px;
  font-size: 13px;
}

.foot-col .foot-head {
  margin: 0 0 16px;
  font-family: 'Geist Mono', monospace;
  font-size: 11px;
  font-weight: 400;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--fg-subtle);
}

.foot-col ul {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.foot-col a {
  font-size: 13px;
  color: var(--fg-muted);
  transition: color 0.15s ease;
}

.foot-col a:hover {
  color: var(--fg);
}

/* a larger tap target — the footer nav is the primary nav on phones */
.foot-col li a {
  display: inline-block;
  padding: 5px 0;
}

.foot-bottom {
  display: flex;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 16px;
  margin-top: 56px;
  padding-top: 24px;
  border-top: 1px solid var(--border);
  font-family: 'Geist Mono', monospace;
  font-size: 12px;
  color: var(--fg-subtle);
}

.foot-bottom .status {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}

.foot-bottom .status .dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--safe);
  box-shadow: 0 0 0 3px rgb(107 142 90 / 18%);
  animation: pulse 2.4s infinite;
}

@keyframes pulse {
  0%,
  100% {
    opacity: 1;
  }

  50% {
    opacity: 0.35;
  }
}

/* ---- the one authored entrance ----------------------------------------- *
 *
 * The ask is above the fold on every reading, so it animates on its own frames
 * rather than waiting for an observer that has already fired by then.
 * Everything below it rides the shared .reveal.
 */

@keyframes lg-rise {
  from {
    opacity: 0;
    transform: translateY(14px);
  }

  to {
    opacity: 1;
    transform: none;
  }
}

/* not gated on .js: an animation needs no script, and gating it would hide the
   ask outright from a reader whose JavaScript never arrives */
.ask h1 {
  animation: lg-rise 1s cubic-bezier(0.2, 0.7, 0.2, 1) 0.05s both;
}

.ask .scan {
  animation: lg-rise 1.1s cubic-bezier(0.2, 0.7, 0.2, 1) 0.22s both;
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  .reveal,
  .js .reveal {
    opacity: 1;
    transform: none;
    transition: none;
  }

  .ask h1,
  .ask .scan {
    animation: none;
  }

  .nav-dd-menu,
  .nav-dd-t svg,
  .btn,
  .try,
  .step-ico,
  .foot-bottom .status .dot {
    transition: none;
    animation: none;
  }
}
