:root, html.light {
  --bg-color: #fafafa;
  --text-main: #111111;
  --text-strong: #222222;      /* slightly softer than main, for lede/body emphasis */
  --text-muted: #4b4b4b;
  --link-color: #0645ad;
  --border-color: #e5e5e5;
  --band-surface: #f4f4f5;      /* wide-band background + team-card surface */
  --cta-hover: #333333;         /* primary CTA hover */
  --font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  --font-serif: 'EB Garamond', Georgia, "Times New Roman", Times, serif;
  --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}

/* Dark theme: the SAME tokens swapped to dark values — this swap is the body of
   dark mode. The product-demo miniature keeps its own light --app-* palette (it
   is a faithful screenshot of the light app UI), so those are intentionally not
   remapped here. */
html.dark {
  /* Neutral greyscale ramp (no blue cast), matching the reference dark UI: near
     -black page, off-white headings, a calm mid-grey for muted/body text. */
  --bg-color: #0a0a0a;
  --text-main: #ededed;
  --text-strong: #cfcfcf;
  --text-muted: #9e9e9e;
  --link-color: #8ab4f8;
  --border-color: #262626;
  --band-surface: #161616;
  --cta-hover: #d0d0d0;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  padding: 0;
  background-color: var(--bg-color);
  color: var(--text-main);
  font-family: var(--font-sans);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  transition: background-color 0.3s ease, color 0.3s ease;
}

@media (prefers-reduced-motion: reduce) {
  body {
    transition: none;
  }
}

.container {
  max-width: 1000px;
  margin: 0 auto;
  padding: 24px 40px 0;
  width: 100%;
  display: flex;
  flex-direction: column;
}

/* Header */
header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  border-bottom: 1px solid var(--border-color);
  padding-bottom: 16px;
  margin-bottom: 48px;
}

.brand {
  display: flex;
  align-items: center;
  gap: 12px;
}

.brand-logo {
  max-height: 26px;
  width: auto;
  display: block;
}

/* The logo is a solid-black mark; in dark mode invert it to white. Single-color
   art inverts cleanly, so no separate dark asset is needed. */
html.dark .brand-logo {
  filter: invert(1) brightness(1.6);
}

/* Theme toggle: three segmented icon buttons (light / system / dark). The active
   one is filled; the group sits in a pill that tracks the theme tokens. */
.theme-toggle {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  padding: 3px;
  border: 1px solid var(--border-color);
  border-radius: 999px;
  background-color: color-mix(in srgb, var(--text-main) 4%, transparent);
}

.tt-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  padding: 0;
  border: 0;
  border-radius: 999px;
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
  transition: background-color 0.18s ease, color 0.18s ease;
}

.tt-btn:hover {
  color: var(--text-main);
  background-color: color-mix(in srgb, var(--text-main) 8%, transparent);
}

.tt-btn.is-on {
  color: var(--bg-color);
  background-color: var(--text-main);
}

/* Manifesto */
.manifesto {
  max-width: 800px;
}

.manifesto h1 {
  font-family: var(--font-serif);
  font-weight: normal;
  font-size: clamp(3.5rem, 6vw, 5rem);
  line-height: 1.1;
  margin: 0 0 28px 0;
  letter-spacing: -0.02em;
}

/* One-shot entrance: the headline keeps its line-by-line reveal; everything
   below it enters once as a support group, avoiding orphaned trust-bar labels. */
/* Headline enters word-by-word (one word per .h1-line) with a blur-stagger:
   each line unblurs and drops in from above, offset by ~0.285s. Support group
   below keeps its softer translate-up reveal. */
html.anim .h1-line {
  display: inline-block;
  opacity: 0;
  filter: blur(10px);
  transform: translateY(-50px);
}

html.anim .manifesto-body,
html.anim .cta-button,
html.anim .trust-bar {
  opacity: 0;
  transform: translateY(8px);
}

html.anim.fonts-in .h1-line {
  animation: blur-word-in 0.63s cubic-bezier(0, 0, 0.2, 1) forwards;
}

html.anim.fonts-in .manifesto-body,
html.anim.fonts-in .cta-button,
html.anim.fonts-in .trust-bar {
  animation: h1-line-in 1.2s cubic-bezier(0.22, 1, 0.36, 1) forwards;
}

html.anim.fonts-in .h1-line:nth-of-type(1) {
  animation-delay: 0.3s;
}

html.anim.fonts-in .h1-line:nth-of-type(2) {
  animation-delay: 0.585s;
}

html.anim.fonts-in .h1-line:nth-of-type(3) {
  animation-delay: 0.87s;
}

html.anim.fonts-in .manifesto-body {
  animation-delay: 1.15s;
}

html.anim.fonts-in .cta-button {
  animation-delay: 1.15s;
}

html.anim.fonts-in .trust-bar {
  animation-delay: 1.15s;
}

@keyframes blur-word-in {
  to {
    opacity: 1;
    filter: blur(0);
    transform: translateY(0);
  }
}

@keyframes h1-line-in {
  to {
    opacity: 1;
    transform: none;
  }
}

.manifesto-body {
  font-family: var(--font-serif);
  font-size: clamp(1.125rem, 2vw, 1.375rem);
  line-height: 1.6;
  color: var(--text-strong);
  margin: 0 0 40px;
}

