/* Vocabloot /learn, shared stylesheet for every generated lesson page.
 *
 * The chrome (tokens, buttons, header, footer, signup card) is copied verbatim
 * from public/index.html so a learn page and the landing page are the same
 * object. Do not restyle it here: change it on the landing page and copy it
 * across, or the two drift. learn/tests/chrome.test.mjs guards the pieces that
 * matter most.
 *
 * Everything under "Learn library" is new and belongs only to these pages.
 */

/* ─── Fonts (self-hosted from the app) ───────────────────────────────── */
@font-face {
  font-family: "Satoshi";
  src: url("/assets/fonts/satoshi_medium.otf") format("opentype");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Satoshi";
  src: url("/assets/fonts/satoshi_bold.otf") format("opentype");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Satoshi";
  src: url("/assets/fonts/satoshi_black.otf") format("opentype");
  font-weight: 900;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Lilita One";
  src: url("/assets/fonts/lilita_one_regular.ttf") format("truetype");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
/* Caveat is declared but only used by the post-signup panel, so the browser
   never downloads its 245KB on a normal page view. */
@font-face {
  font-family: "Caveat";
  src: url("/assets/fonts/caveat_bold.ttf") format("truetype");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

/* ─── Design tokens (Vocabloot Neubrutalism) ─────────────────────────── */
:root {
  --paper: #fff9f5;
  --canvas: #f7eae6;
  --canvas-dim: #f0ded7;
  --ink: #1a1512;
  --ink-soft: #4e423b;
  --ink-faint: #6b5b51;
  --coral: #fb7559;
  --coral-deep: #ec5a3d;
  --coral-100: #ffe1d8;
  --mint: #7ed8c3;
  --mint-deep: #2e9e8c;
  --mint-100: #d4f5ec;
  --mint-text: #1d7264;
  --sun: #ffe08a;
  --sun-deep: #f3bd38;
  --sun-100: #fff3cc;
  --pink-100: #f9dfe9;
  --hairline: #d9c8bf;

  --font-display: "Lilita One", ui-rounded, system-ui, sans-serif;
  --font-body:
    "Satoshi", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-hand: "Caveat", ui-rounded, cursive;

  --border: 3px solid var(--ink);
  --shadow: 6px 6px 0 var(--ink);
  --shadow-sm: 4px 4px 0 var(--ink);
  --shadow-lg: 10px 10px 0 var(--ink);
  --radius: 22px;
  --radius-sm: 14px;
  --max: 1200px;
  --gutter: clamp(18px, 5vw, 40px);
}

* {
  box-sizing: border-box;
}
html {
  scroll-behavior: smooth;
}

body {
  min-width: 320px;
  margin: 0;
  background: var(--canvas);
  color: var(--ink);
  font-family: var(--font-body);
  font-weight: 500;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

a {
  color: inherit;
  text-decoration: none;
}
button,
input {
  font: inherit;
}
svg {
  display: block;
}
img {
  max-width: 100%;
}
h1,
h2,
h3 {
  margin: 0;
}

.skip-link {
  position: absolute;
  left: -999px;
  top: 8px;
  z-index: 100;
  padding: 10px 16px;
  border: var(--border);
  border-radius: 999px;
  background: var(--sun);
  font-weight: 800;
}
.skip-link:focus {
  left: 12px;
}

:focus-visible {
  outline: 3px solid var(--ink);
  outline-offset: 3px;
}

.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;
}

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

section.band {
  padding-block: clamp(56px, 8vw, 96px);
}

.display {
  font-family: var(--font-display);
  font-weight: 400;
  line-height: 0.98;
  letter-spacing: 0.005em;
  text-wrap: balance;
}

/* ─── Buttons ────────────────────────────────────────────────────────── */
.btn {
  -webkit-tap-highlight-color: transparent;
  appearance: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  min-height: 52px;
  padding: 0 22px;
  border: var(--border);
  border-radius: 999px;
  background: var(--coral);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 16px;
  font-weight: 800;
  line-height: 1;
  cursor: pointer;
  box-shadow: var(--shadow);
  transition:
    transform 90ms ease,
    box-shadow 90ms ease;
  touch-action: manipulation;
}
.btn:hover {
  transform: translate(-1px, -1px);
  box-shadow: var(--shadow-lg);
}
.btn:active {
  transform: translate(4px, 4px);
  box-shadow: 1px 1px 0 var(--ink);
}
.btn:disabled {
  cursor: wait;
  opacity: 0.65;
  transform: none;
  box-shadow: var(--shadow-sm);
}
.btn svg {
  width: 20px;
  height: 20px;
  flex: 0 0 auto;
}
.btn--paper {
  background: var(--paper);
}
.btn--sm {
  min-height: 48px;
  padding: 0 18px;
  font-size: 15px;
  box-shadow: var(--shadow-sm);
}
.btn--sm:hover {
  box-shadow: var(--shadow);
}
.btn--block {
  width: 100%;
}

.btn-ghost {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-weight: 800;
  color: var(--ink);
  border-bottom: 3px solid transparent;
  padding-bottom: 2px;
}
.btn-ghost:hover {
  border-bottom-color: var(--ink);
}

/* ─── Header ─────────────────────────────────────────────────────────── */
.site-header {
  position: sticky;
  top: 0;
  z-index: 40;
  background: var(--canvas);
  border-bottom: var(--border);
}
.nav {
  display: flex;
  position: relative;
  align-items: center;
  gap: 20px;
  min-height: 74px;
  padding-block: 12px;
}
.brand {
  display: inline-flex;
  align-items: center;
  gap: 11px;
  margin-right: auto;
}
.brand-mark {
  width: 42px;
  height: 42px;
  border: var(--border);
  border-radius: 12px;
  overflow: hidden;
  background: var(--paper);
  box-shadow: var(--shadow-sm);
  flex: 0 0 auto;
}
.brand-mark img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.brand-name {
  font-family: var(--font-display);
  font-size: 24px;
  line-height: 1;
}
.nav-links {
  display: flex;
  align-items: center;
  gap: clamp(14px, 1.6vw, 24px);
  font-weight: 700;
  font-size: 15px;
  white-space: nowrap;
}
.nav-links a {
  border-bottom: 3px solid transparent;
  padding-bottom: 2px;
}
.nav-links a:hover {
  border-bottom-color: var(--ink);
}
.nav-links a[aria-current="page"] {
  border-bottom-color: var(--coral-deep);
}
.mobile-menu {
  display: none;
}
.mobile-menu summary {
  display: inline-grid;
  width: 48px;
  min-height: 48px;
  place-items: center;
  border: var(--border);
  border-radius: 14px;
  background: var(--paper);
  box-shadow: 3px 3px 0 var(--ink);
  cursor: pointer;
  list-style: none;
  transition:
    transform 120ms cubic-bezier(0.22, 1, 0.36, 1),
    box-shadow 120ms cubic-bezier(0.22, 1, 0.36, 1);
}
.mobile-menu summary::-webkit-details-marker {
  display: none;
}
.mobile-menu summary:hover {
  transform: translate(-1px, -1px);
  box-shadow: var(--shadow-sm);
}
.mobile-menu[open] summary {
  background: var(--mint-100);
  transform: translate(2px, 2px);
  box-shadow: 1px 1px 0 var(--ink);
}
.mobile-menu-icon,
.mobile-menu-icon::before,
.mobile-menu-icon::after {
  display: block;
  width: 20px;
  height: 3px;
  border-radius: 999px;
  background: var(--ink);
  content: "";
  transition:
    transform 140ms cubic-bezier(0.22, 1, 0.36, 1),
    opacity 100ms ease;
}
.mobile-menu-icon {
  position: relative;
}
.mobile-menu-icon::before {
  position: absolute;
  transform: translateY(-7px);
}
.mobile-menu-icon::after {
  position: absolute;
  transform: translateY(7px);
}
.mobile-menu[open] .mobile-menu-icon {
  background: transparent;
}
.mobile-menu[open] .mobile-menu-icon::before {
  transform: rotate(45deg);
}
.mobile-menu[open] .mobile-menu-icon::after {
  transform: rotate(-45deg);
}
.mobile-menu-nav {
  position: absolute;
  top: calc(100% + 12px);
  right: var(--gutter);
  z-index: 50;
  display: grid;
  width: min(310px, calc(100vw - 2 * var(--gutter)));
  padding: 9px;
  border: var(--border);
  border-radius: 18px;
  background: var(--paper);
  box-shadow: var(--shadow);
}
.mobile-menu-nav a {
  display: flex;
  min-height: 46px;
  align-items: center;
  justify-content: space-between;
  padding: 10px 12px;
  border-radius: 10px;
  font-weight: 800;
}
.mobile-menu-nav a::after {
  content: "→";
  font-size: 18px;
}
.mobile-menu-nav a:hover,
.mobile-menu-nav a:focus-visible {
  background: var(--sun-100);
}

/* ─── Signup card (copied from the landing page) ─────────────────────── */
.form-row {
  display: grid;
  gap: 12px;
}
.signup-title {
  margin: 0 0 4px;
  font-family: var(--font-display);
  font-size: 22px;
  line-height: 1.05;
}
.field {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 54px;
  padding: 0 15px;
  border: var(--border);
  border-radius: var(--radius-sm);
  background: var(--canvas);
}
.field:focus-within {
  background: var(--sun-100);
  outline: 3px solid var(--ink);
  outline-offset: 2px;
}
.field svg {
  width: 20px;
  height: 20px;
  flex: 0 0 auto;
}
.field input {
  width: 100%;
  min-width: 0;
  border: 0;
  outline: 0;
  background: transparent;
  color: var(--ink);
  font-size: 16px;
  font-weight: 600;
}
.field input::placeholder {
  color: var(--ink-faint);
}

fieldset.platform {
  margin: 0;
  padding: 0;
  border: 0;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}
.platform legend {
  grid-column: 1 / -1;
  margin-bottom: 4px;
  padding: 0;
  color: var(--ink-faint);
  font-size: 13px;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}
.platform-option {
  position: relative;
  cursor: pointer;
}
.platform-option input {
  position: absolute;
  inset: 0;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}
.platform-option span {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 50px;
  border: var(--border);
  border-radius: var(--radius-sm);
  background: var(--canvas-dim);
  color: var(--ink-soft);
  font-size: 15px;
  font-weight: 800;
  box-shadow: none;
  transform: translate(0, 0);
  transition:
    transform 0.12s ease,
    box-shadow 0.12s ease,
    background 0.12s ease,
    color 0.12s ease;
}
.platform-option span svg {
  width: 18px;
  height: 18px;
  opacity: 0.55;
  transition: opacity 0.12s ease;
}
.platform-option input:checked + span {
  background: var(--coral-100);
  color: var(--ink);
  box-shadow: var(--shadow-sm);
  transform: translate(-2px, -2px);
}
.platform-option input:checked + span svg {
  opacity: 1;
}
.platform-option input:checked + span::after {
  content: "";
  position: absolute;
  top: -9px;
  right: -9px;
  width: 22px;
  height: 22px;
  background: var(--coral-deep)
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23FFF9F5' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 13l4 4 10-11'/%3E%3C/svg%3E")
    center / 12px 12px no-repeat;
  border: 2px solid var(--ink);
  border-radius: 50%;
}
.platform-option span:active {
  transform: translate(2px, 2px);
  box-shadow: none;
}
.platform-option input:checked + span:active {
  transform: translate(0, 0);
  box-shadow: none;
}
.platform-option input:focus-visible + span {
  outline: 3px solid var(--ink);
  outline-offset: 2px;
}

.form-msg {
  margin: 12px 0 0;
  min-height: 20px;
  font-size: 14px;
  font-weight: 700;
  color: var(--mint-text);
}
.form-msg.is-error {
  color: var(--coral-deep);
}
.privacy-note {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 12px 0 0;
  color: var(--ink-faint);
  font-size: 13px;
  font-weight: 600;
}
.privacy-note svg {
  width: 15px;
  height: 15px;
  flex: 0 0 auto;
}
.tester-perk {
  margin-top: 12px;
}
.perk-line {
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 5px;
  color: var(--ink-faint);
  font-size: 13px;
  font-weight: 600;
}
.perk-line .btn-ghost {
  gap: 5px;
}
.perk-line .btn-ghost svg {
  color: #5865f2;
}
.perk-line b {
  color: var(--coral-deep);
}
.discord-cta {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  width: auto;
  background: #5865f2;
  color: #fff;
}
.discord-cta:hover {
  background: #4b57d9;
  color: #fff;
}
.perk-note {
  margin: 0;
  font-family: var(--font-hand);
  font-size: 1.15rem;
  line-height: 1.2;
  color: var(--ink);
}
.perk-note b {
  color: var(--coral-deep);
}
.install-panel {
  display: flex;
  flex-direction: column;
  gap: 12px;
  align-items: center;
  text-align: center;
}
.install-panel .btn {
  width: 100%;
}
.install-qr {
  width: 148px;
  height: 148px;
  border: var(--border);
  box-shadow: var(--shadow-sm);
  background: #fff;
  padding: 8px;
}
.install-sub {
  margin: 0;
  font-size: 0.95rem;
  color: var(--ink);
}
.install-alt {
  font-size: 0.9rem;
}

/* ─── Closing CTA band (copied from the landing page) ────────────────── */
.cta-band {
  background: var(--coral);
  border-top: var(--border);
}
.cta-inner {
  display: grid;
  grid-template-columns: 1.1fr 0.9fr;
  align-items: center;
  gap: clamp(28px, 5vw, 60px);
  /* The shared spacing rule is `section.band`, but this band class sits on a
     div, so it never matched and the heading hugged the border. */
  padding-block: clamp(44px, 6vw, 72px);
}
.cta-inner h2 {
  font-family: var(--font-display);
  font-size: clamp(32px, 4.6vw, 52px);
  line-height: 0.98;
  text-wrap: balance;
}
.cta-inner p {
  margin: 16px 0 0;
  max-width: 42ch;
  font-size: clamp(16px, 1.7vw, 19px);
  font-weight: 600;
}
.cta-card {
  padding: 20px;
  border: var(--border);
  border-radius: var(--radius);
  background: var(--paper);
  box-shadow: var(--shadow);
}

/* ─── Footer (copied from the landing page) ──────────────────────────── */
.site-footer {
  border-top: var(--border);
  background: var(--canvas);
}
.footer-inner {
  display: grid;
  gap: 26px;
  padding-block: 36px 26px;
}
.footer-top {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: 32px 48px;
}
.footer-brand-block {
  display: flex;
  flex-direction: column;
  gap: 8px;
  max-width: 260px;
}
.footer-brand {
  display: inline-flex;
  align-items: center;
  gap: 10px;
}
.footer-brand .brand-mark {
  width: 28px;
  height: 28px;
  border-radius: 9px;
}
.footer-brand .brand-name {
  font-size: 20px;
}
.footer-tagline {
  color: var(--ink-faint);
  font-size: 14px;
  font-weight: 600;
}
.footer-cols {
  display: flex;
  flex-wrap: wrap;
  gap: 28px 56px;
  font-weight: 400;
  font-size: 15px;
}
.footer-col {
  display: flex;
  flex-direction: column;
  min-width: 132px;
}
.footer-col-title {
  font-size: 12px;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin-bottom: 8px;
}
.footer-col a,
.footer-col button {
  display: inline-flex;
  min-height: 40px;
  align-items: center;
}
.footer-col button {
  padding: 0;
  border: 0;
  background: transparent;
  font: inherit;
  cursor: pointer;
  text-align: left;
}
.footer-col a:hover,
.footer-col button:hover {
  text-decoration: underline;
  text-underline-offset: 3px;
}
.footer-copy {
  color: var(--ink-faint);
  font-size: 13px;
  font-weight: 600;
}

/* ══════════════════════════════════════════════════════════════════════
   Learn library
   ══════════════════════════════════════════════════════════════════════ */

.learn-head {
  background:
    radial-gradient(circle at 8% 12%, var(--sun-100), transparent 30%),
    radial-gradient(circle at 92% 8%, var(--mint-100), transparent 28%),
    var(--canvas);
  border-bottom: var(--border);
  padding-block: clamp(28px, 4vw, 44px) clamp(34px, 5vw, 56px);
}

/* Breadcrumb */
.crumbs {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin: 0 0 clamp(16px, 2vw, 24px);
  padding: 0;
  list-style: none;
  color: var(--ink-faint);
  font-size: 15px;
  font-weight: 700;
}
.crumbs li {
  display: flex;
  align-items: center;
  gap: 8px;
}
.crumbs li + li::before {
  content: "/";
  color: var(--hairline);
}
.crumbs a {
  border-bottom: 2px solid transparent;
}
.crumbs a:hover {
  border-bottom-color: var(--ink-faint);
}
.crumbs [aria-current="page"] {
  color: var(--ink);
}

.learn-title {
  font-size: clamp(34px, 5.4vw, 62px);
  max-width: 22ch;
}
.learn-intro {
  margin: clamp(16px, 2vw, 22px) 0 0;
  max-width: 62ch;
  color: var(--ink-soft);
  font-size: clamp(17px, 1.7vw, 19px);
  text-wrap: pretty;
}
.learn-meta {
  margin: 18px 0 0;
  color: var(--ink-faint);
  font-size: 14px;
  font-weight: 700;
}

/* Lesson body */
.lesson-body {
  padding-block: clamp(36px, 5vw, 60px);
}
.lesson-block + .lesson-block {
  margin-top: clamp(38px, 5vw, 58px);
}
.block-head {
  font-family: var(--font-display);
  font-size: clamp(24px, 3vw, 34px);
  line-height: 1.02;
  max-width: 28ch;
  text-wrap: balance;
}
.block-head + * {
  margin-top: clamp(18px, 2.4vw, 26px);
}

/* Numeral grid. Hairline gaps rather than a box per cell: the lightest
   separation that still reads as a grid. */
/* One number per row. A multi-column grid of boxed cells packs more onto the
   screen but gives the eye four things to track at once; a single column with
   a hairline between rows lets a beginner take them one at a time. */
.num-grid {
  margin: 0;
  max-width: 760px;
}
.num {
  display: grid;
  grid-template-columns: clamp(64px, 7vw, 92px) minmax(0, 1fr);
  align-items: center;
  gap: 0 22px;
  padding-block: 15px;
  border-top: 1px solid var(--hairline);
}
.num:first-child {
  border-top: 0;
  padding-top: 10px;
}
/* Sized like a flashcard, and right-aligned so 7 and 100 share an edge. */
.num dt {
  font-family: var(--font-display);
  font-size: clamp(44px, 5.2vw, 62px);
  line-height: 1;
  text-align: right;
  color: var(--coral-deep);
  font-variant-numeric: tabular-nums;
}
.num dd {
  margin: 0;
  min-width: 0;
}
/* These lists are built from <p> inside <dt>/<dd>, so the browser's default
   paragraph margin has to go or every row grows by an extra 50px. */
.num-word,
.pair-term,
.pair-meaning {
  margin: 0;
}
.num-word {
  font-size: clamp(21px, 2.2vw, 25px);
  font-weight: 800;
  line-height: 1.2;
  overflow-wrap: anywhere;
}
.num-say,
.pair-say {
  margin: 3px 0 0;
  color: var(--ink-faint);
  font-size: 15px;
  font-weight: 600;
  font-style: normal;
}
.pair-roman {
  color: var(--ink-faint);
  font-size: 15px;
  font-weight: 600;
}
/* Romanisation is the first thing a beginner can actually read in a
   non-Latin script, so it sits closer to the word than the respelling. */
.num-roman {
  margin: 2px 0 0;
  font-size: 17px;
  font-weight: 700;
  color: var(--ink-soft);
}
.num-note,
.pair-note {
  margin: 5px 0 0;
  color: var(--mint-text);
  font-size: 14px;
  font-weight: 600;
  text-wrap: pretty;
}

/* Term and meaning rows */
/* Bounded on purpose: at full container width the meaning drifts so far from
   the word that the two stop reading as a pair. */
.pair-list {
  margin: 0;
  max-width: 860px;
}
.pair {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 6px 28px;
  padding-block: 16px;
  border-top: 1px solid var(--hairline);
}
.pair:first-child {
  border-top: 0;
  padding-top: 4px;
}
.pair dt {
  margin: 0;
  min-width: 0;
}
.pair dd {
  margin: 0;
  min-width: 0;
  color: var(--ink-soft);
}
.pair-term {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 8px;
  font-size: 19px;
  font-weight: 800;
  line-height: 1.25;
  color: var(--ink);
  overflow-wrap: anywhere;
}
.pair-meaning {
  font-size: 17px;
  font-weight: 600;
}
.art {
  padding: 3px 8px;
  border: 2px solid var(--ink);
  border-radius: 999px;
  background: var(--sun-100);
  font-size: 12px;
  font-weight: 800;
  line-height: 1.2;
}
.swatch {
  width: 22px;
  height: 22px;
  border: 2px solid var(--ink);
  border-radius: 7px;
  align-self: center;
  background: var(--swatch, var(--canvas-dim));
}

/* Teaching note */
.note-card {
  padding: clamp(20px, 2.6vw, 28px);
  border: var(--border);
  border-radius: var(--radius);
  background: var(--sun-100);
  box-shadow: var(--shadow);
}
.note-card > .block-head {
  max-width: 30ch;
}
.note-card p {
  margin: 14px 0 0;
  max-width: 72ch;
  font-size: 16px;
  font-weight: 600;
  text-wrap: pretty;
}
.note-examples {
  display: grid;
  gap: 10px;
  margin: 18px 0 0;
  padding: 0;
  list-style: none;
}
.note-examples li {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 6px 12px;
  padding: 11px 14px;
  border: 2px solid var(--ink);
  border-radius: var(--radius-sm);
  background: var(--paper);
}
.note-examples b {
  font-weight: 800;
  font-size: 17px;
}
.note-examples span {
  color: var(--ink-faint);
  font-size: 15px;
  font-weight: 600;
}

/* Comparison pages */
.disclosure {
  margin: 18px 0 0;
  max-width: 62ch;
  padding: 12px 16px;
  border: 2px solid var(--ink);
  border-radius: var(--radius-sm);
  background: var(--sun-100);
  font-size: 15px;
  font-weight: 700;
  text-wrap: pretty;
}
.app-grid {
  display: grid;
  gap: 18px;
}
.app-card {
  padding: clamp(18px, 2.4vw, 26px);
  border: var(--border);
  border-radius: var(--radius);
  background: var(--paper);
  box-shadow: var(--shadow-sm);
}
.app-name {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  font-family: var(--font-display);
  font-size: clamp(22px, 2.6vw, 28px);
  line-height: 1.05;
}
.app-ours {
  padding: 4px 10px;
  border: 2px solid var(--ink);
  border-radius: 999px;
  background: var(--coral-100);
  font-family: var(--font-body);
  font-size: 12px;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.app-rows {
  margin: 14px 0 0;
}
.app-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 2fr);
  gap: 4px 24px;
  padding-block: 12px;
  border-top: 1px solid var(--hairline);
}
.app-row dt {
  margin: 0;
  font-size: 14px;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--ink-faint);
}
.app-row dd {
  margin: 0;
  font-size: 16px;
  font-weight: 600;
  color: var(--ink-soft);
  text-wrap: pretty;
}

