/* karanow.com
   Warm, low-contrast dark. Neutrals lean toward the theme's hue the way the
   app's Stage Ember palette tints them, but softer than the app: this is a
   page to read, not a stage to perform on. Spacing sits on a 4 pt grid. */

:root {
  /* The brand is three colours — cream, ink, red — from Design/. Everything
     below is derived from them so the site, the app icon and the wordmark are
     demonstrably the same palette rather than a near-miss. */
  --paper: #fbf6f2;
  --paper-2: #f3e9e3;
  --card: #ffffff;
  --card-2: #fdf8f5;
  --line: rgba(30, 22, 24, 0.1);
  --line-2: rgba(30, 22, 24, 0.18);

  --text: #1e1618;
  --text-2: #5a5154;
  --text-3: #706569;

  /* The brand accent is #E2661F, but it is only 3.2:1 on paper — enough for
     the Black-weight logotype, not enough to read. So the token is split: the
     orange fills shapes, and a deepened ember carries anything that is text.
     Buttons take ink on orange (5.2:1) rather than cream (3.2:1). */
  --orange: #e2661f;
  --orange-lift: #ee7a2a;
  --orange-ink: #b34d12;
  --accent: var(--orange-ink);
  --brand: linear-gradient(135deg, var(--orange-lift), var(--orange));
  --brand-text: linear-gradient(115deg, #e2661f, #b34d12, #e2661f);
  --on-brand: #1e1618;

  /* The app draws its runway on a dark screen because it lives on a dark
     stage. On cream that reads as a black bar stamped across the card, so
     here the screen is warm paper and the pitch line carries the brand red
     instead. Same information, native to this page. */
  --screen: #f6eee7;

  /* One scale. Before this there were 19 distinct font-sizes and 8
     line-heights in this file, which is what "混乱" looks like in CSS. */
  --t-micro: 12px;
  --t-small: 14px;
  --t-body: 15px;
  --t-lead: 17px;
  --t-h3: 20px;
  --t-h2: clamp(21px, 2.6vw, 33px);
  --t-title: clamp(26px, 3.6vw, 44px);
  --t-display: clamp(28px, min(4.6vw, 5.9svh), 62px);
  --t-numeral: clamp(34px, 4.4vw, 58px);
  --t-lyric: clamp(20px, 2.4vw, 30px);        /* the sung line */
  --t-lyric-desktop: clamp(15px, 2vw, 20px);  /* the same line, on the desktop mock */

  --lh-display: 1.02;
  --lh-title: 1.15;
  --lh-heading: 1.3;
  --lh-body: 1.6;

  --s1: 4px;  --s2: 8px;  --s3: 12px; --s4: 16px;
  --s6: 24px; --s8: 32px; --s12: 48px;
  --s16: 64px; --s24: 96px;

  --r-sm: 10px; --r-md: 16px; --r-lg: 22px; --r-xl: 30px;
  --shell: 1120px;

  /* Three roles, all system faces — nothing is downloaded. Serif carries the
     display type in Latin; CJK overrides it below, because Songti/Mincho at
     display size reads like body copy blown up, not like a headline. */
  --serif: ui-serif, "New York", "Iowan Old Style", Palatino, Georgia,
    "Times New Roman", serif;
  --sans: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI",
    "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue",
    Arial, sans-serif;
  --mono: "SF Mono", ui-monospace, SFMono-Regular, "JetBrains Mono", Menlo,
    monospace;
  --display: var(--serif);
  --display-weight: 600;
}

:lang(zh-Hans), :lang(zh-Hant), :lang(ja), :lang(ko) {
  --display: -apple-system, BlinkMacSystemFont, "PingFang SC", "PingFang TC",
    "Hiragino Sans", "Apple SD Gothic Neo", "Microsoft YaHei", sans-serif;
  --display-weight: 800;
}

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

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

body {
  margin: 0;
  font-family: var(--sans);
  font-size: var(--t-lead);
  line-height: var(--lh-body);
  color: var(--text);
  background: var(--paper);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

/* Warm light pooling at the top of the page, not a spotlight in a dark room. */
body::before {
  content: "";
  position: fixed;
  inset: -10% -20% auto -20%;
  height: 78vh;
  background:
    radial-gradient(58% 58% at 50% 0%, rgba(226, 102, 31, 0.13), transparent 72%),
    radial-gradient(44% 50% at 82% 4%, rgba(238, 122, 42, 0.16), transparent 72%);
  pointer-events: none;
  z-index: 0;
}
main, header, footer, section { position: relative; z-index: 1; }

h1, h2, h3, h4 { margin: 0; font-family: var(--display); font-weight: var(--display-weight); letter-spacing: -0.018em; line-height: var(--lh-heading); }
p { margin: 0; }
a { color: inherit; }
img, svg { max-width: 100%; }

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

.shell { width: 100%; max-width: var(--shell); margin-inline: auto; padding-inline: var(--s6); }



/* ---------- The snap deck ---------- */

/* Home is a deck: one screen per idea, and the scroll settles on it. Scoped by
   data-page so the long-form pages keep ordinary scrolling. */
html[data-page="home"] { scroll-snap-type: y mandatory; }

.snap {
  scroll-snap-align: start;
  min-height: 100vh;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding-block: calc(62px + var(--s6)) var(--s8);
}
/* The hero carries the most in one screen, so it gets the tightest frame. */
.snap.hero { padding-block: calc(62px + var(--s2)) var(--s4); }
.snap--end { padding-bottom: 0; }
.snap--end .site-footer { margin-top: clamp(28px, 6svh, 76px); }

/* A screen that cannot hold its own content should not trap the scroll on it. */
@media (max-height: 560px) {
  html[data-page="home"] { scroll-snap-type: none; }
  .snap { min-height: 0; padding-block: var(--s16) var(--s8); }
}

/* Below the desktop breakpoint the grids collapse to one column, so a section
   is genuinely taller than the screen and mandatory snapping would fight the
   scroll. Ease off to proximity — the sections still settle, they just don't
   hold you. The hero stays a full screen: the demo and its button are the
   whole point of arriving. */
@media (max-width: 940px) {
  html[data-page="home"] { scroll-snap-type: y proximity; }
  .snap { min-height: 0; padding-block: var(--s16) var(--s12); }
  .snap.hero { min-height: 100svh; padding-block: calc(62px + var(--s2)) var(--s4); }
  .snap--end { padding-bottom: 0; }
}

.section-more { margin-top: var(--s6); font-size: var(--t-body); text-align: center; }
.lede {
  max-width: 46ch; margin: 0 auto clamp(18px, 2.8svh, 36px);
  text-align: center; font-size: var(--t-body); color: var(--text-2);
}
.section-more a { color: var(--accent); text-underline-offset: 3px; }

/* ---------- Motion ---------- */

/* Sections arrive instead of just being there. Gated on a flag the script sets,
   so if it never runs — or reduced motion is asked for — nothing is ever
   hidden. */
html[data-reveal-ready="true"] [data-reveal] .shell > * {
  opacity: 0;
  transform: translateY(20px);
  transition: opacity 0.66s cubic-bezier(0.2, 0.7, 0.3, 1),
    transform 0.66s cubic-bezier(0.2, 0.7, 0.3, 1);
}
html[data-reveal-ready="true"] [data-reveal="in"] .shell > * {
  opacity: 1;
  transform: none;
}
html[data-reveal-ready="true"] [data-reveal="in"] .shell > *:nth-child(2) { transition-delay: 0.07s; }
html[data-reveal-ready="true"] [data-reveal="in"] .shell > *:nth-child(3) { transition-delay: 0.14s; }
html[data-reveal-ready="true"] [data-reveal="in"] .shell > *:nth-child(4) { transition-delay: 0.21s; }

   it rather than an animation demanding attention. */
@keyframes drift { to { background-position: 200% 0; } }

/* And the button breathes only while there is still a vocal to remove. Once
   it is gone the pulse stops, because the invitation has been accepted. */
@keyframes breathe {
  0%, 100% { box-shadow: 0 10px 26px -12px rgba(226, 102, 31, 0.55); }
  50%      { box-shadow: 0 16px 34px -10px rgba(226, 102, 31, 0.9); }
}

/* ---------- Editorial furniture ---------- */

/* Every section opens the same way: hairline, index, left-aligned title. The
   repetition is the grid; what sits underneath is what varies. */
.masthead {
  border-top: 1px solid var(--line);
  padding-top: var(--s4);
  margin-bottom: clamp(22px, 3.6svh, 48px);
  text-align: center;
}
.masthead__index {
  display: flex; align-items: baseline; justify-content: center; gap: var(--s3);
  font-family: var(--mono); font-size: var(--t-micro); font-weight: 500;
  letter-spacing: 0.12em; text-transform: uppercase; color: var(--text-3);
}
:lang(zh) .masthead__index { letter-spacing: 0.08em; text-transform: none; }
.masthead__index span { font-weight: 800; color: var(--orange-ink); letter-spacing: 0.04em; }
.masthead__title {
  margin-top: var(--s3);
  font-size: var(--t-h2);
  font-weight: var(--display-weight); letter-spacing: -0.022em;
  max-width: 22ch; margin-inline: auto;
}

/* A spec sheet: term, rule, definition. No boxes, no shadows — the hairlines
   do the separating that six rounded rectangles were doing before. */
.ruled { margin: 0; }
.ruled__row {
  display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  gap: var(--s6); padding: clamp(9px, 1.7svh, 17px) 0;
  border-top: 1px solid var(--line);
}
.ruled__row:last-child { border-bottom: 1px solid var(--line); }
.ruled dt { font-family: var(--sans); font-weight: 650; font-size: var(--t-body); color: var(--text); }
.ruled dd { margin: 0; color: var(--text-2); font-size: var(--t-body); }
.ruled--two {
  display: grid; grid-template-columns: 1fr 1fr;
  column-gap: clamp(24px, 4vw, 64px);
}
.ruled--solo { max-width: 760px; margin-inline: auto; }
.ruled--two .ruled__row { grid-template-columns: 1fr; gap: 2px; }

.showcase {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(24px, 4vw, 64px); align-items: center;
}

.steps {
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(20px, 3vw, 48px);
}
.step { border-top: 1px solid var(--line); padding-top: var(--s4); }
/* Outlined numerals, echoing the wordmark's unsung half. */
.step__n {
  font-family: var(--display); font-weight: 900; line-height: 0.9;
  font-size: var(--t-numeral); letter-spacing: -0.04em;
  color: transparent; -webkit-text-stroke: 1.5px var(--orange);
}
.step h3 { margin-top: var(--s3); font-size: var(--t-lead); font-weight: 700; }
.step p { margin-top: var(--s2); color: var(--text-2); font-size: var(--t-body); }



.cta {
  display: grid; justify-items: center; text-align: center; gap: var(--s6);
  border-top: 1px solid var(--line); padding-top: clamp(26px, 4.5svh, 60px);
}
.cta__title {
  font-size: var(--t-title); font-weight: var(--display-weight);
  letter-spacing: -0.032em; line-height: var(--lh-title);
  max-width: 20ch; margin-inline: auto; text-wrap: balance;
}

/* ---------- Header ---------- */

/* Fixed, not sticky: a sticky header still occupies its 62 px of document
   flow, which pushed every 100svh section that much past the fold. Fixed takes
   it out of flow, so a section really is one screen. Each section pads its own
   top to clear it. */
.site-header {
  position: fixed; top: 0; left: 0; right: 0; z-index: 50;
  backdrop-filter: saturate(160%) blur(20px);
  -webkit-backdrop-filter: saturate(160%) blur(20px);
  background: rgba(250, 247, 245, 0.78);
  border-bottom: 1px solid transparent;
  transition: border-color 0.25s ease;
}
.site-header[data-scrolled="true"] { border-bottom-color: var(--line); }
.site-header .shell { display: flex; align-items: center; gap: var(--s6); height: 62px; }

.brand {
  display: inline-flex; align-items: center; gap: var(--s2);
  text-decoration: none; font-family: var(--sans); font-weight: 650;
  font-size: var(--t-lead); letter-spacing: -0.022em; margin-right: auto;
}
.brand__mark { width: 22px; height: 22px; flex: none; }

.nav { display: flex; align-items: center; gap: var(--s6); }
.nav a { text-decoration: none; font-size: var(--t-body); color: var(--text-2); transition: color 0.15s ease; }
.nav a:hover { color: var(--text); }

.header-tools { display: flex; align-items: center; gap: var(--s3); }
/* Six languages need a menu, not a toggle. Built on <details> so it opens
   and navigates with no JavaScript at all. */
.lang { position: relative; }
.lang > summary {
  list-style: none; cursor: pointer;
  display: inline-flex; align-items: center; gap: var(--s2);
  padding: var(--s1) var(--s3);
  font-family: var(--sans); font-size: var(--t-small); font-weight: 600;
  color: var(--text-2);
  border: 1px solid var(--line-2); border-radius: 999px;
  transition: color 0.15s ease, border-color 0.15s ease;
}
.lang > summary::-webkit-details-marker { display: none; }
.lang > summary::after {
  content: ""; width: 6px; height: 6px; margin-top: -3px;
  border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor;
  transform: rotate(45deg); transition: transform 0.2s ease;
}
.lang > summary:hover { color: var(--text); border-color: var(--text-3); }
.lang[open] > summary { color: var(--text); border-color: var(--text-3); }
.lang[open] > summary::after { transform: rotate(-135deg); margin-top: 2px; }
.lang ul {
  position: absolute; right: 0; top: calc(100% + 10px); z-index: 60;
  margin: 0; padding: var(--s2); list-style: none; min-width: 168px;
  background: var(--card); border: 1px solid var(--line);
  border-radius: var(--r-md);
  box-shadow: 0 18px 40px -20px rgba(30, 22, 24, 0.45);
}
.lang li + li { margin-top: 2px; }
.lang ul a {
  display: block; padding: 7px 10px; border-radius: 8px;
  font-size: var(--t-small); color: var(--text-2); text-decoration: none;
}
.lang ul a:hover { background: var(--card-2); color: var(--text); }
.lang ul a[aria-current="true"] { color: var(--accent); font-weight: 700; }

/* ---------- Buttons ---------- */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--s2);
  padding: 12px var(--s6); border-radius: 999px;
  font-family: var(--sans); font-size: var(--t-body); font-weight: 600;
  text-decoration: none; letter-spacing: -0.005em;
  border: 1px solid transparent; cursor: pointer; white-space: nowrap;
  transition: transform 0.15s ease, box-shadow 0.25s ease, background 0.25s ease,
    border-color 0.2s ease, color 0.2s ease;
}
.btn:active { transform: translateY(1px); }
.btn--primary {
  background: var(--brand); color: var(--on-brand);
  box-shadow: 0 8px 22px -10px rgba(226, 102, 31, 0.55);
}
.btn--primary:hover { box-shadow: 0 14px 30px -10px rgba(226, 102, 31, 0.7); }
.btn--ghost { border-color: var(--line-2); color: var(--text); }
.btn--ghost:hover { border-color: var(--text-3); background: rgba(30, 22, 24, 0.045); }
.btn--sm { padding: 8px var(--s4); font-size: var(--t-small); }

