/* ==========================================================================
   FigureMill — design system
   Self-hosted type, warm paper surfaces, category accents.
   No frameworks, no runtime CSS-in-JS.
   ========================================================================== */

/* ---------- Type ---------- */
@font-face {
  font-family: "Inter"; font-style: normal; font-weight: 400; font-display: swap;
  src: url("/assets/fonts/inter-400.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Inter"; font-style: normal; font-weight: 500; font-display: swap;
  src: url("/assets/fonts/inter-500.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Inter"; font-style: normal; font-weight: 600; font-display: swap;
  src: url("/assets/fonts/inter-600.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Inter"; font-style: normal; font-weight: 700; font-display: swap;
  src: url("/assets/fonts/inter-700.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Space Grotesk"; font-style: normal; font-weight: 600; font-display: swap;
  src: url("/assets/fonts/space-grotesk-600.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Space Grotesk"; font-style: normal; font-weight: 700; font-display: swap;
  src: url("/assets/fonts/space-grotesk-700.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

:root {
  --font-sans: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --font-display: "Space Grotesk", "Inter", system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;

  --paper: #f7f5f0;
  --surface: #ffffff;
  --surface-2: #f1eee7;
  --field: #fbfaf7;
  --ink: #15171e;
  --ink-2: #4c5464;
  --ink-3: #7a8291;
  --line: #e6e1d6;
  --line-2: #d6d0c3;

  /* Blueprint navy rather than indigo-600. Cream + navy is the technical-document
     pairing this site is imitating (drawings, spec sheets); indigo/violet reads as
     generic SaaS and undercuts the "we show the work" premise. */
  --brand: #1e3a8a;
  --brand-2: #1e40af;
  --brand-dark: #172554;
  --brand-soft: #e9eef9;
  --teal: #0d9488;
  --grad-end: #0f766e;

  --ok: #0f7a55;
  --ok-soft: #e6f4ee;
  --warn: #a15c07;
  --warn-soft: #fbf1de;
  --danger: #c0322b;
  --danger-soft: #fdecea;

  --cat-finance: #047857;
  --cat-diy: #b45309;
  --cat-students: #0369a1;
  --cat-dev: #6d28d9;
  --cat-words: #be123c;

  /* The three live clusters. These names must match the body class each page
     carries (cat-materials / cat-hvac / cat-hometax) or every accent silently
     falls back to brand indigo and the colour coding does nothing. */
  --cat-materials: #b45309;
  --cat-hvac: #0f766e;
  --cat-hometax: #047857;

  --radius: 18px;
  --radius-md: 14px;
  --radius-sm: 10px;
  --shadow-xs: 0 1px 2px rgba(20, 24, 35, 0.05);
  --shadow-sm: 0 1px 2px rgba(20, 24, 35, 0.04), 0 6px 16px -10px rgba(20, 24, 35, 0.18);
  --shadow: 0 2px 4px rgba(20, 24, 35, 0.04), 0 22px 44px -26px rgba(20, 24, 35, 0.28);
  --ring: 0 0 0 3px color-mix(in srgb, var(--brand) 26%, transparent);

  --max: clamp(1140px, 92vw, 1720px);
  --prose: min(720px, 68ch);
}

@media (prefers-color-scheme: dark) {
  :root {
    --paper: #0a0d13;
    --surface: #11161f;
    --surface-2: #0d121a;
    --field: #0c1119;
    --ink: #edf0f6;
    --ink-2: #a7b1c2;
    --ink-3: #7c8798;
    --line: #212936;
    --line-2: #303a4c;

    --brand: #93b4f5;
    --brand-2: #b8ccf7;
    --brand-dark: #b8ccf7;
    --brand-soft: #121a2b;
    --teal: #2dd4bf;
    --grad-end: #5eead4;

    --ok: #6ee7b7;
    --ok-soft: #0e2a22;
    --warn: #fbbf24;
    --warn-soft: #2b210f;
    --danger: #fca5a5;
    --danger-soft: #2f1515;

    --cat-finance: #34d399;
    --cat-diy: #fbbf24;
    --cat-students: #38bdf8;
    --cat-dev: #a78bfa;
    --cat-words: #fb7185;

    --cat-materials: #f0b23e;
    --cat-hvac: #2dd4bf;
    --cat-hometax: #4ade9d;

    --shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.4);
    --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.35), 0 8px 20px -12px rgba(0, 0, 0, 0.7);
    --shadow: 0 2px 6px rgba(0, 0, 0, 0.45), 0 26px 50px -28px rgba(0, 0, 0, 0.8);
  }
}

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

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

html { font-size: 17px; }

body {
  margin: 0;
  overflow-x: clip;
  color: var(--ink);
  background-color: var(--paper);
  background-image:
    radial-gradient(820px 420px at 8% -6%, color-mix(in srgb, var(--brand) 9%, transparent), transparent 68%),
    radial-gradient(680px 360px at 96% -10%, color-mix(in srgb, var(--teal) 7%, transparent), transparent 70%);
  background-repeat: no-repeat;
  font-family: var(--font-sans);
  font-size: 1rem;
  line-height: 1.65;
  font-feature-settings: "cv02", "cv03", "cv04", "cv11";
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

img, svg { max-width: 100%; height: auto; }

a { color: var(--brand); text-decoration-color: color-mix(in srgb, var(--brand) 38%, transparent); text-underline-offset: 3px; }
a:hover { color: var(--brand-dark); }

h1, h2, h3, h4 {
  font-family: var(--font-display);
  line-height: 1.12; margin: 0 0 0.55em; letter-spacing: -0.03em; font-weight: 600;
}
h1 { font-size: clamp(2.05rem, 1.4rem + 2.6vw, 3.05rem); font-weight: 700; letter-spacing: -0.04em; text-wrap: balance; }
h2 { font-size: clamp(1.35rem, 1.15rem + 0.8vw, 1.7rem); margin-top: 2.1rem; text-wrap: balance; }
h3 { font-size: 1.14rem; margin-top: 1.5rem; letter-spacing: -0.015em; }
p { margin: 0 0 1em; }

.wrap { width: 100%; max-width: var(--max); margin: 0 auto; padding: 0 22px; }

.skip {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  background: var(--surface); color: var(--ink); padding: 10px 16px; border-radius: 0 0 10px 0;
}
.skip:focus { left: 0; }

:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; border-radius: 6px; }

/* ---------- Category accents ---------- */
.cat-finance { --cat: var(--cat-finance); }
.cat-tax { --cat: var(--cat-finance); }
.cat-diy { --cat: var(--cat-diy); }
.cat-students { --cat: var(--cat-students); }
.cat-dev { --cat: var(--cat-dev); }
.cat-words { --cat: var(--cat-words); }
.cat-materials { --cat: var(--cat-materials); }
.cat-hvac { --cat: var(--cat-hvac); }
.cat-hometax { --cat: var(--cat-hometax); }

/* ---------- Header ---------- */
.site-header {
  position: sticky; top: 0; z-index: 50;
  background: color-mix(in srgb, var(--paper) 78%, transparent);
  -webkit-backdrop-filter: saturate(150%) blur(14px);
  backdrop-filter: saturate(150%) blur(14px);
  border-bottom: 1px solid color-mix(in srgb, var(--line) 80%, transparent);
}
.header-inner { display: flex; align-items: center; gap: 16px; min-height: 68px; flex-wrap: wrap; }

.brand {
  display: inline-flex; align-items: center; gap: 10px;
  font-family: var(--font-display); font-weight: 700; font-size: 1.16rem; letter-spacing: -0.04em;
  color: var(--ink); text-decoration: none;
}
.brand:hover { color: var(--ink); }
.brand-mark {
  width: 34px; height: 34px; border-radius: 10px; display: grid; place-items: center;
  background: linear-gradient(145deg, var(--brand) 10%, var(--brand-2) 90%);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.35), 0 6px 14px -8px color-mix(in srgb, var(--brand) 80%, transparent);
  color: #fff; font-family: var(--font-display); font-size: 1rem; font-weight: 700;
}
.brand em { font-style: normal; color: var(--brand); }

.site-nav { display: flex; align-items: center; gap: 2px; flex-wrap: wrap; margin-left: auto; }
.site-nav a {
  font-size: 0.92rem; font-weight: 500; color: var(--ink-2); text-decoration: none;
  padding: 8px 13px; border-radius: 999px; transition: color 0.15s ease, background 0.15s ease;
}
.site-nav a:hover { color: var(--ink); background: var(--surface-2); }
.site-nav a[aria-current="page"] { color: var(--brand); background: var(--brand-soft); font-weight: 600; }

.nav-toggle {
  display: none; margin-left: auto; align-items: center; gap: 8px;
  background: var(--surface); color: var(--ink); border: 1px solid var(--line-2);
  border-radius: 999px; padding: 9px 15px; font: inherit; font-size: 0.92rem; font-weight: 600; cursor: pointer;
  box-shadow: var(--shadow-xs);
}

@media (max-width: 880px) {
  .nav-toggle { display: inline-flex; }
  .site-nav {
    display: none; width: 100%; margin-left: 0; margin-top: 10px; padding: 8px;
    background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-md);
    box-shadow: var(--shadow-sm);
  }
  .site-nav.is-open { display: flex; flex-direction: column; align-items: stretch; gap: 2px; }
  .site-nav a { padding: 12px 14px; font-size: 1rem; border-radius: 9px; }
}

/* ---------- Breadcrumbs ---------- */
.breadcrumbs { font-size: 0.85rem; color: var(--ink-3); padding: 18px 0 0; }
.breadcrumbs ol { list-style: none; display: flex; flex-wrap: wrap; gap: 7px; margin: 0; padding: 0; }
.breadcrumbs li + li::before { content: "/"; margin-right: 7px; color: var(--line-2); }
.breadcrumbs a { color: var(--ink-2); text-decoration: none; }
.breadcrumbs a:hover { color: var(--brand); text-decoration: underline; }

/* ---------- Page head ---------- */
.page-head { padding: 26px 0 8px; max-width: 780px; }
.page-head .lede { font-size: 1.06rem; color: var(--ink-2); margin-bottom: 0.4em; max-width: 64ch; }
.category-tag {
  display: inline-flex; align-items: center; gap: 7px;
  font-size: 0.72rem; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--cat, var(--brand));
  background: color-mix(in srgb, var(--cat, var(--brand)) 10%, transparent);
  border: 1px solid color-mix(in srgb, var(--cat, var(--brand)) 22%, transparent);
  padding: 5px 11px; border-radius: 999px; margin-bottom: 14px;
}
.category-tag::before {
  content: ""; width: 6px; height: 6px; border-radius: 50%;
  background: currentColor;
}

main { padding-bottom: 64px; }
section[id] { scroll-margin-top: 92px; }

/* ---------- Cards ---------- */
.card {
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: var(--shadow-sm); padding: 26px;
}
.tool-card { position: relative; margin: 24px 0 10px; overflow: hidden; }
.tool-card::before {
  content: ""; position: absolute; inset: 0 0 auto 0; height: 3px;
  background: linear-gradient(90deg, var(--cat, var(--brand)), color-mix(in srgb, var(--cat, var(--brand)) 18%, transparent));
}

.grid { display: grid; gap: 18px; }
.grid-2 { grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); }
.grid-3 { grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }

/* ---------- Forms ---------- */
.field { margin-bottom: 16px; }
.field-row { display: grid; gap: 15px; grid-template-columns: repeat(auto-fit, minmax(165px, 1fr)); }
label, .label { display: block; font-weight: 600; font-size: 0.875rem; margin-bottom: 7px; color: var(--ink); }
.hint { font-size: 0.82rem; color: var(--ink-3); margin-top: 6px; line-height: 1.5; }
/* Number and unit on one line: the unit belongs to the measurement, so stacking it
   under the box reads as a second, separate field. */
.unit-inline { display: grid; grid-template-columns: minmax(0, 1fr) 78px; gap: 6px; }
.unit-inline select { padding-left: 11px; padding-right: 4px; }

input[type="text"], input[type="number"], input[type="search"], input[type="month"], select, textarea {
  width: 100%; padding: 12px 13px; font: inherit; font-size: 1rem; color: var(--ink);
  background: var(--field); border: 1px solid var(--line-2); border-radius: var(--radius-sm);
  transition: border-color 0.15s ease, box-shadow 0.15s ease, background 0.15s ease;
}
input[type="number"] { -moz-appearance: textfield; font-variant-numeric: tabular-nums; }
textarea { min-height: 190px; font-family: var(--font-mono); font-size: 0.9rem; line-height: 1.6; resize: vertical; }
input:hover, select:hover, textarea:hover { border-color: color-mix(in srgb, var(--ink-3) 45%, var(--line-2)); }
input:focus, select:focus, textarea:focus {
  border-color: var(--brand); box-shadow: var(--ring); outline: none; background: var(--surface);
}
input[type="color"] {
  width: 60px; height: 46px; padding: 4px; border: 1px solid var(--line-2);
  border-radius: var(--radius-sm); background: var(--surface); cursor: pointer;
}
input[type="range"] { width: 100%; accent-color: var(--brand); }

.check { display: flex; align-items: flex-start; gap: 11px; font-weight: 500; font-size: 0.95rem; color: var(--ink-2); }
.check input { margin-top: 4px; width: 18px; height: 18px; accent-color: var(--brand); flex: none; }

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  min-height: 46px; padding: 12px 20px; font: inherit; font-size: 0.95rem; font-weight: 600;
  color: #fff; background: linear-gradient(180deg, var(--brand), var(--brand-dark));
  border: 1px solid color-mix(in srgb, var(--brand-dark) 80%, #000);
  border-radius: var(--radius-sm); cursor: pointer; text-decoration: none; white-space: nowrap;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.18), 0 8px 18px -10px color-mix(in srgb, var(--brand) 75%, transparent);
  transition: filter 0.15s ease, transform 0.06s ease, box-shadow 0.15s ease;
}
.btn:hover { filter: brightness(1.07); color: #fff; }
.btn:active { transform: translateY(1px); box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.18); }
.btn-secondary {
  background: var(--surface); color: var(--ink); border-color: var(--line-2); box-shadow: var(--shadow-xs);
}
.btn-secondary:hover { background: var(--surface-2); color: var(--ink); filter: none; }
.btn-ghost { background: transparent; color: var(--brand); border-color: transparent; box-shadow: none; padding-left: 12px; padding-right: 12px; }
.btn-ghost:hover { background: var(--brand-soft); color: var(--brand-dark); filter: none; }
.btn-sm { min-height: 38px; padding: 8px 13px; font-size: 0.86rem; border-radius: 8px; }
.btn[disabled] { opacity: 0.55; cursor: not-allowed; filter: none; }
.btn-row { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 8px; }