.cta-button {
  /* Matches the live tarolabs.dev button exactly (239.68 x 60.79): symmetric
     16px/32px padding, and a 0.25em gap standing in for the single space between
     "Product" and the arrow on the live site (which has no arrow span). The arrow
     stays a span so the hover nudge still works. */
  display: inline-flex;
  align-items: center;
  gap: 0.25em;
  font-family: var(--font-sans);
  font-size: 1.125rem;
  font-weight: 600;
  color: var(--bg-color);
  background-color: var(--text-main);
  text-decoration: none;
  padding: 16px 32px;
  border-radius: 4px;
  transition: background-color 0.2s, transform 0.2s;
}

.cta-button:hover {
  background-color: var(--cta-hover);
  text-decoration: none;
  transform: translateY(-2px);
}

.cta-arrow {
  display: inline-block;
  transition: transform 0.2s;
}

.cta-button:hover .cta-arrow {
  transform: translateX(3px);
}

/* Full-width band: below the trust bar the section backgrounds and hairline
   dividers span the whole viewport, while content stays in a widened, centered
   column. A faintly deeper surface than the page above sets the band apart; the
   transition into it is animated (soft gradient + first-section reveal). */
/* Inner column matches the top .container exactly (same max-width and side
   padding), so the section content lines up with the header/manifesto above.
   Only the band's background + dividers break out to the full viewport width. */
.wide-band {
  position: relative;
  --wide-inner: 1000px;
  --wide-pad: 40px;
  background-color: var(--band-surface);
}

@media (min-width: 1200px) {
  .wide-band {
    --wide-inner: 1200px;
  }
}

/* Animated threshold: a soft gradient softens the top edge of the band so the
   shift from the narrow container into the full-width surface reads as a
   deliberate fade rather than a hard seam. */
.wide-band::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 120px;
  background: linear-gradient(to bottom, var(--bg-color), transparent);
  pointer-events: none;
}

/* Page sections: each section is the SAME centered box as the top .container
   (identical max-width + side padding), so its content shares one left edge
   with the header/manifesto above. Only the band's background spans the full
   viewport; the section box itself is centered exactly like the container. */
.page-section {
  max-width: var(--wide-inner, 1080px);
  margin: 60px auto 0;
  padding: 32px var(--wide-pad, 40px) 0;
  border-top: 1px solid var(--border-color);
}

/* Text blocks (label + lede) narrow their reading MEASURE to 800px — matching
   the top manifesto — while keeping the section's left edge. Right padding does
   the narrowing so the left edge never shifts. */
.page-section > .section-label,
.page-section > .section-lede {
  padding-right: calc(var(--wide-inner, 1080px) - 800px - 2 * var(--wide-pad, 40px));
}

@media (max-width: 840px) {
  .page-section > .section-label,
  .page-section > .section-lede {
    padding-right: 0;
  }
}

/* One-shot divider draw: under html.anim the static border is hidden and a
   hairline redraws left-to-right the first time the section enters the view
   (.sect-in, set by an IntersectionObserver). */
html.anim .page-section,
html.anim .trust-bar {
  position: relative;
  border-top-color: transparent;
}

html.anim .page-section::before,
html.anim .trust-bar::before {
  content: "";
  position: absolute;
  top: -1px;
  left: 0;
  width: 100%;
  height: 1px;
  background-color: var(--border-color);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.6s cubic-bezier(0.22, 1, 0.36, 1);
}

html.anim .sect-in::before {
  transform: scaleX(1);
}

/* The band's first section rises + fades as the page crosses the threshold
   into full-width, making the layout shift feel intentional rather than abrupt. */
html.anim .wide-band > .page-section:first-child {
  opacity: 0;
  transform: translateY(24px);
  transition: opacity 0.7s ease, transform 0.7s cubic-bezier(0.22, 1, 0.36, 1);
}

html.anim .wide-band > .page-section:first-child.sect-in {
  opacity: 1;
  transform: none;
}

.section-lede {
  font-family: var(--font-serif);
  font-size: clamp(1.125rem, 2vw, 1.25rem);
  line-height: 1.6;
  color: var(--text-strong);
  margin: 0 0 32px;
}

.section-lede a {
  color: inherit;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
}

/* Scroll-scrub bell curve: driven per-frame from JS via the --bell-* variables.
   Defaults are the peak (sharp) state, so no-JS and reduced-motion stay fully visible. */
.scroll-bell {
  opacity: var(--bell-op, 1);
  filter: blur(var(--bell-blur, 0px));
  transform: scale(var(--bell-scale, 1));
  will-change: transform, opacity, filter;
}

/* Arrival override for the demo: once it lands center-stage it lifts from the
   50% scrub ceiling to fully visible and stays there. */
.scroll-bell.bell-full {
  opacity: 1;
  transition: opacity 0.6s ease;
}

/* Key features: editorial rows — vignette beside copy, sides alternating
   per row so the section breathes instead of packing a 2x2 grid. The vignette
   takes the larger share; the copy is kept to a tighter measure; rows sit
   closer together for a more compact rhythm.
   The grid is narrower than the section header above it and centered on the
   page, so the vignette and copy don't drift too far apart. */
