/* Home page: Feature Stack (sticky visual + scroll-synced steps) + two card sliders + hero mascot.
   Home page only (SPEC §9). Loads after tokens, base, glass, moqi, effects and keyboard.
   Colour: ink on paper; cyan-soft for your bubbles; the MOQI gradient only in .hl and MOQI's own parts.
   Motion: transform and opacity only. Glass elements keep glass.css's transition list when they set their own. */

/* ---------- Shared bits ---------- */

.sec-head {
  display: grid;
  gap: var(--space-sm);
  max-width: 44rem;
  margin-bottom: var(--space-xl);
}

.sec-head__body {
  max-width: 31em;
  color: var(--color-ink-2);
  font-size: var(--text-md);
}

.sec-head__body:is(:lang(en), :lang(vi), :lang(th)) {
  max-width: 36em;
}

/* Small monochrome label: ink-2 on white with a hairline (SPEC §1.4) */
.tag {
  display: inline-flex;
  align-items: center;
  gap: 0.35em;
  inline-size: fit-content;
  min-block-size: 26px;
  padding: var(--space-3xs) var(--space-xs);
  border-radius: var(--radius-pill);
  background: var(--color-paper);
  box-shadow: inset 0 0 0 1px var(--color-rule);
  color: var(--color-ink-2);
  font-size: var(--text-xs);
  font-weight: 500;
  line-height: 1.3;
  white-space: nowrap;
}

.tag--chip {
  min-block-size: 32px;
  padding-inline: var(--space-xs);
  font-size: var(--text-sm);
}

.panel-label {
  display: flex;
  align-items: center;
  gap: var(--space-2xs);
  margin-bottom: var(--space-2xs);
  color: var(--color-caption);
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.02em;
}

/* Chat bubbles: yours in the app's light cyan, theirs white with a hairline (SPEC §3) */
.bubble {
  position: relative;
  inline-size: fit-content;
  max-inline-size: min(84%, 24rem);
  padding: var(--bubble-pad);
  border-radius: 18px;
  font-size: var(--text-sm);
  line-height: 1.5;
  overflow-wrap: anywhere;
}

.bubble--them {
  align-self: flex-start;
  border-end-start-radius: 6px;
  background: var(--color-paper);
  box-shadow: inset 0 0 0 1px var(--color-rule);
}

.bubble--me {
  align-self: flex-end;
  border-end-end-radius: 6px;
  background: var(--color-cyan-soft);
}

.bubble__sub {
  display: block;
  margin-top: var(--space-3xs);
  padding-top: var(--space-2xs);
  border-top: 1px solid color-mix(in oklch, var(--color-ink) 12%, transparent);
  color: var(--color-ink-2);
  font-size: var(--text-xs);
}

.bubble.is-new {
  animation: bubble-in 460ms var(--ease-out) both;
  transform-origin: 0% 100%;
}

.bubble--me.is-new {
  transform-origin: 100% 100%;
}

@keyframes bubble-in {
  from {
    opacity: 0;
    transform: translateY(10px) scale(0.9);
  }
}

/* A glass pill button (replay, 不像我); text on it stays AA with the strong fill */
.pill-btn {
  --glass-radius: var(--radius-pill);
  --glass-tint: var(--glass-fill-strong);
  --glass-lens-blur: 8px;
  display: inline-flex;
  align-items: center;
  gap: var(--space-2xs);
  min-block-size: 44px;
  padding: 0 var(--space-sm) 0 var(--space-xs);
  border-radius: var(--radius-pill);
  color: var(--color-ink);
  font-size: var(--text-sm);
  font-weight: 600;
  line-height: 1;
  white-space: nowrap;
}

.pill-btn .icon {
  font-size: 1.05rem;
}

.pill-btn.is-spun .icon {
  animation: spin-once 720ms var(--ease-out);
}

@keyframes spin-once {
  from {
    transform: rotate(-360deg);
  }
}

.pill-btn[aria-busy="true"] {
  cursor: progress;
}

/* Glass secondary CTA (hero): ink on white glass over the silk */
.btn--glass {
  --glass-radius: var(--radius-pill);
  --glass-tint: var(--glass-fill);
  --glass-lens-blur: 8px;
  color: var(--color-ink);
  transition:
    transform var(--dur) var(--ease-out),
    --glass-spec 240ms var(--ease-out),
    --gx 520ms var(--ease-out),
    --gy 520ms var(--ease-out);
}

.link-arrow {
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  min-block-size: 44px;
  color: var(--color-ink);
  font-weight: 600;
  text-decoration-line: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.3em;
}

.link-arrow .icon {
  transition: transform var(--dur) var(--ease-out);
}

/* one hover signal: the arrow leans the way it goes */
@media (hover: hover) {
  .link-arrow:hover .icon {
    transform: translateX(4px);
  }
}

/* Reveal that only moves (for blocks that hold glass: an opacity on them would flatten the glass) */
.js [data-reveal="rise"]:not(.is-in) {
  opacity: 1;
  transform: translateY(56px);
}

.js [data-reveal="rise"].is-in {
  animation: reveal-rise 1000ms var(--ease-out) backwards;
}

@keyframes reveal-rise {
  from {
    transform: translateY(56px);
  }
}

/* Section headings rise with the scroll, wide screens only (SPEC §5); elsewhere they are simply there.
   The rise ends once the heading is fully on screen, so a heading is never left half see-through. */
@media (min-width: 40rem) {
  @supports (animation-timeline: view()) {
    .sec-rise {
      animation: sec-rise linear both;
      animation-timeline: view();
      animation-range: entry 0% entry 100%;
    }
  }
}