/* Card grids: topics on a hub, languages on the index */
.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(270px, 1fr));
  gap: 20px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.learn-card {
  display: flex;
  flex-direction: column;
  gap: 8px;
  height: 100%;
  padding: 20px;
  border: var(--border);
  border-radius: var(--radius);
  background: var(--paper);
  box-shadow: var(--shadow-sm);
  transition:
    transform 90ms ease,
    box-shadow 90ms ease;
}
.learn-card:hover {
  transform: translate(-2px, -2px);
  box-shadow: var(--shadow);
}
.learn-card:active {
  transform: translate(2px, 2px);
  box-shadow: 2px 2px 0 var(--ink);
}
.card-title {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  font-family: var(--font-display);
  font-size: 25px;
  line-height: 1.05;
}
.card-title::after {
  content: "→";
  font-family: var(--font-body);
  font-size: 20px;
  font-weight: 800;
}
.card-native {
  color: var(--ink-faint);
  font-size: 14px;
  font-weight: 700;
}
.card-blurb {
  margin: 0;
  color: var(--ink-soft);
  font-size: 15px;
  font-weight: 600;
  text-wrap: pretty;
}

/* Related lessons */
.related {
  padding-block: clamp(30px, 4vw, 46px);
  border-top: var(--border);
  background: var(--paper);
}
.related-head {
  font-family: var(--font-display);
  font-size: clamp(22px, 2.6vw, 30px);
  line-height: 1;
}
.related-list {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin: 20px 0 0;
  padding: 0;
  list-style: none;
}
.related-list a {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 48px;
  padding: 0 18px;
  border: var(--border);
  border-radius: 999px;
  background: var(--canvas);
  font-size: 15px;
  font-weight: 800;
  box-shadow: var(--shadow-sm);
  transition:
    transform 90ms ease,
    box-shadow 90ms ease;
}
.related-list a::after {
  content: "→";
}
.related-list a:hover {
  transform: translate(-1px, -1px);
  box-shadow: var(--shadow);
}