.feature-grid {
  display: flex;
  flex-direction: column;
  gap: 28px;
  max-width: 920px;
  margin-left: auto;
  margin-right: auto;
}

/* Vignette and copy are pushed to opposite ends of the fixed-width section, so
   the container edges read as a stable frame: on odd rows the vignette sits on
   the left and the copy hugs the right edge; row-reverse swaps that on evens. */
.feature {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 40px;
  padding: 22px 0;
  border-top: 1px solid var(--border-color);
}

.feature:first-child {
  border-top: 0;
}

.feature:nth-child(even) {
  flex-direction: row-reverse;
}

/* Copy grows to fill everything the fixed-width vignette leaves, so it hugs the
   section's left edge instead of floating mid-row with a gap beside it. With the
   vignette fixed at 380px in a 920px grid (minus the 40px gap), copy lands at
   ~500px — a ~57/43 copy-to-vignette split that holds identically on every row
   (row-reverse only mirrors the sides, not the ratio). */
.feature-copy {
  flex: 1 1 auto;
  min-width: 0;
  padding-top: 16px;
}

.feature h3 {
  font-family: var(--font-serif);
  font-size: 1.375rem;
  font-weight: 500;
  margin: 0 0 8px;
}

/* Restrained word-by-word blur-stagger for feature titles: the same language as
   the hero headline, dialed way down because it repeats on three rows — blur 6px
   (hero 10px), rise -16px (hero -50px), stagger 0.12s (hero 0.285s) so short 2-4
   word titles read as a calm ripple, not a hero-grade drop. JS splits each h3
   into .word spans; only the title animates — body copy stays put. Fired once per
   row via the .feat-in IntersectionObserver. */
html.anim .feature h3 .word {
  display: inline-block;
  white-space: pre;               /* preserve the trailing space per word so
                                     inline-block words don't collapse together */
  opacity: 0;
  filter: blur(6px);
  transform: translateY(-16px);
}

html.anim .feature.feat-in h3 .word {
  animation: feature-word-in 0.5s cubic-bezier(0, 0, 0.2, 1) forwards;
}

@keyframes feature-word-in {
  to {
    opacity: 1;
    filter: blur(0);
    transform: translateY(0);
  }
}

.feature p {
  font-size: 1rem;
  color: var(--text-muted);
  line-height: 1.6;
  margin: 0;
}

/* Mid widths: scale the vignette back so it doesn't crowd the copy before the
   row stacks; the two still sit at opposite ends. */
@media (max-width: 960px) {
  .feature {
    gap: 32px;
  }

  .feature-copy {
    flex-basis: 300px;
  }

  .feature-visual {
    flex-basis: 320px;
    zoom: 1;
  }
}

/* Stack point: vignette above copy, both left-aligned; the alternating sides
   collapse to a single consistent order and row gaps tighten. */
@media (max-width: 720px) {
  .feature-grid {
    gap: 0;
  }

  .feature,
  .feature:nth-child(even) {
    flex-direction: column-reverse;
    align-items: stretch;
    justify-content: flex-start;
    gap: 14px;
    padding: 24px 0;
  }

  .feature-copy {
    flex: none;
  }

  .feature-visual {
    flex: none;
    align-self: flex-start;
  }
}

/* Mobile: keep the vignette from overflowing and pull the section in tighter. */
@media (max-width: 600px) {
  .feature-grid {
    gap: 0;
  }

  .feature-visual {
    align-self: stretch;
    width: 100%;
    zoom: 1;
    height: auto;
    min-height: 0;
    padding: 12px 0 0;
  }

  .feature h3 {
    font-size: 1.25rem;
  }

  .fv-lang-row p,
  .fv-name {
    font-size: 14px;
  }

  .fv-table,
  .fv-code-line {
    font-size: 12px;
  }

  .fv-foot,
  .fv-daylabel,
  .fv-time {
    font-size: 12px;
  }
}

/* Feature vignettes: product-UI fragments, kept distinct from the copy column
   by scale and spacing rather than a white card shell. */
.feature-visual {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 10px;
  flex: 0 0 auto;
  width: min(100%, 380px);
  min-height: 168px;
  padding: 10px 12px;
  color: var(--app-text);
  font-family: 'Pretendard Variable', Pretendard, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Apple SD Gothic Neo', 'Noto Sans KR', sans-serif;
}

/* Dark: the vignette is an inline fragment with no card shell, so instead of a
   light surface it re-tones its --app-* palette to dark values. The UI chips,
   table borders, and text then read as a dark-app fragment that sits naturally on
   the dark page. (The full product-demo keeps its light screenshot look instead —
   it has a real surface for that.) */
/* Dark app-fragment palette, shared by the feature vignettes AND the pinned
   product demo (same colour logic for both, per the design). The CTA flips to a
   light pill (its foreground is --app-bg, so it inverts cleanly); the record
   button keeps its own red. */
html.dark .feature-visual,
html.dark .product-demo {
  --app-bg: #141416;
  --app-surface: #1c1c1e;
  --app-surface-muted: #262628;
  --app-border: #3a3a3d;
  --app-text: #ededed;
  --app-text-muted: #b0b0b0;
  --app-text-subtle: #8a8a8a;
  --app-error: #ff8a9b;
  --app-cta: #ededed;
  --app-cta-hover: #ffffff;
  --app-record-soft: #3a1e22;
}

