/* Trie static site styles. Everything is local: no external fonts or assets. */

@font-face {
  font-family: "Tektur";
  font-style: normal;
  font-weight: 500 800;
  font-display: swap;
  src: url(fonts/tektur-latin.woff2) format("woff2");
}

@font-face {
  font-family: "IBM Plex Sans";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url(fonts/ibm-plex-sans-latin.woff2) format("woff2");
}

@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url(fonts/ibm-plex-mono-500-latin.woff2) format("woff2");
}

:root {
  color-scheme: light dark;

  --bg: #f6f4f0;
  --surface: #ffffff;
  --ink: #14161a;
  --ink-soft: #3a3f47;
  --muted: #646a73;
  --line: #e2ded7;
  --accent: #e8541e;
  --accent-text: #c2410c;
  --panel: #14161a;
  --panel-ink: #f6f4f0;
  --panel-soft: #c9cdd3;
  --panel-line: #33373e;

  --display: "Tektur", "IBM Plex Sans", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", system-ui, sans-serif;
  --sans: "IBM Plex Sans", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", system-ui, sans-serif;
  --mono: "IBM Plex Mono", ui-monospace, Menlo, monospace;

  --header-h: 3.75rem;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #14161a;
    --surface: #1e2126;
    --ink: #f6f4f0;
    --ink-soft: #c9cdd3;
    --muted: #a7adb6;
    --line: #33373e;
    --accent: #f0703f;
    --accent-text: #f2a07b;
    --panel: #f6f4f0;
    --panel-ink: #14161a;
    --panel-soft: #3a3f47;
    --panel-line: #e2ded7;
  }
}

* {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
  scroll-padding-top: var(--header-h);
}

body {
  margin: 0;
  font-family: var(--sans);
  line-height: 1.6;
  background: var(--bg);
  color: var(--ink);
  -webkit-font-smoothing: antialiased;
}

a {
  color: var(--accent-text);
}

p,
li,
dd,
h1,
h2,
h3 {
  overflow-wrap: anywhere;
}

/* Visible focus for keyboard users. */
:focus {
  outline: 3px solid var(--accent);
  outline-offset: 3px;
}

:focus:not(:focus-visible) {
  outline: none;
}

.container {
  max-width: 66rem;
  margin: 0 auto;
  padding: 0 1.5rem;
}

.skip-link {
  position: absolute;
  z-index: 20;
  left: 1rem;
  top: 0.5rem;
  transform: translateY(-200%);
  padding: 0.5rem 0.75rem;
  background: var(--surface);
  color: var(--ink);
  border-radius: 10px;
}

.skip-link:focus {
  transform: none;
}

/* Header: stays at the top of every page, frosted over what scrolls under. */

.site-header {
  position: sticky;
  top: 0;
  z-index: 10;
  background: var(--bg);
  background: color-mix(in srgb, var(--bg) 84%, transparent);
  -webkit-backdrop-filter: saturate(1.5) blur(14px);
  backdrop-filter: saturate(1.5) blur(14px);
}

.site-header .container {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 0.75rem;
  min-height: var(--header-h);
  padding-top: 0.75rem;
  padding-bottom: 0.75rem;
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  font-family: var(--mono);
  font-weight: 500;
  font-size: 0.95rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--ink);
}

.brand-group {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem 0.9rem;
}

.brand-tagline {
  font-size: 0.85rem;
  color: var(--muted);
}

.brand-mark {
  width: auto;
  height: 1.75rem;
}

/* The mark is a single ink-coloured image; in dark mode invert it to the light ink. */
@media (prefers-color-scheme: dark) {
  .brand-mark {
    filter: invert(1) brightness(1.045);
  }
}

.site-nav {
  display: flex;
  flex-wrap: wrap;
  max-width: 100%;
  gap: 0.4rem;
  font-size: 0.85rem;
}

.site-nav a {
  text-decoration: none;
  color: var(--ink-soft);
  padding: 0.3rem 0.8rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface);
}

.site-nav a[aria-current="page"] {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--bg);
}

/* Home page header: install first, the other language as a quiet link. */

.site-actions {
  display: flex;
  align-items: center;
  gap: 1.1rem;
  font-size: 0.85rem;
}

.site-cta {
  padding: 0.42rem 1.1rem;
  border-radius: 999px;
  background: var(--ink);
  color: var(--bg);
  font-weight: 600;
  text-decoration: none;
}

.site-cta:hover {
  background: var(--accent);
  color: #ffffff;
}

.site-lang {
  color: var(--muted);
  text-decoration: none;
}

.site-lang:hover {
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 0.2em;
}

/* Type */

h1,
h2,
h3,
.lede,
.hero-sub {
  text-wrap: balance;
}

h1,
h2,
h3 {
  font-family: var(--display);
  font-weight: 700;
  letter-spacing: -0.012em;
  line-height: 1.12;
  margin: 0;
}

h1 {
  font-size: clamp(2.3rem, 7vw, 4.6rem);
}

h2 {
  font-size: clamp(1.7rem, 4vw, 2.6rem);
}

h3 {
  font-size: 1.35rem;
}

.eyebrow {
  font-family: var(--mono);
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 0.9rem;
}

/* Hero */

.hero {
  text-align: center;
  padding: 3.5rem 0 4.5rem;
  border-bottom: 1px solid var(--line);
}

.hero h1 {
  max-width: 16em;
  margin: 0 auto;
}

.lede {
  max-width: 36rem;
  margin: 1.5rem auto 2rem;
  font-size: 1.1rem;
  color: var(--ink-soft);
}