/* Hub and index sections */
.learn-section {
  padding-block: clamp(36px, 5vw, 60px);
}
.learn-section + .learn-section {
  border-top: var(--border);
}
.section-note {
  margin: 20px 0 0;
  max-width: 60ch;
  color: var(--ink-faint);
  font-size: 15px;
  font-weight: 600;
  text-wrap: pretty;
}

/* ─── Responsive ─────────────────────────────────────────────────────── */
@media (max-width: 1100px) {
  .nav-links {
    display: none;
  }
  .mobile-menu {
    display: block;
  }
}
@media (max-width: 960px) {
  .cta-inner {
    grid-template-columns: 1fr;
  }
}
@media (max-width: 760px) {
  .nav {
    gap: 12px;
  }
  .pair {
    grid-template-columns: 1fr;
    gap: 4px;
  }
  /* Stacked, the meaning sits below the pronunciation, so it needs the extra
     weight to stay the second thing the eye lands on. */
  .pair-meaning {
    font-size: 17px;
    font-weight: 700;
    color: var(--ink);
  }
  .app-row {
    grid-template-columns: 1fr;
    gap: 2px;
  }
  .crumbs {
    font-size: 14px;
  }
}
@media (max-width: 620px) {
  .brand-name {
    font-size: 21px;
  }
  .num {
    gap: 0 16px;
    padding-block: 13px;
  }
}
@media (max-width: 430px) {
  .brand-name {
    display: none;
  }
  .nav {
    gap: 10px;
  }
  .btn--sm {
    padding-inline: 14px;
  }
}
@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
  * {
    transition-duration: 0.01ms !important;
  }
}