/* Vignette: multilingual interpretation */
/* Language and formula/table vignettes read better with a little extra air
   between items (stacks with the container's 10px gap). */
.fv-lang-row,
.fv-table {
  margin-bottom: 6px;
}

.fv-lang-row {
  display: flex;
  align-items: flex-start;
  gap: 8px;
}

.fv-lang-row p {
  margin: 0;
  font-size: 13px;
  line-height: 1.5;
}

.fv-lang {
  flex: none;
  width: 26px;
  text-align: center;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.04em;
  color: var(--app-text-subtle);
  background-color: var(--app-surface-muted);
  border-radius: 4px;
  padding: 2px 0;
}

.fv-foot {
  font-size: 11px;
  font-weight: 600;
  color: var(--app-text-subtle);
}

/* Vignette: formulas, tables, code */
.fv-math {
  margin: 0 0 6px;
  font-family: var(--font-serif);
  font-style: italic;
  font-size: 15px;
  text-align: center;
}

.fv-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 11px;
  line-height: 1.4;
}

.fv-table th,
.fv-table td {
  padding: 4px 8px;
  border: 1px solid var(--app-border);
  text-align: left;
}

.fv-table th {
  background-color: var(--app-surface-muted);
  font-weight: 600;
}

.fv-code-line {
  margin: 0;
  font-size: 12px;
  text-align: center;
  white-space: nowrap;
}

/* Inline code, exactly as the nocose note renders it:
   rounded surface-muted chip, mono, 0.9em, error-rose text */
.fv-code {
  font-family: var(--font-mono);
  font-size: 0.9em;
  padding: 2px 6px;
  background-color: var(--app-surface-muted);
  border-radius: 4px;
  color: var(--app-error);
}

/* Vignette: calendar month view (mirrors the mockup calendar overlay's "월" tab in
   docs/web-mvp/mockup-v5_Startup/home.html — month grid + selected day's list) */
.fv-mgrid {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 3px;
  text-align: center;
}

.fv-mdow {
  font-size: 9px;
  font-weight: 600;
  color: var(--app-text-subtle);
  padding-bottom: 2px;
}

.fv-mday {
  height: 17px;
  font-size: 11px;
  font-weight: 500;
  line-height: 17px;
  border-radius: 6px;
  color: var(--app-text-muted);
}

.fv-evt {
  background-color: var(--app-surface-muted);
  color: var(--app-text);
}

.fv-mday.fv-today {
  background-color: var(--app-text);
  color: var(--app-bg);
  font-weight: 700;
}

.fv-mfoot {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-top: 2px;
  border-top: 1px solid var(--app-border);
  padding-top: 8px;
}

.fv-daylabel {
  margin: 2px 0 0;
  font-size: 11px;
  font-weight: 600;
  color: var(--app-text-subtle);
}

.fv-sched {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 12px;
  background-color: color-mix(in srgb, var(--app-surface) 55%, transparent);
  border: 1px solid var(--app-border);
  border-radius: 8px;
}

.fv-time {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 600;
  color: var(--app-text-subtle);
}

.fv-name {
  flex: 1;
  font-size: 13px;
  font-weight: 600;
}


.fv-mic-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background-color: var(--app-record);
  flex: none;
}

/* Vignette: call agent */
.fv-center {
  align-items: center;
  text-align: center;
  gap: 6px;
}

.fv-call-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background-color: var(--app-surface);
  border: 1px solid var(--app-border);
  color: var(--app-text-muted);
  margin-bottom: 2px;
}

.fv-call-title {
  margin: 0;
  font-size: 14px;
  font-weight: 700;
}

.fv-call-desc {
  margin: 0;
  font-size: 12px;
  color: var(--app-text-muted);
}

.fv-btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-top: 6px;
  padding: 9px 16px;
  font-size: 12px;
  font-weight: 600;
  /* Foreground tracks --app-bg so the pill flips cleanly: dark text on the light
     CTA in light mode, light text on the light CTA... — i.e. always the inverse
     of --app-cta, which is dark in light mode and light in dark mode. */
  color: var(--app-bg);
  background-color: var(--app-cta);
  border-radius: 8px;
}

/* Interactive product demo — faithful miniature of the nocose app.
   Colors/type mirror web/src/app/globals.css tokens; UI strings mirror the real screens. */

/* Scrub track: taller than the demo so there is scroll room to drive first the
   recording and then reading the finished note — all while the demo-wrap stays
   stuck to the viewport center. --scrub-room drives recording; --note-room lets
   the note viewer scroll internally before the demo finally releases. */
.demo-track {
  --demo-h: 700px;
  /* More scrub room = the recording (and its 6 transcript lines) plays out over
     more scroll, so it feels slower/fuller. More note room = the longer note has
     room to scroll all the way through before the demo releases. */
  /* scrub-room drives the recording; note-room is a short tail that keeps the
     demo pinned for a beat after recording finishes (so the note viewer settles
     on screen) before it releases. The note itself scrolls natively, so this no
     longer has to span the whole note. */
  --scrub-room: 140vh;
  --note-room: 90vh;
  height: calc(var(--demo-h) + var(--scrub-room) + var(--note-room));
}