@keyframes sec-rise {
  from {
    opacity: 0;
    transform: translateY(64px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

/* zh headings break at punctuation, not inside a word (overflow-wrap still saves a too-long line) */
.t-section:is(:lang(zh), :lang(ko)) {
  word-break: keep-all;
}

/* ---------- 2. Hero ---------- */

/* The hero stands on the moment's paper (paper-2), so the silk melts straight into the next band: no seam
   between the two (owner, 2026-10-02: they read as two blocks). */
.hero {
  position: relative;
  z-index: 1; /* MOQI may dive over the next band while it shrinks away */
  padding-block: calc(76px + var(--space-lg)) var(--space-2xl);
  background: var(--color-paper-2);
}

/* The silk melts into the paper instead of ending on a line; an eased fade, so its start shows no band. */
.hero > .silk {
  -webkit-mask-image: linear-gradient(180deg, #000 0%, #000 46%, rgb(0 0 0 / .86) 58%, rgb(0 0 0 / .6) 70%, rgb(0 0 0 / .32) 82%, rgb(0 0 0 / .1) 92%, transparent 100%);
  mask-image: linear-gradient(180deg, #000 0%, #000 46%, rgb(0 0 0 / .86) 58%, rgb(0 0 0 / .6) 70%, rgb(0 0 0 / .32) 82%, rgb(0 0 0 / .1) 92%, transparent 100%);
}

.hero__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-sm);
  align-items: center;
}

.hero__stage {
  order: -1;
  display: flex;
  justify-content: flex-end;
  transform-origin: 50% 50%;
}

.hero__float {
  display: grid;
  place-items: center;
}

.hero__moqi {
  --moqi-size: clamp(128px, 36vw, 172px);
  display: block;
  inline-size: var(--moqi-size);
  aspect-ratio: 1;
  border-radius: 50%;
  cursor: pointer;
}

.hero__moqi:focus-visible {
  outline-offset: 10px;
}

.hero__moqi-still {
  inline-size: 100%;
  block-size: 100%;
}

.hero__title {
  max-width: 11em;
  font-size: var(--text-display);
}

.hero__title:lang(zh) {
  max-width: 7.2em;
  line-height: 1.16;
  word-break: keep-all;
}

.hero__title:lang(ja) {
  max-width: 8.4em;
  line-height: 1.24;
}

.hero__title:lang(ko) {
  max-width: 8.6em;
  line-height: 1.22;
}

.hero__title:lang(th) {
  max-width: 11em;
  line-height: 1.32;
}

.hero__title:lang(vi) {
  line-height: 1.14;
}

.hero__sub {
  max-width: 27em;
  margin-top: var(--space-md);
  color: var(--color-ink-2);
  font-size: var(--text-md);
}

.hero__sub:is(:lang(en), :lang(vi), :lang(th)) {
  max-width: 31em;
}

.hero__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-xs);
  margin-top: var(--space-lg);
}

.hero__note {
  margin-top: var(--space-sm);
  color: var(--color-ink-2);
  font-size: var(--text-sm);
}

.hero__people {
  margin-top: var(--space-xl);
}

.hero__people-label {
  margin-bottom: var(--space-2xs);
  color: var(--color-ink-2);
  font-size: var(--text-sm);
}

.hero__chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2xs);
}

/* The person MOQI is thinking of: a short ink bar grows under the name (as for the nav's current page),
   the pill rises a little and becomes a glass lens (site.js), so the silk bends at its rim */
.hero__chip {
  --glass-tint: var(--glass-fill);
  --glass-lens-blur: 2px;
  --glass-refract: 0.9;
  --glass-bezel: 12px;
  padding-inline: var(--space-sm);
  color: var(--color-ink-2);
  font-size: var(--text-sm);
  transition:
    transform 520ms var(--ease-out),
    --glass-spec 240ms var(--ease-out),
    --gx 520ms var(--ease-out),
    --gy 520ms var(--ease-out);
}

.hero__chip::before {
  content: "";
  position: absolute;
  inset-inline-start: calc(50% - 7px);
  inset-block-end: 2px;
  inline-size: 14px;
  block-size: 2px;
  border-radius: 1px;
  background: var(--color-ink);
  transform: scaleX(0);
  transition: transform 420ms var(--ease-out); /* UI state: no overshoot (spring is for MOQI and key presses) */
}

.hero__chip.is-on {
  --glass-tint: var(--glass-fill-strong);
  color: var(--color-ink);
  transform: translateY(-3px);
}

.hero__chip.is-on::before {
  transform: none;
}

@media (min-width: 48rem) {
  .hero {
    padding-block: calc(80px + var(--space-2xl)) var(--space-3xl);
  }

  .hero__grid {
    grid-template-columns: minmax(0, 1.25fr) minmax(0, 0.85fr);
    gap: var(--space-xl);
  }

  .hero__stage {
    order: 0;
    justify-content: center;
  }

  .hero__moqi {
    --moqi-size: clamp(220px, 26vw, 360px);
  }
}

/* ---------- 3. The moment ---------- */

.moment__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  grid-template-areas: "copy" "stage" "cap";
  gap: var(--space-lg);
}

.moment__copy {
  grid-area: copy;
}

.moment__copy .sec-head {
  margin-bottom: var(--space-lg);
}

.moment__wrap {
  grid-area: stage;
  position: relative;
  inline-size: 100%;
  max-inline-size: 420px;
  justify-self: center;
}

.moment__caption {
  grid-area: cap;
  min-block-size: calc(3 * 1.6em);
  max-inline-size: 30em;
  color: var(--color-caption);
  font-size: var(--text-sm);
}

@media (min-width: 60rem) {
  .moment__grid {
    grid-template-columns: minmax(0, 1fr) minmax(0, 420px);
    grid-template-rows: 1fr auto auto 1.2fr;
    grid-template-areas: ". stage" "copy stage" "cap stage" ". stage";
    column-gap: clamp(var(--space-xl), 7vw, var(--space-3xl));
    row-gap: var(--space-md);
  }
}

/* 心動 · 工作: a real radio group; the glass lens thumb slides and magnifies the label under it */
.seg {
  position: relative;
  display: inline-grid;
  grid-template-columns: 1fr 1fr;
  min-inline-size: 0;
  margin: 0;
  padding: 4px;
  border: 0;
  isolation: isolate;
}

.seg__bg {
  --glass-radius: var(--radius-pill);
  --glass-tint: color-mix(in oklch, var(--color-paper) 55%, transparent);
  position: absolute;
  inset: 0;
  z-index: 0;
  border-radius: var(--radius-pill);
}

.seg__opt {
  position: relative;
  z-index: 1;
  display: grid;
  place-items: center;
  min-inline-size: 6.5rem;
  min-block-size: 48px;
  padding: 0 var(--space-md);
  border-radius: var(--radius-pill);
  cursor: pointer;
  font-size: var(--text-base);
  font-weight: 600;
  white-space: nowrap;
}

.seg__opt:is(:lang(zh), :lang(ja)) {
  letter-spacing: 0.08em;
}

.seg__input {
  position: absolute;
  inset: 0;
  margin: 0;
  border-radius: inherit;
  opacity: 0;
  cursor: pointer;
  appearance: none;
}

.seg__opt:has(.seg__input:focus-visible) {
  outline: 2px solid var(--color-focus);
  outline-offset: 2px;
}

.seg__label {
  position: relative;
  color: var(--color-ink-2);
}

.seg__opt:has(.seg__input:checked) .seg__label {
  color: var(--color-ink);
}

.seg__thumb {
  --glass-radius: var(--radius-pill);
  --glass-blur: 0px;
  --glass-lens-blur: 0px;
  --glass-tint: color-mix(in oklch, var(--color-paper) 12%, transparent);
  --glass-sheen: 0.16;
  --glass-magnify: 1.14;
  position: absolute;
  z-index: 2;
  inset-block: 4px;
  inset-inline-start: 4px;
  inline-size: calc(50% - 4px);
  border-radius: var(--radius-pill);
  pointer-events: none;
  transition:
    translate 600ms var(--ease-spring),
    --glass-spec 240ms var(--ease-out),
    --gx 520ms var(--ease-out),
    --gy 520ms var(--ease-out);
}

.seg[data-scene="work"] .seg__thumb {
  translate: 100% 0;
}

/* The chat thread: a white glass panel; the screen inside lifts when MOQI's panel grows */
.moment__replay {
  position: absolute;
  z-index: 3;
  inset-block-start: -20px;
  inset-inline-end: -8px;
}

.chat {
  --glass-radius: var(--radius-card);
  --glass-tint: color-mix(in oklch, var(--color-paper) 72%, transparent);
  display: flex;
  flex-direction: column;
  block-size: clamp(270px, 72vw, 312px);
  overflow: hidden;
  border-radius: var(--radius-card);
}