/* ─── Store badges ─────────────────────────────────────────────────────
   Apple and Google both require clear space around their badge; the gap here
   and the margin are it, which is why the artwork itself is used untouched
   (only the Play PNG's own transparent padding was cropped, so the two line
   up on height). */
.store-cta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 14px;
  margin: 2px 0 4px;
}
.store-badge {
  display: inline-flex;
  border-radius: 9px;
  transition: transform 110ms ease-out;
}
.store-badge:hover { transform: translateY(-2px); }
.store-badge:focus-visible { outline: 3px solid currentColor; outline-offset: 4px; }
.store-badge img { display: block; width: auto; }
/* Equal VISIBLE height, not equal CSS height. Apple ships ~4% transparent
   margin inside its artwork (the black rect fills rows 4-195 of 200) while
   Google's is flush to the edge, so setting both to the same height renders
   two rectangles that visibly disagree. These numbers land both black rects
   on 50px. The remaining width difference is intrinsic to the two wordmarks
   and is not ours to "fix". Neither badge may be stretched. */
.store-badge[data-store-badge="ios"] img { height: 52px; }
.store-badge[data-store-badge="android"] img { height: 51px; }
@media (max-width: 560px) {
  .store-badge[data-store-badge="ios"] img { height: 47px; }
  .store-badge[data-store-badge="android"] img { height: 45px; }
}