.demo-wrap {
  position: sticky;
  top: calc(50vh - var(--demo-h) / 2);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
}

/* Reduced motion / no sticky support: fall back to a normal in-flow demo. */
@media (prefers-reduced-motion: reduce) {
  .demo-track {
    height: auto;
  }

  .demo-wrap {
    position: relative;
    top: 0;
  }
}

/* Margin memo beside the note viewer (wide screens only); top is set per-frame
   by JS so each card rides beside its anchor while scrolling. Cards alternate
   sides down the note via .memo-left / .memo-right. The demo is 640px wide, so
   each side sits 336px out from center (its own width taken off on the left). */
.note-memo {
  display: none;
  position: absolute;
  top: 0;
  width: 216px;
  padding: 14px 16px;
  background-color: var(--app-surface);
  border: 1px solid var(--app-border);
  border-radius: 8px;
  box-shadow: 0 8px 24px rgba(15, 23, 42, 0.08);
  font-family: 'Pretendard Variable', Pretendard, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Apple SD Gothic Neo', 'Noto Sans KR', sans-serif;
  color: var(--app-text);
  opacity: 0;
  transition: opacity 0.3s, transform 0.3s;
  pointer-events: none;
}

.memo-right {
  left: calc(50% + 336px);
  transform: translateX(8px);
}

.memo-left {
  left: calc(50% - 336px - 216px);
  transform: translateX(-8px);
}

.note-memo.show {
  opacity: 1;
  transform: none;
}

.memo-title {
  margin: 0 0 6px;
  font-size: 13px;
  font-weight: 700;
}

.memo-body {
  margin: 0;
  font-size: 12px;
  line-height: 1.6;
  color: var(--app-text-muted);
}

/* Memos need room to the right of the 640px demo without overflowing the
   band's inner column, so they only appear once the viewport is wide enough. */
@media (min-width: 1240px) {
  .note-memo {
    display: block;
  }
}

.product-demo,
.feature-visual,
.note-memo {
  --app-bg: #f8fafc;
  --app-surface: #ffffff;
  --app-surface-muted: #f1f5f9;
  --app-border: #e2e8f0;
  --app-text: #0f172a;
  --app-text-muted: #475569;
  --app-text-subtle: #64748b;
  --app-cta: #000000;
  --app-cta-hover: #1f1f1f;
  --app-record: #b91c1c;
  --app-record-hover: #991b1b;
  --app-record-soft: #fef2f2;
  --app-error: #e11d48;
  --app-success: #059669;
  --app-success-soft: #d1fae5;
}

.product-demo {
  position: relative;
  width: 100%;
  max-width: 680px;
  height: 700px;
  /* No card shell: the demo pins to the viewport center, so the screen itself is
     the frame — it sits directly on the page with no surface, border, or shadow.
     In dark mode it re-tones its --app-* palette to dark values (see the
     html.dark rule below), exactly like .feature-visual, so the app UI reads as a
     dark-app fragment on the dark page rather than a pasted-on light card. */
  color: var(--app-text);
  font-family: 'Pretendard Variable', Pretendard, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Apple SD Gothic Neo', 'Noto Sans KR', sans-serif;
  overflow: hidden;
  text-align: left;
  transition: filter 0.6s ease;
}


/* Waiting = scrolled-not-yet-into-view: keep the recording screen still */
.product-demo.waiting .rec-dot {
  animation-play-state: paused;
}

/* Dormant while approaching: same grayscale-at-rest language as the trust-bar
   logos. Removing .waiting at the center zone lets the 0.6s filter transition
   "switch the product on" — color returns with the settle + ping. */
.product-demo.waiting {
  filter: grayscale(1) opacity(0.5);
}

/* Arrival: as the demo enters the record zone (scroll scrub removes .waiting),
   the record dot emits a single sonar ping — the "recording starts now" signal,
   using only the page's existing record-red accent. The demo's own transform is
   owned by the scroll-bell scrub, so no transform animation is used here. */
.product-demo.arrived .rec-dot {
  animation: demo-pulse 1.2s ease-in-out infinite, demo-ping 0.9s ease-out 1;
}

@keyframes demo-ping {
  from { box-shadow: 0 0 0 0 rgba(185, 28, 28, 0.3); }
  to { box-shadow: 0 0 0 14px rgba(185, 28, 28, 0); }
}

/* Both screens are stacked and cross-faded via opacity so the recording->note
   handoff is a smooth dissolve rather than an instant swap. The inactive screen
   is faded out and non-interactive; the active one fades in. */
.app-screen {
  position: absolute;
  inset: 0;
  height: 100%;
  display: flex;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 0.5s ease, visibility 0s linear 0.5s;
}

.product-demo[data-state="recording"] .screen-recording,
.product-demo[data-state="done"] .screen-done {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transition: opacity 0.5s ease;
}

@media (prefers-reduced-motion: reduce) {
  .app-screen {
    transition: none;
  }
}

/* Screen: active recording */
.screen-recording {
  flex-direction: column;
}

.rec-top {
  display: flex;
  justify-content: center;
  padding: 28px 20px 0;
}