/* ---------- Hero ---------- */

.hero { text-align: center; }
.hero__title {
  margin-top: 0;
  font-family: var(--display); font-weight: var(--display-weight);
  font-size: var(--t-display);
  letter-spacing: -0.04em; line-height: var(--lh-display);
  max-width: 15ch; margin-inline: auto;
}
/* One word, not a whole line. Italic is a Latin device — synthetic oblique on
   CJK glyphs looks broken, so those scripts take the colour alone. */
.hero__title .accent { color: var(--orange); font-style: italic; }
:lang(zh-Hans) .accent, :lang(zh-Hant) .accent, :lang(ja) .accent, :lang(ko) .accent {
  font-style: normal;
}
:lang(zh) .hero__title { letter-spacing: -0.02em; line-height: var(--lh-title); }

.hero__demo { margin-top: clamp(14px, 2.2svh, 36px); }

/* ---------- Demo ---------- */

.demo { text-align: left; }

.demo__frame {
  border-radius: var(--r-xl);
  border: 1px solid var(--line);
  background: linear-gradient(170deg, #ffffff 0%, #fefaf8 55%, #fbf2ee 100%);
  box-shadow: 0 26px 60px -34px rgba(30, 22, 24, 0.3), 0 2px 6px -2px rgba(30, 22, 24, 0.06);
  overflow: hidden;
}

.demo__bar {
  display: flex; align-items: center; gap: var(--s2);
  padding: var(--s3) var(--s4);
  border-bottom: 1px solid var(--line);
}
.dot { width: 11px; height: 11px; border-radius: 50%; }
.dot--r { background: #ec6d63; }
.dot--y { background: #e0b04f; }
.dot--g { background: #56b96a; }

.demo__source {
  margin-left: auto; display: inline-flex; align-items: center; gap: var(--s2);
  font-size: var(--t-micro); color: var(--text-2);
  padding: var(--s1) var(--s3); border-radius: 999px;
  border: 1px solid var(--line); background: rgba(30, 22, 24, 0.04);
}
.demo__source i {
  width: 6px; height: 6px; border-radius: 50%; background: var(--orange);
  box-shadow: 0 0 0 3px rgba(255, 193, 120, 0.16);
}
.demo[data-state="playing"] .demo__source i { animation: pulse 2.4s ease-in-out infinite; }
@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.4; } }

.demo__body { padding: clamp(14px, 2.2vh, 34px) var(--s8) var(--s6); }

.demo__lyrics {
  text-align: center; display: grid; align-content: center; gap: 2px;
  min-height: clamp(86px, 13vh, 152px);
  min-height: clamp(86px, 13svh, 152px);
}
/* Inactive lines are held back with solid tone rather than opacity: faded to
   0.32 they measured 1.86:1, and an upcoming lyric is text a person reads,
   not decoration. Size and the gradient carry the hierarchy instead. */
.lyric {
  font-size: var(--t-body); line-height: var(--lh-body); color: var(--text-3);
  transition: color 0.4s ease, font-size 0.3s ease;
}
.lyric[data-state="past"] { color: #6f6367; }
.lyric[data-state="now"] {
  opacity: 1; font-size: var(--t-lyric); font-weight: 700;
  letter-spacing: -0.018em; padding-block: var(--s1);
  background: var(--brand-text);
  background-size: 200% 100%;
  -webkit-background-clip: text; background-clip: text; color: transparent;
}

.runway {
  position: relative; margin-top: var(--s4);
  height: clamp(76px, 12vh, 136px);
  height: clamp(76px, 12svh, 136px);
  border-radius: var(--r-md);
  border: 1px solid rgba(30, 22, 24, 0.07);
  background:
    linear-gradient(180deg, rgba(255, 255, 255, 0.7), rgba(255, 255, 255, 0) 42%),
    var(--screen);
  box-shadow: inset 0 1px 2px rgba(30, 22, 24, 0.05);
  overflow: hidden;
}
.runway canvas { display: block; width: 100%; height: 100%; }
.runway__label {
  position: absolute; top: var(--s2); left: var(--s3); z-index: 2;
  font-family: var(--mono); font-size: var(--t-micro); letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--text-2);
}
:lang(zh) .runway__label { letter-spacing: 0.06em; text-transform: none; }

.demo__seek { margin-top: var(--s2); height: 3px; border-radius: 999px; background: rgba(30, 22, 24, 0.1); }
.demo__seek span { display: block; height: 100%; width: 0; border-radius: 999px; background: var(--brand); }

/* The transport lives inside the window now. A symmetric 1fr / auto / 1fr grid
   keeps the vocal button dead-centre whatever width the play control and the
   mixer happen to take. */
.demo__controls {
  margin-top: var(--s4);
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: var(--s4);
}
.demo__controls .demo__play { justify-self: start; }
.demo__mix { justify-self: end; width: 100%; max-width: 208px; transition: opacity 0.3s ease; }

.demo__play {
  width: 48px; height: 48px; border-radius: 50%; flex: none;
  display: inline-grid; place-items: center; cursor: pointer;
  border: 0; background: rgba(30, 22, 24, 0.07); color: var(--text);
  transition: background 0.2s ease, transform 0.15s ease;
}
.demo__play:hover { background: rgba(30, 22, 24, 0.13); }
.demo__play:active { transform: scale(0.96); }
.demo__play svg { width: 24px; height: 24px; display: block; }
.demo__play-icon { grid-area: 1 / 1; display: none; }
.demo__play-icon--play { display: block; }
.demo[data-state="playing"] .demo__play-icon--play { display: none; }
.demo[data-state="playing"] .demo__play-icon--pause { display: block; }

.demo__toggle {
  min-width: min(240px, 100%); padding: 13px var(--s8); border: 0; cursor: pointer;
  border-radius: 999px; font-family: inherit;
  font-family: var(--sans); font-size: var(--t-body); font-weight: 600; letter-spacing: -0.01em;
  background: var(--brand); color: var(--on-brand);
  box-shadow: 0 10px 26px -10px rgba(226, 102, 31, 0.6);
  transition: transform 0.15s ease, box-shadow 0.25s ease, background 0.3s ease, color 0.3s ease;
}
.demo__toggle:hover { box-shadow: 0 16px 34px -10px rgba(226, 102, 31, 0.75); }
.demo__toggle:active { transform: translateY(1px); }
/* Once the voice is gone the button stops shouting — it is now the way back. */
.demo[data-vocal="on"] .demo__toggle { animation: breathe 3.4s ease-in-out infinite; }
.demo[data-vocal="off"] .demo__toggle {
  background: transparent; color: var(--text);
  box-shadow: none; border: 1px solid var(--line-2);
}
.demo[data-vocal="off"] .demo__toggle:hover { border-color: var(--text-3); background: rgba(30, 22, 24, 0.045); }

/* Locked until the vocal is actually gone — there is nothing to trim before
   then, and an inert-looking control says so better than a tooltip. */
.demo[data-vocal="on"] .demo__mix { opacity: 0.68; }

.demo__mix-row {
  font-family: var(--mono); letter-spacing: 0.02em;
  display: flex; justify-content: space-between; align-items: baseline;
  font-size: var(--t-small); color: var(--text-2); margin-bottom: var(--s2);
}
.demo__slider {
  -webkit-appearance: none; appearance: none;
  width: 100%; height: 6px; border-radius: 999px; cursor: pointer;
  /* The fill is sized to the value from script, so the track reads its own
     level instead of looking full at every position. */
  background-image: linear-gradient(90deg, var(--orange-lift), var(--orange));
  background-repeat: no-repeat;
  background-size: 100% 100%;
  background-color: rgba(30, 22, 24, 0.12);
}
.demo__slider:disabled { cursor: not-allowed; }
.demo__slider::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 18px; height: 18px; border-radius: 50%;
  background: #fff; border: 0; box-shadow: 0 2px 6px rgba(30, 22, 24, 0.35);
}
.demo__slider::-moz-range-thumb {
  width: 18px; height: 18px; border-radius: 50%;
  background: #fff; border: 0; box-shadow: 0 2px 6px rgba(30, 22, 24, 0.35);
}

.demo__hint { margin-top: var(--s3); font-size: var(--t-small); color: var(--text-3); text-align: center; }
.demo__note {
  margin: var(--s4) auto 0; max-width: 62ch; text-align: center;
  font-size: var(--t-small); line-height: var(--lh-body); color: var(--text-3);
}
.demo__note a { color: var(--accent); text-underline-offset: 3px; }
.demo[data-state="loading"] .demo__hint::after { content: " ·"; animation: pulse 1s steps(3) infinite; }

.demo__unsupported { display: none; margin-top: var(--s4); font-size: var(--t-small); color: var(--text-3); text-align: center; }
.demo[data-state="unsupported"] .demo__controls,
.demo[data-state="unsupported"] .demo__hint { display: none; }
.demo[data-state="unsupported"] .demo__unsupported { display: block; }


/* ---------- Showcase ---------- */

/* The mock is the section's whole argument, so it gets the room — but sized
   against viewport height, not width, or a 4:3 box at full shell width runs
   two screens tall. */
.showcase__figure {
  margin: 0 auto;
  width: min(100%, clamp(400px, 74svh, 780px));
}
.showcase__figure figcaption { margin-top: var(--s4); font-size: var(--t-small); color: var(--text-3); text-align: center; }

/* A desktop, with the lyrics floating over it. */
.desktop {
  position: relative; aspect-ratio: 16 / 10; border-radius: var(--r-lg);
  border: 1px solid var(--line); overflow: hidden;
  background: linear-gradient(148deg, #ffeadb 0%, #fcd3b4 46%, #f4b98f 100%);
}
.desktop__menubar {
  position: absolute; inset: 0 0 auto 0; height: 20px;
  background: rgba(255, 255, 255, 0.34); display: flex; align-items: center;
  justify-content: flex-end; gap: 8px; padding-inline: 10px;
}
.desktop__menubar span { width: 12px; height: 4px; border-radius: 2px; background: rgba(30, 22, 24, 0.3); }
.desktop__win {
  position: absolute; border-radius: 10px;
  border: 1px solid rgba(255, 255, 255, 0.75);
  background: rgba(255, 255, 255, 0.72);
  backdrop-filter: blur(10px);
  box-shadow: 0 12px 30px -14px rgba(70, 30, 10, 0.45);
}
.desktop__win--back { left: 8%; top: 16%; width: 52%; height: 44%; }
.desktop__win--front { left: 24%; top: 26%; width: 60%; height: 46%; padding: 22px 14px 0; }
.desktop__winbar { position: absolute; inset: 0 0 auto 0; height: 14px; background: rgba(30, 22, 24, 0.07); border-radius: 10px 10px 0 0; }
.desktop__line { display: block; height: 5px; border-radius: 3px; background: rgba(30, 22, 24, 0.16); margin-bottom: 8px; }
.desktop__line--short { width: 55%; }

.desktop__lyric {
  position: absolute; left: 6%; right: 6%; bottom: 9%;
  text-align: center; font-size: var(--t-lyric-desktop); font-weight: 700;
  letter-spacing: -0.01em; color: var(--text);
  text-shadow: 0 1px 8px rgba(255, 255, 255, 0.7);
  transition: opacity 0.4s ease;
}
.desktop__lyric[data-idle="true"] { opacity: 0.85; }

.privacy-band {
  border-block: 1px solid var(--line);
  background: radial-gradient(70% 100% at 50% 0%, rgba(226, 102, 31, 0.07), transparent 70%), var(--paper-2);
}


.faq details { border-top: 1px solid var(--line); padding: var(--s4) 0; }
.faq details:last-child { border-bottom: 1px solid var(--line); }
.faq summary {
  cursor: pointer; list-style: none; font-size: var(--t-lead); font-weight: 600;
  display: flex; justify-content: space-between; align-items: center;
  gap: var(--s4); padding-block: var(--s2);
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: ""; flex: none; width: 9px; height: 9px;
  border-right: 2px solid var(--text-3); border-bottom: 2px solid var(--text-3);
  transform: rotate(45deg) translate(-2px, -2px); transition: transform 0.25s ease;
}
.faq details[open] summary::after { transform: rotate(-135deg) translate(-2px, -2px); }
.faq p { margin-top: var(--s2); color: var(--text-2); max-width: 76ch; font-size: var(--t-body); }

/* ---------- Closing CTA, footer ---------- */


.site-footer {
  border-top: 1px solid var(--line);
  padding-block: var(--s12) var(--s8); background: var(--paper-2);
}
.footer-grid { display: grid; grid-template-columns: 2fr 1fr 1fr; gap: var(--s8); }
.site-footer h4 {
  font-size: var(--t-small); letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--text-3); font-weight: 600;
}
:lang(zh) .site-footer h4 { letter-spacing: 0.04em; text-transform: none; }
.site-footer ul { list-style: none; margin: var(--s4) 0 0; padding: 0; display: grid; gap: var(--s3); }
.site-footer a { color: var(--text-2); text-decoration: none; font-size: var(--t-body); }
.site-footer a:hover { color: var(--text); }
.footer-tagline { margin-top: var(--s3); color: var(--text-3); font-size: var(--t-body); max-width: 34ch; }
.footer-base {
  margin-top: var(--s8); padding-top: var(--s6); border-top: 1px solid var(--line);
  display: flex; flex-wrap: wrap; gap: var(--s4); justify-content: space-between;
  font-size: var(--t-small); color: var(--text-3);
}

/* ---------- Long-form pages ---------- */

.doc { padding-block: calc(62px + var(--s12)) var(--s12); }
.doc h1 { font-size: var(--t-title); }
.doc__meta { margin-top: var(--s3); font-size: var(--t-small); color: var(--text-3); }
/* Which language is authoritative, said once and quietly. */
.doc__governing {
  margin-top: var(--s6); padding: var(--s4) var(--s6);
  border-left: 2px solid var(--orange); border-radius: 0 var(--r-sm) var(--r-sm) 0;
  background: var(--card-2); max-width: 72ch;
  font-size: var(--t-small); color: var(--text-2);
}
.doc__intro { margin-top: var(--s6); font-size: var(--t-lead); color: var(--text-2); max-width: 72ch; }
.doc section { margin-top: var(--s12); max-width: 76ch; }
.doc section h2 { font-size: var(--t-h3); }
.doc section p { margin-top: var(--s4); color: var(--text-2); }
.doc__group { margin-top: var(--s12); }
.doc__group > h2 { font-size: var(--t-h3); margin-bottom: var(--s2); }
.doc a.link { color: var(--accent); text-decoration: underline; text-underline-offset: 3px; }

.contact-card {
  margin-top: var(--s8); padding: var(--s8); border-radius: var(--r-lg);
  border: 1px solid rgba(226, 102, 31, 0.22); max-width: 76ch;
  background: linear-gradient(135deg, rgba(238, 122, 42, 0.16), rgba(226, 102, 31, 0.1));
}
.contact-card h2 { font-size: var(--t-h3); }
.contact-card p { margin-top: var(--s3); color: var(--text-2); }
.contact-card a { display: inline-block; margin-top: var(--s4); font-size: var(--t-lead); color: var(--accent); }

/* ---------- Responsive ---------- */

@media (max-width: 940px) {
  .showcase { grid-template-columns: 1fr; gap: var(--s8); }
  .steps { grid-template-columns: 1fr; }
  .ruled__row { grid-template-columns: 1fr; gap: 2px; }
  .steps { grid-template-columns: 1fr; }
  .ruled--two { grid-template-columns: 1fr; }
  .footer-grid { grid-template-columns: 1fr 1fr; }
  .nav { display: none; }
}

@media (max-width: 620px) {
  body { font-size: var(--t-body); }
  .section { padding-block: var(--s16); }
  .shell { padding-inline: var(--s4); }
  .demo__body { padding: var(--s4) var(--s3) var(--s3); }
  .demo__source { display: none; }
  /* Phones have the least height of anything, and the height-based tiers
     above deliberately do not apply here: on iOS the viewport grows as the
     URL bar retracts, so a max-height rule would flip layouts mid-scroll.
     Compact unconditionally instead, and let svh handle the rest. */
  :root { --t-display: clamp(24px, 6.8vw, 32px); }
    .demo__bar { padding: var(--s2) var(--s3); }
  .demo__lyrics { min-height: clamp(70px, 11svh, 104px); }
  .runway { height: clamp(60px, 9svh, 96px); }
  .demo__play { width: 44px; height: 44px; }
  .demo__toggle { padding: 13px var(--s6); font-size: var(--t-body); min-width: 0; }
  /* Three controls abreast is too tight at phone width — the mixer label and
     its readout collide. Give it the row underneath. */
  .demo__controls { grid-template-columns: auto 1fr; row-gap: var(--s3); }
  .demo__mix { grid-column: 1 / -1; justify-self: stretch; max-width: none; }
  .footer-grid { grid-template-columns: 1fr; }
}

/* Short desktop viewports — a 1366×768 laptop has about 660 px of page once
   browser chrome is gone. Pull the demo in so the button and its slider still
   land above the fold. */
@media (min-width: 621px) and (max-height: 800px) {
    .demo__lyrics { min-height: clamp(64px, 10svh, 116px); }
  .runway { height: clamp(56px, 8.6svh, 104px); }
  .demo__body { padding: clamp(10px, 1.8vh, 40px) var(--s8) var(--s3); }
  .demo__note { margin-top: var(--s3); }
  .snap.hero { padding-bottom: var(--s1); }
  .demo__play { width: 44px; height: 44px; }
  .demo__toggle { padding: 13px var(--s8); }
}

/* Shorter still. The headline and the demo already say what the lede says,
   so it goes rather than push the controls off the screen. */
@media (min-width: 621px) and (max-height: 700px) {
    .hero__title { margin-top: 0; }
}

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

/* Anchor targets clear the fixed header. Snap sections are excluded: they pad
   their own top already, and a scroll margin would shift the snap position
   itself, parking each section 78 px down the screen. */
[id] { scroll-margin-top: 78px; }
.snap { scroll-margin-top: 0; }