.pill {
  display: inline-flex;
  align-items: center;
  gap: 0.75rem;
  max-width: 100%;
  padding: 0.5rem 0.55rem 0.5rem 1.2rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface);
  color: var(--ink);
  font-weight: 600;
  font-size: 0.95rem;
  text-decoration: none;
}

.pill-arrow {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 1.9rem;
  height: 1.9rem;
  border-radius: 50%;
  background: var(--bg);
  border: 1px solid var(--line);
}

.pill:hover .pill-arrow {
  background: var(--accent);
  border-color: var(--accent);
  color: #ffffff;
}

/* Sections */

main > section:not(.hero) {
  padding: 4rem 0 0;
}

main > section:last-child {
  padding-bottom: 5rem;
}

/* Steps */

.steps {
  list-style: none;
  margin: 2rem 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 2rem;
}

.step-rule {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin: 0 0 1rem;
}

.step-rule::before {
  content: "";
  flex: none;
  width: 0.6rem;
  height: 0.6rem;
  border-radius: 50%;
  border: 2px solid var(--accent);
}

.step-rule::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--line);
}

.step-num {
  font-family: var(--mono);
  font-size: 0.75rem;
  letter-spacing: 0.08em;
  color: var(--muted);
}

.step p:last-child {
  margin: 0.5rem 0 0;
  color: var(--ink-soft);
}

/* Cards */

.two-up {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1.25rem;
}

.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 22px;
  padding: 2.25rem;
}

.card h2 {
  font-size: clamp(1.5rem, 3vw, 2rem);
}

.card-lede {
  margin: 1rem 0 0;
  color: var(--ink-soft);
}

.card-dark {
  background: var(--panel);
  border-color: var(--panel);
  color: var(--panel-ink);
}

.card-dark .eyebrow {
  color: var(--panel-soft);
}

.rows {
  margin: 1.75rem 0 0;
}

.row {
  display: grid;
  grid-template-columns: 7rem minmax(0, 1fr);
  gap: 1rem;
  padding: 0.9rem 0;
  border-top: 1px solid var(--line);
}

.row dt {
  font-weight: 600;
}

.row dd {
  margin: 0;
  color: var(--ink-soft);
}

.facts {
  list-style: none;
  margin: 1.75rem 0 0;
  padding: 0;
}

.facts li {
  padding: 0.9rem 0;
  border-top: 1px solid var(--panel-line);
  color: var(--panel-soft);
}

.facts strong {
  display: block;
  color: var(--panel-ink);
  font-weight: 600;
}

kbd {
  font-family: var(--mono);
  font-size: 0.85em;
  padding: 0.05rem 0.4rem;
  border: 1px solid var(--line);
  border-radius: 5px;
  background: var(--bg);
}

.status {
  margin: 1.25rem 0 0;
  padding-top: 1.25rem;
  border-top: 1px solid var(--line);
  color: var(--ink-soft);
}

.status-label {
  display: inline-block;
  margin-right: 0.5rem;
  padding: 0.15rem 0.7rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--ink);
  background: var(--bg);
}

.status-label::before {
  content: "";
  display: inline-block;
  width: 0.45rem;
  height: 0.45rem;
  margin-right: 0.45rem;
  border-radius: 50%;
  background: var(--accent);
  vertical-align: 0.08em;
}

/* Commands and the installation guide */

.command {
  max-width: 100%;
  margin: 1.25rem 0;
  padding: 1rem 1.25rem;
  border-radius: 10px;
  background: var(--panel);
  color: var(--panel-ink);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

/* Home page install block (#139): the command with a copy button beside it.
   The button is hidden until the inline script enables it; without the script
   one click selects the whole command for Command-C. */

.install-card {
  margin-top: 2rem;
}

.install-card .status .text-link {
  margin-left: 0.25rem;
}

.command code,
code {
  font-family: var(--mono);
  font-size: 0.9em;
}

.doc h1 {
  font-size: clamp(2rem, 5vw, 3.2rem);
}

.doc h2 {
  margin-bottom: 1.5rem;
}

/* A sub-heading after a lede or card needs air above it (release notes). */
.doc .container > h3 {
  margin: 2rem 0 0.9rem;
}

/* The full list sits inside the disclosure: indented under a rule, with
   smaller, quieter headings, so 新增 / 改进 / 修复 read as parts of it and
   not as peers of 要点 and 已知限制. */
.changes[open] {
  padding-left: 1.25rem;
  border-left: 2px solid var(--line);
}

.changes > h3 {
  margin: 1.5rem 0 0.75rem;
  font-size: 1.05rem;
  color: var(--ink-soft);
}

.lede-left {
  max-width: 38rem;
  margin: 1.25rem 0 0;
  font-size: 1.1rem;
  color: var(--ink-soft);
}

.doc .card .rows {
  margin-top: 0;
}

.doc .card .row:first-child {
  border-top: 0;
  padding-top: 0;
}

.guide {
  margin: 0;
  padding: 0;
  list-style: none;
  counter-reset: guide;
}

.guide > li {
  counter-increment: guide;
  padding: 1.75rem 0;
  border-top: 1px solid var(--line);
}

.guide > li h3::before {
  content: "0" counter(guide);
  display: block;
  margin-bottom: 0.5rem;
  font-family: var(--mono);
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.08em;
  color: var(--accent-text);
}

.guide > li p {
  max-width: 40rem;
  color: var(--ink-soft);
}

.guide .rows {
  max-width: 40rem;
}

.back {
  margin-top: 2rem;
}

.changes {
  margin-top: 1.75rem;
}

.changes > summary {
  cursor: pointer;
  font-weight: 500;
  color: var(--ink-soft);
}

/* Footer */

.site-footer {
  border-top: 1px solid var(--line);
}

.site-footer .container {
  padding-top: 1.5rem;
  padding-bottom: 2rem;
}

.site-footer p {
  margin: 0;
  font-family: var(--mono);
  font-size: 0.72rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
}

.site-footer p + p {
  margin-top: 0.6rem;
}

/* The second line is links and an address, in the body face. */
.site-footer .site-footer-links {
  font-family: var(--sans);
  font-size: 0.85rem;
  letter-spacing: 0;
  text-transform: none;
}

/* Home page: hero additions */

.hero .eyebrow {
  margin-bottom: 1.25rem;
}

.hero-sub {
  margin: 0.9rem auto 0;
  font-family: var(--display);
  font-weight: 600;
  font-size: clamp(1.25rem, 3vw, 1.9rem);
  line-height: 1.25;
  color: var(--ink-soft);
}

.hero-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 0.75rem 1.5rem;
  margin: 0;
}