.rec-badge {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 12px;
  font-size: 13px;
  font-weight: 600;
  background-color: var(--app-surface-muted);
  border-radius: 8px;
}

.rec-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background-color: var(--app-record);
  flex: none;
  animation: demo-pulse 1.2s ease-in-out infinite;
}

.rec-center {
  flex: 1;
  min-height: 0;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.rec-wave {
  position: relative;
  height: 120px;
  margin: 0 0 24px;
}

.rec-wave::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 0;
  bottom: 0;
  width: 2px;
  background: linear-gradient(to bottom, transparent, #dc2626, transparent);
}

.rec-wave canvas {
  display: block;
  width: 100%;
  height: 100%;
}

.rec-timer {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 44px;
  line-height: 1;
  font-weight: 600;
  text-align: center;
}

/* Live transcript: same segment styling as the full-script tab. The list is
   taller than its window; as new lines appear beyond the fold, JS scrolls the
   inner box so the latest line stays visible (auto-follow, like a real feed). */
.rec-live {
  margin-top: 24px;
  padding: 0 64px;
}

.rec-live-label {
  display: block;
  margin-bottom: 12px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.08em;
  color: var(--app-text-subtle);
}

.rec-live-scroll {
  height: 232px;
  overflow: hidden;
  /* Fade only the TOP edge, where older lines scroll up and out — the bottom
     stays crisp so the newest line reads clearly. A small 8px fade keeps the
     first line (pinned at the very top before overflow) mostly sharp. */
  -webkit-mask-image: linear-gradient(to bottom, transparent, #000 8px);
  mask-image: linear-gradient(to bottom, transparent, #000 8px);
}

.rec-live .app-seg {
  margin-bottom: 16px;
}

/* Not-yet-spoken lines take NO layout space (display:none), so the transcript
   box grows one line at a time. That keeps scrollHeight honest, so the newest
   line lands correctly at the bottom once the list overflows its window.
   The line fades + rises in as it appears: display is animated with
   allow-discrete + @starting-style so the fade actually plays on the
   none->block switch (a plain opacity transition would be skipped). */
.live-seg {
  display: none;
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 0.45s ease, transform 0.45s cubic-bezier(0.22, 1, 0.36, 1),
              display 0.45s allow-discrete;
}

.live-seg.show {
  display: block;
  opacity: 1;
  transform: none;
}

@starting-style {
  .live-seg.show {
    opacity: 0;
    transform: translateY(8px);
  }
}

.live-seg.past p {
  color: var(--app-text-subtle);
  transition: color 0.4s;
}

.rec-controls {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 24px;
  padding: 8px 0 28px;
}

.rec-pause,
.rec-stop {
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  border-radius: 50%;
  cursor: pointer;
}

.rec-pause {
  width: 64px;
  height: 64px;
  background-color: var(--app-surface-muted);
  color: var(--app-text);
  transition: background-color 0.2s, color 0.2s;
}

.rec-stop {
  position: relative;
  width: 80px;
  height: 80px;
  background-color: var(--app-record);
  color: #fff;
  box-shadow: 0 8px 20px rgba(185, 28, 28, 0.35);
  transition: background-color 0.2s;
}

.rec-stop:hover {
  background-color: var(--app-record-hover);
}

/* Pulse ring emitted from the stop button at the moment recording completes,
   just before the screen cross-fades to the note. Record-red, plays once. */
.rec-stop::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  pointer-events: none;
  opacity: 0;
}

.product-demo.stop-ring .rec-stop::after {
  animation: stop-ring 0.7s ease-out 1;
}

@keyframes stop-ring {
  from {
    opacity: 0.5;
    box-shadow: 0 0 0 0 rgba(185, 28, 28, 0.5);
  }
  to {
    opacity: 0;
    box-shadow: 0 0 0 28px rgba(185, 28, 28, 0);
  }
}

@media (prefers-reduced-motion: reduce) {
  .product-demo.stop-ring .rec-stop::after {
    animation: none;
  }
}

.icon-play {
  display: none;
}

.product-demo.paused .rec-pause {
  background-color: var(--app-text);
  color: var(--app-bg);
}

.product-demo.paused .icon-pause {
  display: none;
}

.product-demo.paused .icon-play {
  display: block;
}

.product-demo.paused .rec-dot {
  animation-play-state: paused;
}

/* Screen: session detail (note viewer) */
.screen-done {
  flex-direction: column;
  position: relative;
}

.app-header {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 16px 16px 10px;
}

.app-back {
  display: flex;
  color: var(--app-text);
}

.app-title {
  display: block;
  font-size: 17px;
  font-weight: 700;
  line-height: 1.3;
}

.app-meta {
  display: block;
  margin-top: 2px;
  font-size: 12px;
  color: var(--app-text-subtle);
}

.app-tabs {
  position: relative;
  display: flex;
  gap: 20px;
  padding: 0 16px;
  border-bottom: 1px solid var(--app-border);
}

.app-tab {
  font: inherit;
  font-size: 14px;
  font-weight: 600;
  color: var(--app-text-muted);
  background: none;
  border: none;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  padding: 8px 2px 10px;
  cursor: pointer;
}

.app-tab.active {
  color: var(--app-text);
}

/* Sliding active-tab underline (positioned by JS), replacing per-tab borders */
.tab-ink {
  position: absolute;
  bottom: -1px;
  height: 2px;
  background-color: var(--app-text);
  transition: left 0.25s cubic-bezier(0.32, 0.72, 0, 1), width 0.25s cubic-bezier(0.32, 0.72, 0, 1);
}

/* The note scrolls natively with the mouse/touch. It is NOT driven by page
   scroll — that earlier approach made the JS-set scrollTop fight the user's own
   scrolling and re-jump the note. No overscroll-behavior:contain here: once the
   note reaches its end, the wheel must chain to the page so the sticky demo can
   release and the next section can follow. */
.app-scroll {
  flex: 1;
  overflow-y: auto;
  padding: 20px 16px 32px;
  scrollbar-width: none;
}

/* When the scroll-scrub is live (html.anim), the note is driven entirely by page
   scroll (travelled) — see applyScrub's done branch. The box must NOT scroll
   natively here: if the wheel landed on the note it would move the note's own
   overflow instead of the page, freezing travelled while the note scrolled, and
   the next scrub frame would then snap the note back to the top ("restart to note
   start"). Disabling native scroll routes every wheel/touch to the page so there
   is a single scroll authority. No-JS / reduced-motion keeps overflow:auto above
   so the note stays readable without the scrub. */
html.anim .app-scroll {
  overflow-y: hidden;
  overscroll-behavior: contain;
  touch-action: none;
}

.app-scroll::-webkit-scrollbar {
  display: none;
}

.app-panel {
  display: none;
}

.app-panel.active {
  display: block;
}

/* Note markdown (mirrors the app's document styles) */
.note-md {
  font-size: 15px;
  line-height: 1.65;
}

.note-md h4 {
  margin: 0 0 12px;
  font-size: 22px;
  line-height: 1.3;
  font-weight: 700;
}

.note-md h5 {
  margin: 24px 0 10px;
  font-size: 18px;
  line-height: 1.3;
  font-weight: 700;
}

.note-md h6 {
  margin: 18px 0 8px;
  font-size: 15px;
  font-weight: 700;
}

.note-md p {
  margin: 0 0 12px;
}

.note-tldr {
  margin: 0 0 14px;
  padding-left: 14px;
  border-left: 3px solid var(--app-text);
  color: var(--app-text-muted);
  font-size: 14px;
  line-height: 1.6;
}

.note-md ul {
  margin: 0 0 12px;
  padding-left: 20px;
}

.note-md li {
  margin-bottom: 4px;
}

.note-md hr {
  margin: 20px 0;
  border: none;
  border-top: 1px solid var(--app-border);
}

.note-callout {
  margin: 0 0 14px;
  padding: 12px 14px;
  font-size: 14px;
  line-height: 1.6;
  background-color: var(--app-surface-muted);
  border-radius: 8px;
}

@media (max-width: 600px) {
  .note-md [data-memo]::after {
    content: attr(data-memo-title) ": " attr(data-memo);
    display: block;
    margin-top: 8px;
    padding: 10px 12px;
    font-size: 12px;
    line-height: 1.55;
    font-weight: 500;
    color: var(--app-text-muted);
    background-color: var(--app-surface-muted);
    border-radius: 8px;
  }
}

.note-md table {
  width: 100%;
  margin: 0 0 14px;
  border-collapse: collapse;
  font-size: 13px;
  line-height: 1.5;
}

.note-md th,
.note-md td {
  padding: 6px 8px;
  border: 1px solid var(--app-border);
  text-align: left;
  vertical-align: top;
}

.note-md th {
  background-color: var(--app-surface-muted);
  font-weight: 600;
}

.note-md details {
  margin: 0 0 8px;
  padding: 10px 14px;
  font-size: 14px;
  border: 1px solid var(--app-border);
  border-radius: 8px;
}

.note-md summary {
  font-weight: 600;
  cursor: pointer;
}

.note-md details p {
  margin: 8px 0 0;
  color: var(--app-text-muted);
}

/* Transcript segments */
.app-seg {
  margin-bottom: 24px;
}

.app-seg time {
  display: block;
  margin-bottom: 4px;
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 600;
  color: var(--app-text-subtle);
}

.app-seg p {
  margin: 0;
  font-size: 15px;
  line-height: 1.65;
}

@keyframes demo-pulse {
  50% { opacity: 0.35; }
}

@media (prefers-reduced-motion: reduce) {
  .rec-dot {
    animation: none;
  }

  .product-demo {
    transition: none;
  }

  .live-seg {
    transition: none;
  }

  .tab-ink {
    transition: none;
  }
}

.team-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 20px;
}

/* Restrained 3D: a sheet of paper lifted just off the page. Depth comes from
   the surface being a touch brighter than the #fafafa band plus a two-layer
   low-angle shadow (tight contact + soft ambient) and a 1px top highlight —
   not from heavy blur or large radii. Hover nudges the lift by 2px. */
.team-card {
  min-width: 0;
  padding: 26px 28px;
  /* Same tone as the #f4f4f5 band — no brighter fill to "pop" against it. The
     3D read comes entirely from the soft bottom shadow, so the card looks lifted
     a hair off the page with no top highlight edge to catch the eye. */
  background-color: var(--band-surface);
  border-radius: 10px;
  box-shadow:
    0 1px 1px rgba(15, 23, 42, 0.04),
    0 6px 14px rgba(15, 23, 42, 0.045);
  transition: transform 0.25s cubic-bezier(0.22, 1, 0.36, 1),
    box-shadow 0.25s cubic-bezier(0.22, 1, 0.36, 1);
}

.team-card:hover {
  transform: translateY(-2px);
  box-shadow:
    0 2px 3px rgba(15, 23, 42, 0.05),
    0 12px 24px rgba(15, 23, 42, 0.07);
}

/* Dark: the light-navy shadow vanishes on a near-black band, so lift is carried
   by a deeper black shadow plus a faint 1px inner top border catching the light,
   and the surface sits a touch above the band instead of matching it exactly. */
html.dark .team-card {
  background-color: color-mix(in srgb, var(--band-surface) 100%, #ffffff 4%);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.04),
    0 1px 2px rgba(0, 0, 0, 0.4),
    0 8px 20px rgba(0, 0, 0, 0.35);
}

html.dark .team-card:hover {
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.06),
    0 2px 4px rgba(0, 0, 0, 0.45),
    0 14px 30px rgba(0, 0, 0, 0.45);
}

.member-name {
  font-family: var(--font-serif);
  font-size: 1.375rem;
  font-weight: 500;
  margin: 0;
}

.member-role {
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--text-muted);
  margin: 4px 0 8px;
}