/* On dark surfaces --brand is a pale lavender, so a white-on-lavender button
   lands around 1.8:1. Flip the label to ink instead of lightening the fill. */
@media (prefers-color-scheme: dark) {
  .btn {
    color: #0c0f16;
    background: linear-gradient(180deg, #b8b3ff, #918bfb);
    border-color: #7d76ef;
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.30), 0 8px 18px -10px rgba(124, 116, 255, 0.55);
  }
  .btn:hover { color: #0c0f16; filter: brightness(1.06); }
  .btn:active { color: #0c0f16; }
  .btn-secondary { color: var(--ink); background: var(--surface); border-color: var(--line-2); }
  .btn-secondary:hover { color: var(--ink); background: var(--surface-2); }
  /* .btn re-declares border-color inside this block, which outranks the
     .btn-ghost reset above and left ghost buttons wearing a lavender outline. */
  .btn-ghost { background: transparent; color: var(--brand); border-color: transparent; box-shadow: none; }
  .btn-ghost:hover { background: var(--brand-soft); color: var(--ink); }
  .tn-player-btn.is-main { color: #0c0f16; }
}

/* ---------- Results ---------- */
.result {
  margin-top: 20px; padding: 22px; border-radius: var(--radius-md);
  background: linear-gradient(180deg, color-mix(in srgb, var(--brand) 4%, var(--surface)), var(--surface) 60%);
  border: 1px solid var(--line);
}
.result.is-error { background: var(--danger-soft); border-color: color-mix(in srgb, var(--danger) 32%, var(--line)); color: var(--danger); }
.result.is-ok { background: var(--ok-soft); border-color: color-mix(in srgb, var(--ok) 28%, var(--line)); }
.result h2, .result h3 { margin-top: 0; }

.big-number {
  font-family: var(--font-display); font-size: clamp(1.85rem, 1.4rem + 2vw, 2.5rem);
  font-weight: 700; letter-spacing: -0.04em; line-height: 1.05; font-variant-numeric: tabular-nums;
}
.big-number small { font-family: var(--font-sans); font-size: 0.82rem; font-weight: 600; color: var(--ink-3); letter-spacing: 0; }

.stat-grid { display: grid; gap: 12px; grid-template-columns: repeat(auto-fit, minmax(155px, 1fr)); margin-top: 6px; }
.stat {
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-sm);
  padding: 13px 15px; box-shadow: var(--shadow-xs);
}
.stat .stat-label { font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.09em; color: var(--ink-3); font-weight: 700; }
.stat .stat-value { font-family: var(--font-display); font-size: 1.3rem; font-weight: 600; margin-top: 3px; font-variant-numeric: tabular-nums; letter-spacing: -0.02em; }
.stat .stat-sub { font-size: 0.8rem; color: var(--ink-3); margin-top: 1px; }

table { width: 100%; border-collapse: collapse; font-size: 0.93rem; }
/* Numeric columns should never wrap mid-range: "$5,800–" on one line and "$9,400"
   on the next reads as two numbers. Tabular figures also keep the ranges aligned. */
.table-wrap th.num, .table-wrap td.num { white-space: nowrap; font-variant-numeric: tabular-nums; }
th, td { text-align: left; padding: 11px 13px; border-bottom: 1px solid var(--line); }
th { font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.08em; color: var(--ink-3); background: var(--surface-2); font-weight: 700; }
tbody tr:hover td { background: color-mix(in srgb, var(--surface-2) 55%, transparent); }
tbody tr:last-child td { border-bottom: none; }
.table-wrap { overflow-x: auto; border: 1px solid var(--line); border-radius: var(--radius-sm); background: var(--surface); margin: 1.2em 0 1.6em; }
/* The table's own margin sits inside the frame once it is wrapped, which shows up
   as padding. Move that spacing out to the frame so a caption can sit flush with
   the top edge instead of floating in white space. */
.table-wrap > table { margin: 0; }
/* A captioned table is meant to be citable as a unit: the caption names the data,
   so it reads as a label on the frame rather than as another heading. */
caption {
  caption-side: top; text-align: left;
  padding: 12px 13px 10px;
  font-size: 0.78rem; font-weight: 600; line-height: 1.4;
  color: var(--ink-2);
  border-bottom: 1px solid var(--line);
}
/* The source line belongs to the table, not to the page: a table cropped or quoted
   on its own still carries its provenance. Weaker than the caption so it reads as
   a footnote rather than a second title. */
caption .src {
  display: block; margin-top: 3px;
  font-weight: 400; font-size: 0.72rem; color: var(--ink-3);
}

/* ---------- Chips / word results ---------- */
.chips { display: flex; flex-wrap: wrap; gap: 7px; margin-top: 12px; }
.chip {
  font-family: var(--font-mono); font-size: 0.9rem; padding: 5px 10px; border-radius: 8px;
  background: var(--surface); border: 1px solid var(--line-2); color: var(--ink);
  box-shadow: var(--shadow-xs);
}
.chip b { color: var(--teal); font-weight: 700; margin-left: 3px; }
.chip-list { max-height: 420px; overflow: auto; padding-right: 4px; }

/* Wordle input grid */
.wordle-grid { display: grid; gap: 8px; grid-template-columns: repeat(5, minmax(0, 1fr)); max-width: 360px; }
.tile-col { display: grid; gap: 6px; }
.tile-input {
  width: 100%; text-align: center; font-family: var(--font-display); font-size: 1.35rem; font-weight: 700;
  text-transform: uppercase; height: 58px; padding: 4px; border-radius: 10px;
}
.tile-color {
  height: 30px; border-radius: 8px; border: 1px solid var(--line-2); background: var(--surface-2);
  cursor: pointer; transition: transform 0.12s ease, filter 0.12s ease;
}
.tile-color:hover { filter: brightness(1.06); }
.tile-color:active { transform: scale(0.97); }
.tile-col[data-state="absent"] .tile-color { background: #787c7e; border-color: #787c7e; }
.tile-col[data-state="present"] .tile-color { background: #c9b458; border-color: #c9b458; }
.tile-col[data-state="correct"] .tile-color { background: #6aaa64; border-color: #6aaa64; }
.tile-col[data-state="absent"] .tile-input { border-color: #9aa0a6; }
.tile-col[data-state="present"] .tile-input { border-color: #c9b458; }
.tile-col[data-state="correct"] .tile-input { border-color: #6aaa64; }
.tile-legend { display: flex; flex-wrap: wrap; gap: 14px; font-size: 0.83rem; color: var(--ink-2); margin-top: 12px; }
.tile-legend span { display: inline-flex; align-items: center; gap: 7px; }
.swatch-dot { width: 13px; height: 13px; border-radius: 4px; display: inline-block; border: 1px solid rgba(0, 0, 0, 0.12); }

/* ---------- Ad slots (reserved, no ad code) ---------- */
/* Reserved ad space. Before AdSense is live the slot is empty, and a 100px
   striped billboard above the calculator reads as a broken element rather than
   as reserved space. Keep the reserved height, drop the texture. */
.ad-slot {
  /* Hidden until there is real inventory. An empty reserved box was rendering as a
     grey dashed band directly under the hero — the second thing a visitor saw — and
     a fixed-height empty container also shifts layout when an ad finally fills it.
     Restore `display: grid` once AdSense is approved. */
  position: relative; margin: 26px auto; display: none; place-items: center; text-align: center;
  min-height: 100px; padding: 14px; border-radius: var(--radius-md);
  border: 1px dashed color-mix(in srgb, var(--line-2) 65%, transparent);
  background: color-mix(in srgb, var(--surface-2) 45%, transparent);
  color: color-mix(in srgb, var(--ink-3) 72%, transparent);
  font-size: 0.64rem; letter-spacing: 0.18em; text-transform: uppercase; font-weight: 600;
}
.ad-slot span { display: inline-flex; align-items: center; gap: 8px; }
.ad-slot span::before, .ad-slot span::after {
  content: ""; width: 18px; height: 1px; background: var(--line-2);
}
.ad-slot--leaderboard { max-width: 970px; min-height: 90px; }
.ad-slot--rectangle { max-width: 336px; min-height: 280px; }
/* A centred 336px box between a full-width card and a left-aligned text column
   reads as a floating rectangle. Sit it on the text column's left edge. */
@media (min-width: 900px) {
  .ad-slot--rectangle { margin-left: 0; margin-right: auto; }
  .prose .ad-slot--rectangle, .prose + .ad-slot--rectangle { margin-left: 0; }
}
@media (max-width: 640px) {
  .ad-slot--rectangle { min-height: 250px; max-width: 100%; }
  /* The leaderboard sat between the H1 and the first input. On a phone that
     pushes the tool half a screen down, so it gets a shorter reservation. */
  .ad-slot--leaderboard { min-height: 66px; margin: 16px auto; padding: 8px; }
  /* Data tables have to earn their width at 390px. Trimming the cell padding and
     a point of type size keeps four-column tables from wrapping every number
     onto two lines — which reads as two separate figures. */
  .table-wrap table { font-size: 0.86rem; }
  .table-wrap th, .table-wrap td { padding: 9px 10px; }
}

/* ---------- Prose ---------- */
.prose { max-width: var(--prose); }
/* A hairline above each section heading. Long pages are otherwise one
   undifferentiated column of text; the rule gives the eye somewhere to land
   without adding colour. */
.prose h2 {
  margin-top: 2.6rem; padding-top: 1.4rem;
  border-top: 1px solid color-mix(in srgb, var(--line) 90%, transparent);
}
.prose > h2:first-child { margin-top: 0.4rem; padding-top: 0; border-top: 0; }
.prose ul, .prose ol { padding-left: 1.3em; margin: 0 0 1.1em; }
.prose li { margin-bottom: 0.45em; }
.prose li::marker { color: var(--ink-3); }
.prose code {
  font-family: var(--font-mono); font-size: 0.86em; background: var(--surface-2);
  border: 1px solid var(--line); padding: 1px 6px; border-radius: 6px;
}
/* Spacing belongs to the frame, not the table inside it — see .table-wrap > table. */
.prose table { margin: 0; }

.callout {
  border: 1px solid color-mix(in srgb, var(--brand) 20%, var(--line));
  border-left: 3px solid color-mix(in srgb, var(--brand) 62%, var(--line));
  background: linear-gradient(180deg, var(--brand-soft), color-mix(in srgb, var(--brand-soft) 40%, var(--surface)));
  padding: 17px 20px; border-radius: 3px var(--radius-md) var(--radius-md) 3px; margin: 1.7em 0; font-size: 0.95rem;
  line-height: 1.62;
}
.callout > strong:first-child { color: var(--ink); font-weight: 700; }
.callout--warn { border-color: color-mix(in srgb, var(--warn) 28%, var(--line)); border-left-color: color-mix(in srgb, var(--warn) 62%, var(--line)); background: var(--warn-soft); }
.disclaimer {
  font-size: 0.85rem; color: var(--ink-3); border-top: 1px solid var(--line);
  padding-top: 16px; margin-top: 34px; line-height: 1.6;
}

details.faq {
  border: 1px solid var(--line); border-radius: var(--radius-sm); background: var(--surface);
  padding: 0 18px; margin-bottom: 10px; transition: border-color 0.15s ease;
}
details.faq[open] { border-color: color-mix(in srgb, var(--brand) 30%, var(--line)); }
details.faq summary {
  cursor: pointer; font-weight: 600; padding: 15px 30px 15px 0; list-style: none; position: relative;
  font-family: var(--font-display); letter-spacing: -0.01em;
}
details.faq summary::-webkit-details-marker { display: none; }
details.faq summary::after {
  content: "+"; position: absolute; right: 2px; top: 12px; font-size: 1.3rem;
  color: var(--ink-3); font-weight: 400; line-height: 1.2;
}
details.faq[open] summary::after { content: "–"; }
details.faq .faq-body { padding-bottom: 16px; color: var(--ink-2); font-size: 0.94rem; }
details.faq .faq-body p:last-child { margin-bottom: 0; }

/* ---------- Home ---------- */
.hero {
  position: relative; padding: 62px 0 18px; max-width: none; overflow: clip;
  display: grid; gap: 44px; align-items: center;
}
@media (min-width: 1000px) {
  .hero { grid-template-columns: minmax(0, 1.22fr) minmax(0, 0.78fr); padding: 74px 0 30px; gap: 48px; }
}
.hero-copy { max-width: 720px; }
.hero::before {
  content: ""; position: absolute; z-index: -1; left: -60px; top: -80px; width: min(460px, 90vw); height: 400px;
  background: radial-gradient(closest-side, color-mix(in srgb, var(--brand) 16%, transparent), transparent 72%);
  filter: blur(8px); pointer-events: none;
}

/* Product mock in the hero (decorative). Shown at every width: below 1000px it
   is the only concrete proof on the first screen, so hiding it left phones with
   a headline, three reassurance chips and nothing to act on. */
.hero-figure { display: block; position: relative; }
.mock-wrap { position: relative; transform: rotate(-2deg); }
.mock-wrap::before {
  content: ""; position: absolute; inset: -44px -34px; z-index: -1;
  background: radial-gradient(60% 60% at 58% 42%, color-mix(in srgb, var(--brand) 20%, transparent), transparent 72%);
  filter: blur(18px);
}
.mock-card {
  background: var(--surface); border: 1px solid var(--line); border-radius: 20px; padding: 22px;
  box-shadow: 0 34px 64px -34px rgba(20, 24, 35, 0.4), 0 2px 6px rgba(20, 24, 35, 0.06);
}
.mock-top { display: flex; align-items: center; gap: 8px; margin-bottom: 16px; font-size: 0.7rem; letter-spacing: 0.09em; text-transform: uppercase; color: var(--ink-3); font-weight: 700; }
.mock-dot { width: 7px; height: 7px; border-radius: 50%; background: #22c55e; box-shadow: 0 0 0 4px color-mix(in srgb, #22c55e 16%, transparent); }
.mock-big { font-family: var(--font-display); font-size: 2.35rem; font-weight: 700; letter-spacing: -0.04em; font-variant-numeric: tabular-nums; line-height: 1.1; }
.mock-sub { color: var(--ink-3); font-size: 0.8rem; margin: 4px 0 16px; }
.mock-row { display: flex; justify-content: space-between; gap: 12px; padding: 9px 0; border-top: 1px solid var(--line); font-size: 0.85rem; color: var(--ink-2); }
.mock-row b { font-variant-numeric: tabular-nums; color: var(--ink); font-weight: 600; }
.mock-foot { display: flex; justify-content: space-between; align-items: center; margin-top: 16px; }
.mock-pill { font-size: 0.66rem; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--brand); background: var(--brand-soft); border: 1px solid color-mix(in srgb, var(--brand) 22%, transparent); padding: 5px 10px; border-radius: 999px; }
.mock-meta { font-size: 0.72rem; color: var(--ink-3); }
.mock-chip {
  position: absolute; background: var(--surface); border: 1px solid var(--line); border-radius: 12px;
  padding: 9px 13px; font-size: 0.76rem; font-weight: 600; color: var(--ink-2);
  box-shadow: 0 10px 24px -14px rgba(20, 24, 35, 0.5), var(--shadow-sm);
}
/* Two white chips sitting 14px from two white card corners merge into one
   shape. Push them clear of the card's edge and give them their own shadow so
   they read as annotations pinned to the mock, not as part of it. */
.mock-chip--a { left: -34px; bottom: -30px; transform: rotate(-2deg); }
.mock-chip--b { right: -30px; top: -30px; transform: rotate(2deg); }
@media (max-width: 1080px) {
  .mock-chip--a { left: -8px; bottom: -18px; }
  .mock-chip--b { right: -8px; top: -18px; }
}
/* Single-column hero: the card drops the rotation and the two floating chips
   (which hang off the corners and read as broken layout at this size), and
   tightens its own spacing so it costs about one thumb-scroll, not two. */
@media (max-width: 999px) {
  .hero-figure { max-width: 440px; }
  .mock-wrap { transform: none; }
  .mock-wrap::before { inset: -26px -18px; }
  .mock-chip { display: none; }
  .mock-card { padding: 18px 18px 16px; border-radius: 16px; }
  .mock-big { font-size: 2rem; }
  .mock-sub { margin-bottom: 12px; }
  .mock-row { padding: 7px 0; font-size: 0.82rem; }
}
.hero-badge {
  display: inline-flex; align-items: center; gap: 9px; margin: 0 0 20px;
  padding: 7px 14px 7px 10px; border-radius: 999px;
  background: var(--surface); border: 1px solid var(--line); box-shadow: var(--shadow-xs);
  font-size: 0.8rem; font-weight: 600; color: var(--ink-2); letter-spacing: 0.01em;
}
.hero-badge .dot { width: 8px; height: 8px; border-radius: 50%; background: #22c55e; box-shadow: 0 0 0 4px color-mix(in srgb, #22c55e 18%, transparent); }
.hero h1 { margin-bottom: 0.3em; }
.hero .hero-sub { font-size: 1.12rem; color: var(--ink-2); max-width: 62ch; }
/* Was a brand -> violet -> teal gradient clipped to the text. A three-hue sweep
   across a heading is the strongest "generated page" tell there is, and on a site
   whose whole argument is "we show the work", looking machine-made costs trust.
   Now: one warm accent, borrowed from the materials category colour, which is
   also the colour of the material in the hero photo. */
.grad { color: var(--cat-materials); }
.trust-row { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 22px; }.trust-row span {
  display: inline-flex; align-items: center; gap: 7px; font-size: 0.86rem; color: var(--ink-2);
  background: color-mix(in srgb, var(--surface) 70%, transparent);
  border: 1px solid var(--line); border-radius: 999px; padding: 6px 12px;
}
.tick { color: var(--ok); font-weight: 800; }

/* The hero had no action at all. The headline states a problem and the trust
   row answers objections, but nothing on the first screen was clickable. */
.hero-actions { margin-top: 26px; }
.hero-actions .btn { min-height: 50px; padding: 12px 24px; font-size: 1rem; }
@media (max-width: 560px) {
  .hero-actions { margin-top: 20px; gap: 4px; }
  .hero-actions .btn { width: 100%; }
  /* Two full-width buttons stack to 100px of scroll; the ghost one can shrink
     to a plain link at this width without losing the target. */
  .hero-actions .btn-ghost { min-height: 42px; width: auto; justify-content: flex-start; }
  /* Three chips wrapping one per line cost 110px and pushed the result card
     past the fold. Tightened so two fit per row. */
  .trust-row { gap: 7px; margin-top: 16px; }
  .trust-row span { font-size: 0.78rem; padding: 5px 10px; gap: 5px; }
}

.section-head {
  display: flex; align-items: flex-end; justify-content: space-between; gap: 14px; flex-wrap: wrap;
  margin: 46px 0 16px; padding-top: 26px; border-top: 1px solid var(--line);
}
/* align-items:center drops the marker into the middle of a two-line heading;
   pin it to the first line instead so it reads as a bullet. */
.section-head h2 { margin: 0; display: flex; align-items: flex-start; gap: 11px; }
.section-head h2::before {
  content: ""; flex: none; margin-top: 0.38em;
  width: 9px; height: 9px; border-radius: 3px; background: var(--cat, var(--brand));
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--cat, var(--brand)) 14%, transparent);
}
/* Was --ink-3 (#7a8291) at 0.86rem — roughly 3.5:1 on the cream ground, below the
   4.5:1 floor for small text, and in practice the line was unreadable. It is a
   real sentence, not decoration, so it gets a real contrast ratio. */
.section-head p { margin: 0; color: var(--ink-2); font-size: 0.86rem; }
#finance { --cat: var(--cat-finance); }
#diy { --cat: var(--cat-diy); }
#students { --cat: var(--cat-students); }
#dev { --cat: var(--cat-dev); }
#word-games { --cat: var(--cat-words); }
#materials { --cat: var(--cat-materials); }
#hvac { --cat: var(--cat-hvac); }
#home-tax { --cat: var(--cat-hometax); }

.tool-grid { display: grid; gap: 14px; grid-template-columns: repeat(auto-fill, minmax(268px, 1fr)); }

/* A section holding two or three cards inside a four-column track leaves a
   hole at the end of the row, and the hole reads as a rendering bug. Collapse
   the track count to the number of cards, and cap the width so the cards do
   not stretch into banners. Browsers without :has() keep the auto-fill grid. */
@media (min-width: 760px) {
  .tool-grid:has(> :nth-child(1):last-child) { grid-template-columns: minmax(0, 1fr); max-width: 420px; }
  .tool-grid:has(> :nth-child(2):last-child) { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (min-width: 980px) {
  .tool-grid:has(> :nth-child(3):last-child) { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  /* Five cards in a four-column track leaves one card alone on a second row
     with three-quarters of the width empty. One row of five is tidier. */
  .tool-grid:has(> :nth-child(5):last-child) { grid-template-columns: repeat(5, minmax(0, 1fr)); }
  /* Nine cards in four columns leaves one card alone on a third row; three by
     three is the layout the home-tax hub is meant to have. */
  .tool-grid:has(> :nth-child(9):last-child) { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  /* Ten tools on the home page: two clean rows of five. */
  .tool-grid:has(> :nth-child(10):last-child) { grid-template-columns: repeat(5, minmax(0, 1fr)); }
  /* Thirteen tools on the home-tax hub: five per row leaves three on the last
     row, where four per row would leave one card stranded under three empty columns. */
  .tool-grid:has(> :nth-child(13):last-child) { grid-template-columns: repeat(5, minmax(0, 1fr)); }
}
.tool-link {
  position: relative; display: flex; flex-direction: column; gap: 2px;
  padding: 20px; border-radius: var(--radius); text-decoration: none; color: var(--ink);
  background: var(--surface); border: 1px solid var(--line); box-shadow: var(--shadow-xs);
  transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease;
}
.tool-link:hover {
  transform: translateY(-3px); color: var(--ink);
  border-color: color-mix(in srgb, var(--cat, var(--brand)) 45%, var(--line));
  box-shadow: 0 18px 34px -20px color-mix(in srgb, var(--ink) 45%, transparent);
}
.icon-tile {
  width: 40px; height: 40px; border-radius: 12px; display: grid; place-items: center;
  margin-bottom: 14px; color: var(--cat, var(--brand));
  background: color-mix(in srgb, var(--cat, var(--brand)) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--cat, var(--brand)) 20%, transparent);
  transition: transform 0.18s ease;
}
.tool-link:hover .icon-tile { transform: scale(1.06) rotate(-3deg); }
.icon { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.tool-link .badge { font-size: 0.68rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.11em; color: var(--ink-3); margin-bottom: 5px; }
.tool-link h3 { margin: 0 0 5px; font-size: 1.03rem; color: var(--ink); letter-spacing: -0.02em; }
.tool-link:hover h3 { color: var(--cat, var(--brand)); }
.tool-link p { margin: 0; font-size: 0.89rem; color: var(--ink-2); line-height: 1.55; }

/* ---------- Footer ---------- */
.site-footer {
  border-top: 1px solid var(--line); background: color-mix(in srgb, var(--surface-2) 65%, var(--paper));
  padding: 40px 0 30px; font-size: 0.9rem; color: var(--ink-2);
}
.footer-inner { display: grid; gap: 26px; grid-template-columns: 1.4fr 1fr 1fr; align-items: start; }
.footer-inner h4 { font-family: var(--font-sans); font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.11em; color: var(--ink-3); margin: 4px 0 10px; font-weight: 700; }
.footer-inner ul { list-style: none; margin: 0; padding: 0; }
.footer-inner li { margin-bottom: 7px; }
.footer-inner a { color: var(--ink-2); text-decoration: none; }
.footer-inner a:hover { color: var(--brand); text-decoration: underline; }
.footer-bottom {
  border-top: 1px solid var(--line); margin-top: 28px; padding-top: 18px;
  display: flex; justify-content: space-between; gap: 10px; flex-wrap: wrap;
  font-size: 0.82rem; color: var(--ink-3);
}
@media (max-width: 760px) { .footer-inner { grid-template-columns: 1fr; } }

/* ---------- Repeating course rows ---------- */
.course-rows { display: grid; gap: 10px; margin-bottom: 14px; }
.course-row {
  display: grid; gap: 10px; align-items: end;
  grid-template-columns: 1.6fr 0.9fr 0.8fr 1fr auto;
  padding: 13px; border: 1px solid var(--line); border-radius: var(--radius-sm); background: var(--surface-2);
}
.course-row .field { margin-bottom: 0; }
.course-row label { font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--ink-3); margin-bottom: 5px; }
.course-row .c-remove { color: var(--danger); font-weight: 600; }
@media (max-width: 720px) {
  .course-row { grid-template-columns: 1fr 1fr; }
  .course-row .c-remove { grid-column: 1 / -1; justify-self: start; }
}

/* ---------- Utilities ---------- */
.mono { font-family: var(--font-mono); font-size: 0.92em; }
.muted { color: var(--ink-2); }
.small { font-size: 0.85rem; }
.cite-line {
  margin-top: 18px; padding: 10px 13px;
  border-left: 2px solid color-mix(in srgb, var(--brand) 32%, var(--line));
  background: color-mix(in srgb, var(--brand) 5%, transparent);
  border-radius: 0 7px 7px 0;
}
.cite-line strong { color: var(--ink); font-weight: 600; }
.cite-line .cite-target { font-family: var(--font-mono); font-size: 0.78rem; word-break: break-all; }
.nowrap { white-space: nowrap; }
.center { text-align: center; }
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
[hidden] { display: none !important; }
.spin { display: inline-block; width: 15px; height: 15px; border: 2px solid currentColor; border-right-color: transparent; border-radius: 50%; animation: spin 0.8s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: 0.001ms !important; transition-duration: 0.001ms !important; }
}

/* ---------- Small screens ---------- */
@media (max-width: 860px) {
  .hero { padding-top: 42px; }
  .tool-card { padding: 20px; }
  .result { padding: 18px; }
  /* 14px breadcrumb links are a 17px-tall tap target. Pad them without
     shifting the layout (negative margin cancels the padding). */
  .breadcrumbs a { display: inline-block; padding: 9px 2px; margin: -9px -2px; }
  .brand { padding-block: 6px; }
}
@media (max-width: 480px) {
  body { font-size: 1rem; }
  .wrap { padding: 0 16px; }
  /* One column turned a nine-field calculator into an 800px-tall stack with the
     Calculate button far below the fold. Two columns, with selects keeping the
     full width they need. */
  .field-row { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
  .field-row > .field:has(select), .field-row > .field:has(textarea) { grid-column: 1 / -1; }
  /* A three-field row inside two columns leaves one empty cell, which reads as a
     broken form. Let the orphan take the full width instead. */
  .field-row > .field:nth-child(odd):last-child:not(:first-child) { grid-column: 1 / -1; }
  /* Two-line labels push their input out of line with the neighbour's. Reserve
     the space for every label in the row so the inputs stay on one baseline. */
  /* The payment form opens a row with a short select ("30 years — fixed").
     Spanning it there would strand the next field alone in a half-empty row. */
  #mpForm .field-row > .field:first-child:has(select) { grid-column: auto; }
  .field-row > .field > label { min-height: 2.4em; margin-bottom: 6px; }
  .field-row > .field > .hint { font-size: 0.76rem; }
  .field { margin-bottom: 13px; }
  .tool-card, .card { padding: 16px; }
  .stat-grid { gap: 10px; }
  .stat { padding: 11px 13px; }
  .big-number { font-size: 1.9rem; }
  .hero-sub { font-size: 1.02rem; }
}

@media print {
  .site-header, .site-footer, .ad-slot, .nav-toggle { display: none !important; }
  body { background: #fff; color: #000; }
}

/* Respect forced-colors mode: gradient text is invisible there. */
@media (forced-colors: active) {
  .grad { background: none; -webkit-text-fill-color: currentColor; color: var(--ink); }
}

/* ---------- Music player (circular) ---------- */
.tn-player { position: fixed; right: 18px; bottom: 18px; z-index: 70; font-family: var(--font-sans); }
.tn-disc {
  position: relative; width: 64px; height: 64px; border-radius: 50%;
  background:
    repeating-radial-gradient(circle at 50% 50%, #1a1a1a 0 2px, #232323 2px 4px),
    #1a1a1a;
  box-shadow: 0 10px 22px -8px rgba(0,0,0,.55), inset 0 0 0 1px rgba(255,255,255,.06);
  display: grid; place-items: center;
}
.tn-disc::after {
  content: ""; width: 26px; height: 26px; border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, color-mix(in srgb, var(--brand) 78%, #fff), var(--brand));
  box-shadow: 0 0 0 3px rgba(0,0,0,.55);
}
.tn-disc-label {
  position: absolute; z-index: 2; font-size: 9px; font-weight: 800; letter-spacing: .04em;
  color: #fff; text-shadow: 0 1px 2px rgba(0,0,0,.6); pointer-events: none;
}
.tn-player-dock { position: relative; }
.tn-player-toggle {
  padding: 0; border: 0; background: transparent; cursor: pointer; border-radius: 50%;
  line-height: 0; -webkit-tap-highlight-color: transparent;
}
/* The disc is a widget on every page. Give the visitor a way out: a small ×
   pinned to the disc's corner, quiet until hovered or focused. */
.tn-player-dismiss {
  position: absolute; top: -6px; right: -6px; width: 22px; height: 22px;
  display: grid; place-items: center; padding: 0;
  border: 1px solid var(--line-2); border-radius: 50%;
  /* Alpha on the element itself lets the black disc bleed through and the
     button turns grey. Keep it opaque; go quiet with colour instead. */
  background: var(--surface); color: color-mix(in srgb, var(--ink-3) 85%, transparent);
  font-size: 15px; line-height: 1; cursor: pointer;
  box-shadow: 0 2px 6px rgba(20, 24, 35, 0.22);
  transition: color 0.15s ease, transform 0.15s ease, border-color 0.15s ease;
}
.tn-player-dismiss:hover, .tn-player-dismiss:focus-visible {
  color: var(--ink); transform: scale(1.08);
  border-color: color-mix(in srgb, var(--ink-3) 55%, var(--line-2));
}
.tn-player-dismiss:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
/* 22px is the right visual weight on a 64px disc but a finger needs 44px, so the
   hit area is expanded invisibly. */
.tn-player-dismiss::before { content: ""; position: absolute; inset: -11px; border-radius: 50%; }
.tn-player-toggle:focus-visible { outline: 3px solid color-mix(in srgb, var(--brand) 70%, transparent); outline-offset: 3px; }
.tn-player.is-playing .tn-disc { animation: tn-spin 6s linear infinite; }
@keyframes tn-spin { to { transform: rotate(360deg); } }
.tn-player-panel {
  position: absolute; right: 0; bottom: 80px; width: min(340px, calc(100vw - 36px));
  background: var(--surface); border: 1px solid var(--line); border-radius: 16px;
  box-shadow: var(--shadow); padding: 16px; display: none;
}
.tn-player.is-open .tn-player-panel { display: block; }
.tn-player-head { display: flex; align-items: flex-start; gap: 12px; }
.tn-mini-disc {
  flex: none; width: 40px; height: 40px; border-radius: 50%; position: relative;
  background: repeating-radial-gradient(circle at 50% 50%, #1a1a1a 0 1.5px, #262626 1.5px 3px);
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.06);
}
.tn-mini-disc::after {
  content: ""; position: absolute; inset: 13px; border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, color-mix(in srgb, var(--brand) 78%, #fff), var(--brand));
}
.tn-player.is-playing .tn-mini-disc { animation: tn-spin 6s linear infinite; }
.tn-player-title { font-family: var(--font-display); font-size: 1rem; font-weight: 600; line-height: 1.25; }
.tn-player-meta { font-size: 0.78rem; color: var(--ink-3); margin-top: 2px; }
.tn-player-close { margin-left: auto; border: 0; background: transparent; color: var(--ink-3); font-size: 1.1rem; line-height: 1; cursor: pointer; padding: 4px; border-radius: 6px; }
.tn-player-close:hover { background: var(--surface-2); color: var(--ink); }
.tn-player-range { width: 100%; accent-color: var(--brand); margin: 12px 0 4px; }
.tn-player-times { display: flex; justify-content: space-between; font-size: 0.72rem; color: var(--ink-3); font-variant-numeric: tabular-nums; }
.tn-player-controls { display: flex; align-items: center; justify-content: center; gap: 10px; margin-top: 10px; }
.tn-player-btn {
  width: 38px; height: 38px; border-radius: 50%; border: 1px solid var(--line-2); background: var(--surface);
  color: var(--ink); cursor: pointer; display: grid; place-items: center; font-size: 0.95rem;
}
.tn-player-btn:hover { background: var(--surface-2); }
.tn-player-btn.is-main { width: 46px; height: 46px; background: var(--brand); border-color: var(--brand); color: #fff; font-size: 1rem; }
.tn-player-btn.is-main:hover { filter: brightness(1.07); background: var(--brand); }
.tn-player-foot { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: 8px 10px; margin-top: 12px; font-size: 0.72rem; color: var(--ink-3); }
.tn-player-foot span { flex: 1 1 auto; min-width: 0; }
.tn-player-foot a { color: var(--ink-3); }
.tn-player-vol { width: 84px; accent-color: var(--brand); }
@media print { .tn-player { display: none !important; } }
@media (max-width: 480px) {
  .tn-player { right: 12px; bottom: 12px; }
  .tn-player-panel { width: calc(100vw - 24px); }
}
/* ---------- Home hero background carousel ---------- */
.hero { overflow: clip; }
.hero-copy, .hero-figure { position: relative; z-index: 1; }
.hero-bg {
  position: absolute; inset: 0; border-radius: 26px;
  z-index: -2; overflow: hidden; pointer-events: none;
}
.hero-bg picture { display: contents; }
.hero-bg img {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  opacity: 0; transition: opacity 1.6s ease; filter: saturate(0.92) contrast(1.03);
}
.hero-bg img.is-active { opacity: 1; }
.hero-bg::after {
  content: ""; position: absolute; inset: 0;
  background:
    linear-gradient(90deg, var(--paper) 0%, color-mix(in srgb, var(--paper) 88%, transparent) 30%, color-mix(in srgb, var(--paper) 58%, transparent) 56%, color-mix(in srgb, var(--paper) 10%, transparent) 80%, transparent 100%),
    linear-gradient(180deg, transparent 0%, transparent 58%, var(--paper) 99%);
}
/* One-column hero (<=999px) puts the copy across the full width, so the
   left-to-right veil stops protecting it and the sub-text runs over the
   busiest part of the photo. Switch to a vertical veil at the same breakpoint
   the layout collapses at, not 300px later. */
@media (max-width: 999px) {
  .hero-bg::after {
    background:
      linear-gradient(180deg, color-mix(in srgb, var(--paper) 76%, transparent) 0%, color-mix(in srgb, var(--paper) 90%, transparent) 54%, var(--paper) 100%);
  }
}
@media (prefers-reduced-motion: reduce) {
  .hero-bg img { transition: none; }
}
/* The hero photo is a daylight scene. Left at full brightness it becomes a
   glowing band across the top of an otherwise dark page. */
@media (prefers-color-scheme: dark) {
  .hero-bg img { filter: saturate(0.55) brightness(0.42) contrast(1.12); }
  .hero-bg::after {
    background:
      linear-gradient(90deg, var(--paper) 0%, color-mix(in srgb, var(--paper) 92%, transparent) 26%, color-mix(in srgb, var(--paper) 74%, transparent) 52%, color-mix(in srgb, var(--paper) 34%, transparent) 78%, color-mix(in srgb, var(--paper) 12%, transparent) 100%),
      linear-gradient(180deg, color-mix(in srgb, var(--paper) 40%, transparent) 0%, transparent 40%, var(--paper) 98%);
  }
}

/* ---------- Wide screens (fill the viewport) ---------- */
@media (min-width: 1500px) {
  .wrap { padding: 0 34px; }
  .tool-grid { grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 18px; }
  .prose { max-width: min(800px, 74ch); }
  .hero { padding: 86px 0 34px; gap: 56px; }
  .card.tool-card { padding: 32px 34px; }
  .footer-inner { gap: 56px; }
}
@media (min-width: 1760px) {
  .lede { font-size: 1.15rem; }
  .hero-copy { max-width: 780px; }
  .tool-grid { grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); }
}
/* Full-bleed hero band on desktop */
@media (min-width: 1200px) {
  .hero {
    margin-inline: calc(50% - 50vw);
    padding-inline: calc(50vw - 50%);
  }
  .hero-bg { border-radius: 0 0 30px 30px; }
}
html { overflow-x: clip; }
/* ---------- Touch targets ---------- */
/* 30px colour swatches on wordle and a 39px checkbox row were the only
   remaining <40px targets in the visual audit. Desktop keeps its compact
   sizing; on a phone both go to the 44px guideline. */
@media (max-width: 700px) {
  .tile-color { height: 44px; }
  /* .field-row > .field > label sets min-height: 2.4em (0,3,0) and wins over
     a bare .check rule, so match its specificity to get to 44px. */
  .field-row > .field > label.check { min-height: 44px; align-items: center; }
  .check input { margin-top: 0; }
}