/* ─── "Coming soon" stand-ins ──────────────────────────────────────────
   Shipping on one store weeks before the other is normal, and an empty gap
   where the second badge belongs reads as a broken page. These sit at the
   badge's size, in the badge's place, and say what is actually happening.

   Built as one of the site's own stickers, not as a greyed-out store badge:
   mint fill, ink outline, hard offset shadow, the store name in the display
   face, so the row reads as one live button plus one object that is plainly
   waiting, never as a button that failed to load. Neither store's artwork is used, because a store badge is
   licensed to point AT that store, not to announce that we are not on it, and
   Apple's guidelines forbid a badge of your own making. Spans, not links or
   disabled buttons: there is nowhere to go yet, so nothing here should take
   focus or invite a click. */
.store-soon {
  box-sizing: border-box;
  display: inline-flex;
  align-items: center;
  min-width: 156px;
  height: 52px;
  padding: 0 15px;
  border: 3px solid var(--ink);
  border-radius: 14px;
  background: var(--mint);
  box-shadow: var(--shadow-sm);
  color: var(--ink);
  font-family: var(--font-body);
  cursor: default;
  -webkit-user-select: none;
  user-select: none;
}
.store-soon[data-store-soon="android"] { min-width: 171px; }
.store-soon-text {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.store-soon-line {
  font-size: 10px;
  font-weight: 900;
  line-height: 1;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-soft);
}
.store-soon-store {
  font-family: var(--font-display);
  font-size: 18px;
  line-height: 1;
  letter-spacing: 0.01em;
}
@media (max-width: 560px) {
  .store-soon { height: 47px; min-width: 146px; padding: 0 13px; }
  .store-soon[data-store-soon="android"] { min-width: 158px; }
  .store-soon-store { font-size: 16px; }
}