.member-bio {
  font-size: 0.9375rem;
  color: var(--text-muted);
  margin: 0;
  font-weight: 500;
}

@media (max-width: 720px) {
  .team-grid {
    grid-template-columns: 1fr;
  }

  .team-card {
    padding: 24px 24px;
  }
}

/* Trust bar */
.trust-bar {
  margin-top: 60px;
  padding-top: 32px;
  border-top: 1px solid var(--border-color);
  display: flex;
  flex-wrap: wrap;
  gap: 48px;
}

.trust-group {
  flex: 1;
  min-width: 300px;
}

.trust-group h2,
.section-label {
  font-family: var(--font-sans);
  font-size: 0.875rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--text-muted);
  margin: 0 0 24px 0;
  font-weight: 700;
}

.logo-grid {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 24px 40px;
}

.logo-grid img {
  max-height: 44px;
  width: auto;
  object-fit: contain;
  filter: grayscale(100%) opacity(0.7);
  transition: filter 0.3s ease;
  display: block;
}

.logo-grid img:hover {
  filter: grayscale(0%) opacity(1);
}

/* Dark: show every logo in its original colours by default (no greyscale, no
   chip, no silhouette). This is DIFFERENT from light mode, which desaturates at
   rest and only reveals colour on hover — in dark the full-colour marks read
   best against the near-black page, so there is nothing extra to do on hover. */
