/* Braille Link public website. Decisions and rules: DESIGN.md.
   Monochrome: white with dark text in light mode, black with white text in dark mode.
   Glass is used only for the sticky header, the one layer that floats over content as the page
   scrolls beneath it. Everything else sits on plain surfaces.

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

/* ---------- Tokens ---------- */
/* Each colour is written once as light-dark(light, dark). The page follows the system setting;
   the header toggle sets data-theme to force one scheme. */
:root { color-scheme: light dark; }
:root[data-theme="light"] { color-scheme: light; }
:root[data-theme="dark"] { color-scheme: dark; }

:root {
  --bg: light-dark(#ffffff, #000000);
  --bg-alt: light-dark(#f4f4f5, #0e0e10);
  --surface: light-dark(#ffffff, #141416);
  --text: light-dark(#0a0a0a, #ffffff);
  --text-soft: light-dark(#52525b, #a1a1aa);    /* 7.7:1 on white, 8.7:1 on black */
  --line: light-dark(#e4e4e7, #27272a);
  --line-strong: light-dark(#71717a, #8b8b93);  /* 3:1+ for borders and rules that carry meaning */
  --invert-bg: light-dark(#0a0a0a, #ffffff);
  --invert-text: light-dark(#ffffff, #000000);
  --invert-soft: light-dark(#d4d4d8, #3f3f46);
  --btn-hover: light-dark(#27272a, #e4e4e7);
  --hover-wash: light-dark(rgba(0, 0, 0, 0.05), rgba(255, 255, 255, 0.08));
  --focus: light-dark(#0a0a0a, #ffffff);
  --error: light-dark(#b42318, #ff8a80);
  --error-bg: light-dark(#fef3f2, #2a0e0c);

  /* Glass: only for layers over content. */
  --glass-bg: light-dark(rgba(255, 255, 255, 0.72), rgba(20, 20, 22, 0.66));
  --glass-solid: light-dark(#ffffff, #141416);
  --glass-border: light-dark(rgba(0, 0, 0, 0.08), rgba(255, 255, 255, 0.12));
  --glass-rim: light-dark(rgba(255, 255, 255, 0.9), rgba(255, 255, 255, 0.18));
  --shadow: light-dark(0 1px 2px rgba(0, 0, 0, 0.05), 0 1px 2px rgba(0, 0, 0, 0.6));
  --shadow-float: light-dark(0 18px 40px -20px rgba(0, 0, 0, 0.3), 0 18px 40px -20px rgba(0, 0, 0, 0.9));

  --key-bg: light-dark(linear-gradient(#ffffff, #efeff1), linear-gradient(#26262a, #1b1b1e));
  --key-border: light-dark(#c9c9cf, #3f3f46);
  --dot-off-border: light-dark(rgba(0, 0, 0, 0.35), rgba(255, 255, 255, 0.45));
  --dot-lift: light-dark(rgba(0, 0, 0, 0.35), rgba(255, 255, 255, 0.35));

  --radius-lg: 20px;
  --radius: 12px;
  --radius-sm: 8px;

  --font: "Atkinson Hyperlegible Next", "Segoe UI", system-ui, -apple-system, sans-serif;
  --braille-font: "Segoe UI Symbol", "Apple Braille", "DejaVu Sans", sans-serif;
  /* Type: one ratio (1.25, a major third) from a 17px base; the two display sizes grow with the window. */
  --step--1: 0.875rem;
  --step-0: 1.0625rem;
  --step-1: 1.328rem;
  --step-2: 1.66rem;
  --step-3: 2.075rem;
  --step-4: clamp(2.075rem, 1.5rem + 1.9vw, 2.594rem);
  --step-5: clamp(2.594rem, 1.6rem + 3.4vw, 4.053rem);
  /* Space: one scale, used for every gap and margin. */
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 1rem;
  --space-4: 1.5rem;
  --space-5: 2rem;
  --space-6: 3rem;
  --space-7: 4rem;
  --space-8: 6rem;

  --gutter: clamp(1rem, 0.6rem + 1.6vw, 1.5rem);
  --section: clamp(var(--space-7), 2.5rem + 4vw, var(--space-8));
  --header-h: 4.5rem;
}

/* ---------- Base ---------- */
*, *::before, *::after { box-sizing: border-box; }
html {
  -webkit-text-size-adjust: 100%; text-size-adjust: 100%;
  /* The sticky header must never hide a focused or linked-to element (WCAG 2.4.11). */
  scroll-padding-top: calc(var(--header-h) + 1rem);
}
body {
  margin: 0; font-family: var(--font); font-size: var(--step-0); line-height: 1.6;
  color: var(--text); background: var(--bg); overflow-wrap: break-word;
}
img, svg { max-width: 100%; height: auto; display: block; }
[hidden] { display: none !important; } /* the hidden attribute always wins over component display values */
h1, h2, h3 { line-height: 1.15; margin: 0 0 0.6em; font-weight: 760; letter-spacing: -0.015em; text-wrap: balance; }
h2 { font-size: var(--step-4); }
h3 { font-size: var(--step-1); line-height: 1.3; }
p { margin: 0 0 1em; }
p:last-child { margin-bottom: 0; }
p, li, dd { max-width: 62ch; text-wrap: pretty; }
a { color: var(--text); text-decoration: underline; text-underline-offset: 0.2em; text-decoration-thickness: 1px; }
a:hover { text-decoration-thickness: 2px; }
ul[role="list"] { list-style: none; margin: 0; padding: 0; }
code { font-family: ui-monospace, Consolas, monospace; font-size: 0.9em; }
main:focus { outline: none; }
:focus-visible { outline: 3px solid var(--focus); outline-offset: 3px; border-radius: 4px; }

.visually-hidden {
  position: absolute !important; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.skip-link {
  position: absolute; left: 1rem; top: -100px; z-index: 100; padding: 0.75rem 1.25rem;
  background: var(--invert-bg); color: var(--invert-text); border-radius: var(--radius); font-weight: 800; text-decoration: none;
}
.skip-link:focus { top: 1rem; }

/* ---------- Layout ---------- */
.container { width: 100%; max-width: 76rem; margin-inline: auto; padding-inline: var(--gutter); }
.section { padding-block: var(--section); }
.section--alt { background: var(--bg-alt); }
.lead { color: var(--text-soft); font-size: var(--step-1); line-height: 1.5; }
.section-head { margin-bottom: var(--space-6); }
.section-head > p { color: var(--text-soft); font-size: var(--step-1); line-height: 1.5; }

/* Components size themselves from their container, not the window. */
.container, .split > *, .cell-demo > * { container-type: inline-size; }

.split { display: grid; gap: 3rem; align-items: start; }
@media (min-width: 60em) {
  .split { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 4.5rem; }
  .split--center { align-items: center; }
}

/* Balanced grids: columns chosen from the item count, so rows are always full. */
.grid, .plans { display: grid; gap: 1.25rem; grid-template-columns: minmax(0, 1fr); }
@container (min-width: 34rem) {
  .grid:has(> :nth-child(2):last-child), .grid:has(> :nth-child(4):last-child) { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@container (min-width: 60rem) {
  .grid:has(> :nth-child(3):last-child), .plans:has(> :nth-child(3):last-child) { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .grid:has(> :nth-child(4):last-child) { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 0.5rem;
  min-height: 3rem; padding: 0.65rem 1.3rem; border-radius: var(--radius); border: 2px solid transparent;
  background: transparent; font: inherit; font-weight: 750; line-height: 1.2; text-decoration: none; text-align: center;
  cursor: pointer; transition: background-color 0.15s, border-color 0.15s;
}
.btn--sm { min-height: 2.75rem; padding: 0.45rem 1rem; font-size: var(--step--1); }
.btn--primary { background: var(--invert-bg); color: var(--invert-text); }
.btn--primary:hover { background: var(--btn-hover); color: var(--invert-text); }
.btn--outline { border-color: var(--text); color: var(--text); }
.btn--outline:hover { background: var(--hover-wash); color: var(--text); }
.actions { display: flex; flex-wrap: wrap; gap: var(--space-3); margin-top: var(--space-5); }

/* ---------- Header: the one glass layer that is always present ---------- */
.site-header {
  position: sticky; top: 0; z-index: 30; color: var(--text);
  background: var(--glass-solid); border-bottom: 1px solid var(--glass-border);
}
@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  @media (prefers-reduced-transparency: no-preference) {
    .site-header {
      background: var(--glass-bg);
      -webkit-backdrop-filter: blur(20px) saturate(150%);
      backdrop-filter: blur(20px) saturate(150%);
    }
  }
}
.site-header__inner { display: flex; align-items: center; gap: 1.25rem; min-height: var(--header-h); max-width: 84rem; }
.brand { display: inline-flex; align-items: center; gap: 0.65rem; color: inherit; text-decoration: none; flex-shrink: 0; }
.brand__mark { width: 2.5rem; height: 2.5rem; color: var(--text); }
.brand__mark .brand__dot { fill: var(--bg); }
.brand__mark .brand__line { stroke: var(--bg); }
.brand__text { display: flex; flex-direction: column; line-height: 1.1; }
.brand__name { font-size: 1.2rem; font-weight: 800; letter-spacing: -0.01em; }
.brand__by { font-size: 0.8125rem; color: var(--text-soft); }

.site-menu { display: flex; align-items: center; gap: 1.25rem; margin-left: auto; }
.primary-nav ul { display: flex; }
.primary-nav a {
  display: flex; align-items: center; min-height: 2.75rem; padding: 0 0.7rem; white-space: nowrap;
  color: var(--text); text-decoration: none; font-size: var(--step--1); font-weight: 650;
}
.primary-nav a:hover { text-decoration: underline; }
/* Current page: an underline, not a filled pill. */
.primary-nav a[aria-current="page"] { text-decoration: underline; text-decoration-thickness: 3px; text-underline-offset: 0.45em; }
.header-actions { display: flex; gap: 0.5rem; align-items: center; flex-shrink: 0; }

.icon-btn, .menu-toggle {
  display: inline-flex; align-items: center; justify-content: center; gap: 0.4rem;
  min-width: 2.75rem; min-height: 2.75rem; padding: 0 0.6rem; border-radius: var(--radius);
  border: 1px solid var(--line-strong); background: transparent; color: var(--text); font: inherit; font-weight: 750; cursor: pointer;
}
.icon-btn:hover, .menu-toggle:hover { background: var(--hover-wash); }
.icon-btn .icon, .menu-toggle .icon { width: 1.2rem; height: 1.2rem; }
.theme-toggle[aria-pressed="true"] .theme-toggle__to-dark,
.theme-toggle[aria-pressed="false"] .theme-toggle__to-light { display: none; }
html:not(.js) .theme-toggle { display: none; }
.menu-toggle { display: none; margin-left: auto; }

/* Below 60em (phones and portrait tablets) the header shows a Menu button, which opens the side menu (a modal dialog, below).
   "js" is set in the page head before first paint, so the links never flash under the logo. Without
   JavaScript, or in a browser without modal dialogs, the links wrap under the logo instead. */
@media (max-width: 59.99em) {
  .site-header__inner { flex-wrap: wrap; }
  .site-menu { flex-basis: 100%; flex-wrap: wrap; }
  .primary-nav ul { flex-wrap: wrap; }
  @supports selector(:modal) {
    .js .menu-toggle { display: inline-flex; }
    .js .site-header .site-menu { display: none; }
  }
}

/* ---------- Side menu ----------
   Slides in from the right, only as wide as its longest item plus padding, never the whole screen.
   The page behind is dimmed a little and blurred (5px) through the dialog's own backdrop. The slide
   uses CSS alone: it animates in and out where the browser can animate a dialog opening and
   closing, and simply appears elsewhere. Under reduced motion it fades instead of sliding. */
.side-menu {
  --slide: 0.3s;
  position: fixed; inset: 0 0 0 auto; margin: 0; height: 100dvh; max-height: none;
  width: max-content; max-width: calc(100vw - 3.5rem);
  padding: var(--space-3) var(--space-5) var(--space-5); overflow-y: auto; overscroll-behavior: contain;
  border: 0; border-left: 1px solid var(--line-strong); background: var(--glass-solid); color: var(--text);
  box-shadow: var(--shadow-float);
  transform: translateX(100%);
  transition: transform var(--slide) cubic-bezier(0.2, 0.8, 0.2, 1), display var(--slide) allow-discrete, overlay var(--slide) allow-discrete;
}
.side-menu[open] { display: flex; flex-direction: column; gap: var(--space-4); transform: none; }
@starting-style { .side-menu[open] { transform: translateX(100%); } }
.side-menu::backdrop {
  background: rgb(0 0 0 / 0); -webkit-backdrop-filter: blur(0); backdrop-filter: blur(0);
  transition: background var(--slide), backdrop-filter var(--slide), -webkit-backdrop-filter var(--slide), display var(--slide) allow-discrete, overlay var(--slide) allow-discrete;
}
.side-menu[open]::backdrop { background: rgb(0 0 0 / 0.22); -webkit-backdrop-filter: blur(5px); backdrop-filter: blur(5px); }
@starting-style { .side-menu[open]::backdrop { background: rgb(0 0 0 / 0); -webkit-backdrop-filter: blur(0); backdrop-filter: blur(0); } }
@media (prefers-reduced-motion: reduce) {
  .side-menu { transform: none; opacity: 0; transition: opacity 0.2s, display 0.2s allow-discrete, overlay 0.2s allow-discrete; }
  .side-menu[open] { opacity: 1; }
  @starting-style { .side-menu[open] { opacity: 0; transform: none; } }
}
/* The page underneath does not scroll while the menu is open. */
html:has(.side-menu[open]) { overflow: hidden; }

.side-menu__head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-5); }
.side-menu__title { margin: 0; font-size: var(--step-0); font-weight: 800; }
.side-menu__nav ul { display: flex; flex-direction: column; }
.side-menu__nav a { min-height: 3rem; padding: 0 0.25rem; font-size: var(--step-1); border-bottom: 1px solid var(--line); }
.side-menu__nav a[aria-current="page"] { text-underline-offset: 0.3em; }
.side-menu__actions { display: flex; flex-direction: column; gap: var(--space-2); }
.side-menu__actions .btn { width: 100%; }
.side-menu__theme {
  display: inline-flex; align-items: center; gap: 0.6rem; min-height: 2.75rem; padding: 0 0.25rem;
  border: 0; background: none; color: var(--text); font: inherit; font-weight: 650; cursor: pointer;
}
.side-menu__theme .icon { width: 1.2rem; height: 1.2rem; }
/* The side menu is only for narrow screens: never shown once the full navigation fits. */
@media (min-width: 60em) { .side-menu { display: none !important; } }

/* ---------- Page introductions ---------- */
.hero { padding-block: clamp(3rem, 2rem + 4vw, 5.5rem); border-bottom: 1px solid var(--line); }
.hero__grid { display: grid; gap: 3rem; align-items: center; }
@media (min-width: 60em) { .hero__grid--media { grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); gap: var(--space-7); } }
.hero__title { font-size: var(--step-5); line-height: 1.04; letter-spacing: -0.03em; margin-bottom: 1.25rem; font-weight: 800; }
.hero--compact .hero__title { font-size: clamp(2.2rem, 1.4rem + 3vw, 3.4rem); }
.hero__lead { font-size: var(--step-1); line-height: 1.5; max-width: 38rem; }
.hero__body { color: var(--text-soft); max-width: 38rem; }
.hero__note { margin-top: 1.25rem; font-size: var(--step--1); color: var(--text-soft); }
.hero__media .media { border-radius: var(--radius-lg); }
.media { width: 100%; height: auto; border-radius: var(--radius); }

/* ---------- Keycaps and Braille ---------- */
kbd {
  display: inline-grid; place-items: center; min-width: 2.2rem; height: 2.2rem; padding: 0 0.5rem;
  border-radius: var(--radius-sm); font: inherit; font-weight: 800; color: var(--text);
  background: var(--key-bg); border: 1px solid var(--key-border); border-bottom-width: 3px;
}
kbd.is-on { background: var(--invert-bg); color: var(--invert-text); border-color: var(--invert-bg); }
.braille-svg { display: inline-block; height: 1.5em; width: auto; margin-right: 0.55em; vertical-align: middle; fill: currentColor; }
.braille-svg circle:not(.off) { filter: drop-shadow(0 1.2px 0.6px var(--dot-lift)); }
.braille-svg .off { fill: none; stroke: currentColor; stroke-width: 1; opacity: 0.3; }

/* ---------- Home: the story ---------- */
/* An opening set in large type, then chapters: one idea each, a sentence or two, at most one picture.
   Chapters alternate background and side, so the eye moves down the page in a gentle zigzag. */
.opening { padding-block: calc(var(--header-h) + var(--space-7)) var(--space-8); border-bottom: 1px solid var(--line); }
.opening__title { font-size: clamp(2.75rem, 1.5rem + 5vw, 5.25rem); line-height: 1.02; letter-spacing: -0.035em; font-weight: 800; max-width: 14ch; margin-bottom: var(--space-5); }
.opening__braille { display: flex; flex-wrap: wrap; row-gap: var(--space-2); font-size: clamp(1.1rem, 0.9rem + 0.8vw, 1.6rem); color: var(--text-soft); margin-bottom: var(--space-6); }
.opening__lead { font-size: var(--step-1); line-height: 1.5; max-width: 40ch; }

.chapter { padding-block: var(--space-8); }
.chapter--alt { background: var(--bg-alt); }
.chapter h2 { font-size: var(--step-4); letter-spacing: -0.025em; }
.chapter__text > p { font-size: var(--step-1); line-height: 1.55; color: var(--text-soft); max-width: 36ch; }
/* The answer after a problem: bold text inside softer paragraphs is set in full ink. */
.chapter__text > p strong, .lead strong { color: var(--text); }
.chapter__text--solo > p { max-width: 44ch; }
.chapter__aside { font-size: var(--step-0) !important; color: var(--text) !important; font-weight: 700; }
.chapter__grid { display: grid; gap: var(--space-6); align-items: center; }
@media (min-width: 60em) {
  .chapter__grid { grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); gap: var(--space-7); }
  .chapter__grid--flip > :first-child { order: 2; }
  .chapter__grid--flip { grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); }
}
.more-link { display: inline-flex; align-items: center; min-height: 2.75rem; margin-top: var(--space-3); font-weight: 750; }

/* Braille paired with its print: the whole point of the product in one picture. */
.pairing { margin: 0; display: grid; gap: var(--space-4); }
.pairing p { margin: 0; max-width: none; }
.pairing__braille { display: flex; flex-wrap: wrap; row-gap: var(--space-3); font-size: clamp(1.6rem, 1.2rem + 1.4vw, 2.4rem); }
.pairing__braille--sm { font-size: clamp(1.2rem, 1rem + 0.8vw, 1.6rem); }
.pairing__print { font-size: var(--step-2); font-weight: 750; padding-top: var(--space-4); border-top: 2px solid var(--text); }
.pairing__question { font-size: var(--step-0); color: var(--text-soft); font-weight: 700; }

/* ---------- Home: live Braille cell ---------- */

/* The six keys (and A), with the dot each writes; they light up for the letter being made. */
.homerow__keys { list-style: none; margin: var(--space-5) 0 0; padding: 0; display: grid; grid-template-columns: repeat(4, 1fr) 0.5fr repeat(3, 1fr); gap: var(--space-2); max-width: 30rem; }
.homerow__keys li { display: grid; justify-items: center; gap: var(--space-1); }
.homerow__keys kbd { width: 100%; height: 3rem; min-width: 0; font-size: var(--step-1); transition: transform 0.08s, background-color 0.08s, color 0.08s, border-bottom-width 0.08s; }
.homerow__keys span { font-size: var(--step--1); color: var(--text-soft); white-space: nowrap; }
.homerow__keys li.is-on kbd { background: var(--invert-bg); color: var(--invert-text); border-color: var(--invert-bg); }
.homerow__keys li.is-on span { color: var(--text); font-weight: 700; }
.homerow__keys li.is-down kbd { transform: translateY(2px); border-bottom-width: 1px; }

/* Parts of the Braille writer reused from the earlier demo. */
.cell { display: grid; grid-template-columns: repeat(2, 3.5rem); grid-auto-flow: column; grid-template-rows: repeat(3, 3.5rem); gap: 0.65rem; flex-shrink: 0; }
.cell__dot {
  width: 3.5rem; height: 3.5rem; border-radius: 50%; border: 2px solid var(--dot-off-border); background: var(--surface);
  color: var(--text); font: inherit; font-weight: 800; font-size: 1rem; cursor: pointer; display: grid; place-items: center;
  transition: background-color 0.12s, color 0.12s, transform 0.12s;
}
.cell__dot:hover { border-color: var(--text); }
.cell__dot[aria-pressed="true"] { background: var(--invert-bg); color: var(--invert-text); border-color: var(--invert-bg); box-shadow: 0 3px 0 var(--dot-lift); transform: translateY(-2px); }
.cell__dot:focus-visible { outline-offset: 3px; border-radius: 50%; }

.result__letter { font-size: var(--step-5); font-weight: 800; line-height: 1; margin: 0; min-width: 3ch; }
.cell-demo__speech { display: flex; align-items: center; gap: var(--space-2); min-height: 2.75rem; font-size: var(--step--1); }
.cell-demo__speech input { width: 1.25rem; height: 1.25rem; accent-color: var(--text); }
.text-btn { min-height: 2.75rem; padding: 0; border: 0; background: none; color: var(--text); font: inherit; font-size: var(--step--1); font-weight: 700; text-decoration: underline; text-underline-offset: 0.2em; cursor: pointer; }
.text-btn:hover { text-decoration-thickness: 2px; }


/* ---------- Text lists (in place of cards) ---------- */
/* Definition list with hairlines: a term and one or two sentences. */
.rows { margin: 0; padding: 0; display: grid; }
.rows > div, .rows > li { display: grid; gap: 0.3rem; padding-block: 1.1rem; border-top: 1px solid var(--line); }
.rows > :last-child { border-bottom: 1px solid var(--line); }
@container (min-width: 36rem) { .rows > div { grid-template-columns: minmax(8rem, 12rem) minmax(0, 1fr); gap: 1.5rem; align-items: baseline; } }
.rows dt, .rows h3 { font-weight: 800; font-size: var(--step-1); margin: 0; }
.rows dd { margin: 0; color: var(--text-soft); }
/* Two columns of short facts, divided by rules. */
.spec-list { margin: 0; display: grid; column-gap: 4rem; }
@container (min-width: 46rem) { .spec-list { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.spec-list > div { padding-block: 1.4rem; border-top: 1px solid var(--line-strong); }
.spec-list dt { font-weight: 800; font-size: var(--step-2); letter-spacing: -0.01em; margin-bottom: 0.4rem; }
.spec-list dd { margin: 0; color: var(--text-soft); font-size: var(--step-1); line-height: 1.55; }
/* Plain bulleted list for running content. */
.bullets { margin: 1rem 0 0; padding-left: 1.25rem; display: grid; gap: 0.45rem; }
.bullets li::marker { color: var(--text-soft); }
/* A real sequence: numbered, on a single rule. */
.sequence { list-style: none; margin: 0; padding: 0; counter-reset: step; display: grid; }
.sequence li { counter-increment: step; position: relative; padding: 0 0 1.75rem 3.25rem; }
.sequence li::before {
  content: counter(step); position: absolute; left: 0; top: 0; width: 2rem; height: 2rem; display: grid; place-items: center;
  border-radius: 50%; border: 2px solid var(--text); font-weight: 800; background: var(--bg);
}
.sequence li::after { content: ""; position: absolute; left: calc(1rem - 1px); top: 2.25rem; bottom: 0.25rem; width: 2px; background: var(--line); }
.sequence li:last-child { padding-bottom: 0; }
.sequence li:last-child::after { display: none; }
.sequence h3 { margin: 0.1rem 0 0.35rem; }
.sequence p { color: var(--text-soft); }
@container (min-width: 60rem) {
  .sequence--row { grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); column-gap: 2rem; }
  .sequence--row li { padding: 3.25rem 0 0; }
  .sequence--row li::after { left: 2.5rem; right: -1.5rem; top: calc(1rem - 1px); bottom: auto; width: auto; height: 2px; }
}

/* ---------- Comparison table ---------- */
.compare { width: 100%; border-collapse: collapse; font-size: var(--step-0); }
.compare caption { text-align: left; color: var(--text-soft); margin-bottom: 1rem; }
.compare th, .compare td { text-align: left; vertical-align: top; padding: 0.9rem 1rem 0.9rem 0; border-bottom: 1px solid var(--line); }
.compare thead th { font-size: var(--step-1); border-bottom: 2px solid var(--text); }
.compare tbody th { font-weight: 700; width: 62%; }
.compare td { color: var(--text-soft); }
@media (max-width: 40em) {
  .compare thead { display: none; }
  .compare tr { display: grid; padding-block: 0.75rem; border-bottom: 1px solid var(--line); }
  .compare th, .compare td { border: 0; padding: 0.15rem 0; width: auto; }
  .compare td::before { content: attr(data-label) ": "; font-weight: 700; color: var(--text); }
}

/* ---------- Pricing ---------- */
.plan { display: flex; flex-direction: column; gap: 0.9rem; padding: 1.75rem; border-radius: var(--radius-lg); border: 1px solid var(--line); background: var(--surface); }
.plan--featured { border: 2px solid var(--text); }
.plan h2 { font-size: var(--step-2); margin: 0; }
.plan__audience, .plan__note { color: var(--text-soft); margin: 0; }
.plan__note { font-size: var(--step--1); }
.plan__price { font-size: var(--step-3); font-weight: 800; margin: 0; line-height: 1.2; }
.plan .bullets { margin-block: 0.25rem 1rem; }
.plan .btn { margin-top: auto; }

/* ---------- Forms ---------- */
.contact-grid { display: grid; gap: 3rem; }
@media (min-width: 60em) { .contact-grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1.5fr); } }
.form { display: grid; gap: 1.25rem; padding: clamp(1.5rem, 1rem + 2vw, 2.25rem); border-radius: var(--radius-lg); border: 1px solid var(--line); background: var(--surface); }
.form__row { display: grid; gap: 1.25rem; }
@media (min-width: 40em) { .form__row { grid-template-columns: 1fr 1fr; } }
.field { display: grid; gap: 0.4rem; }
.field label, .field legend { font-weight: 750; }
.field__hint { color: var(--text-soft); font-size: var(--step--1); margin: 0; }
.field__optional { font-weight: 400; color: var(--text-soft); }
.field input, .field select, .field textarea {
  width: 100%; min-height: 3rem; padding: 0.6rem 0.85rem; border: 2px solid var(--line-strong); border-radius: var(--radius-sm);
  font: inherit; color: var(--text); background: var(--bg);
}
.field textarea { min-height: 9rem; resize: vertical; }
.field input:focus-visible, .field select:focus-visible, .field textarea:focus-visible { outline-offset: 1px; border-color: var(--text); }
.field [aria-invalid="true"] { border-color: var(--error); }
.field__error { color: var(--error); font-weight: 700; font-size: var(--step--1); margin: 0; }
fieldset.form__group { border: 1px solid var(--line); border-radius: var(--radius); padding: 1.25rem; margin: 0; display: grid; gap: 1.25rem; }
fieldset.form__group legend { font-weight: 800; padding-inline: 0.4rem; }
.error-summary { border: 2px solid var(--error); border-radius: var(--radius); padding: 1.25rem; background: var(--error-bg); }
.error-summary h2 { font-size: var(--step-1); color: var(--error); margin-bottom: 0.5rem; }
.error-summary ul { margin: 0; padding-left: 1.2rem; }
.error-summary a { color: var(--error); font-weight: 700; }
.form__note { color: var(--text-soft); font-size: var(--step--1); margin: 0; }
.form__status { padding: 1rem 1.25rem; border-radius: var(--radius); background: var(--invert-bg); color: var(--invert-text); font-weight: 650; }

/* ---------- FAQ ---------- */
.faq { display: grid; border-top: 1px solid var(--line); }
.faq details { border-bottom: 1px solid var(--line); }
.faq summary { cursor: pointer; padding: 1.1rem 0; font-weight: 750; font-size: var(--step-1); min-height: 3rem; }
.faq details p { padding-bottom: 1.25rem; color: var(--text-soft); }

/* ---------- Closing call to action: a section, not a box ---------- */
.closing { padding-block: var(--section); background: var(--bg-alt); border-top: 1px solid var(--line); }
.closing h2 { font-size: var(--step-4); }
.closing p { color: var(--text-soft); font-size: var(--step-1); }

/* ---------- Footer ---------- */
.site-footer { background: #0a0a0a; color: #d4d4d8; font-size: var(--step--1); }
:root[data-theme="dark"] .site-footer { border-top: 1px solid var(--line); }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .site-footer { border-top: 1px solid var(--line); } }
.site-footer a { color: #ffffff; text-decoration: none; }
.site-footer a:hover { text-decoration: underline; }
.site-footer :focus-visible { outline-color: #ffffff; }
/* One thin bar: the copyright beside the legal links; on phones the links first, then the copyright.
   Links keep at least a 2rem (32px) target, above the 24px WCAG 2.2 AA minimum. */
.site-footer__legal { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-6); justify-content: space-between; align-items: center; padding-block: var(--space-4); }
.site-footer__legal p { margin: 0; }
.site-footer__legal ul { display: flex; flex-wrap: wrap; gap: 0 var(--space-4); }
.site-footer__legal a { display: inline-flex; align-items: center; min-height: 2rem; }
@media (max-width: 40em) {
  .site-footer__legal { flex-direction: column-reverse; align-items: flex-start; }
}

/* ---------- Articles ---------- */
.prose { max-width: 44rem; }
.prose h2 { font-size: var(--step-3); margin-top: 2em; }

/* ---------- User preferences ---------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition: none !important; animation: none !important; scroll-behavior: auto !important; }
}
@media (prefers-contrast: more) {
  .site-header { background: var(--bg) !important; backdrop-filter: none !important; -webkit-backdrop-filter: none !important; }
  .writer, .plan, .form { border: 2px solid var(--text); }
}
/* Parallax Braille field (assets/js/parallax.js): decoration behind a section's content, faded out
   over the text column. Taller than the section, so it can drift without showing an edge. */
.has-parallax { position: relative; isolation: isolate; overflow: clip; }
.parallax-field {
  position: absolute; inset: -8rem 0; z-index: -1; pointer-events: none;
  color: var(--text); opacity: 0.07;
  -webkit-mask-image: linear-gradient(to right, transparent 38%, #000 82%);
  mask-image: linear-gradient(to right, transparent 38%, #000 82%);
}
.parallax-field svg { display: block; width: 100%; height: 100%; fill: currentColor; }
@media (max-width: 48em) {
  .parallax-field { opacity: 0.045; -webkit-mask-image: linear-gradient(to right, transparent 55%, #000); mask-image: linear-gradient(to right, transparent 55%, #000); }
}

@media (forced-colors: active) {
  .parallax-field { display: none; }
  .btn, .cell__dot, .plan, .icon-btn, .menu-toggle { border: 1px solid CanvasText; }
  .cell__dot[aria-pressed="true"] { background: Highlight; color: HighlightText; forced-color-adjust: none; }
  .braille-svg, .brand__mark { fill: CanvasText; color: CanvasText; }
  :focus-visible { outline-color: Highlight; }
}
@media print {
  /* Text the reader had not scrolled to yet must still print. */
  main [style*="opacity"], main [style*="transform"] { opacity: 1 !important; transform: none !important; }
  .site-header, .skip-link, .closing, .writer, .parallax-field { display: none !important; }
  .site-footer { background: none; color: #000; }
}

.note { margin-top: 1.5rem; color: var(--text-soft); }
.faq { max-width: 48rem; }

/* ---------- Balance ---------- */
/* Bookends are centred: the opening, the page introductions without an image, single-column
   interludes and the closing call to action. Chapters with a picture alternate sides in between,
   so the page balances as a whole: symmetry at the ends, a zigzag through the middle. */
.opening .container, .chapter__text--solo, .closing .container,
.hero:not(:has(.hero__grid--media)) .hero__copy { text-align: center; }
.opening__title, .opening__lead, .chapter__text--solo > p, .closing p,
.hero:not(:has(.hero__grid--media)) :is(.hero__title, .hero__lead, .hero__body, .hero__note) { margin-inline: auto; }
.opening__braille { justify-content: center; }
.opening .actions, .closing .actions, .hero:not(:has(.hero__grid--media)) .actions { justify-content: center; }
.hero:not(:has(.hero__grid--media)) .hero__grid--single, .hero:not(:has(.hero__grid--media)) .hero__grid { justify-items: center; }
.opening__title { max-width: 16ch; }
.closing h2 { text-wrap: balance; }
.closing p { max-width: 44ch; }
/* Text-only sections: a centred reading column, text left-aligned inside it (centred paragraphs are
   hard to read). Keeps a single column of text from leaving half the page empty. */
.container--narrow { max-width: calc(46rem + 2 * var(--gutter)); }
.container--narrow .faq { max-width: none; }

/* ---------- Home: landing ---------- */
/* Three reassurances under the buttons, divided by hairlines rather than dots. */
.assurances { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--space-2) 0; margin-top: var(--space-5); font-size: var(--step--1); color: var(--text-soft); font-weight: 650; }
.assurances li { padding-inline: var(--space-4); }
.assurances li + li { border-left: 1px solid var(--line-strong); }
@media (max-width: 30em) { .assurances { flex-direction: column; align-items: center; } .assurances li + li { border-left: 0; } }

/* Three doors: one reason and one action for each kind of visitor. */
.chapter__head { margin-bottom: var(--space-6); max-width: 20ch; }
/* A problem and how Braille Link solves it (the "shifts" component): one row per person or
   situation. Who it is for, the problem in the softer ink, then the answer in full ink behind a heavy
   rule, so the eye travels from problem to answer. Stacks on phones; problem and answer sit side by
   side on tablets; the person moves to the left on wide screens. */
.shifts { display: grid; }
.shift { display: grid; gap: var(--space-3) var(--space-6); padding-block: var(--space-5); border-top: 1px solid var(--line-strong); }
.shift:last-child { border-bottom: 1px solid var(--line-strong); }
.shift h3 { margin: 0; font-size: var(--step-2); letter-spacing: -0.015em; max-width: 18ch; text-wrap: balance; }
.shift__pair { margin: 0; display: grid; gap: var(--space-4) var(--space-6); align-items: start; }
.shift__pair dt { font-weight: 800; font-size: var(--step--1); margin-bottom: var(--space-1); }
.shift__pair dd { margin: 0; }
.shift__pair dd p { margin: 0; }
.shift__before dd { color: var(--text-soft); }
.shift__after { padding-left: var(--space-4); border-left: 3px solid var(--text); }
.shift__after .more-link { display: inline-flex; align-items: center; min-height: 2.75rem; margin-top: var(--space-2); }
@media (min-width: 48em) { .shift__pair { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 64em) { .shift { grid-template-columns: minmax(0, 3fr) minmax(0, 8fr); } }

/* The motto, under the logo in the footer. */
.opening .assurances { margin-top: var(--space-5); }
.chapter__text--solo .actions { justify-content: center; }

/* ---------- Home: "Try it now" and the Braille writer ---------- */
/* The button beats three times each time it comes into view (under five seconds, WCAG 2.2.2).
   For visitors who ask for reduced motion, a ring glows and fades around it instead: no movement. */
@keyframes heartbeat {
  0%, 100% { transform: scale(1); }
  14% { transform: scale(1.08); }
  28% { transform: scale(1); }
  42% { transform: scale(1.06); }
  70% { transform: scale(1); }
}
@keyframes glow {
  0%, 100% { box-shadow: 0 0 0 0 transparent; }
  45% { box-shadow: 0 0 0 6px color-mix(in srgb, var(--text) 35%, transparent); }
}
.btn--beat { min-height: 3.5rem; padding-inline: var(--space-6); font-size: var(--step-1); }
@media (prefers-reduced-motion: no-preference) {
  .btn--beat.is-beating { animation: heartbeat 1.3s ease-in-out 0.3s 3; }
}
@media (prefers-reduced-motion: reduce) {
  .btn--beat.is-beating { animation: glow 1.3s ease-in-out 0.3s 3 !important; }
}

/* The writer: a compact native modal dialog, so the writing and the dots are always in view. */
.writer {
  width: min(38rem, calc(100vw - 2 * var(--gutter))); max-height: calc(100dvh - 2 * var(--gutter));
  padding: var(--space-5); border: 1px solid var(--line); border-radius: var(--radius-lg);
  background: var(--surface); color: var(--text); box-shadow: var(--shadow-float); overflow-y: auto;
}
.writer::backdrop { background: rgba(0, 0, 0, 0.55); }
@supports (backdrop-filter: blur(1px)) { .writer::backdrop { backdrop-filter: blur(4px); } }
.writer__head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); margin-bottom: var(--space-3); }
.writer__head h2 { font-size: var(--step-1); margin: 0; }

/* On top: the print. In the challenge, the goal is pale and darkens letter by letter. */
.writer__output { display: flex; align-items: center; gap: var(--space-4); padding: var(--space-3) var(--space-4); border-radius: var(--radius); background: var(--bg-alt); }
.writer__text { flex: 1; min-width: 0; }
.writer__print { font-size: var(--step-4); font-weight: 800; line-height: 1.15; margin: 0; max-width: none; overflow-wrap: anywhere; min-height: 1.15em; }
.writer__print.is-goal span { transition: color 0.15s; }
.writer__print .is-todo { color: var(--line-strong); opacity: 0.45; }
.writer__print .is-next { color: var(--line-strong); opacity: 0.6; text-decoration: underline; text-decoration-thickness: 3px; text-underline-offset: 0.15em; }
.writer__print .is-done { color: var(--text); }
.writer__print .is-space { display: inline-block; width: 0.5em; }
.writer__prompt { margin: var(--space-1) 0 0; font-size: var(--step--1); color: var(--text-soft); font-weight: 650; min-height: 1.4em; max-width: none; }
.writer.is-complete .writer__output { background: var(--invert-bg); }
.writer.is-complete .writer__print .is-done, .writer.is-complete .writer__prompt { color: var(--invert-text); }

/* The box: what you write, in Braille. */
.writer__work { margin-top: var(--space-4); }
.writer__label { display: block; font-weight: 800; font-size: var(--step--1); margin: 0 0 var(--space-1); }
.writer__braille {
  width: 100%; min-height: 3.5rem; padding: var(--space-1) var(--space-3); border-radius: var(--radius);
  border: 2px solid var(--line-strong); background: var(--bg); color: var(--text);
  font-family: var(--braille-font); font-size: 2.4rem; letter-spacing: 0.08em; line-height: 1.15;
}
.writer__braille:focus-visible { outline-offset: 2px; border-color: var(--text); }
/* The small cell sits in the top panel, beside the print; once the challenge is done it steps aside. */
.writer__tap { display: grid; justify-items: center; gap: var(--space-2); flex-shrink: 0; }
.writer.is-complete .writer__tap { visibility: hidden; }
.cell--small { grid-template-columns: repeat(2, 2rem); grid-template-rows: repeat(3, 2rem); gap: 0.35rem; }
.cell--small .cell__dot { width: 2rem; height: 2rem; font-size: 0.75rem; border-width: 1.5px; }
.writer__pending { display: inline-block; min-width: 0.6em; font-weight: 800; }

/* The six keys, small; the next letter's keys and dots are outlined as a hint. */
.homerow__keys--small { margin-top: var(--space-3); max-width: none; gap: var(--space-1); }
.homerow__keys--small kbd { height: 2.25rem; font-size: var(--step-0); }
.homerow__keys li.is-hint kbd, .cell__dot.is-hint { outline: 2px dashed var(--text); outline-offset: 2px; }
.homerow__keys li.is-on kbd { outline: none; }

.writer__foot { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: var(--space-2) var(--space-4); margin-top: var(--space-3); padding-top: var(--space-2); border-top: 1px solid var(--line); }
.writer__modes { display: flex; flex-wrap: wrap; gap: var(--space-4); }
@media (max-width: 30em) {
  .writer { width: 100vw; max-width: none; max-height: 100dvh; height: 100dvh; margin: 0; border-radius: 0; border: 0; padding: var(--space-4); }
}

/* ---------- Responsive edges ---------- */
/* Narrow screens and large text: the header row never pushes the Menu button off-screen. These use
   em, which follows the visitor's own text-size setting, so they apply earlier when text is larger. */
.brand { min-width: 0; }
.brand__text { min-width: 0; }
.brand__name, .brand__by { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
@media (max-width: 59.99em) { .site-header__inner { flex-wrap: wrap; row-gap: var(--space-2); } }
@media (max-width: 26em) { .brand__by { display: none; } }

/* Short screens (a phone held sideways): the header scrolls away with the page instead of taking
   a fifth of the screen, and the Braille writer fills the screen. */
@media (max-height: 30em) and (orientation: landscape) {
  .site-header { position: relative; }
  .writer { width: 100vw; max-width: none; height: 100dvh; max-height: 100dvh; margin: 0; border-radius: 0; border: 0; padding: var(--space-3) var(--space-4); }
}
/* A single long word in a large heading ("Technologies") must never push the page sideways when text
   is enlarged on a phone: it hyphenates, or breaks, instead. */
h1, h2, h3 { overflow-wrap: break-word; hyphens: auto; }
.hero__copy, .hero__grid > * { min-width: 0; }
/* The two display sizes: a word may break anywhere as a last resort, so it can never set a minimum
   width wider than the screen. */
.hero__title, .opening__title { overflow-wrap: anywhere; }
/* The narrowest screens with the largest text: the logo mark alone, so it and Menu share one row.
   The name stays available to screen readers. */
@media (max-width: 17em) {
  .site-header .brand__text { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
}

/* Hover ripple (assets/js/hover.js): split letters sit in inline blocks, which do not receive a
   link's underline, so each one carries it on itself. */
.hover-split, .hover-split div, .hover-split span { text-decoration: inherit; }