/* ─── Launch switch: waitlist ⇄ store badges ───────────────────────────
   Driven entirely by attributes /app-live.js puts on <html>; see that file
   for the contract. The page ships in waitlist mode, so no JS, a dead
   /api/capabilities or a slow network all leave today's signup form in
   place rather than a page with no call to action.

   Every rule here only ever HIDES, and nothing restores a display value.
   That is deliberate: a rule that switches [data-launched] back on cannot
   know which display the element wanted, and an earlier `display: block`
   flattened .btn's flex centering and stretched the header button. Hiding
   with :not() leaves the element's own CSS untouched when it is shown. */
:root:not([data-app-live]) [data-launched] { display: none; }
:root[data-app-live] [data-waitlist] { display: none; }
/* One store at a time is a normal launch (iPhone first, Android later): a
   badge appears only once its URL is configured, and until then its slot holds
   the "coming soon" chip. Exactly one of the pair is visible, so the row never
   collapses to a single badge with a hole beside it. */
:root:not([data-app-ios]) [data-store-badge="ios"] { display: none; }
:root:not([data-app-android]) [data-store-badge="android"] { display: none; }
:root[data-app-ios] [data-store-soon="ios"] { display: none; }
:root[data-app-android] [data-store-soon="android"] { display: none; }

/* Copy that names platforms. Exactly one variant survives, so an Android-only
   launch never claims an iPhone app that is still in review, and when iOS
   ships, pasting its URL into the admin swaps the wording with no redeploy.
   An element may list several sets (data-stores="both ios android") for copy
   that is right in all of them; it is hidden when the live set is not among
   them, which is why this is written as "hide what does not match" rather than
   a rule per set. */