.chat__head {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--space-xs);
  min-block-size: 58px;
  padding: var(--space-2xs) var(--space-sm);
  border-bottom: 1px solid var(--glass-hairline);
}

.chat__av {
  display: grid;
  place-items: center;
  flex: none;
  inline-size: 34px;
  block-size: 34px;
  border-radius: 50%;
  background: var(--color-paper-3);
  color: var(--color-ink);
  font-size: var(--text-sm);
  font-weight: 600;
}

.chat__who {
  display: grid;
  min-inline-size: 0;
  line-height: 1.3;
}

.chat__name {
  font-size: var(--text-sm);
  font-weight: 600;
}

.chat__meta {
  overflow: hidden;
  color: var(--color-ink-2);
  font-size: var(--text-xs);
  white-space: nowrap;
  text-overflow: ellipsis;
}

/* The closeness heart sits on the avatar like a badge (the replay button floats over the far corner) */
.chat__heart {
  position: absolute;
  inset-block-start: 36px;
  inset-inline-start: 38px;
  display: grid;
  place-items: center;
  border-radius: 50%;
}

.chat__heart:not(:empty) {
  background: var(--color-paper);
  box-shadow: 0 0 0 2px var(--color-paper);
}

.chat__view {
  position: relative;
  flex: 1 1 auto;
  min-block-size: 0;
  overflow: hidden;
  -webkit-mask-image: linear-gradient(180deg, transparent, var(--color-ink) 22px);
  mask-image: linear-gradient(180deg, transparent, var(--color-ink) 22px);
}

.chat__screen {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  transition: transform 520ms var(--ease-in-out);
}

.chat__list {
  display: flex;
  flex-direction: column;
  gap: var(--space-2xs);
  padding: var(--space-xs) var(--space-xs) var(--space-2xs);
}

.chat__list > li {
  display: flex;
  flex-direction: column;
}

.chat__list > li > .fx-typing {
  align-self: flex-start;
  animation: bubble-in 380ms var(--ease-out) both;
  transform-origin: 0% 100%;
}

.chat__note {
  align-self: flex-end;
  max-inline-size: 84%;
  margin-top: var(--space-3xs);
  color: var(--color-ink-2);
  font-size: var(--text-xs);
  text-align: end;
}

.chat__note.is-new {
  animation: reveal-fade 500ms var(--ease-out) 200ms both;
}

.chat__input {
  display: flex;
  align-items: center;
  gap: var(--space-2xs);
  min-block-size: 44px;
  margin: 0 var(--space-xs) var(--space-xs);
  padding: var(--space-3xs) var(--space-3xs) var(--space-3xs) var(--space-sm);
  border-radius: 22px;
  background: var(--color-paper);
  box-shadow: inset 0 0 0 1px var(--color-rule);
}

.chat__field {
  flex: 1 1 auto;
  min-inline-size: 0;
  font-size: var(--text-sm);
  line-height: 1.4;
  overflow-wrap: anywhere;
}

.chat__send {
  display: grid;
  place-items: center;
  flex: none;
  inline-size: 32px;
  block-size: 32px;
  border-radius: 50%;
  background: var(--color-cyan);
  color: var(--color-on-brand);
  font-size: 0.9rem;
}

.chat__fx {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.chat__list,
.chat__input {
  position: relative;
  z-index: 1;
}

.moment__kb {
  margin-top: var(--space-3xs);
}

/* ---------- 4. Feature story ---------- */

.story__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-xl);
}

.story__steps {
  display: grid;
  gap: var(--space-2xl);
}

.story__step {
  scroll-margin-top: 112px;
}

/* One step per scroll (owner, 2026-10-02: a flick used to fly past several steps). site.js sets
   html.story-snap only while the middle of the screen is between the first and the last step; there the
   steps are mandatory snap points a fling cannot skip (snap-stop), and the story's heading above and the next
   section's heading below are the ways out. Everywhere else, and on narrow screens, the page scrolls freely.
   Native snapping only: nothing takes over the wheel. */
@media (min-width: 60rem) {
  html.story-snap {
    scroll-snap-type: y mandatory;
  }

  /* Centred on the screen, level with the sticky keyboard: the bottom margin cancels html's 96px
     scroll-padding-top, which would otherwise put the snap centre 48px low. */
  .story__step {
    scroll-snap-align: center;
    scroll-snap-stop: always;
    scroll-margin-block: 0 96px;
  }

  .story__head,
  .story + .section .sec-head {
    scroll-snap-align: start;
    scroll-margin-top: 24px;
  }
}

.story__title {
  font-size: var(--text-xl);
}

.story__body {
  max-width: 28em;
  margin-top: var(--space-xs);
  color: var(--color-ink-2);
}

.story__body:is(:lang(en), :lang(vi), :lang(th)) {
  max-width: 34em;
}

.story__mini {
  display: grid;
  gap: var(--space-2xs);
  max-inline-size: 420px;
  margin-top: var(--space-md);
}

.story__who {
  margin-inline-start: 4px;
  color: var(--color-ink-2);
  font-size: var(--text-xs);
}

.story__draft {
  min-block-size: 44px;
  padding: var(--space-xs) var(--space-sm);
  border-radius: 22px;
  background: var(--color-paper);
  box-shadow: inset 0 0 0 1px var(--color-rule);
  font-size: var(--text-sm);
}

.story__aside {
  display: none;
}

@media (min-width: 60rem) {
  .story__grid {
    grid-template-columns: minmax(0, 1fr) minmax(0, 420px);
    column-gap: clamp(72px, 8vw, 140px);
  }

  .story__steps {
    gap: 0;
    padding-block: 0 min(18vh, 180px);
  }

  .story__step {
    display: flex;
    flex-direction: column;
    justify-content: center;
    min-block-size: clamp(380px, 56vh, 560px);
  }

  .story__step .story__title {
    font-size: var(--text-2xl);
  }

  .story__step .story__body {
    font-size: var(--text-md);
  }

  .story__step .story__title {
    color: var(--color-ink-2);
  }

  .story__step .story__body {
    color: var(--color-caption);
  }

  .story__step .story__title,
  .story__step .story__body {
    transition: transform 520ms var(--ease-out);
  }

  .story__step.is-active .story__title,
  .story__step.is-active .story__body {
    color: var(--color-ink);
  }

  .story__step.is-active .story__body {
    color: var(--color-ink-2);
  }

  .story__step.is-active .story__title,
  .story__step.is-active .story__body {
    transform: translateX(10px);
  }

  .story__step.is-active .story__title {
    transition-delay: 40ms;
  }

  .story__step.is-active .story__body {
    transition-delay: 90ms;
  }

  .story__mini {
    display: none;
  }

  .story__aside {
    display: block;
    position: relative;
  }

  .story__sticky {
    position: sticky;
    top: max(92px, calc(50dvh - 320px));
  }
}

.story__demo {
  position: relative;
}

.story__screen {
  display: grid;
  gap: var(--space-xs);
  margin-bottom: var(--space-2xs);
  transition: transform 520ms var(--ease-in-out);
}