.hero-sub + .hero-actions {
  margin-top: 2.25rem;
}

.pill-primary {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--bg);
}

.pill-primary .pill-arrow {
  background: var(--accent);
  border-color: var(--accent);
  color: #ffffff;
}

.text-link {
  font-weight: 600;
  font-size: 0.95rem;
  color: var(--ink);
  text-underline-offset: 0.25em;
}

.hero-facts {
  margin: 1.5rem auto 0;
  font-family: var(--mono);
  font-size: 0.75rem;
  letter-spacing: 0.04em;
  color: var(--muted);
}

.fineprint {
  margin: 0.9rem auto 0;
  font-size: 0.8rem;
  color: var(--muted);
}

/* Section intro */

.section-lede {
  max-width: 40rem;
  margin: 1rem 0 0;
  font-size: 1.1rem;
  color: var(--ink-soft);
}

/* Demo: one terminal window, animated with CSS only. An 11 s loop:
   listen (0.3-2.6 s), polish (2.6-3.1 s), deliver (3.1 s), Return at 4.2 s,
   then the agent's run (4.4-7 s) and a rest on the result.
   It never pauses: a paused loop reads as a slow product. */

:root {
  --term-bg: #1b1d22;
  --term-bar: #24272d;
  --term-ink: #ecebe6;
  --term-dim: #8b919b;
  --term-line: #33373e;
  --term-hud: #2b2f36;
  --term-flash: #f0703f55;
  /* 浮层状态行的琥珀，与 Trie 浮层深色模式「说」阶段同色（docs/voice.md §5）。 */
  --term-amber: #e8b923;
}

.term {
  border: 1px solid var(--term-line);
  border-radius: 14px;
  background: var(--term-bg);
  color: var(--term-ink);
  overflow: hidden;
}

.term-bar {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0;
  padding: 0.65rem 1rem;
  background: var(--term-bar);
  border-bottom: 1px solid var(--term-line);
  font-family: var(--mono);
  font-size: 0.75rem;
  color: var(--term-dim);
}

.term-dots {
  position: absolute;
  left: 1rem;
  display: flex;
  gap: 0.45rem;
}

.term-dots span {
  width: 0.7rem;
  height: 0.7rem;
  border-radius: 50%;
  background: var(--term-line);
}

.term-body {
  position: relative;
  min-height: 27rem;
  padding: 1.25rem 1.5rem;
  font-family: var(--mono), "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", monospace;
  font-size: 0.88rem;
  line-height: 1.75;
}

.term-line,
.term-prompt {
  margin: 0;
}

.term-dim {
  color: var(--term-dim);
}

.term-prompt {
  display: flex;
  gap: 0.75rem;
  max-width: 46rem;
  margin-top: 1.1rem;
}

.term-mark {
  flex: none;
  color: var(--accent);
}

.term-input {
  position: relative;
  flex: 1;
  min-width: 0;
}

.term-pasted {
  border-radius: 3px;
  animation: term-pasted 11s infinite;
}

.caret {
  display: inline-block;
  width: 0.5em;
  height: 1.1em;
  margin-left: 2px;
  vertical-align: -0.18em;
  background: var(--term-ink);
}

.caret-idle {
  position: absolute;
  left: 0;
  top: 0.3em;
  margin: 0;
  visibility: hidden;
  animation: pulse 1.1s steps(2, jump-none) infinite, caret-idle 11s infinite;
}

.caret-after {
  animation: pulse 1.1s steps(2, jump-none) infinite, caret-after 11s infinite;
}

/* What the external agent does after Return. Each step enters in turn; the
   whole run is cleared before the loop starts over. */

.term-run {
  margin-top: 1rem;
  animation: term-run 11s infinite;
}

.term-reply {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  color: var(--term-dim);
}

.term-step {
  margin: 0.15rem 0 0;
  padding-left: 1.1rem;
  animation: term-step 11s infinite backwards;
}

.term-tool {
  font-weight: 700;
}

.term-diff,
.term-out {
  padding-left: 2.2rem;
  color: var(--term-dim);
}

.term-del {
  text-decoration: line-through;
}

.term-add {
  color: var(--term-ink);
}

.term-done {
  margin-top: 0.6rem;
  padding-left: 0;
  color: var(--accent);
  font-weight: 700;
}

.term-step:nth-child(2) {
  animation-delay: 4.8s;
}

.term-step:nth-child(3) {
  animation-delay: 5.2s;
}

.term-step:nth-child(4) {
  animation-delay: 5.4s;
}

.term-step:nth-child(5) {
  animation-delay: 5.8s;
}

.term-step:nth-child(6) {
  animation-delay: 6.2s;
}

.term-step:nth-child(7) {
  animation-delay: 6.5s;
}

.term-step:nth-child(8) {
  animation-delay: 7s;
}

.rec {
  flex: none;
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  background: var(--accent);
  animation: pulse 1.4s ease-in-out infinite;
}