:root[data-app-stores="both"] [data-stores]:not([data-stores~="both"]),
:root[data-app-stores="ios"] [data-stores]:not([data-stores~="ios"]),
:root[data-app-stores="android"] [data-stores]:not([data-stores~="android"]),
:root[data-app-stores="none"] [data-stores]:not([data-stores~="none"]),
:root:not([data-app-stores]) [data-stores] { display: none; }

/* Launched, the CTA is badges and a line of copy, the paper card, its ink
   border and its hard shadow existed to hold a form. With no form to contain,
   the box is just a box, so it goes and the badges sit on the section itself. */
:root[data-app-live] .signup,
:root[data-app-live] .cta-card {
  background: none;
  border: 0;
  box-shadow: none;
  padding: 0;
}

/* The closing band used to take its height from a tall form card, and had no
   vertical padding of its own, so with two badges in that column it hugged
   the heading. Give it its own rhythm, and send the badges to the outside
   edge so they mirror the heading instead of floating mid-column. Below 960px
   the band is a single column, where left-aligned is the right answer. */
:root[data-app-live] .cta-inner { padding-block: clamp(44px, 6vw, 72px); }
@media (min-width: 961px) {
  :root[data-app-live] .cta-band .store-cta { justify-content: flex-end; }
}


/* ---------------------------------------------------------------------------
   404. Generated by site/build-404.mjs into the same shell as every other page.
   The viewfinder is the brand's own idea turned into an error state: Vocabloot
   is a camera you point at things to get their name, so a page that is not
   there is a frame with nothing in it.
   --------------------------------------------------------------------------- */