.story__context {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  gap: var(--space-2xs);
  block-size: 150px;
  padding-inline: 4px;
}

.story__context > * {
  animation: bubble-in 460ms var(--ease-out) both;
}

/* 自動切換對象: one conversation at a time, the person's name over their last message. A new one slides in
   from the right as the old one leaves to the left, the way you move between chats. */
.story__chat {
  display: grid;
  justify-items: start;
  gap: var(--space-2xs);
  animation: chat-in 340ms var(--ease-out) both;
}

@keyframes chat-in {
  from {
    opacity: 0;
    transform: translateX(28px);
  }
}

.story__chat-head {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2xs);
  color: var(--color-ink);
  font-size: var(--text-sm);
  font-weight: 600;
}

/* The app's Avatar: the first letter on MOQI's soft cyan → pink. */
.story__chat-av {
  display: grid;
  place-items: center;
  flex: none;
  inline-size: 28px;
  block-size: 28px;
  border-radius: 50%;
  background: var(--moqi-avatar);
  color: var(--color-cyan-ink);
  font-size: 13px;
  font-weight: 600;
  line-height: 1;
}

/* Narrow screens: the card, then the avatar and the toast under it. */
.story__switch {
  display: grid;
  align-content: end;
  min-block-size: 96px;
}

.story__switch-bar {
  display: flex;
  align-items: center;
  gap: var(--space-xs);
  min-block-size: 40px;
}

.story__switch-av {
  inline-size: 36px;
  block-size: 36px;
  font-size: 15px;
  box-shadow: 0 0 0 1px var(--color-rule);
}

.story__switch-av:empty {
  visibility: hidden;
}

.story__switch-toast {
  --glass-tint: oklch(100% 0 0 / .94);
  --glass-radius: 999px;
  padding: 6px 14px;
  border-radius: var(--radius-pill);
  color: var(--color-ink);
  font-size: var(--text-sm);
}

.story__switch-toast:empty {
  visibility: hidden;
}

.story__field {
  --glass-radius: 22px;
  min-block-size: 46px;
  padding: var(--space-xs) var(--space-sm);
  border-radius: 22px;
  background: var(--color-paper);
  box-shadow: inset 0 0 0 1px var(--color-rule), var(--shadow-soft);
  font-size: var(--text-sm);
  line-height: 1.4;
}

/* 鍵盤主題 (owner, 2026-10-02): a wall of keyboards in the app's themes, on a plane tilted back and turned so
   they face the reader from the upper left, rows drifting slowly to the top right. On wide screens it covers the
   screen (fixed) under everything in the section: it is a child of the section, which isolates it, with z-index
   -1. Not inside the sticky column: a sticky element is its own stacking context, so the wall would paint over
   the text. It fades in only while that step is on, and out towards the left edge of the window, where it is all
   but gone, so the text stays clear. */
.story {
  isolation: isolate;
}

@media (min-width: 60rem) {
  .story {
    overflow: clip; /* the wall never shows outside the section; clip keeps the sticky column working */
  }
}

