/* ==========================================================================
   InputTestHub — self-hosted webfonts
   ==========================================================================
   IBM Plex Sans and IBM Plex Mono, served from this origin. They used to come
   from fonts.googleapis.com, which made two third-party connections on every
   page and handed every visitor's IP address to Google — on a site whose whole
   argument is that nothing leaves your device, and which invites people to open
   their Network tab and check. These were the only third-party requests left.

   Generated from Google's own CSS2 response, URLs swapped for local ones and
   everything else kept verbatim, so rendering is unchanged. Latin and
   Latin Extended only; Cyrillic, Greek and Vietnamese are dropped because
   nothing on this site uses them.

   unicode-range is what makes this cheap: a visitor reading English fetches the
   two latin files and nothing else. The Latin Extended files are fetched only
   when a character in that range actually appears — usually pasted into a text
   tool rather than part of the interface.

   IBM Plex is licensed under the SIL Open Font License 1.1.
   https://github.com/IBM/plex — see assets/fonts/OFL.txt

   REPLACING A FONT FILE NEEDS A NEW FILENAME. These URLs sit inside a
   stylesheet, so they cannot carry ASSET_VER, and the files ship with a
   one-year immutable cache header like every other asset.
   ========================================================================== */

/* IBM Plex Mono 400 — latin-ext */
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/ibm-plex-mono-400-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;
}
/* IBM Plex Mono 400 — latin */
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/ibm-plex-mono-400-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;
}
/* IBM Plex Mono 500 — latin-ext */
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('../fonts/ibm-plex-mono-500-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;
}
/* IBM Plex Mono 500 — latin */
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('../fonts/ibm-plex-mono-500-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;
}
/* IBM Plex Sans 400 — latin-ext */
@font-face {
  font-family: 'IBM Plex Sans';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/ibm-plex-sans-400-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;
}
/* IBM Plex Sans 400 — latin */
@font-face {
  font-family: 'IBM Plex Sans';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/ibm-plex-sans-400-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;
}
/* IBM Plex Sans 500 — latin-ext */
@font-face {
  font-family: 'IBM Plex Sans';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('../fonts/ibm-plex-sans-400-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;
}
/* IBM Plex Sans 500 — latin */
@font-face {
  font-family: 'IBM Plex Sans';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('../fonts/ibm-plex-sans-400-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;
}
/* IBM Plex Sans 600 — latin-ext */
@font-face {
  font-family: 'IBM Plex Sans';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('../fonts/ibm-plex-sans-400-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;
}
/* IBM Plex Sans 600 — latin */
@font-face {
  font-family: 'IBM Plex Sans';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('../fonts/ibm-plex-sans-400-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;
}
/* IBM Plex Sans 700 — latin-ext */
@font-face {
  font-family: 'IBM Plex Sans';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('../fonts/ibm-plex-sans-400-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;
}
/* IBM Plex Sans 700 — latin */
@font-face {
  font-family: 'IBM Plex Sans';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('../fonts/ibm-plex-sans-400-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;
}

/* ==========================================================================
   InputTestHub — "Paper & Ink" design system
   Swiss utility: warm paper, near-black ink, one cobalt accent, hairline rules.
   Rules: 2-3px radii only. No gradients on surfaces. No glass blur. No shadows
   except one popover elevation. Numbers are always tabular. Labels are mono.
   ========================================================================== */

/* ---------- 1. Tokens ---------------------------------------------------- */

:root {
  /* surfaces */
  --paper:      #f7f6f2;
  --paper-sunk: #f0eee8;
  --card:       #fffefb;
  --card-alt:   #faf9f5;

  /* ink */
  --ink:        #111214;
  --ink-2:      #4c4d52;
  --ink-3:      #86868c;
  --ink-4:      #a8a8ac;

  /* lines */
  --line:       #e3e0d8;
  --line-2:     #d2cec2;
  --line-3:     #bcb7a8;

  /* accent */
  --accent:     #1b4dff;
  --accent-ink: #ffffff;
  --accent-2:   #123ad0;
  --wash:       #edf1ff;
  --wash-line:  #c9d5ff;

  /* semantic */
  --ok:      #0e7a4c;
  --ok-wash: #e6f4ec;
  --warn:      #a35c07;
  --warn-wash: #fbf0dd;
  --err:      #bb3320;
  --err-wash: #fbeae6;

  /* type */
  --sans: "IBM Plex Sans", ui-sans-serif, -apple-system, "Segoe UI", Roboto, sans-serif;
  --mono: "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;

  /* scale */
  --s1: 4px;  --s2: 8px;  --s3: 12px; --s4: 16px; --s5: 24px;
  --s6: 32px; --s7: 48px; --s8: 64px; --s9: 96px;

  --r:    3px;
  --r-sm: 2px;
  --shadow-pop: 0 1px 2px rgba(17,18,20,.06), 0 12px 32px -8px rgba(17,18,20,.18);

  --wrap: 1240px;
  --nav-h: 60px;

  --t-fast: 110ms cubic-bezier(.2,0,.15,1);
  --t-mid:  190ms cubic-bezier(.2,0,.15,1);
}

[data-theme="dark"] {
  --paper:      #0e0f11;
  --paper-sunk: #0a0b0c;
  --card:       #16181b;
  --card-alt:   #131518;

  --ink:        #eceae4;
  --ink-2:      #a3a4a3;
  --ink-3:      #7c7d7f;
  --ink-4:      #5d5f62;

  --line:       #24262a;
  --line-2:     #2f3237;
  --line-3:     #3c4046;

  --accent:     #6d8cff;
  --accent-ink: #0b0d14;
  --accent-2:   #8aa2ff;
  --wash:       #161c33;
  --wash-line:  #2a3560;

  --ok:      #46b98a;  --ok-wash:   #10231b;
  --warn:    #d6a04a;  --warn-wash: #241c0e;
  --err:     #e0705c;  --err-wash:  #2a1512;

  --shadow-pop: 0 1px 2px rgba(0,0,0,.5), 0 16px 40px -10px rgba(0,0,0,.7);
}

/* ---------- 2. Reset ----------------------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--nav-h) + 16px);
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

body {
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 16px;
  line-height: 1.6;
  font-feature-settings: "kern" 1, "liga" 1, "cv05" 1;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  /* barely-there paper tooth; disappears on dark */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='.028'/%3E%3C/svg%3E");
}
[data-theme="dark"] body { background-image: none; }

img, svg, video, canvas { display: block; max-width: 100%; }
svg { flex: none; }

/* The icons ship a 24-unit viewBox and no width/height attribute, so with no CSS
   size they fall back to the replaced-element default of 300px (capped by the
   max-width above) and render enormous — which is exactly what the category
   headings on the homepage did, at anything from 131px to 322px depending on how
   much room the container had. This is the floor for every .ico on the site; the
   scoped rules further down are all more specific and still win. Do not remove
   it because "every icon already has a size" — sixteen contexts do, and any new
   one that forgets is broken again. */
.ico { width: 18px; height: 18px; }
input, button, textarea, select { font: inherit; color: inherit; }
button { background: none; border: 0; cursor: pointer; }
a { color: inherit; text-decoration: none; }
table { border-collapse: collapse; width: 100%; }
::selection { background: var(--accent); color: var(--accent-ink); }

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--r-sm);
}

/* ---------- 3. Type ------------------------------------------------------ */

h1, h2, h3, h4 { font-weight: 600; line-height: 1.16; letter-spacing: -.021em; }
h1 { font-size: clamp(30px, 4.4vw, 46px); }
h2 { font-size: clamp(22px, 2.7vw, 30px); }
h3 { font-size: 19px; letter-spacing: -.013em; }
h4 { font-size: 16px; letter-spacing: -.008em; }

.lede { font-size: clamp(16px, 1.7vw, 19px); color: var(--ink-2); line-height: 1.55; max-width: 62ch; }
.prose p { max-width: 72ch; margin-bottom: var(--s4); color: var(--ink-2); }
.prose p strong { color: var(--ink); font-weight: 600; }
.prose ul, .prose ol { max-width: 72ch; margin: 0 0 var(--s4); padding-left: 20px; color: var(--ink-2); }
.prose li { margin-bottom: 6px; }
.prose h2 { margin: var(--s6) 0 var(--s3); }
.prose h3 { margin: var(--s5) 0 var(--s2); color: var(--ink); }
.prose a { color: var(--accent); text-decoration: underline; text-underline-offset: 3px; text-decoration-thickness: 1px; }
.prose a:hover { text-decoration-thickness: 2px; }

.eyebrow {
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.mono { font-family: var(--mono); font-variant-numeric: tabular-nums; }
.num  { font-variant-numeric: tabular-nums; font-feature-settings: "tnum" 1; }
.muted { color: var(--ink-3); }

/* ---------- 4. Layout ---------------------------------------------------- */

.wrap { width: 100%; max-width: var(--wrap); margin-inline: auto; padding-inline: 20px; }
@media (max-width: 640px) { .wrap { padding-inline: 16px; } }

main { flex: 1 0 auto; }
.section { padding-block: var(--s7); }
.section--tight { padding-block: var(--s6); }
.rule { height: 1px; background: var(--line); border: 0; }

.sec-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--s4); flex-wrap: wrap;
  padding-bottom: var(--s3);
  margin-bottom: var(--s5);
  border-bottom: 1px solid var(--line);
}
.sec-head h2 { font-size: 22px; }
/* Homepage category headings: the glyph sits with the title, so align it to the
   text rather than the baseline the parent uses, and let the accent carry it. */
.sec-head .flex { align-self: center; }
.sec-head .flex > .ico { width: 20px; height: 20px; color: var(--accent); }
.sec-head .link-more { font-family: var(--mono); font-size: 12px; color: var(--ink-3); letter-spacing: .04em; display: inline-flex; align-items: center; gap: 6px; }
.sec-head .link-more:hover { color: var(--accent); }
.sec-head .link-more .ico { width: 14px; height: 14px; transition: transform var(--t-fast); }
.sec-head .link-more:hover .ico { transform: translateX(3px); }

/* ---------- 5. Header ---------------------------------------------------- */

.top {
  position: sticky; top: 0; z-index: 60;
  background: color-mix(in srgb, var(--paper) 88%, transparent);
  backdrop-filter: saturate(180%) blur(12px);
  border-bottom: 1px solid var(--line);
}
.top__in { display: flex; align-items: center; gap: var(--s5); height: var(--nav-h); }

.brand { display: inline-flex; align-items: center; gap: 9px; flex: none; }
.brand__mark {
  width: 26px; height: 26px; border-radius: var(--r-sm);
  background: var(--ink); color: var(--paper);
  display: grid; place-items: center;
  font-family: var(--mono); font-size: 13px; font-weight: 600; letter-spacing: -.04em;
}
.brand__name { font-weight: 600; font-size: 16px; letter-spacing: -.025em; }
.brand__name b { font-weight: 600; }
.brand__name span { color: var(--ink-3); font-weight: 400; }

.nav { display: flex; align-items: center; gap: 2px; margin-left: auto; }
.nav a {
  font-size: 14px; color: var(--ink-2); padding: 7px 11px; border-radius: var(--r-sm);
  transition: color var(--t-fast), background var(--t-fast);
}
.nav a:hover { color: var(--ink); background: var(--paper-sunk); }
.nav a.is-on { color: var(--ink); font-weight: 500; }

.searchbtn {
  display: inline-flex; align-items: center; gap: 8px;
  height: 34px; padding: 0 9px 0 10px;
  border: 1px solid var(--line-2); border-radius: var(--r);
  background: var(--card); color: var(--ink-3);
  font-size: 13px; min-width: 190px;
  transition: border-color var(--t-fast), color var(--t-fast);
}
.searchbtn:hover { border-color: var(--line-3); color: var(--ink-2); }
.searchbtn .ico { width: 15px; height: 15px; }
.searchbtn kbd { margin-left: auto; }
kbd {
  font-family: var(--mono); font-size: 10.5px; line-height: 1;
  padding: 3px 5px; border: 1px solid var(--line-2); border-bottom-width: 2px;
  border-radius: 3px; background: var(--paper-sunk); color: var(--ink-3);
}

.iconbtn {
  width: 34px; height: 34px; display: grid; place-items: center;
  border: 1px solid transparent; border-radius: var(--r); color: var(--ink-2);
  transition: background var(--t-fast), color var(--t-fast), border-color var(--t-fast);
}
.iconbtn:hover { background: var(--paper-sunk); color: var(--ink); border-color: var(--line); }
.iconbtn .ico { width: 18px; height: 18px; }
[data-theme="dark"] .theme-sun { display: none; }
:root:not([data-theme="dark"]) .theme-moon { display: none; }

.burger { display: none; }
@media (max-width: 900px) {
  .nav { display: none; }
  .searchbtn { min-width: 0; }
  .searchbtn span, .searchbtn kbd { display: none; }
  .searchbtn { width: 34px; justify-content: center; padding: 0; }
  .burger { display: grid; }
}

/* mobile drawer */
.drawer {
  position: fixed; inset: var(--nav-h) 0 0; z-index: 55;
  background: var(--paper); border-top: 1px solid var(--line);
  padding: var(--s4) 0 var(--s7); overflow-y: auto;
  display: none;
}
.drawer.is-open { display: block; }
.drawer a {
  display: flex; align-items: center; gap: 10px;
  padding: 12px 0; border-bottom: 1px solid var(--line); color: var(--ink);
}
.drawer a .ico { width: 17px; height: 17px; color: var(--ink-3); }
.drawer a small { margin-left: auto; font-family: var(--mono); font-size: 11px; color: var(--ink-4); }

/* ---------- 6. Buttons --------------------------------------------------- */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  height: 40px; padding: 0 16px;
  border: 1px solid var(--ink); border-radius: var(--r);
  background: var(--ink); color: var(--paper);
  font-size: 14px; font-weight: 500; letter-spacing: -.005em;
  white-space: nowrap;
  transition: background var(--t-fast), border-color var(--t-fast), color var(--t-fast), transform var(--t-fast);
}
.btn:hover { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
.btn:active { transform: translateY(1px); }
.btn .ico { width: 16px; height: 16px; }

.btn--ghost { background: transparent; color: var(--ink); border-color: var(--line-2); }
.btn--ghost:hover { background: var(--card); border-color: var(--ink); color: var(--ink); }
.btn--accent { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
.btn--accent:hover { background: var(--accent-2); border-color: var(--accent-2); }
.btn--sm { height: 32px; padding: 0 11px; font-size: 13px; }
.btn--block { width: 100%; }
.btn[disabled] { opacity: .45; pointer-events: none; }

.btnrow { display: flex; flex-wrap: wrap; gap: var(--s2); }

/* ---------- 7. Tool cards ------------------------------------------------ */

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(268px, 1fr));
  gap: -1px;
  border: 1px solid var(--line);
  border-radius: var(--r);
  overflow: hidden;
  background: var(--line);
  gap: 1px;
}
.grid--3 { grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); }