/* Which key was just pressed, like a keystroke visualiser. */

.term-keys {
  position: absolute;
  top: 1.1rem;
  right: 1.25rem;
  display: grid;
  margin: 0;
}

.term-keys kbd {
  grid-area: 1 / 1;
  justify-self: end;
  padding: 0.2rem 0.7rem;
  border: 1px solid var(--accent);
  border-radius: 8px;
  background: var(--term-hud);
  color: var(--term-ink);
  font-size: 0.85rem;
  opacity: 0;
}

.key-cmd {
  animation: key-cmd 11s infinite;
}

.key-return {
  animation: key-return 11s infinite;
}

/* The Trie overlay floats above whatever app is in front. It is drawn the way
   the real one is (docs/voice.md §5): a rounded glass panel at the bottom
   centre, the draft top-left in body colour, the status line bottom-right in
   amber with a ⌘ at its end, no dot, no brand. */

.hud {
  position: absolute;
  left: 50%;
  bottom: 1.25rem;
  width: min(36rem, calc(100% - 2.5rem));
  padding: 0.9rem 1.15rem 0.85rem;
  border-radius: 12px;
  background: #2b2f36c0;
  -webkit-backdrop-filter: blur(24px) saturate(1.2);
  backdrop-filter: blur(24px) saturate(1.2);
  box-shadow: 0 10px 30px #00000055;
  font-family: var(--sans);
  opacity: 0;
  transform: translate(-50%, 10px);
  animation: hud 11s infinite;
}

.hud-draft {
  margin: 0;
  color: var(--term-ink);
  font-size: 0.95rem;
  line-height: 1.7;
}

.hud-status {
  display: flex;
  justify-content: flex-end;
  align-items: baseline;
  gap: 0.35em;
  margin: 0.4rem 0 0;
  font-weight: 500;
  font-size: 0.9rem;
  line-height: 1.4;
  color: var(--term-amber);
}

.hud-state {
  display: grid;
  justify-items: end;
}

.hud-state span {
  grid-area: 1 / 1;
  white-space: nowrap;
}

.hud-listening {
  animation: hud-listening 11s infinite;
}

.hud-thinking {
  opacity: 0;
  animation: hud-thinking 11s infinite;
}

.hud-pasting {
  opacity: 0;
  animation: hud-pasting 11s infinite;
}

.hud-draft span {
  margin-right: 0.5em;
  opacity: 0;
  animation: chunk 11s infinite;
}

.hud-draft s {
  text-decoration-color: transparent;
  animation: cut 11s infinite;
}

.hud-draft span:nth-child(1) {
  animation-delay: 0.4s;
}

.hud-draft span:nth-child(2) {
  animation-delay: 0.54s;
}

.hud-draft span:nth-child(3) {
  animation-delay: 0.69s;
}

.hud-draft span:nth-child(4) {
  animation-delay: 0.83s;
}

.hud-draft span:nth-child(5) {
  animation-delay: 0.98s;
}

.hud-draft span:nth-child(6) {
  animation-delay: 1.12s;
}

.hud-draft span:nth-child(7) {
  animation-delay: 1.26s;
}

.hud-draft span:nth-child(8) {
  animation-delay: 1.41s;
}

.hud-draft span:nth-child(9) {
  animation-delay: 1.55s;
}

.hud-draft span:nth-child(10) {
  animation-delay: 1.7s;
}

.hud-draft span:nth-child(11) {
  animation-delay: 1.84s;
}

.hud-draft span:nth-child(12) {
  animation-delay: 1.98s;
}

.hud-draft span:nth-child(13) {
  animation-delay: 2.13s;
}

.hud-draft span:nth-child(14) {
  animation-delay: 2.27s;
}

/* Home page (#139): a scroll narrative in full-height acts under the fixed
   header. Each act pins a stage while the visitor scrolls through it: the
   opening, "why", then "what we believe", whose card turns over into a
   keyboard that hands out the install command. Motion is CSS scroll-driven
   animation; browsers without it see the same acts standing still. */

main > section.act {
  padding: 0;
}

.act {
  view-timeline-axis: block;
}

.act-open {
  view-timeline-name: --open;
}

.act-why {
  view-timeline-name: --why;
}

.act-believe {
  view-timeline-name: --believe;
}

.act-stage {
  display: grid;
  /* One track that can shrink below its content's min width: otherwise a
     wide child (the keyboard row on a phone) stretches the whole stage past
     the viewport (#235). */
  grid-template-columns: minmax(0, 1fr);
  align-items: center;
  min-height: calc(100vh - var(--header-h));
}

/* A grid item with auto margins is sized to its content; the stage's
   container must span the row, not depend on a long line somewhere inside. */
.act-stage > .container {
  width: 100%;
}

/* Every act after the title puts the same heading in the same place: eyebrow
   and title centred just under the header, the body in the room below. */

.act-head {
  text-align: center;
}

.act-head .eyebrow {
  margin-bottom: 0.55rem;
}

.act-head h2 {
  font-size: clamp(1.9rem, 4.2vw, 3rem);
}

.act-head .section-lede {
  margin-left: auto;
  margin-right: auto;
}

.act-open .act-stage,
.act-why .act-stage,
.act-believe .act-stage {
  align-items: start;
  padding-top: 2.5rem;
}

.act-why .act-stage > .container,
.act-believe .act-stage > .container {
  display: grid;
  grid-template-rows: auto minmax(0, 1fr);
  align-items: center;
  min-height: calc(100vh - var(--header-h) - 2.5rem);
}

/* Opening: the title sits high with air under it, and the window takes the
   rest of the screen. The second heading exists for the scroll version only,
   where it takes the title's place as the window slides over. */

.open-layout {
  max-width: 80rem;
}