.themes {
  position: fixed;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  pointer-events: none;
  opacity: 0;
  visibility: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent 0%, rgb(0 0 0 / .04) 12%, rgb(0 0 0 / .22) 34%, rgb(0 0 0 / .7) 52%, #000 66%);
  mask-image: linear-gradient(90deg, transparent 0%, rgb(0 0 0 / .04) 12%, rgb(0 0 0 / .22) 34%, rgb(0 0 0 / .7) 52%, #000 66%);
  transition: opacity 600ms var(--ease-out), visibility 0s linear 600ms;
}

.story.is-themes .themes {
  opacity: 1;
  visibility: visible;
  transition: opacity 900ms var(--ease-out);
}

.themes__plane {
  position: absolute;
  inset-block-start: 50%;
  inset-inline-start: 62%;
  inline-size: 3000px;
  block-size: 1900px;
  margin: -950px 0 0 -1150px;
  transform: perspective(1800px) rotateX(48deg) rotateZ(-32deg);
}

.themes__row {
  --half: calc(8 * (340px + 34px)); /* one run of themes: the loop's length */
  display: flex;
  gap: 34px;
  inline-size: max-content;
  margin-block-end: 34px;
  animation: themes-drift 90s linear infinite;
  animation-play-state: paused;
}

.themes__row:nth-child(2n) {
  margin-inline-start: -190px;
}

.story.is-themes .themes__row,
.themes--mini.is-on .themes__row {
  animation-play-state: running;
}

.themes__row img {
  flex: none;
  inline-size: 340px;
  block-size: auto;
  border-radius: 22px;
  box-shadow: 0 18px 40px -18px oklch(27.54% 0.0114 225.53 / .35);
}

@keyframes themes-drift {
  from { transform: translateX(calc(-1 * var(--half))); }
  to { transform: none; }
}

/* The keyboard steps aside while the wall is on. */
.story__demo {
  transition: opacity 500ms var(--ease-out), scale 600ms var(--ease-out);
}

.story.is-themes .story__demo {
  opacity: 0;
  scale: .97;
}

/* Narrow screens: the same wall, smaller, in the step's own box. */
.themes--mini {
  position: relative;
  inset: auto;
  z-index: 0;
  block-size: 240px;
  margin-block-start: var(--space-md);
  border-radius: var(--radius-card);
  opacity: 1;
  visibility: visible;
  -webkit-mask-image: none;
  mask-image: none;
}

.themes--mini .themes__plane {
  transform: perspective(1800px) rotateX(48deg) rotateZ(-32deg) scale(.42);
}

/* MOQI 的觀察 (owner, 2026-10-02): a person's page from the app (編輯對象 › 關於 {name}) as a floating glass
   panel: the header, the 親密度 card (the closeness heart, the score, its level word and the app's cyan → pink
   bar) and what MOQI has noticed, in the app's four groups of chips. On wide screens it takes the keyboard's
   place in the sticky column while that step is on. */
.person {
  --glass-radius: var(--radius-card);
  display: grid;
  gap: var(--space-sm);
  padding: var(--space-md) var(--space-md) var(--space-sm);
  border-radius: var(--radius-card);
  color: var(--color-ink);
}

@media (min-width: 60rem) {
  .story__sticky > .person {
    position: absolute;
    inset-block-start: 0;
    inset-inline: 0;
    opacity: 0;
    visibility: hidden;
    transform: translateY(18px);
    transition: opacity 400ms var(--ease-out), transform 500ms var(--ease-out), visibility 0s linear 400ms;
  }

  .story.is-person .story__sticky > .person {
    opacity: 1;
    visibility: visible;
    transform: none;
    transition: opacity 600ms var(--ease-out) 120ms, transform 700ms var(--ease-out) 120ms;
  }

  .story.is-person .story__demo {
    opacity: 0;
    scale: .97;
  }
}

.story__mini .person {
  margin-block-start: var(--space-md);
}

.person__head {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
}

/* The app's Avatar at page size: the first letter on MOQI's soft cyan → pink. */
.person__av {
  display: grid;
  place-items: center;
  flex: none;
  inline-size: 56px;
  block-size: 56px;
  border-radius: 50%;
  background: var(--moqi-avatar);
  color: var(--color-cyan-ink);
  font-size: 22px;
  font-weight: 600;
  line-height: 1;
}

.person__name {
  font-size: var(--text-md);
  font-weight: 600;
  line-height: 1.3;
}

.person__rel {
  color: var(--color-ink-2);
  font-size: var(--text-sm);
}

.person__close {
  padding: var(--space-xs) var(--space-sm) var(--space-sm);
  border-radius: 18px;
  background: var(--color-card);
  box-shadow: inset 0 0 0 1px var(--color-rule);
}

.person__label {
  color: var(--color-ink-2);
  font-size: var(--text-xs);
  font-weight: 600;
}

.person__meter {
  display: flex;
  align-items: center;
  gap: var(--space-2xs);
  margin-block-start: var(--space-3xs);
}

.person__heart {
  display: grid;
  place-items: center;
  inline-size: 34px;
  block-size: 34px;
}

.person__num {
  font-size: 30px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
}

.person__level {
  font-weight: 600;
}

.person__delta {
  margin-inline-start: auto;
  color: var(--color-muted);
  font-size: var(--text-xs);
  text-align: end;
}

/* The app's closeness bar: filled to the score, cyan to pink (an app effect, SPEC §5). */
.person__bar {
  block-size: 10px;
  margin-block-start: var(--space-2xs);
  overflow: hidden;
  border-radius: 5px;
  background: var(--color-paper-3);
}

.person__fill {
  display: block;
  block-size: 100%;
  border-radius: inherit;
  background: linear-gradient(90deg, var(--moqi-cyan), var(--moqi-pink));
  transform: scaleX(var(--v, 0));
  transform-origin: 0 50%;
  transition: transform 900ms var(--ease-out);
}

/* The page's two tabs, the current one on the app's cyan pill. */
.person__tabs {
  display: flex;
  gap: var(--space-3xs);
  padding: var(--space-3xs);
  border-radius: var(--radius-pill);
  background: var(--color-paper-3);
}

.person__tab {
  flex: 1 1 0;
  min-inline-size: 0;
  padding: 6px 10px;
  overflow: hidden;
  border-radius: var(--radius-pill);
  color: var(--color-ink-2);
  font-size: var(--text-sm);
  text-align: center;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.person__tab.is-on {
  background: var(--color-cyan);
  color: var(--color-on-brand);
  font-weight: 600;
}

.person__notes {
  display: grid;
  gap: var(--space-xs);
}

.person__gist {
  font-size: var(--text-base);
  line-height: 1.6;
}

.person__group-h {
  display: flex;
  align-items: center;
  gap: 6px;
  color: var(--color-ink-2);
  font-size: var(--text-xs);
  font-weight: 600;
}

.person__chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-block-start: 6px;
}

.person__chip {
  padding: 4px 11px;
  border-radius: var(--radius-pill);
  background: var(--color-card);
  box-shadow: inset 0 0 0 1px var(--color-rule);
  font-size: var(--text-sm);
  line-height: 1.5;
}

.person__status {
  color: var(--color-muted);
  font-size: var(--text-xs);
}

/* Short screens: the page has to fit beside the sticky column without its last lines dropping out of view. */
@media (min-width: 60rem) and (max-height: 880px) {
  .story__sticky > .person {
    gap: var(--space-xs);
    padding: var(--space-sm) var(--space-md) var(--space-xs);
  }

  .story__sticky > .person .person__av {
    inline-size: 46px;
    block-size: 46px;
    font-size: 19px;
  }

  .story__sticky > .person .person__num {
    font-size: 26px;
  }

  .story__sticky > .person .person__notes {
    gap: var(--space-2xs);
  }

  .story__sticky > .person .person__gist {
    font-size: var(--text-sm);
    line-height: 1.55;
  }

  .story__sticky > .person .person__chip {
    padding: 2px 10px;
    font-size: var(--text-xs);
  }

  .story__sticky > .person .person__chips {
    margin-block-start: 4px;
  }
}

/* Very short screens: the tabs (only context) give their room to what MOQI has noticed. */
@media (min-width: 60rem) and (max-height: 760px) {
  .story__sticky > .person .person__tabs {
    display: none;
  }
}

/* The vertical dot indicator: grey dots, and MOQI's eye (.story__thumb) on the current step */
.story__dots {
  position: absolute;
  inset-block-start: 50%;
  inset-inline-start: -56px;
  translate: 0 -50%;
}

.story__dots ol {
  display: grid;
}

/* The current step: MOQI's eye, with its gradient and glint, sliding from dot to dot (owner, 2026-10-02).
   site.js sets --at (the step) and plays the slide with a little stretch. */
.story__thumb {
  position: absolute;
  inset-block-start: 3px;    /* centred on the first dot: 15px down a 30px slot, minus half its height */
  inset-inline-start: 18.5px; /* centred in the 44px dot column */
  inline-size: 7px;
  block-size: 24px;
  border-radius: 3.5px;
  background:
    radial-gradient(circle at 50% 22%, rgb(255 255 255 / .95) 0 1.3px, rgb(255 255 255 / 0) 2.1px),
    var(--grad-moqi);
  transform: translateY(calc(var(--at, 0) * 30px));
  pointer-events: none;
}

.story__dot {
  position: relative;
  display: grid;
  place-items: center;
  inline-size: 44px;
  block-size: 30px;
}

.story__dot::before {
  content: "";
  inline-size: 6px;
  block-size: 6px;
  border-radius: 3px;
  background: color-mix(in oklch, var(--color-ink) 26%, transparent);
  transition: opacity 200ms var(--ease-out);
}

@media (hover: hover) {
  .story__dot:hover::before {
    background: var(--color-ink-2);
  }
}

.story__dot[aria-current="step"]::before {
  opacity: 0; /* the eye sits here */
}

/* ---------- Sliders (work, people) ---------- */

.slider {
  position: relative;
}

.slider__rail {
  /* the first card lines up with the .wrap content above it (heading, filters) */
  --rail-pad: max(var(--page-gutter), calc((100% - var(--page-max)) / 2));
  position: relative;
  display: flex;
  gap: var(--space-md);
  overflow-x: auto;
  overflow-y: hidden;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  scroll-padding-inline: var(--rail-pad);
  padding: var(--space-sm) var(--rail-pad) var(--space-xl);
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}

.slider__rail::-webkit-scrollbar {
  display: none;
}

.slider__rail:focus-visible {
  outline-offset: -4px;
  border-radius: var(--radius-card);
}

.slider__slide {
  flex: none;
  scroll-snap-align: start;
}

/* Cards in a rail are all as tall as the tallest, so the buttons below sit right under the card you
   see; the spare room stays inside the card (wide screens: above MOQI's answer, so answers line up) */
.slider__rail {
  align-items: stretch;
}

@media (hover: hover) and (pointer: fine) {
  .slider__rail {
    cursor: grab;
  }
}

.slider__rail.is-dragging {
  scroll-snap-type: none;
  cursor: grabbing;
  user-select: none;
  -webkit-user-select: none;
}

.slider__rail.is-dragging .slider__slide {
  pointer-events: none;
}

/* Round prev / next discs centred under the rail, clear of the cards (the rail's bottom padding holds
   the cards' shadow; the discs sit just below the cards, over the shadow's soft edge) */
.slider__controls {
  position: relative;
  z-index: 2;
  display: flex;
  justify-content: center;
  align-items: center;
  gap: var(--space-sm);
  margin-top: calc(var(--space-sm) - var(--space-xl));
}

.slider__btn {
  --glass-radius: 50%;
  --glass-tint: color-mix(in oklch, var(--color-paper) 50%, transparent);
  --glass-refract: 0.8;
  --glass-bezel: 16px;
  display: grid;
  place-items: center;
  inline-size: 52px;
  block-size: 52px;
  border-radius: 50%;
  color: var(--color-ink);
  font-size: 1.1rem;
}

.slider__btn:disabled {
  opacity: 0.38;
  cursor: default;
}

.slider__count {
  position: absolute;
  inline-size: 1px;
  block-size: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Slides come in from the side once, when the rail first shows */
.js .slider:not(.is-in) .slider__slide:nth-child(-n + 4) {
  opacity: 0;
}

.slider.is-in .slider__slide:nth-child(-n + 4) {
  animation: reveal-right 860ms var(--ease-out) backwards;
}

.slider.is-in .slider__slide:nth-child(2) { animation-delay: 90ms; }
.slider.is-in .slider__slide:nth-child(3) { animation-delay: 200ms; }
.slider.is-in .slider__slide:nth-child(4) { animation-delay: 270ms; }

/* ---------- 5. Work cards ---------- */

.work__head {
  margin-bottom: var(--space-md);
}

.wcard {
  inline-size: min(88%, 37rem);
}

.wcard__in {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--space-md);
  block-size: 100%;
  padding: var(--space-lg) var(--space-md);
  border-radius: var(--radius-card);
  background: var(--color-paper);
  box-shadow: var(--shadow-soft);
}

@media (min-width: 40rem) {
  .wcard__in {
    padding-inline: var(--space-lg);
  }
}

.wcard__chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2xs);
}