.notfound {
  padding-block: clamp(28px, 7vw, 64px);
  max-width: 760px;
  text-align: center;
}

/* Stage holds the viewfinder and the loose doodles around it. */
.nf-stage {
  position: relative;
  display: flex;
  justify-content: center;
  padding: 18px 0 6px;
}

.nf-doodle {
  position: absolute;
  color: var(--ink-faint);
  pointer-events: none;
}

.nf-sparkle {
  width: 26px;
  height: 26px;
  top: 4px;
  left: calc(50% - 165px);
  color: var(--sun-deep);
}

.nf-dashes {
  width: 34px;
  height: 22px;
  bottom: 16px;
  right: calc(50% - 178px);
  color: var(--coral);
}

.nf-dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--mint);
  top: 34px;
  right: calc(50% - 150px);
}

/* Four corner brackets, no box: a camera frame, not a card. */
.nf-viewfinder {
  position: relative;
  display: grid;
  place-items: center;
  width: min(260px, 74vw);
  aspect-ratio: 16 / 10;
}

.nf-corner {
  position: absolute;
  width: 26px;
  height: 26px;
  border: 4px solid var(--ink);
}

.nf-corner--tl { top: 0; left: 0; border-right: 0; border-bottom: 0; border-radius: 10px 0 0 0; }
.nf-corner--tr { top: 0; right: 0; border-left: 0; border-bottom: 0; border-radius: 0 10px 0 0; }
.nf-corner--bl { bottom: 0; left: 0; border-right: 0; border-top: 0; border-radius: 0 0 0 10px; }
.nf-corner--br { bottom: 0; right: 0; border-left: 0; border-top: 0; border-radius: 0 0 10px 0; }

.nf-code {
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(3.4rem, 13vw, 5rem);
  line-height: 1;
  color: var(--coral-deep);
  -webkit-text-stroke: 3px var(--ink);
  paint-order: stroke fill;
  letter-spacing: 0.02em;
}

.nf-title {
  margin: 14px 0 10px;
}

.nf-lead {
  margin: 0 auto 30px;
  max-width: 46ch;
  font-size: 1.05rem;
  line-height: 1.6;
  color: var(--ink-soft);
}

.nf-cards {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  gap: 12px;
  grid-template-columns: repeat(auto-fit, minmax(min(230px, 100%), 1fr));
  text-align: left;
}

.nf-cards a {
  position: relative;
  display: block;
  height: 100%;
  padding: 15px 40px 15px 17px;
  border: var(--border);
  border-radius: var(--radius-sm);
  background: var(--paper);
  box-shadow: var(--shadow-sm);
  text-decoration: none;
  color: inherit;
  transition: transform 0.12s ease, box-shadow 0.12s ease, background 0.12s ease;
}

.nf-cards a:hover,
.nf-cards a:focus-visible {
  transform: translate(-3px, -3px);
  box-shadow: var(--shadow);
  background: var(--sun-100);
}

.nf-card-label {
  display: block;
  font-family: var(--font-display);
  font-size: 1.15rem;
}

.nf-card-note {
  display: block;
  margin-top: 3px;
  font-size: 0.88rem;
  color: var(--ink-faint);
  line-height: 1.45;
}

.nf-card-arrow {
  position: absolute;
  top: 50%;
  right: 16px;
  transform: translateY(-50%);
  font-size: 1.2rem;
  color: var(--coral-deep);
  transition: transform 0.12s ease;
}

.nf-cards a:hover .nf-card-arrow {
  transform: translate(3px, -50%);
}

.nf-languages {
  margin-top: 32px;
  border-top: 2px solid var(--hairline);
  padding-top: 20px;
}

.nf-languages-title {
  margin: 0 0 12px;
  font-weight: 600;
  color: var(--ink-soft);
}

.nf-language-links {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px;
}

.nf-language-links a {
  display: inline-block;
  padding: 6px 14px;
  border: 2px solid var(--hairline);
  border-radius: 999px;
  background: var(--paper);
  text-decoration: none;
  font-weight: 600;
  font-size: 0.92rem;
  transition: border-color 0.12s ease, background 0.12s ease;
}

.nf-language-links a:hover,
.nf-language-links a:focus-visible {
  border-color: var(--ink);
  background: var(--mint-100);
}

/* Narrow screens leave no room beside the frame, so the doodles end up pinned
   to the page edges reading as stray marks. Better to drop them than to place
   them badly; the viewfinder carries the idea on its own. */
@media (max-width: 560px) {
  .nf-doodle { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .nf-cards a,
  .nf-card-arrow,
  .nf-language-links a { transition: none; }
}