.open-head {
  display: grid;
  align-items: center;
  justify-items: center;
  text-align: center;
}

.open-copy h1 {
  font-size: clamp(2.4rem, 4.4vw, 4.4rem);
}

.open-copy .hero-sub {
  margin-top: 0.5rem;
  font-size: clamp(1.1rem, 1.9vw, 1.6rem);
}

.open-copy-how {
  display: none;
}

.open-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 17rem;
  gap: 2.5rem;
  align-items: stretch;
  margin-top: clamp(2rem, 5vh, 3.5rem);
}

/* The window keeps a screen-like shape and its text scales with its width,
   so on a big display it reads as one big window rather than a dark slab
   with small print in one corner. The ratio and the height cap sit on the
   window itself, not on its body: when the cap bites, the browser turns it
   into a max-width through the ratio, and the whole window shrinks and stays
   centred. Putting them on the body alone left the body narrower than the
   window, with the overlay centred in the body and a blank strip on the
   right. */
.open-term .term {
  display: flex;
  flex-direction: column;
  width: 100%;
  aspect-ratio: 16 / 10;
  /* Floor the cap: on a short desktop window (1024×600) the viewport-based
     limit alone would leave a 250px window that clips the demo. */
  max-height: max(calc(100vh - 22rem), 24rem);
  margin-inline: auto;
  container-type: inline-size;
}

.open-term .term-bar {
  flex: none;
}

.open-term .term-body {
  flex: 1 1 auto;
  min-height: 0;
  padding: 1.6cqw 1.9cqw;
  font-size: clamp(0.8rem, 1.5cqw, 1.1rem);
  line-height: 1.6;
}

.open-term .hud {
  width: min(48rem, calc(100% - 3.5cqw));
  padding: 1.1cqw 1.5cqw 1cqw;
}

.open-term .hud-draft {
  font-size: clamp(0.95rem, 1.75cqw, 1.3rem);
}

.open-term .hud-status {
  margin-top: 0.5cqw;
  font-size: clamp(0.9rem, 1.6cqw, 1.2rem);
}

.open-term .term-keys kbd {
  font-size: clamp(0.8rem, 1.3cqw, 1rem);
}

/* The three steps hang on one vertical rail, read top to bottom. The marker
   borrows the step's animated border colour, so it lights up with the text. */

.open-steps {
  position: relative;
  align-self: center;
  display: grid;
  gap: 2.25rem;
  margin: 0;
  padding: 0 0 0 3.1rem;
  list-style: none;
}

.open-steps::before {
  content: "";
  position: absolute;
  top: 1.1rem;
  bottom: 1.1rem;
  left: calc(1.1rem - 1px);
  width: 2px;
  background: var(--line);
  transform-origin: 50% 0;
}

.open-steps .stage {
  position: relative;
  display: grid;
  gap: 0.2rem;
  padding: 0;
  border: 0;
}

.open-steps .stage-num {
  position: absolute;
  top: 0;
  left: -3.1rem;
  display: grid;
  place-items: center;
  width: 2.2rem;
  height: 2.2rem;
  border: 2px solid;
  border-color: inherit;
  border-radius: 50%;
  background: var(--bg);
  font-size: 0.68rem;
  letter-spacing: 0.04em;
}

.open-steps .stage strong {
  font-size: 1.2rem;
  line-height: 1.25;
}

.open-steps .stage-text {
  font-size: 0.92rem;
}

.act-why .pillars {
  margin-top: 0;
}

/* What we believe, turned over: the three lines stand on the front of a card
   and a keyboard waits on the back, to try the gesture on. Without
   scroll-driven animation the two faces simply stack. The panel keeps the
   terminal's fixed dark palette whatever the colour scheme. */

.flip {
  perspective: 1400px;
}

.flip-inner {
  position: relative;
  transform-style: preserve-3d;
}

.flip-front,
.flip-back {
  -webkit-backface-visibility: hidden;
  backface-visibility: hidden;
}

.flip-front {
  display: grid;
  align-content: center;
  min-height: 20rem;
}

/* The three lines stand side by side, each under its own title, with a
   hairline between the columns. */
.tenets {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 2rem;
  margin: 0;
}

.tenet {
  text-align: center;
}

.tenet + .tenet {
  padding-left: 2rem;
  border-left: 1px solid var(--line);
}

.tenet dt {
  margin-bottom: 0.6rem;
  font-family: var(--display);
  font-weight: 700;
  font-size: 1.25rem;
  line-height: 1.2;
  color: var(--ink);
}

.tenet dd {
  margin: 0;
  line-height: 1.7;
  color: var(--ink-soft);
}

.flip-back {
  margin-top: 1.25rem;
}

.try {
  display: grid;
  align-content: center;
  gap: 1rem;
  padding: 1.5rem 1.75rem 1.25rem;
  border: 1px solid var(--term-line);
  border-radius: 22px;
  background: var(--term-bg);
  color: var(--term-ink);
}

.try-hint {
  margin: 0;
  font-size: 1.05rem;
  text-align: center;
}

.try-screen {
  display: grid;
  align-items: center;
  min-height: 4.5rem;
  padding: 0.75rem 1rem;
  border: 1px solid var(--term-line);
  border-radius: 12px;
  background: var(--term-hud);
  font-family: var(--mono);
  font-size: 0.9rem;
}

.try-draft,
.try-command {
  display: none;
  margin: 0;
}

.try-draft {
  align-items: center;
  gap: 0.6rem;
}