/* Glass lenses (glass.js): thin frost and fill, so the card's edge and shadow show and bend under them */
.wchip {
  --glass-radius: var(--radius-pill);
  --glass-tint: var(--glass-fill);
  --glass-lens-blur: 2px;
  --glass-refract: 0.9;
  --glass-bezel: 12px;
  font-size: var(--text-xs);
  font-weight: 500;
}

.wchip:empty {
  display: none;
}

.wchip .icon {
  color: var(--color-ink-2);
}

.wchip__stage::before {
  content: "・";
}

.wchip__who {
  white-space: nowrap;
}

.wchip__stage:is(:lang(en), :lang(vi), :lang(th), :lang(ko))::before {
  content: "·";
  margin-inline: 0.4em;
}

.wcard__situation {
  font-size: var(--text-md);
  font-weight: 500;
  line-height: 1.5;
}

.wcard__before {
  padding-inline-start: var(--space-sm);
  border-inline-start: 2px solid var(--color-rule);
  --color-caption: var(--color-ink-2);
}

.wcard__before-text {
  color: var(--color-ink-2);
}

.wcard__label {
  display: flex;
  align-items: center;
  gap: var(--space-2xs);
  margin-bottom: var(--space-3xs);
  color: var(--color-caption);
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.02em;
}

.wcard__after {
  padding-inline: 2px;
}

.wcard__after-text {
  font-size: var(--text-md);
  line-height: 1.6;
}

.wcard__gloss {
  margin-top: var(--space-2xs);
  color: var(--color-ink-2);
  font-size: var(--text-sm);
}

.wcard__gloss-label {
  font-weight: 600;
}

.wcard__gloss:has(.wcard__gloss-text:empty) {
  display: none;
}

/* Wide cards: the chips float on the card's top edge as glass pills, half over the card and half over the
   band, so the edge and its shadow bend through them */
@media (min-width: 48rem) {
  .slider--work .slider__rail {
    padding-top: var(--space-lg);
  }

  .wcard__chips {
    position: absolute;
    z-index: 2;
    inset-block-start: calc(-1 * var(--space-sm));
    inset-inline-end: var(--space-md);
    flex-wrap: nowrap;
    justify-content: flex-end;
  }

  .wcard__in {
    padding-top: var(--space-xl);
  }

  /* side by side, MOQI's answers line up along the bottom of the cards */
  .wcard__after {
    margin-top: auto;
  }
}

/* As a card becomes current its chips drift in, then keep drifting slowly (only that card's) */
.wcard.is-current .wchip {
  animation:
    chip-in 760ms var(--ease-out) backwards,
    chip-drift 5.6s var(--ease-in-out) 760ms infinite alternate;
}

.wcard.is-current .wchip:nth-child(2) {
  animation-delay: 110ms, 870ms;
  animation-duration: 760ms, 6.8s;
}

.wcard.is-current .wchip:nth-child(3) {
  animation-delay: 230ms, 990ms;
  animation-duration: 760ms, 6.1s;
}

@keyframes chip-in {
  from {
    opacity: 0.2;
    transform: translate(26px, 8px) scale(0.94);
  }
}

@keyframes chip-drift {
  from {
    translate: 0 0;
  }
  to {
    translate: -5px 4px;
  }
}

/* ---------- 6. People profiles ---------- */

.people__head {
  display: grid;
  gap: var(--space-md);
}

.people__head .sec-head {
  margin-bottom: 0;
}

.people__ask {
  display: grid;
  justify-items: start;
  gap: var(--space-2xs);
}

.people__ask-label {
  color: var(--color-caption);
  font-size: var(--text-xs);
  font-weight: 600;
}

.people__ask-bubble {
  max-inline-size: none;
  font-size: var(--text-md);
}

@media (min-width: 60rem) {
  .people__head {
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: end;
  }

  .people__ask {
    padding-bottom: var(--space-2xs);
  }
}

/* One row that never breaks; on a narrow phone it scrolls sideways out to the screen edge */
.filters {
  display: flex;
  gap: var(--space-2xs);
  margin-top: var(--space-md);
  margin-inline: calc(-1 * var(--page-gutter));
  padding: var(--space-2xs) var(--page-gutter);
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-padding-inline: var(--page-gutter);
  scrollbar-width: none;
}

.filters::-webkit-scrollbar {
  display: none;
}

.filter {
  flex: none;
  min-block-size: 44px;
  padding: 0 var(--space-xs);
  border-radius: var(--radius-pill);
  background: var(--color-paper);
  box-shadow: inset 0 0 0 1px var(--color-rule);
  color: var(--color-ink-2);
  font-size: var(--text-sm);
  font-weight: 500;
  white-space: nowrap;
  transition: transform var(--dur) var(--ease-out);
}

@media (hover: hover) {
  .filter:hover {
    background: var(--color-paper-2);
    color: var(--color-ink);
  }
}

@media (min-width: 40rem) {
  .filter {
    padding-inline: var(--space-sm);
  }
}

.filter:active {
  transform: scale(0.96);
  transition-duration: 90ms;
}

.filter[aria-pressed="true"] {
  background: var(--color-ink);
  box-shadow: none;
  color: var(--color-paper);
}