.tcard {
  position: relative;
  display: flex; flex-direction: column; gap: 6px;
  padding: 16px 16px 15px;
  background: var(--card);
  transition: background var(--t-fast);
  min-height: 108px;
}
.tcard:hover { background: var(--card-alt); }
.tcard:hover .tcard__go { opacity: 1; transform: none; }
.tcard__top { display: flex; align-items: center; gap: 8px; }
.tcard__idx {
  font-family: var(--mono); font-size: 10.5px; letter-spacing: .06em;
  color: var(--ink-4); font-variant-numeric: tabular-nums;
}
.tcard__cat {
  margin-left: auto; font-family: var(--mono); font-size: 10px;
  letter-spacing: .1em; text-transform: uppercase; color: var(--ink-4);
}
.tcard__name { font-size: 15.5px; font-weight: 600; letter-spacing: -.014em; line-height: 1.3; }
/* Stretched link: the overlay must belong to the <a>, not to the heading, and
   needs z-index so it sits above siblings that come later in the DOM.
   On the heading it covers the whole card and swallows every click without
   navigating anywhere — the card looks clickable and does nothing. */
.tcard__name a::after { content: ""; position: absolute; inset: 0; z-index: 1; }
.tcard__desc {
  font-size: 13px; line-height: 1.5; color: var(--ink-3);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.tcard__go {
  position: absolute; right: 14px; bottom: 13px;
  width: 16px; height: 16px; color: var(--accent);
  opacity: 0; transform: translateX(-4px);
  transition: opacity var(--t-fast), transform var(--t-fast);
}
.tcard--hot .tcard__idx { color: var(--accent); }

/* dense list variant for category index */
.tlist { border: 1px solid var(--line); border-radius: var(--r); overflow: hidden; background: var(--card); }
.tlist a {
  display: flex; align-items: center; gap: 12px;
  padding: 11px 14px; border-bottom: 1px solid var(--line);
  transition: background var(--t-fast);
}
.tlist a:last-child { border-bottom: 0; }
.tlist a:hover { background: var(--card-alt); }
.tlist a:hover .tlist__n { color: var(--accent); }
.tlist__i { font-family: var(--mono); font-size: 11px; color: var(--ink-4); width: 30px; flex: none; }
.tlist__n { font-size: 14.5px; font-weight: 500; flex: none; transition: color var(--t-fast); }
.tlist__d { font-size: 13px; color: var(--ink-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@media (max-width: 700px) { .tlist__d { display: none; } }

/* ---------- 8. Category tiles -------------------------------------------- */

.cats { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 1px; background: var(--line); border: 1px solid var(--line); border-radius: var(--r); overflow: hidden; }
.cat {
  position: relative; display: flex; flex-direction: column; gap: 10px;
  padding: 20px 18px 18px; background: var(--card);
  transition: background var(--t-fast);
}
.cat:hover { background: var(--card-alt); }
.cat__hd { display: flex; align-items: center; gap: 10px; }
.cat__ico { width: 20px; height: 20px; color: var(--accent); }
.cat__n { font-size: 16px; font-weight: 600; letter-spacing: -.017em; }
.cat__n a::after { content: ""; position: absolute; inset: 0; z-index: 1; }
.cat__c { margin-left: auto; font-family: var(--mono); font-size: 11px; color: var(--ink-4); }
.cat__d { font-size: 13.5px; color: var(--ink-3); line-height: 1.5; }
.cat__peek { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 2px; }
.cat__peek span {
  font-family: var(--mono); font-size: 10.5px; color: var(--ink-3);
  border: 1px solid var(--line); border-radius: 2px; padding: 2px 6px;
}

/* ---------- 8b. A-Z index list ------------------------------------------- */
/* /tools/ used to render all 1,584 tools as .tcard articles: 1,170 KB of HTML and
   1,584 multi-element cards to lay out. An index should be an index, so it is a
   dense link list now. Every tool keeps its link — that shallow path is what
   offsets the extra click the converter sub-hubs added. */
.azlist { display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: 0 22px; list-style: none; }
.azlist li { display: flex; align-items: baseline; gap: 10px; padding: 6px 0; border-bottom: 1px solid var(--line); }
.azlist a { font-size: 14px; color: var(--ink-2); }
.azlist a:hover { color: var(--accent); }
.azlist .azlist__c { margin-left: auto; font-family: var(--mono); font-size: 10px; color: var(--ink-4); white-space: nowrap; }

/* ---------- 9. Hero ------------------------------------------------------ */

.hero { padding-block: var(--s8) var(--s7); border-bottom: 1px solid var(--line); }
.hero__grid { display: grid; grid-template-columns: minmax(0,1.15fr) minmax(0,.85fr); gap: var(--s7); align-items: end; }
@media (max-width: 900px) { .hero__grid { grid-template-columns: 1fr; gap: var(--s5); } .hero { padding-block: var(--s6) var(--s6); } }
.hero h1 { max-width: 15ch; }
.hero h1 em { font-style: normal; color: var(--accent); }
.hero .lede { margin-top: var(--s4); }
.hero__cta { margin-top: var(--s5); }

.stats { display: grid; grid-template-columns: repeat(2, 1fr); gap: 1px; background: var(--line); border: 1px solid var(--line); border-radius: var(--r); overflow: hidden; }
.stat { background: var(--card); padding: 16px 16px 14px; }
.stat__v { font-size: 26px; font-weight: 600; letter-spacing: -.03em; font-variant-numeric: tabular-nums; line-height: 1.1; }
.stat__l { font-family: var(--mono); font-size: 10.5px; letter-spacing: .1em; text-transform: uppercase; color: var(--ink-4); margin-top: 5px; }

/* big search on hero */
.hsearch { position: relative; margin-top: var(--s5); max-width: 560px; }
.hsearch input {
  width: 100%; height: 52px; padding: 0 108px 0 44px;
  border: 1px solid var(--line-2); border-radius: var(--r);
  background: var(--card); font-size: 15.5px;
  transition: border-color var(--t-fast), box-shadow var(--t-fast);
}
.hsearch input:focus { outline: none; border-color: var(--ink); box-shadow: 0 0 0 3px var(--wash); }
.hsearch input::placeholder { color: var(--ink-4); }
.hsearch .ico-l { position: absolute; left: 15px; top: 17px; width: 18px; height: 18px; color: var(--ink-3); pointer-events: none; }
.hsearch .btn { position: absolute; right: 6px; top: 6px; height: 40px; }
.hsearch__hint { margin-top: 10px; font-size: 12.5px; color: var(--ink-4); display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }
.hsearch__hint a { color: var(--ink-3); border-bottom: 1px solid var(--line-2); }
.hsearch__hint a:hover { color: var(--accent); border-color: var(--accent); }

/* ---------- 10. Marquee strip -------------------------------------------- */

.strip { border-bottom: 1px solid var(--line); background: var(--card); overflow: hidden; }
.strip__in { display: flex; gap: 0; align-items: stretch; }
.strip__lab {
  flex: none; display: flex; align-items: center; padding: 0 14px;
  border-right: 1px solid var(--line); background: var(--paper-sunk);
  /* The opaque background is here to hide the track sliding past underneath, but
     both siblings were static, so paint order followed the DOM and the track drew
     straight over the label — tool names collided with the words "Most opened".
     Lifting the label onto its own layer is what makes the mask actually mask. */
  position: relative; z-index: 1;
}
.strip__track { display: flex; gap: 0; animation: slide 46s linear infinite; }
.strip:hover .strip__track { animation-play-state: paused; }
.strip__track a {
  flex: none; display: flex; align-items: center; gap: 8px;
  padding: 10px 16px; font-size: 13px; color: var(--ink-2);
  border-right: 1px solid var(--line); white-space: nowrap;
}
.strip__track a:hover { color: var(--accent); background: var(--card-alt); }
.strip__track a i { font-family: var(--mono); font-style: normal; font-size: 10.5px; color: var(--ink-4); }
@keyframes slide { from { transform: translateX(0); } to { transform: translateX(-50%); } }

/* ---------- 11. Breadcrumbs ---------------------------------------------- */

.crumbs { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; padding-block: var(--s4) 0; font-size: 12.5px; color: var(--ink-4); }
.crumbs a { color: var(--ink-3); }
.crumbs a:hover { color: var(--accent); }
.crumbs span.sep { color: var(--line-3); }

/* ---------- 12. Tool page ------------------------------------------------ */

.toolhd { padding-block: var(--s4) var(--s5); border-bottom: 1px solid var(--line); }
.toolhd__row { display: flex; align-items: flex-start; gap: var(--s4); flex-wrap: wrap; }
.toolhd h1 { font-size: clamp(26px, 3.4vw, 36px); }
.toolhd .lede { margin-top: 10px; font-size: 16px; }
.toolhd__side { margin-left: auto; display: flex; gap: var(--s2); align-items: center; }

.badges { display: flex; flex-wrap: wrap; gap: 6px; margin-top: var(--s3); }
.badge {
  display: inline-flex; align-items: center; gap: 5px;
  font-family: var(--mono); font-size: 10.5px; letter-spacing: .07em; text-transform: uppercase;
  padding: 4px 8px; border: 1px solid var(--line-2); border-radius: 2px; color: var(--ink-3);
}
.badge .ico { width: 12px; height: 12px; }
.badge--ok { color: var(--ok); border-color: color-mix(in srgb, var(--ok) 35%, transparent); background: var(--ok-wash); }
.badge--accent { color: var(--accent); border-color: var(--wash-line); background: var(--wash); }

.toolwrap { display: grid; grid-template-columns: minmax(0,1fr) 300px; gap: var(--s6); padding-block: var(--s5) var(--s7); align-items: start; }
/* minmax(0,1fr), not a bare 1fr: a bare 1fr is minmax(auto,1fr), whose auto
   minimum is the track's MIN-CONTENT width. A wide table then pushes the column
   past the viewport and the whole page scrolls sideways on a phone. The desktop
   rule above already guards against it; this one did not. */
@media (max-width: 1000px) { .toolwrap { grid-template-columns: minmax(0,1fr); } }

.aside { position: sticky; top: calc(var(--nav-h) + 20px); display: flex; flex-direction: column; gap: var(--s4); }
@media (max-width: 1000px) { .aside { position: static; } }
.panel { border: 1px solid var(--line); border-radius: var(--r); background: var(--card); overflow: hidden; }
.panel__hd { padding: 10px 14px; border-bottom: 1px solid var(--line); background: var(--card-alt); display: flex; align-items: center; gap: 8px; }
.panel__bd { padding: 14px; }
.panel__bd--flush { padding: 0; }

/* ---------- 13. Tool UI shell -------------------------------------------- */

.tool {
  border: 1px solid var(--line-2); border-radius: var(--r);
  background: var(--card); overflow: hidden;
}
.tool__bar {
  display: flex; align-items: center; gap: var(--s2); flex-wrap: wrap;
  padding: 10px 14px; border-bottom: 1px solid var(--line); background: var(--card-alt);
}
.tool__bar .eyebrow { margin-right: auto; }
.tool__body { padding: var(--s4); display: flex; flex-direction: column; gap: var(--s4); }
.tool__split { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s4); }
@media (max-width: 820px) { .tool__split { grid-template-columns: 1fr; } }

.field { display: flex; flex-direction: column; gap: 6px; }
.field > label, .lab {
  font-family: var(--mono); font-size: 10.5px; letter-spacing: .1em;
  text-transform: uppercase; color: var(--ink-3);
  display: flex; align-items: center; gap: 6px;
}
.field .hint { font-size: 12px; color: var(--ink-4); }

.inp, textarea.inp, select.inp {
  width: 100%; padding: 10px 12px; min-height: 40px;
  border: 1px solid var(--line-2); border-radius: var(--r);
  background: var(--paper); color: var(--ink); font-size: 14.5px;
  transition: border-color var(--t-fast), box-shadow var(--t-fast), background var(--t-fast);
}
.inp:focus, textarea.inp:focus, select.inp:focus {
  outline: none; border-color: var(--ink); background: var(--card); box-shadow: 0 0 0 3px var(--wash);
}
.inp[readonly] { background: var(--paper-sunk); color: var(--ink-2); }
textarea.inp { min-height: 180px; resize: vertical; line-height: 1.6; }
textarea.code, .inp.code, pre.code { font-family: var(--mono); font-size: 13.5px; line-height: 1.62; }
select.inp {
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%2386868c' stroke-width='2.4' stroke-linecap='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 12px center; padding-right: 34px;
}
.inp.num-in { font-variant-numeric: tabular-nums; }

.row { display: grid; gap: var(--s3); }
.row-2 { grid-template-columns: 1fr 1fr; }
.row-3 { grid-template-columns: repeat(3, 1fr); }
.row-4 { grid-template-columns: repeat(4, 1fr); }
@media (max-width: 760px) { .row-3, .row-4 { grid-template-columns: 1fr 1fr; } }
@media (max-width: 460px) { .row-2, .row-3, .row-4 { grid-template-columns: 1fr; } }

/* segmented control */
.seg { display: inline-flex; border: 1px solid var(--line-2); border-radius: var(--r); overflow: hidden; background: var(--paper); }
.seg button {
  padding: 7px 12px; font-size: 13px; color: var(--ink-2);
  border-right: 1px solid var(--line); transition: background var(--t-fast), color var(--t-fast);
}
.seg button:last-child { border-right: 0; }
.seg button:hover { background: var(--card-alt); color: var(--ink); }
.seg button.is-on { background: var(--ink); color: var(--paper); }

/* checkbox / radio */
.check { display: inline-flex; align-items: center; gap: 8px; font-size: 13.5px; color: var(--ink-2); cursor: pointer; }
.check input { appearance: none; width: 16px; height: 16px; border: 1px solid var(--line-3); border-radius: 2px; background: var(--paper); flex: none; transition: background var(--t-fast), border-color var(--t-fast); }
.check input:checked { background: var(--accent); border-color: var(--accent); background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='3.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12.5l4.5 4.5L19 7.5'/%3E%3C/svg%3E"); background-size: 12px; background-position: center; background-repeat: no-repeat; }
.check input[type="radio"] { border-radius: 50%; }
.checks { display: flex; flex-wrap: wrap; gap: var(--s3) var(--s5); }

/* range */
input[type="range"] { -webkit-appearance: none; appearance: none; width: 100%; height: 22px; background: transparent; }
input[type="range"]::-webkit-slider-runnable-track { height: 3px; background: var(--line-2); border-radius: 2px; }
input[type="range"]::-webkit-slider-thumb { -webkit-appearance: none; width: 15px; height: 15px; margin-top: -6px; border-radius: 50%; background: var(--ink); border: 2px solid var(--card); box-shadow: 0 0 0 1px var(--line-3); }
input[type="range"]::-moz-range-track { height: 3px; background: var(--line-2); border-radius: 2px; }
input[type="range"]::-moz-range-thumb { width: 13px; height: 13px; border-radius: 50%; background: var(--ink); border: 2px solid var(--card); }

/* ---------- 14. Results -------------------------------------------------- */

.res { border: 1px solid var(--line); border-radius: var(--r); background: var(--paper-sunk); overflow: hidden; }
.res__hd { display: flex; align-items: center; gap: var(--s2); padding: 9px 13px; border-bottom: 1px solid var(--line); background: var(--card-alt); }
.res__hd .eyebrow { margin-right: auto; }
.res__bd { padding: var(--s4); }

.hero-num { font-size: clamp(30px, 5vw, 44px); font-weight: 600; letter-spacing: -.035em; font-variant-numeric: tabular-nums; line-height: 1.05; }
.hero-num small { font-size: 15px; font-weight: 500; color: var(--ink-3); letter-spacing: 0; margin-left: 6px; }
.hero-sub { font-size: 13.5px; color: var(--ink-3); margin-top: 6px; }

.stats-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 1px; background: var(--line); border: 1px solid var(--line); border-radius: var(--r); overflow: hidden; }
.stats-grid .cell { background: var(--card); padding: 13px 14px; }
.stats-grid .cell b { display: block; font-size: 21px; font-weight: 600; letter-spacing: -.025em; font-variant-numeric: tabular-nums; }
.stats-grid .cell span { display: block; font-family: var(--mono); font-size: 10px; letter-spacing: .1em; text-transform: uppercase; color: var(--ink-4); margin-top: 4px; }

.kv { width: 100%; font-size: 14px; }
.kv tr { border-bottom: 1px solid var(--line); }
.kv tr:last-child { border-bottom: 0; }
.kv th { text-align: left; font-weight: 400; color: var(--ink-3); padding: 8px 0; font-size: 13.5px; }
.kv td { text-align: right; padding: 8px 0; font-variant-numeric: tabular-nums; font-weight: 500; }
.kv td.mono { font-family: var(--mono); font-size: 13px; }

.dtable { font-size: 13.5px; }
.dtable th { text-align: left; font-family: var(--mono); font-size: 10.5px; letter-spacing: .09em; text-transform: uppercase; color: var(--ink-4); padding: 8px 10px; border-bottom: 1px solid var(--line-2); white-space: nowrap; }
.dtable td { padding: 8px 10px; border-bottom: 1px solid var(--line); font-variant-numeric: tabular-nums; }
.dtable tr:hover td { background: var(--card-alt); }
.dtable td.r, .dtable th.r { text-align: right; }
.tablescroll { overflow-x: auto; border: 1px solid var(--line); border-radius: var(--r); background: var(--card); }

pre.out {
  margin: 0; padding: 14px; overflow: auto; max-height: 460px;
  font-family: var(--mono); font-size: 13px; line-height: 1.62;
  background: var(--paper-sunk); border: 1px solid var(--line); border-radius: var(--r);
  white-space: pre-wrap; word-break: break-word;
}
pre.out.is-empty { color: var(--ink-4); }

.note { display: flex; gap: 9px; padding: 11px 13px; border: 1px solid var(--line-2); border-left-width: 3px; border-radius: var(--r); font-size: 13.5px; color: var(--ink-2); background: var(--card); }
.note .ico { width: 16px; height: 16px; flex: none; margin-top: 2px; color: var(--ink-3); }
.note--ok   { border-left-color: var(--ok);   background: var(--ok-wash); }
.note--warn { border-left-color: var(--warn); background: var(--warn-wash); }
.note--err  { border-left-color: var(--err);  background: var(--err-wash); }
.note--err .ico, .note--err { color: var(--err); }

/* chips of generated output (titles, tags, hashtags) */
.chips { display: flex; flex-wrap: wrap; gap: 6px; }
.chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 9px; border: 1px solid var(--line-2); border-radius: 2px;
  background: var(--card); font-size: 13px; cursor: pointer;
  transition: border-color var(--t-fast), color var(--t-fast);
}
.chip:hover { border-color: var(--accent); color: var(--accent); }
.chip.is-copied { border-color: var(--ok); color: var(--ok); }

.olist { display: flex; flex-direction: column; gap: 1px; background: var(--line); border: 1px solid var(--line); border-radius: var(--r); overflow: hidden; }
.olist__i { display: flex; gap: 12px; padding: 11px 13px; background: var(--card); align-items: flex-start; }
.olist__i:hover { background: var(--card-alt); }
.olist__n { font-family: var(--mono); font-size: 11px; color: var(--ink-4); flex: none; padding-top: 3px; width: 22px; }
.olist__t { flex: 1; font-size: 14.5px; line-height: 1.5; }
.olist__t em { font-style: normal; color: var(--ink-3); font-size: 12.5px; display: block; margin-top: 3px; }
.olist__c { flex: none; opacity: 0; transition: opacity var(--t-fast); }
.olist__i:hover .olist__c { opacity: 1; }

/* dropzone */
.drop {
  border: 1px dashed var(--line-3); border-radius: var(--r);
  padding: var(--s7) var(--s4); text-align: center; background: var(--paper);
  transition: border-color var(--t-fast), background var(--t-fast);
  cursor: pointer;
}
.drop:hover, .drop.is-over { border-color: var(--accent); background: var(--wash); }
.drop .ico { width: 26px; height: 26px; margin: 0 auto 10px; color: var(--ink-3); }
.drop b { display: block; font-size: 15px; font-weight: 600; }
.drop span { display: block; font-size: 13px; color: var(--ink-3); margin-top: 4px; }

.filelist { display: flex; flex-direction: column; gap: 1px; background: var(--line); border: 1px solid var(--line); border-radius: var(--r); overflow: hidden; }
.filerow { display: flex; align-items: center; gap: 10px; padding: 10px 12px; background: var(--card); font-size: 13.5px; }
.filerow .ico { width: 16px; height: 16px; color: var(--ink-3); flex: none; }
.filerow .nm { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.filerow .sz { font-family: var(--mono); font-size: 11.5px; color: var(--ink-4); }
.filerow .x { color: var(--ink-4); display: grid; place-items: center; width: 22px; height: 22px; border-radius: 2px; }
.filerow .x:hover { color: var(--err); background: var(--err-wash); }

.thumbgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: var(--s3); }
.thumb { border: 1px solid var(--line); border-radius: var(--r); overflow: hidden; background: var(--card); }
.thumb img, .thumb canvas { width: 100%; height: 120px; object-fit: contain; background: var(--paper-sunk); }
.thumb figcaption { padding: 8px 10px; font-size: 12px; color: var(--ink-3); border-top: 1px solid var(--line); display: flex; justify-content: space-between; gap: 8px; }

/* colour swatches */
.swatches { display: grid; grid-template-columns: repeat(auto-fill, minmax(92px, 1fr)); gap: var(--s2); }
.sw { border: 1px solid var(--line); border-radius: var(--r); overflow: hidden; cursor: pointer; }
.sw__c { height: 62px; }
.sw__t { padding: 6px 8px; font-family: var(--mono); font-size: 11px; text-align: center; background: var(--card); border-top: 1px solid var(--line); }

/* ---------- 15. FAQ / accordion ------------------------------------------ */

.faq { border-top: 1px solid var(--line); }
.faq details { border-bottom: 1px solid var(--line); }
.faq summary {
  list-style: none; cursor: pointer; padding: 15px 34px 15px 0; position: relative;
  font-size: 15.5px; font-weight: 500; letter-spacing: -.01em;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: ""; position: absolute; right: 6px; top: 21px;
  width: 10px; height: 10px; border-right: 1.6px solid var(--ink-3); border-bottom: 1.6px solid var(--ink-3);
  transform: rotate(45deg); transition: transform var(--t-mid);
}
.faq details[open] summary::after { transform: rotate(225deg); top: 24px; }
.faq summary:hover { color: var(--accent); }
.faq__a { padding: 0 0 17px; color: var(--ink-2); font-size: 14.5px; max-width: 74ch; }

/* the AEO "direct answer" block */
.answer {
  border: 1px solid var(--wash-line); border-left-width: 3px;
  background: var(--wash); border-radius: var(--r);
  padding: 14px 16px; font-size: 15px; color: var(--ink); max-width: 78ch;
}
.answer .eyebrow { color: var(--accent); margin-bottom: 6px; display: block; }

/* ---------- 16. Steps ---------------------------------------------------- */

.steps { counter-reset: st; display: flex; flex-direction: column; gap: 1px; background: var(--line); border: 1px solid var(--line); border-radius: var(--r); overflow: hidden; }
.steps li { counter-increment: st; list-style: none; display: flex; gap: 12px; padding: 12px 14px; background: var(--card); font-size: 14.5px; color: var(--ink-2); }
.steps li::before {
  content: counter(st, decimal-leading-zero);
  font-family: var(--mono); font-size: 11px; color: var(--accent); flex: none; padding-top: 3px;
}

/* ---------- 17. Command palette ------------------------------------------ */

.cmdk { position: fixed; inset: 0; z-index: 200; display: none; }
.cmdk.is-open { display: block; }
.cmdk__scrim { position: absolute; inset: 0; background: rgba(17,18,20,.32); backdrop-filter: blur(2px); }
[data-theme="dark"] .cmdk__scrim { background: rgba(0,0,0,.6); }
.cmdk__box {
  position: relative; width: min(640px, calc(100% - 32px)); margin: 9vh auto 0;
  background: var(--card); border: 1px solid var(--line-2); border-radius: 5px;
  box-shadow: var(--shadow-pop); overflow: hidden;
  animation: pop var(--t-mid);
}
@keyframes pop { from { opacity: 0; transform: translateY(-6px) scale(.99); } }
.cmdk__in { display: flex; align-items: center; gap: 10px; padding: 0 14px; border-bottom: 1px solid var(--line); }
.cmdk__in .ico { width: 17px; height: 17px; color: var(--ink-3); }
.cmdk__in input { flex: 1; height: 52px; border: 0; background: transparent; font-size: 16px; }
.cmdk__in input:focus { outline: none; }
.cmdk__list { max-height: min(420px, 56vh); overflow-y: auto; padding: 6px; }
.cmdk__grp { font-family: var(--mono); font-size: 10px; letter-spacing: .11em; text-transform: uppercase; color: var(--ink-4); padding: 9px 10px 5px; }
.cmdk__i { display: flex; align-items: center; gap: 10px; padding: 9px 10px; border-radius: var(--r-sm); cursor: pointer; }
.cmdk__i .ico { width: 15px; height: 15px; color: var(--ink-3); flex: none; }
.cmdk__i b { font-weight: 500; font-size: 14.5px; }
.cmdk__i em { font-style: normal; font-size: 12.5px; color: var(--ink-4); margin-left: auto; font-family: var(--mono); }
.cmdk__i.is-sel { background: var(--wash); }
.cmdk__i.is-sel .ico, .cmdk__i.is-sel b { color: var(--accent); }
.cmdk__ft { display: flex; align-items: center; gap: 14px; padding: 9px 14px; border-top: 1px solid var(--line); background: var(--card-alt); font-size: 11.5px; color: var(--ink-4); }
.cmdk__ft span { display: inline-flex; align-items: center; gap: 5px; }
.cmdk__empty { padding: 28px 14px; text-align: center; color: var(--ink-4); font-size: 14px; }

/* ---------- 18. Footer --------------------------------------------------- */

.foot { border-top: 1px solid var(--line); background: var(--card); margin-top: var(--s8); }
.foot__grid { display: grid; grid-template-columns: 1.4fr repeat(4, 1fr); gap: var(--s5); padding-block: var(--s7) var(--s6); }
@media (max-width: 980px) { .foot__grid { grid-template-columns: 1fr 1fr; gap: var(--s5); } }
@media (max-width: 560px) { .foot__grid { grid-template-columns: 1fr; } }
.foot h4 { font-family: var(--mono); font-size: 10.5px; letter-spacing: .11em; text-transform: uppercase; color: var(--ink-4); font-weight: 500; margin-bottom: 12px; }
.foot ul { list-style: none; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.foot a { font-size: 13.5px; color: var(--ink-2); }
.foot a:hover { color: var(--accent); }
.foot__about p { font-size: 13.5px; color: var(--ink-3); max-width: 34ch; margin-top: 12px; }
.foot__bar { border-top: 1px solid var(--line); padding-block: 16px; display: flex; gap: var(--s4); flex-wrap: wrap; align-items: center; font-size: 12.5px; color: var(--ink-4); }
.foot__bar nav { margin-left: auto; display: flex; gap: var(--s4); flex-wrap: wrap; }

/* ---------- 19. Misc ----------------------------------------------------- */

.pillrow { display: flex; gap: 6px; flex-wrap: wrap; }
.pill {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 11px; border: 1px solid var(--line-2); border-radius: 100px;
  font-size: 13px; color: var(--ink-2); background: var(--card);
  transition: border-color var(--t-fast), color var(--t-fast);
}
.pill:hover { border-color: var(--ink); color: var(--ink); }
.pill.is-on { background: var(--ink); border-color: var(--ink); color: var(--paper); }

.az { display: flex; flex-wrap: wrap; gap: 4px; }
.az a { width: 30px; height: 30px; display: grid; place-items: center; border: 1px solid var(--line); border-radius: 2px; font-family: var(--mono); font-size: 12px; color: var(--ink-2); }
.az a:hover { border-color: var(--ink); color: var(--ink); }

.copybtn { display: inline-flex; align-items: center; gap: 6px; font-family: var(--mono); font-size: 11px; letter-spacing: .06em; text-transform: uppercase; color: var(--ink-3); padding: 5px 8px; border: 1px solid var(--line-2); border-radius: 2px; transition: all var(--t-fast); }
.copybtn:hover { color: var(--ink); border-color: var(--ink); }
.copybtn.is-done { color: var(--ok); border-color: var(--ok); }
.copybtn .ico { width: 13px; height: 13px; }

.toast {
  position: fixed; left: 50%; bottom: 26px; transform: translateX(-50%) translateY(10px);
  background: var(--ink); color: var(--paper); padding: 10px 16px; border-radius: var(--r);
  font-size: 13.5px; z-index: 300; opacity: 0; pointer-events: none;
  transition: opacity var(--t-mid), transform var(--t-mid);
}
.toast.is-on { opacity: 1; transform: translateX(-50%); }

.skip { position: absolute; left: -9999px; }
.skip:focus { left: 12px; top: 12px; z-index: 400; background: var(--ink); color: var(--paper); padding: 10px 14px; border-radius: var(--r); }

.pager { display: flex; gap: 6px; justify-content: center; align-items: center; margin-top: var(--s6); flex-wrap: wrap; }
.pager a, .pager span { min-width: 34px; height: 34px; padding: 0 10px; display: grid; place-items: center; border: 1px solid var(--line); border-radius: var(--r-sm); font-size: 13.5px; font-variant-numeric: tabular-nums; }
.pager a:hover { border-color: var(--ink); }
.pager .is-on { background: var(--ink); color: var(--paper); border-color: var(--ink); }

.adslot { margin-block: var(--s5); min-height: 90px; display: grid; place-items: center; }

.empty { text-align: center; padding: var(--s8) var(--s4); color: var(--ink-3); }
.empty .ico { width: 30px; height: 30px; margin: 0 auto var(--s3); color: var(--ink-4); }

.spin { width: 15px; height: 15px; border: 2px solid var(--line-3); border-top-color: var(--accent); border-radius: 50%; animation: spin .7s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }

.is-hidden { display: none !important; }
.nowrap { white-space: nowrap; }
.mt2 { margin-top: var(--s2); } .mt3 { margin-top: var(--s3); } .mt4 { margin-top: var(--s4); }
.mt5 { margin-top: var(--s5); } .mt6 { margin-top: var(--s6); }
.flex { display: flex; gap: var(--s2); align-items: center; }
.flex-wrap { flex-wrap: wrap; }
.push { margin-left: auto; }

/* ---------- Live hardware tests (ui: live) --------------------------------
   The stage is the handler's canvas. It stays a plain bordered surface here;
   individual tests paint it (including edge-to-edge colour fills in
   fullscreen, which is why .stage:fullscreen drops all chrome). */

.stage {
  position: relative;
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: var(--card);
  margin-top: var(--s4);
  overflow: hidden;
}
.stage:empty { display: none; }
.stage:fullscreen { border: 0; border-radius: 0; margin: 0; }
.stage:fullscreen .stage__hint { position: fixed; left: 50%; bottom: 24px; transform: translateX(-50%); z-index: 5; }

/* Full-bleed colour field — dead pixel, backlight bleed, uniformity. */
.stage__fill { position: absolute; inset: 0; }
.stage--fill { min-height: 320px; cursor: pointer; }
.stage__hint {
  font: 500 12px/1.4 var(--mono);
  letter-spacing: .02em;
  padding: var(--s2) var(--s3);
  background: rgba(17,18,20,.78);
  color: #fff;
  border-radius: var(--r);
  pointer-events: none;
}

/* Key / button grid — keyboard, numpad, gamepad, mouse tests. */
.keys { display: flex; flex-direction: column; gap: 5px; padding: var(--s4); }
.keys__row { display: flex; gap: 5px; }
.key {
  flex: 0 0 auto;
  min-width: 38px; height: 38px;
  display: flex; align-items: center; justify-content: center;
  padding: 0 var(--s2);
  border: 1px solid var(--line-2);
  border-radius: var(--r-sm);
  background: var(--card-alt);
  font: 500 11px/1 var(--mono);
  color: var(--ink-2);
  text-align: center;
  transition: background var(--t-fast), color var(--t-fast), border-color var(--t-fast);
}
.key.is-down { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
.key.is-seen { background: var(--wash); border-color: var(--wash-line); color: var(--accent-2); }
.key--w15 { min-width: 58px; } .key--w20 { min-width: 78px; }
.key--w25 { min-width: 98px; } .key--w60 { min-width: 240px; flex: 1 1 auto; }

/* Keyboard diagnostics (plan batch 1). Only tokens this sheet defines are used. */
.stage--kb { outline: none; }
.stage--kb:focus-visible { box-shadow: 0 0 0 2px var(--accent); }
.stage--kb .keys { overflow-x: auto; }
.stage--kb .stage__hint { position: static !important; left: auto !important; transform: none !important; display: inline-block; margin: 0 var(--s4) var(--s4); }
.key.is-touch { border-style: dashed; border-color: var(--line-3); color: var(--ink-3); }
.kbbar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s2); padding: var(--s3) var(--s4); border-bottom: 1px solid var(--line); background: var(--card-alt); }
.kbpill { font: 500 12px/1.4 var(--mono); padding: 4px var(--s2); border-radius: var(--r-sm); margin-right: auto; }
.kbpill--on { color: var(--ok); background: var(--ok-wash); }
.kbpill--off { color: var(--warn); background: var(--warn-wash); }
.kbghost { margin: var(--s4) var(--s4) 0; padding: var(--s3) var(--s4); border: 1px solid var(--wash-line); border-radius: var(--r); background: var(--wash); }
.kbghost__t { font-weight: 600; color: var(--ink); }
.kbghost__t .eyebrow { margin-right: var(--s2); }
.kbghost__keys { display: flex; flex-wrap: wrap; gap: 6px; margin: var(--s2) 0; }
.kbchip { font: 600 12px/1 var(--mono); padding: 6px 10px; border: 1px solid var(--accent); border-radius: var(--r-sm); color: var(--accent-2); background: var(--card); }
.kbghost__v { font-size: 14px; color: var(--ink-2); min-height: 1.4em; }
.kbghost__v.is-pass { color: var(--ok); }
.kbghost__v.is-apart { color: var(--warn); }
.kbghost__v.is-missing { color: var(--err); }
.kbghost__nav { display: flex; gap: var(--s2); margin-top: var(--s2); }
.kblive { padding: 0 var(--s4) var(--s3); }
.kblive .readout dd { font-size: 15px; word-break: break-all; }
.kblog { padding: 0 var(--s4) var(--s3); }
.kblog__hd { display: flex; align-items: baseline; gap: var(--s2); margin-bottom: var(--s2); font-size: 12px; }
.kblog__t td, .kblog__t th { font-family: var(--mono); font-size: 12px; white-space: nowrap; }
.kblog__rep td { color: var(--ink-3); }
.kblog__up td { color: var(--ink-3); }
.kblog__warn td { color: var(--warn); }
.kblog__note td { color: var(--ink-2); font-family: var(--sans); white-space: normal; background: var(--paper-sunk); }

/* Media, controller and mouse diagnostics (plan batch 2). Defined tokens only. */
.mediaui { display: block; }
.mediaintro { padding: var(--s4); }
.mediaintro p { margin: 0 0 var(--s3); color: var(--ink-2); max-width: 70ch; }
.mediabar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s2); padding: var(--s3) var(--s4); border-bottom: 1px solid var(--line); background: var(--card-alt); }
.mediaintro .mediabar { padding: 0; border: 0; background: none; }
.mediasel { max-width: 100%; min-width: 0; flex: 1 1 200px; }
.mediaissue { margin: var(--s3) var(--s4); }
.mediaissue ol { margin: var(--s2) 0 0; padding-left: 1.3em; }
.micmeter { padding: var(--s3) var(--s4) 0; }
.micmeter__lbl { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 6px; font-size: 13px; }
.micmeter__bar { position: relative; overflow: visible; }
.micmeter__peak { position: absolute; top: -3px; bottom: -3px; width: 2px; margin-left: -1px; background: var(--ink); }
.micwave { display: block; width: 100%; height: 140px; background: var(--card-alt); border-top: 1px solid var(--line); margin-top: var(--s3); }
.micwave--rec { height: 90px; cursor: pointer; border: 1px solid var(--line); border-radius: var(--r); margin: var(--s2) 0; }
.micrec { padding: 0 var(--s4) var(--s3); }
.micrec__hd { display: flex; flex-wrap: wrap; gap: var(--s2); align-items: baseline; margin-top: var(--s3); font-size: 13px; }
.micrec__audio { display: block; width: 100%; margin: var(--s2) 0; }
.camvideo { display: block; width: 100%; max-height: 460px; background: #000; object-fit: contain; }
.padinfo { padding: var(--s3) var(--s4); color: var(--ink-2); font: 500 13px/1.5 var(--mono); border-bottom: 1px solid var(--line); word-break: break-word; }
.paddz { display: inline-flex; align-items: center; gap: var(--s2); font-size: 13px; color: var(--ink-2); }
.paddz input { width: 120px; }
.paddrift { margin: var(--s3) var(--s4) 0; padding: var(--s3); border: 1px solid var(--line); border-radius: var(--r); background: var(--card-alt); font-size: 14px; color: var(--ink-2); }
.paddrift__r + .paddrift__r { margin-top: var(--s2); }
.paddrift__r.is-noise { color: var(--ok); }
.paddrift__r.is-slight { color: var(--ink); }
.paddrift__r.is-noticeable { color: var(--warn); }
.paddrift__r.is-drift { color: var(--err); }
.padsticks { display: flex; flex-wrap: wrap; gap: var(--s4); padding: var(--s4); }
.padstick { margin: 0; flex: 1 1 220px; max-width: 260px; }
.padstick canvas { display: block; width: 100%; height: auto; aspect-ratio: 1; border: 1px solid var(--line); border-radius: var(--r); background: var(--card-alt); }
.padstick figcaption { font-size: 11px; color: var(--ink-3); margin-top: 6px; }
.padbtns { display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 6px; padding: 0 var(--s4) var(--s4); }
.padbtn { position: relative; display: flex; justify-content: space-between; gap: var(--s2); padding: 8px 10px; border: 1px solid var(--line-2); border-radius: var(--r-sm); background: var(--card-alt); font-size: 12px; overflow: hidden; }
.padbtn__l { position: relative; z-index: 1; color: var(--ink-2); }
.padbtn__v { position: relative; z-index: 1; color: var(--ink-3); }
.padbtn__f { position: absolute; left: 0; top: 0; bottom: 0; width: 0; background: var(--wash); }
.padbtn.is-seen { border-color: var(--wash-line); }
.padbtn.is-down { border-color: var(--accent); }
.padbtn.is-down .padbtn__l { color: var(--accent-2); font-weight: 600; }
.padaxes { padding: 0 var(--s4) var(--s4); }
.padaxis { display: grid; grid-template-columns: 64px 1fr 64px; align-items: center; gap: var(--s2); font-size: 12px; margin-top: 6px; }
.padaxis__track { position: relative; height: 8px; border: 1px solid var(--line-2); border-radius: var(--r-sm); background: var(--paper-sunk); }
.padaxis__track::after { content: ''; position: absolute; left: 50%; top: -2px; bottom: -2px; width: 1px; background: var(--line-3); }
.padaxis__fill { position: absolute; top: 0; bottom: 0; left: 50%; width: 0; background: var(--accent); }
.padaxis__v { text-align: right; }
.pad__msg { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; text-align: center; padding: var(--s4); color: var(--ink-3); font: 500 13px/1.4 var(--mono); pointer-events: none; }
.clickzone { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px; min-height: 220px; padding: var(--s4); text-align: center; cursor: pointer; user-select: none; background: var(--card-alt); outline: none; transition: background var(--t-fast); }
.clickzone span { color: var(--ink-3); font-size: 13px; }
.clickzone:focus-visible { box-shadow: inset 0 0 0 2px var(--accent); }
.clickzone.is-hit { background: var(--wash); }
.clickzone.is-hit.is-bad { background: var(--warn-wash); }

/* Meters — mic level, battery, polling rate, tilt. */
.meter { height: 10px; border: 1px solid var(--line-2); border-radius: var(--r-sm); background: var(--paper-sunk); overflow: hidden; }
.meter__bar { height: 100%; width: 0; background: var(--accent); transition: width 60ms linear; }
.meter__bar.is-hot { background: var(--err); }
.meter--tall { height: 130px; display: flex; align-items: flex-end; }
.meter--tall .meter__bar { width: 100%; height: 0; transition: height 60ms linear; }

/* Read-out grid used by most sensor tests. */
.readout { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 1px; background: var(--line); border: 1px solid var(--line); border-radius: var(--r); overflow: hidden; }
.readout > div { background: var(--card); padding: var(--s3); }
.readout dt { font: 500 11px/1 var(--mono); text-transform: uppercase; letter-spacing: .05em; color: var(--ink-3); margin-bottom: 6px; }
.readout dd { font: 600 19px/1.2 var(--sans); font-variant-numeric: tabular-nums; color: var(--ink); margin: 0; }

/* Typing test. */
.typing { padding: var(--s4); }
.typing__text { font: 400 19px/1.75 var(--mono); color: var(--ink-4); letter-spacing: .01em; word-break: break-word; }
.typing__text b { font-weight: 400; color: var(--ink); }
.typing__text .is-bad { color: var(--err); background: var(--err-wash); border-radius: 2px; }
.typing__text .is-at { border-bottom: 2px solid var(--accent); color: var(--ink); }
.typing__in { width: 100%; margin-top: var(--s4); font-family: var(--mono); }

/* Pointer surface — mouse accuracy, drag, touch, stylus. */
.pad { position: relative; height: 300px; background: var(--card-alt); touch-action: none; cursor: crosshair; }
.pad__dot { position: absolute; width: 9px; height: 9px; margin: -4.5px 0 0 -4.5px; border-radius: 50%; background: var(--accent); }
.pad__target { position: absolute; width: 40px; height: 40px; margin: -20px 0 0 -20px; border: 2px solid var(--accent); border-radius: 50%; }

@media (max-width: 640px) {
  .key { min-width: 30px; height: 34px; font-size: 10px; }
  .key--w60 { min-width: 120px; }
  .typing__text { font-size: 16px; }
}

/* print */
@media print {
  .top, .foot, .aside, .cmdk, .strip, .adslot, .tool__bar { display: none !important; }
  body { background: #fff; }
  .tool { border: 0; }
}


/* --- Guide figures -------------------------------------------------------
   Images carry width/height in the markup so the browser reserves the box and
   the layout does not shift while they load. */
.guidefig { margin: var(--s5) 0; }
.guidefig img {
  display: block; width: 100%; height: auto; max-width: 100%;
  border: 1px solid var(--line); border-radius: var(--r); background: var(--card-alt);
}
.guidefig figcaption {
  margin-top: var(--s2); font-size: 13px; color: var(--ink-3); line-height: 1.5;
}


/* --- Text compare and cleaner preview -------------------------------------
   Added and removed pieces carry a wash AND a text decoration, so the change
   still reads without colour. Whitespace marks inside a change are dimmed. */
.diffbar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s2) var(--s3); margin-bottom: var(--s3); }
.diffleg { font-size: 12.5px; color: var(--ink-3); display: inline-flex; flex-wrap: wrap; align-items: center; gap: 4px 8px; }
.diffview ins, .diffleg ins { background: var(--ok-wash); color: var(--ink); text-decoration: underline; text-decoration-color: var(--ok); text-underline-offset: 3px; border-radius: 2px; }
.diffview del, .diffleg del { background: var(--err-wash); color: var(--ink); text-decoration: line-through; text-decoration-color: var(--err); border-radius: 2px; }
.diffview {
  max-height: 560px; overflow: auto; max-width: 100%;
  border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--card);
  font: 400 13.5px/1.6 var(--mono); color: var(--ink-2);
}
.diffview:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.diffview--word, .diffview--char { padding: var(--s3); white-space: pre-wrap; overflow-wrap: anywhere; }
.diffview--line { padding: var(--s1) 0; }
.dl { position: relative; white-space: pre-wrap; overflow-wrap: anywhere; padding: 0 var(--s3) 0 2em; min-height: 1.6em; }
.dl--del { background: var(--err-wash); }
.dl--add { background: var(--ok-wash); }
.dl--del del, .dl--add ins { background: transparent; font-weight: 600; }
.dg { position: absolute; left: 0; top: 0; width: 2em; text-align: center; color: var(--ink-4); user-select: none; }
.dl--del .dg { color: var(--err); }
.dl--add .dg { color: var(--ok); }
.dws { color: var(--ink-4); font-size: .85em; }
.diffmore { font-size: 13px; margin-top: var(--s2); }
.diffbusy { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s3); padding: var(--s4); border: 1px dashed var(--line-2); border-radius: var(--r-sm); color: var(--ink-3); }
.typechart { display: block; width: 100%; height: auto; max-width: 100%; margin-top: var(--s3); border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--card); }