.try-command {
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.try[data-state="listening"] .try-draft {
  display: flex;
}

.try[data-state="done"] .try-command {
  display: block;
}

/* What the machine needs, in small print under the keys. */
.try-reqs {
  margin: 0;
  font-size: 0.78rem;
  line-height: 1.6;
  text-align: center;
  color: var(--term-dim);
}

/* Without a script the panel never leaves "static": the command is shown
   outright and the keys that would do nothing are not. */
.try[data-state="static"] .try-command {
  display: block;
}

.try[data-state="static"] .keyboard {
  display: none;
}

.keyboard {
  display: grid;
  grid-template-columns: 1fr 1.3fr 1.2fr 1.6fr 6fr 1.6fr 1.2fr;
  gap: 0.4rem;
  padding: 0.6rem;
  border-radius: 14px;
  background: var(--term-hud);
}

.key {
  display: grid;
  align-content: center;
  justify-items: center;
  gap: 0.1rem;
  min-height: 3.4rem;
  min-width: 0;
  overflow: hidden;
  margin: 0;
  padding: 0.3rem 0.2rem;
  border: 1px solid var(--term-line);
  border-radius: 8px;
  background: var(--term-bg);
  color: var(--term-dim);
  font: inherit;
  font-family: var(--mono);
  font-size: 0.62rem;
  letter-spacing: 0.04em;
  text-align: center;
}

.key b {
  font-size: 1.1rem;
  font-weight: 500;
  line-height: 1;
  color: var(--term-ink);
}

.key-target {
  cursor: pointer;
  border-color: var(--accent);
  color: var(--term-ink);
  animation: key-glow 1.8s ease-in-out infinite;
}

.key-target:hover {
  background: var(--term-hud);
}

.key-target.is-pressed {
  transform: translateY(2px);
  background: var(--accent);
  animation: none;
}

.try[data-state="done"] .key-target {
  animation: none;
}

@keyframes key-glow {
  50% {
    box-shadow: 0 0 0 5px #f0703f33;
  }
}

/* Scroll-driven motion, desktop only. The pinned acts play over their view
   timeline's "contain" range and dissolve on "exit"; the others come in over
   "entry". Longhands throughout, because the `animation` shorthand would
   reset the timeline. Gated on the motion preference here, not overridden
   below: these selectors outrank the `.act *` reset, and a pinned stage that
   never moves is just a tall page. Print gets the still acts too. */
@media screen and (min-width: 761px) and (prefers-reduced-motion: no-preference) {
  @supports (animation-timeline: view()) {
    .act-open {
      height: 280vh;
    }

    .act-why {
      height: 320vh;
    }

    .act-believe {
      height: 220vh;
    }

    .act-open .act-stage,
    .act-why .act-stage,
    .act-believe .act-stage {
      position: sticky;
      top: var(--header-h);
      height: calc(100vh - var(--header-h));
      min-height: 0;
    }

    /* Opening: title out, "how" in, the window slides left off centre, then
       the rail draws and the steps light in turn. */
    .open-copy-how {
      display: block;
    }

    .open-head > * {
      grid-area: 1 / 1;
    }

    .open-copy,
    .open-copy-how,
    .open-term,
    .open-steps::before {
      animation-timing-function: linear;
      animation-fill-mode: both;
      animation-timeline: --open;
      animation-range: contain 0% contain 100%;
    }

    .open-copy {
      animation-name: open-copy;
    }

    .open-copy-how {
      animation-name: open-copy-how;
    }

    .open-term {
      animation-name: open-term;
    }

    .open-steps::before {
      animation-name: open-rail;
    }

    /* Each step keeps its 11 s highlight as a second animation. Three classes
       deep so this outranks `.stage:nth-child()` below, which sets the same
       longhands through the shorthand. */
    .open-grid .open-steps .stage {
      animation-duration: auto, 11s;
      animation-timing-function: linear, ease;
      animation-iteration-count: 1, infinite;
      animation-fill-mode: both, none;
      animation-timeline: --open, auto;
      animation-range: contain 0% contain 100%, normal;
    }

    .open-steps .stage:nth-child(1) {
      animation-name: open-step-1, stage-1;
    }

    .open-steps .stage:nth-child(2) {
      animation-name: open-step-2, stage-2;
    }

    .open-steps .stage:nth-child(3) {
      animation-name: open-step-3, stage-3;
    }

    /* Pinned stages dissolve as the next act pushes them up. */
    .act-open .act-stage > .container,
    .act-why .act-stage > .container {
      animation-name: stage-leave;
      animation-timing-function: linear;
      animation-fill-mode: both;
      animation-range: exit 0% exit 80%;
    }

    .act-open .act-stage > .container {
      animation-timeline: --open;
    }

    .act-why .act-stage > .container {
      animation-timeline: --why;
    }

    /* Why: the heading rises as the act arrives; the cards follow one by one,
       and the focus moves down the row while the stage is pinned. */
    .why-head {
      animation-name: rise;
      animation-timing-function: linear;
      animation-fill-mode: both;
      animation-timeline: --why;
      animation-range: entry 45% entry 95%;
    }

    .act-why .pillars .card {
      animation-timing-function: linear;
      animation-fill-mode: both;
      animation-timeline: --why;
      animation-range: entry 70% contain 100%;
      transform-origin: 50% 50%;
    }

    .act-why .pillars .card:nth-child(1) {
      animation-name: why-1;
    }

    .act-why .pillars .card:nth-child(2) {
      animation-name: why-2;
    }

    .act-why .pillars .card:nth-child(3) {
      animation-name: why-3;
    }

    /* What we believe comes in on entry, heading first. */
    .believe-head,
    .flip {
      animation-timing-function: linear;
      animation-fill-mode: both;
    }

    .believe-head {
      animation-name: rise;
      animation-timeline: --believe;
      animation-range: entry 35% entry 80%;
    }

    .flip {
      animation-name: rise;
      animation-timeline: --believe;
      animation-range: entry 50% entry 100%;
    }

    /* Then, while the stage is pinned, the card turns over and the keyboard
       on its back waits for a tap. */
    .flip-back {
      position: absolute;
      inset: 0;
      margin-top: 0;
      transform: rotateX(180deg);
    }

    .flip-inner {
      animation-name: flip;
      animation-timing-function: linear;
      animation-fill-mode: both;
      animation-timeline: --believe;
      animation-range: contain 10% contain 55%;
    }
  }
}

@keyframes open-copy {
  0%,
  8% {
    opacity: 1;
    transform: none;
  }

  22%,
  100% {
    opacity: 0;
    transform: translateY(-1rem);
  }
}

@keyframes open-copy-how {
  0%,
  18% {
    opacity: 0;
    transform: translateY(1rem);
  }

  32%,
  100% {
    opacity: 1;
    transform: none;
  }
}

/* At rest the window sits centred over the steps' empty column: half of the
   column plus the gap. */
@keyframes open-term {
  0%,
  8% {
    transform: translateX(9.75rem);
  }

  34%,
  100% {
    transform: none;
  }
}

@keyframes open-rail {
  0%,
  30% {
    transform: scaleY(0);
  }

  62%,
  100% {
    transform: none;
  }
}

@keyframes open-step-1 {
  0%,
  30% {
    opacity: 0;
    transform: translateX(0.75rem);
  }

  40%,
  100% {
    opacity: 1;
    transform: none;
  }
}

@keyframes open-step-2 {
  0%,
  42% {
    opacity: 0;
    transform: translateX(0.75rem);
  }

  52%,
  100% {
    opacity: 1;
    transform: none;
  }
}

@keyframes open-step-3 {
  0%,
  54% {
    opacity: 0;
    transform: translateX(0.75rem);
  }

  64%,
  100% {
    opacity: 1;
    transform: none;
  }
}

@keyframes stage-leave {
  0% {
    opacity: 1;
    transform: none;
  }

  100% {
    opacity: 0;
    transform: translateY(-1.5rem) scale(0.97);
  }
}

@keyframes why-1 {
  0% {
    opacity: 0;
    transform: translateY(2.5rem) scale(0.96);
  }

  12%,
  40% {
    opacity: 1;
    transform: scale(1.03);
  }

  48%,
  100% {
    opacity: 0.45;
    transform: scale(0.94);
  }
}

@keyframes why-2 {
  0%,
  10% {
    opacity: 0;
    transform: translateY(2.5rem) scale(0.96);
  }

  20%,
  40% {
    opacity: 0.45;
    transform: scale(0.94);
  }

  48%,
  72% {
    opacity: 1;
    transform: scale(1.03);
  }

  80%,
  100% {
    opacity: 0.45;
    transform: scale(0.94);
  }
}

@keyframes why-3 {
  0%,
  16% {
    opacity: 0;
    transform: translateY(2.5rem) scale(0.96);
  }

  26%,
  72% {
    opacity: 0.45;
    transform: scale(0.94);
  }

  80%,
  100% {
    opacity: 1;
    transform: scale(1.03);
  }
}

@keyframes rise {
  0% {
    opacity: 0;
    transform: translateY(2.5rem);
  }

  100% {
    opacity: 1;
    transform: none;
  }
}

@keyframes flip {
  0% {
    transform: rotateX(0);
  }

  100% {
    transform: rotateX(180deg);
  }
}

.stage {
  display: grid;
  align-content: start;
  gap: 0.2rem;
  padding-top: 0.9rem;
  border-top: 2px solid var(--line);
  color: var(--muted);
}

.stage strong {
  font-family: var(--display);
  font-size: 1.25rem;
  line-height: 1.2;
}

.stage-num {
  font-family: var(--mono);
  font-size: 0.72rem;
  letter-spacing: 0.08em;
}

.stage-text {
  font-size: 0.95rem;
}

.stage:nth-child(1) {
  animation: stage-1 11s infinite;
}

.stage:nth-child(2) {
  animation: stage-2 11s infinite;
}

.stage:nth-child(3) {
  animation: stage-3 11s infinite;
}

@keyframes pulse {
  50% {
    opacity: 0.2;
  }
}

@keyframes hud {
  0%,
  2.73% {
    opacity: 0;
    transform: translate(-50%, 10px);
  }

  4.09%,
  28.45% {
    opacity: 1;
    transform: translate(-50%, 0);
  }

  29.6%,
  100% {
    opacity: 0;
    transform: translate(-50%, 10px);
  }
}

/* The status line reads 说 → 想 → 做: listening while the draft streams in,
   thinking after the second tap, then a flash of pasting as the text lands. */
@keyframes hud-listening {
  0%,
  23.64% {
    opacity: 1;
  }

  23.73%,
  100% {
    opacity: 0;
  }
}

@keyframes hud-thinking {
  0%,
  23.64% {
    opacity: 0;
  }

  23.73%,
  27.09% {
    opacity: 1;
  }

  27.18%,
  100% {
    opacity: 0;
  }
}

@keyframes hud-pasting {
  0%,
  27.09% {
    opacity: 0;
  }

  27.18%,
  29.5% {
    opacity: 1;
  }

  29.6%,
  100% {
    opacity: 0;
  }
}

/* Each chunk runs this with its own delay, so it enters in turn and is gone
   well after the overlay itself has closed. */
@keyframes chunk {
  0% {
    opacity: 0;
  }

  0.73%,
  31.82% {
    opacity: 1;
  }

  32.73%,
  100% {
    opacity: 0;
  }
}

@keyframes cut {
  0%,
  23.64% {
    text-decoration-color: transparent;
    opacity: 1;
  }

  24.73%,
  100% {
    text-decoration-color: var(--accent);
    opacity: 0.4;
  }
}

@keyframes term-pasted {
  0%,
  28.09% {
    opacity: 0;
    background-color: transparent;
  }

  28.18% {
    opacity: 1;
    background-color: var(--term-flash);
  }

  33.64%,
  93.64% {
    opacity: 1;
    background-color: transparent;
  }

  96.36%,
  100% {
    opacity: 0;
    background-color: transparent;
  }
}

@keyframes caret-idle {
  0%,
  28.09% {
    visibility: visible;
  }

  28.18%,
  100% {
    visibility: hidden;
  }
}

@keyframes caret-after {
  0%,
  28.09% {
    visibility: hidden;
  }

  28.18%,
  38.18% {
    visibility: visible;
  }

  38.27%,
  100% {
    visibility: hidden;
  }
}

@keyframes term-run {
  0%,
  39.91% {
    opacity: 0;
  }

  40.45%,
  93.64% {
    opacity: 1;
  }

  96.36%,
  100% {
    opacity: 0;
  }
}

@keyframes term-step {
  0% {
    opacity: 0;
  }

  0.91%,
  59.09% {
    opacity: 1;
  }

  60%,
  100% {
    opacity: 0;
  }
}

@keyframes key-cmd {
  0%,
  2.18%,
  5.55%,
  22.64%,
  26.45%,
  100% {
    opacity: 0;
  }

  2.27%,
  5.45%,
  22.73%,
  26.36% {
    opacity: 1;
  }
}

@keyframes key-return {
  0%,
  37.18%,
  41%,
  100% {
    opacity: 0;
  }

  37.27%,
  40.91% {
    opacity: 1;
  }
}

@keyframes stage-1 {
  0%,
  3.09%,
  23.73%,
  100% {
    border-color: var(--line);
    color: var(--muted);
  }

  3.18%,
  23.64% {
    border-color: var(--accent);
    color: var(--ink);
  }
}

@keyframes stage-2 {
  0%,
  23.64%,
  28.18%,
  100% {
    border-color: var(--line);
    color: var(--muted);
  }

  23.73%,
  28.09% {
    border-color: var(--accent);
    color: var(--ink);
  }
}

@keyframes stage-3 {
  0%,
  28.09%,
  93.73%,
  100% {
    border-color: var(--line);
    color: var(--muted);
  }

  28.18%,
  93.64% {
    border-color: var(--accent);
    color: var(--ink);
  }
}

/* Three pillars */

.pillars {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1.25rem;
  margin-top: 2rem;
}

.pillars .card {
  padding: 1.75rem;
}

.pillars h3 {
  font-size: 1.5rem;
}

.pillars .facts {
  margin-top: 1.25rem;
}

.card:not(.card-dark) .facts li {
  border-top-color: var(--line);
  color: var(--ink-soft);
}

.card:not(.card-dark) .facts strong {
  color: var(--ink);
}

/* What we believe: the promise card sits under the heading. */

#promise {
  margin-top: 0;
}