.slider--people .slider__rail {
  padding-top: var(--space-md);
}

.pcard {
  inline-size: min(82%, 21rem);
}

.pcard__in {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  block-size: 100%;
  padding: var(--space-md) var(--space-md) var(--space-lg);
  overflow: hidden;
  border-radius: var(--radius-card);
  background: var(--color-paper);
  box-shadow: inset 0 0 0 1px var(--color-rule), var(--shadow-soft);
}

.pcard__in > :not(.fx-hearts) {
  position: relative;
  z-index: 1;
}

.pcard__head {
  display: flex;
  align-items: center;
  gap: var(--space-xs);
  min-block-size: 32px;
}

.pcard__icon {
  font-size: 1.35rem;
}

.pcard__role {
  font-size: var(--text-lg);
}

.pcard__heart {
  display: grid;
  place-items: center;
  inline-size: 30px;
  block-size: 30px;
  margin-inline-start: auto;
  color: var(--color-muted);
  font-size: 1.15rem;
}

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

/* The beating heart (effects.js) takes the still one's place on the current card */
.pcard__heart.is-live > .icon {
  display: none;
}

.stages {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2xs);
}

.stage {
  padding: var(--space-3xs) var(--space-xs);
  border-radius: var(--radius-pill);
  box-shadow: inset 0 0 0 1px var(--color-rule);
  color: var(--color-ink-2);
  font-size: var(--text-xs);
  line-height: 1.4;
  white-space: nowrap;
}

.stage[aria-current="true"] {
  background: var(--color-ink);
  box-shadow: none;
  color: var(--color-paper);
  font-weight: 600;
}

.pcard__reply {
  position: relative;
  display: flex;
  flex-direction: column;
  margin-top: auto;
  padding-block: var(--space-2xs) var(--space-3xs);
}

/* Little hearts drift up behind the reply on the current love card (effects.js) */
.pcard__reply > .fx-hearts {
  inset: -8px -12px;
}

.pcard__reply > :not(.fx-hearts) {
  position: relative;
  z-index: 1;
}

.pcard__reply .bubble {
  max-inline-size: 92%;
  font-size: var(--text-base);
}

.pcard__label {
  display: block;
  margin-bottom: var(--space-2xs);
  color: var(--color-caption);
  font-size: var(--text-xs);
  font-weight: 600;
}

.pcard__why {
  color: var(--color-ink-2);
  font-size: var(--text-sm);
}

/* ---------- 7. Sounds like you ---------- */

.style__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-xl);
}

.style__head {
  margin-bottom: 0;
}

.style__note {
  max-width: 31em;
  padding-top: var(--space-sm);
  border-top: 1px solid var(--color-rule);
  color: var(--color-ink-2);
}

@media (min-width: 60rem) {
  .style__grid {
    grid-template-columns: minmax(0, 1fr) minmax(0, 30rem);
    column-gap: clamp(var(--space-xl), 7vw, var(--space-3xl));
    align-items: center;
  }
}

.style__panel {
  display: grid;
  gap: var(--space-md);
  padding: var(--space-lg) var(--space-md);
  border-radius: var(--radius-card);
  background: var(--color-paper);
  box-shadow: var(--shadow-soft);
}

@media (min-width: 40rem) {
  .style__panel {
    padding-inline: var(--space-lg);
  }
}

.style__habits {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2xs);
}

.style__habits .tag {
  transition: transform 420ms var(--ease-out);
}

.style__habits .tag::before {
  content: "\2713";
  display: inline-block;
  inline-size: 0;
  overflow: hidden;
  font-weight: 700;
  transform: scale(0);
  transition: transform 360ms var(--ease-out);
}

/* A habit MOQI just used: filled, with a tick */
.style__habits .tag.is-used {
  background: var(--color-paper-3);
  box-shadow: inset 0 0 0 1px color-mix(in oklch, var(--color-ink) 22%, transparent);
  color: var(--color-ink);
}

.style__habits .tag.is-used::before {
  inline-size: auto;
  transform: none;
}

.style__habits .tag.is-blip {
  animation: habit-blip 520ms var(--ease-out);
}

@keyframes habit-blip {
  40% {
    transform: translateY(-3px) scale(1.04);
  }
}

.js .style__habits .tag:not(.is-seen) {
  opacity: 0;
  transform: translateY(6px);
}

.style__habits .tag.is-seen {
  transition:
    opacity 420ms var(--ease-out),
    transform 420ms var(--ease-out);
}

.style__chat {
  display: flex;
  flex-direction: column;
}

.style__sugg {
  padding-top: var(--space-sm);
  border-top: 1px solid var(--color-rule);
  --color-caption: var(--color-ink-2);
}

.style__text {
  min-block-size: 3.3em;
  font-size: var(--text-md);
  line-height: 1.55;
}

.style__text .ch {
  display: inline-block;
  white-space: pre;
}

.style__text .ch.is-out {
  animation: char-out 260ms var(--ease-in) forwards;
}

@keyframes char-out {
  to {
    opacity: 0;
    transform: translateY(-6px);
  }
}

.style__actions {
  display: flex;
  justify-content: flex-start;
}

/* ---------- 8. Typing ---------- */

.typing__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-xl);
}

@media (min-width: 60rem) {
  .typing__grid {
    grid-template-columns: minmax(0, 1fr) minmax(0, 420px);
    column-gap: clamp(var(--space-xl), 7vw, var(--space-3xl));
    align-items: center;
  }
}

.typing__copy .sec-head {
  margin-bottom: var(--space-lg);
}

.typing__prompt {
  font-size: var(--text-2xl);
  line-height: 1.2;
}

.typing__prompt:lang(zh) {
  font-family: var(--font-display-zh);
}

.typing__prompt:lang(en) {
  font-family: var(--font-display-en);
  font-weight: 700;
}

.typing__prompt:lang(ja) {
  font-family: var(--font-display-ja);
  font-weight: 700;
}

.typing__prompt:lang(ko) {
  font-family: var(--font-display-ko);
}

.typing__prompt:lang(th) {
  font-family: var(--font-display-th);
  font-weight: 500;
}

.typing__prompt:lang(vi) {
  font-family: var(--font-display-vi);
  font-weight: 700;
}

.typing__hint {
  margin-top: var(--space-2xs);
  color: var(--color-caption);
  font-size: var(--text-sm);
}

/* A phone has no computer keyboard to press J, V, S on */
@media (hover: none) and (pointer: coarse) {
  .typing__hint {
    display: none;
  }
}

/* Under the keyboard, the result takes the try-hint's place instead of adding a row */
.typing__foot {
  position: relative;
  z-index: 1;
  display: grid;
  margin-top: var(--space-sm);
}

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

.typing__foot .typing__try-hint {
  margin-top: 0;
  transition: opacity var(--dur) var(--ease-out);
}

.typing__foot:has(.typing__result.is-on) .typing__try-hint {
  opacity: 0;
}

.typing__result {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2xs);
  min-block-size: 2em;
  font-weight: 600;
  text-align: center;
}

.typing__result .icon {
  flex: none;
}

.js .typing__result:not(.is-on) .icon {
  opacity: 0;
}