html.dark .logo-grid img {
  filter: none;
}

html.dark .logo-grid img:hover {
  filter: none;
}

/* Footer — sits inside the band, sharing its surface (no separate background).
   Its inner width and side padding match the section columns so it lines up. */
footer {
  margin-top: 60px;
  padding: 24px var(--wide-pad, 40px) 32px;
  font-size: 0.875rem;
  color: var(--text-muted);
  max-width: var(--wide-inner, 1080px);
  width: 100%;
  margin-left: auto;
  margin-right: auto;
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: 16px;
}

footer a {
  color: var(--text-muted);
  text-decoration: underline;
  transition: color 0.2s;
}

footer a:hover {
  color: var(--text-main);
}

.footer-team-info {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 12px;
}

.footer-grant {
  display: block;
  width: 180px;
  max-width: 100%;
}

.footer-grant img {
  display: block;
  width: 100%;
  height: auto;
}

.footer-grant .footer-grant-dark,
html.dark .footer-grant-light {
  display: none;
}

html.dark .footer-grant .footer-grant-dark {
  display: block;
}

/* Use wider screens for the supporting trust content without widening the copy. */
@media (min-width: 1200px) {
  .container,
  footer {
    max-width: 1200px;
  }

  .logo-grid img {
    max-height: 56px;
  }
}

/* Match the top .container's side padding (40px, 24px on mobile) so section
   content and the header/manifesto share the same left edge at every width. */
@media (max-width: 600px) {
  .wide-band {
    --wide-pad: 24px;
  }
}

/* Mobile adjustments */
@media (max-width: 600px) {
  .container {
    padding: 20px 24px 0;
  }

  .trust-group {
    flex: 0 0 100%;
    min-width: 0;
    width: 100%;
  }

  .logo-grid img {
    max-width: 100%;
  }

  .cta-button {
    font-size: 1rem;
    padding: 12px 24px;
  }

  .product-demo {
    height: 680px;
  }

  /* Keep --demo-h in sync with the shorter demo so the sticky pin point and the
     scrub math (which both read --demo-h) stay correct on small screens. */
  .demo-track {
    --demo-h: 680px;
    --scrub-room: 120vh;
    --note-room: 70vh;
  }

  .rec-wave {
    height: 90px;
  }

  .rec-live {
    padding: 0 24px;
  }

  footer {
    padding: 16px 24px 24px;
  }
}