/* Without motion the window rests on the delivered text. */
@media (prefers-reduced-motion: reduce) {
  .act *,
  .act *::before {
    animation: none;
  }

  .stage {
    border-color: var(--ink);
    color: var(--ink);
  }
}

@media print {
  .act * {
    animation: none;
  }
}

/* Narrow screens */

@media (max-width: 760px) {
  .steps,
  .two-up,
  .pillars,
  .stages,
  .open-grid {
    grid-template-columns: minmax(0, 1fr);
  }

  .brand-tagline {
    display: none;
  }

  .open-grid {
    gap: 1.5rem;
    margin-top: 1.5rem;
  }

  /* 窄屏不按 16:10 定形：外框的比例与高度上限解除，随正文的 40rem 撑开，
     否则 overflow: hidden 的外框会把正文下半截和浮层裁掉。 */
  .open-term .term {
    aspect-ratio: auto;
    max-height: none;
  }

  .open-term .term-body {
    min-height: 40rem;
  }

  .open-steps {
    gap: 1.5rem;
  }

  .tenets {
    grid-template-columns: minmax(0, 1fr);
    gap: 1.5rem;
  }

  .tenet + .tenet {
    padding-left: 0;
    padding-top: 1.5rem;
    border-left: 0;
    border-top: 1px solid var(--line);
  }

  /* Phone-width keyboard: keep ⌘ · space · ⌘ · option, drop the three keys
     on the left, so the row fits without overflowing (#235). */
  .keyboard {
    grid-template-columns: 1.6fr 4fr 1.6fr 1.2fr;
    gap: 0.3rem;
    padding: 0.45rem;
  }

  .keyboard .key:nth-child(-n + 3) {
    display: none;
  }

  .key {
    min-height: 3rem;
    font-size: 0.56rem;
  }

  .act-stage {
    min-height: 0;
    padding: 3rem 0;
  }

  .act-open .act-stage,
  .act-why .act-stage,
  .act-believe .act-stage {
    padding-top: 2rem;
  }

  .act-why .act-stage > .container,
  .act-believe .act-stage > .container {
    min-height: 0;
    gap: 2rem;
  }

  .term-body {
    min-height: 40rem;
    padding: 1rem;
    font-size: 0.8rem;
  }

  .term-keys {
    top: 0.75rem;
    right: 0.75rem;
  }

  .hud {
    bottom: 1rem;
    width: calc(100% - 2rem);
  }

  .hero {
    padding: 2.5rem 0 3.5rem;
  }

  .card {
    padding: 1.5rem;
    border-radius: 18px;
  }

  .row {
    grid-template-columns: minmax(0, 1fr);
    gap: 0.2rem;
  }
}