.typing__result.is-on {
  animation: reveal-up 600ms var(--ease-out) backwards;
}

.typing__methods {
  margin-top: var(--space-lg);
}

.typing__chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2xs);
}

.typing__voice {
  margin-top: var(--space-lg);
  padding-top: var(--space-md);
  border-top: 1px solid var(--color-rule);
  color: var(--color-ink-2);
}

.typing__voice-title {
  display: flex;
  align-items: center;
  gap: var(--space-2xs);
  margin-bottom: var(--space-3xs);
  font-size: var(--text-md);
}

.typing__voice-title .icon {
  transition: transform 420ms var(--ease-out);
}

.typing__voice.is-on .typing__voice-title .icon {
  transform: scale(1.25);
}

.typing__note {
  max-width: var(--measure-zh);
  margin-top: var(--space-md);
  color: var(--color-caption);
  font-size: var(--text-sm);
}

.typing__note:is(:lang(en), :lang(vi), :lang(th)) {
  max-width: var(--measure-en);
}

.typing__try {
  position: relative;
  isolation: isolate;
}

/* Big Zhuyin behind the keyboard, so its frosted glass has something to soften. Huninn on every page,
   English too: it is the Zhuyin glyphs' face here (Geist has none), a picture rather than text. */
.typing__ghost {
  position: absolute;
  inset-inline: 0;
  inset-block-start: 24%;
  z-index: 0;
  color: color-mix(in oklch, var(--color-ink) 9%, transparent);
  font-family: var(--font-zhuyin);
  font-size: clamp(5rem, 24vw, 8.5rem);
  line-height: 1;
  letter-spacing: 0.06em;
  text-align: center;
  white-space: nowrap;
  pointer-events: none;
  user-select: none;
}

.typing__bar {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  gap: var(--space-xs);
  margin-bottom: var(--space-xs);
}

.typing__moqi {
  --moqi-size: 52px;
  flex: none;
  inline-size: 52px;
  block-size: 52px;
}

.typing__field {
  flex: 1 1 auto;
  min-inline-size: 0;
  min-block-size: 54px;
  padding: var(--space-xs) var(--space-sm);
  border-radius: 20px;
  background: var(--color-paper);
  box-shadow: inset 0 0 0 1px var(--color-rule), var(--shadow-soft);
  font-size: var(--text-md);
  line-height: 1.4;
  overflow-wrap: anywhere;
}

.typing__kb {
  position: relative;
  z-index: 1;
}

.typing__try-hint {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2xs);
  margin-top: var(--space-sm);
  color: var(--color-caption);
  font-size: var(--text-sm);
}

/* ---------- 9. Privacy ---------- */

.privacy__head .sec-head {
  margin-bottom: var(--space-2xl);
}

.privacy__body {
  position: relative;
}

/* MOQI peeks over the top edge of the statements */
.privacy__peek {
  position: absolute;
  z-index: 0;
  inset-block-end: 100%;
  inset-inline-end: var(--space-lg);
  inline-size: 92px;
  block-size: 60px;
  /* Hide MOQI below the card edge only; its soft glow stays round on the other three sides */
  clip-path: inset(-40px -40px 0 -40px);
}

.privacy__moqi {
  --moqi-size: 84px;
  position: absolute;
  inset-inline-start: 4px;
  inset-block-start: 8px;
  inline-size: 84px;
  block-size: 84px;
  transform: translateY(100%);
}

.privacy__peek.is-in .privacy__moqi {
  transform: none;
  transition: transform 1100ms var(--ease-spring) 250ms;
}

.privacy__list {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-sm);
}

.privacy__item {
  padding: var(--space-md);
  border-radius: 22px;
  background: var(--color-paper);
  box-shadow: inset 0 0 0 1px var(--color-rule);
  color: var(--color-ink-2);
}

.privacy__title {
  display: flex;
  align-items: center;
  gap: var(--space-xs);
  margin-bottom: var(--space-2xs);
  font-size: var(--text-md);
}

.privacy__title .icon {
  flex: none;
  font-size: 1.1rem;
}

.privacy__item--lead p {
  font-size: var(--text-body);
}

/* the wide card keeps a reading measure too */
.privacy__item p {
  max-width: var(--measure-zh);
}

.privacy__item p:is(:lang(en), :lang(vi), :lang(th)) {
  max-width: var(--measure-en);
}

@media (min-width: 48rem) {
  .privacy__list {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .privacy__item--lead {
    grid-column: 1 / -1;
  }
}

@media (min-width: 64rem) {
  .privacy__list {
    grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr) minmax(0, 1fr);
  }

  .privacy__item--lead {
    grid-column: 1;
    grid-row: 1 / span 2;
    padding: var(--space-lg);
  }

  .privacy__item:last-child {
    grid-column: 2 / span 2;
  }
}

.privacy__foot {
  display: grid;
  gap: var(--space-xs);
  max-width: 40rem;
  margin-top: var(--space-lg);
}

.privacy__work {
  color: var(--color-ink-2);
}

/* ---------- 10. FAQ ---------- */

.faq__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-md);
}

@media (min-width: 60rem) {
  .faq__grid {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.9fr);
    column-gap: var(--space-2xl);
    align-items: start;
  }
}

.faq__item {
  border-top: 1px solid var(--color-rule);
}

.faq__item:last-child {
  border-bottom: 1px solid var(--color-rule);
}

.faq__q {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-sm);
  min-block-size: 64px;
  padding-block: var(--space-sm);
  cursor: pointer;
  list-style: none;
  font-size: var(--text-md);
  font-weight: 600;
  line-height: 1.4;
}

/* zh questions break after their own question marks, not mid-phrase */
.faq__q > span:is(:lang(zh), :lang(ko)) {
  min-width: 0;
  word-break: keep-all;
  overflow-wrap: anywhere;
}

.faq__q::-webkit-details-marker {
  display: none;
}

.faq__q .icon {
  flex: none;
  color: var(--color-ink-2);
  transition: transform 360ms var(--ease-out);
}

.faq__item[open] .faq__q .icon {
  transform: rotate(180deg);
}

@media (hover: hover) {
  .faq__q:hover .icon {
    color: var(--color-ink);
  }
}

.faq__a {
  max-width: 38em;
  padding-bottom: var(--space-md);
  color: var(--color-ink-2);
}

.faq__a a {
  color: var(--color-ink);
}

.faq__item[open] .faq__a {
  animation: faq-open 420ms var(--ease-out);
}

@keyframes faq-open {
  from {
    opacity: 0;
    transform: translateY(-6px);
  }
}

/* ---------- Join ---------- */

.final__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-lg);
}

@media (min-width: 60rem) {
  .final__grid {
    grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr);
    column-gap: var(--space-2xl);
    align-items: end;
  }
}

.final__title {
  max-width: 13em;
}

.final__body {
  max-width: 26em;
  color: var(--color-ink-2);
  font-size: var(--text-md);
}

.final__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-sm) var(--space-md);
  margin-top: var(--space-md);
}

.final__mail {
  color: var(--color-ink-2);
  font-size: var(--text-sm);
}

.final__mail a {
  color: var(--color-ink);
}
