/* Moment — base reset + tokens.
   Locked per Section 0.3: warm off-white, ink, single warm accent.
   Plex Sans Latin (1.45) + Plex Sans Thai Looped (1.7), JetBrains Mono.
*/

:root {
  --bg:        #FAFAF7;
  --bg-soft:   #F4F1EA;
  --ink:       #111111;
  --ink-2:     #2a2620;
  --ink-3:     #6b6557;
  --ink-4:     #736e60;
  --rule:      rgba(17, 17, 17, 0.08);
  --rule-2:    rgba(17, 17, 17, 0.14);
  --scrim:     rgba(250, 250, 247, 0.86);
  --scrim-dk:  rgba(17, 17, 17, 0.55);

  /* Accent options. Default = temple umber. */
  --accent-umber: oklch(0.58 0.10 55);    /* temple-interior umber */
  --accent-ochre: oklch(0.66 0.12 70);    /* Bangsaen late-afternoon */
  --accent-dusk:  oklch(0.50 0.07 245);   /* Chao Phraya dusk */
  --accent: var(--accent-umber);

  --serif: "IBM Plex Serif", Georgia, serif;
  --sans:  "IBM Plex Sans", "IBM Plex Sans Thai Looped", system-ui, sans-serif;
  --thai:  "IBM Plex Sans Thai Looped", "IBM Plex Sans", system-ui, sans-serif;
  --mono:  "JetBrains Mono", ui-monospace, monospace;
}

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
  font-family: var(--sans);
  background: #efece5;
  color: var(--ink);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* Latin defaults */
[lang="en"], .latin {
  font-family: var(--sans);
  line-height: 1.45;
  letter-spacing: 0;
}
/* Thai defaults — Section 0.3 lock */
[lang="th"], .thai {
  font-family: var(--thai);
  line-height: 1.7;
  letter-spacing: -0.005em;
}
.mono { font-family: var(--mono); letter-spacing: 0.01em; }

/* Strip tap highlight on the prototype */
button, a { -webkit-tap-highlight-color: transparent; }
button { font-family: inherit; }

/* Stage — center the device frame on a soft warm field */
.stage {
  min-height: 100vh;
  display: grid;
  place-items: center;
  padding: 24px;
  background:
    radial-gradient(ellipse at 30% 0%, #f6f2e8 0%, #efece5 60%) ,
    #efece5;
}

/* Hide native scrollbar inside the device */
.scrollarea {
  overflow-y: auto;
  scrollbar-width: none;
}
.scrollarea::-webkit-scrollbar { display: none; }

/* Reusable: monospace caption-on-photo */
.wash-caption {
  position: absolute;
  left: 14px; bottom: 12px;
  font-family: var(--mono);
  font-size: 9.5px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: rgba(255,255,255,0.78);
  text-shadow: 0 1px 2px rgba(0,0,0,0.35);
}

/* Hide native scrollbars app-wide — the mockup should never show a
   vertical scroll track. Scrolling still works (wheel / drag / touch). */
*::-webkit-scrollbar { width: 0 !important; height: 0 !important; background: transparent; }
* { scrollbar-width: none; }

@keyframes momentLivePulse {
  0%   { box-shadow: 0 0 0 0 rgba(196,74,58,0.55); }
  70%  { box-shadow: 0 0 0 6px rgba(196,74,58,0); }
  100% { box-shadow: 0 0 0 0 rgba(196,74,58,0); }
}
@keyframes momentTabFade {
  from { opacity: 0; transform: translateY(2px); }
  to   { opacity: 1; transform: translateY(0); }
}
.momentTabFade { animation: momentTabFade 200ms ease-out both; }

/* Trip day-page slide transitions. Direction-aware: a forward tap
   (later day) slides the new page in from the right; a backward tap
   slides from the left. Plays once on mount of the keyed wrapper. */
@keyframes momentDaySlideInRight {
  from { opacity: 0; transform: translateX(28px); }
  to   { opacity: 1; transform: translateX(0); }
}
@keyframes momentDaySlideInLeft {
  from { opacity: 0; transform: translateX(-28px); }
  to   { opacity: 1; transform: translateX(0); }
}
.momentDaySlideInRight { animation: momentDaySlideInRight 320ms cubic-bezier(.2,.7,.25,1) both; }
.momentDaySlideInLeft  { animation: momentDaySlideInLeft  320ms cubic-bezier(.2,.7,.25,1) both; }

/* Day-tab strip — hide the native scrollbar; the tabs row scrolls
   horizontally when there are more days than fit. */
.momentTripTabs::-webkit-scrollbar { display: none; }
@keyframes shimmer {
  0%   { background-position: -200% 0; }
  100% { background-position:  200% 0; }
}
.skeleton {
  background: linear-gradient(
    100deg,
    rgba(17,17,17,0.06) 0%,
    rgba(17,17,17,0.10) 50%,
    rgba(17,17,17,0.06) 100%
  );
  background-size: 200% 100%;
  animation: shimmer 1.6s ease-in-out infinite;
  border-radius: 2px;
}

/* ── Plan · Generating animations (§7.10) ─────────────────────────
   No spinner, no blob. A thin warm-umber line draws itself:
   stroke-dashoffset transitions per stage. The line then breathes
   very gently so the still moments between stage changes feel alive. */
@keyframes momentPathBreathe {
  0%, 100% { opacity: 0.85; }
  50%      { opacity: 1.00; }
}
.momentPathBreathe { animation: momentPathBreathe 3.6s ease-in-out infinite; }

/* ── Generating · progressive-narrative redesign ──────────────────
   Pulsing 3-dot indicator over a drifting hairline wave + a checklist
   that advances ✓ → ◐ → ○. Warm-amber accent, MUJI restraint. */
.genIndicator { display: flex; flex-direction: column; align-items: center; gap: 12px; }
.genDots { display: flex; gap: 9px; align-items: center; justify-content: center; }
.genDots span {
  width: 9px; height: 9px; border-radius: 50%;
  background: var(--accent); display: block;
  animation: genDotPulse 1.2s ease-in-out infinite;
}
.genDots span:nth-child(2) { animation-delay: 0.2s; }
.genDots span:nth-child(3) { animation-delay: 0.4s; }
@keyframes genDotPulse {
  0%, 100% { opacity: 0.22; transform: scale(0.78); }
  50%      { opacity: 1;    transform: scale(1); }
}
.genWave path { stroke-dasharray: 4 6; opacity: 0.32; animation: genWaveShift 1.6s linear infinite; }
@keyframes genWaveShift { from { stroke-dashoffset: 0; } to { stroke-dashoffset: -40; } }
.genActiveDot { animation: genActivePulse 1.1s ease-in-out infinite; }
@keyframes genActivePulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.4; } }
@keyframes genFadeIn { from { opacity: 0; transform: translateY(5px); } to { opacity: 1; transform: translateY(0); } }
.genFade { animation: genFadeIn 320ms ease-out both; }

/* ── Discover · featured card live cover ──────────────────────────
   No real video asset → the static wash gently "breathes" (ken-burns)
   only while the card sits in the viewport centre; frozen otherwise. */
.discoverCover > * { transition: transform 700ms ease; }
.discoverCoverLive > * {
  animation: discoverKenBurns 7s ease-in-out infinite alternate;
  transform-origin: center;
}
@keyframes discoverKenBurns {
  from { transform: scale(1); }
  to   { transform: scale(1.09); }
}

/* ── Plan Result · CardStack swap fade ──────────────────────────────
   Daily stops cycle through alternatives; the new card cross-fades
   in with a soft translate-up. Lives inline so it triggers on
   React key change. */
@keyframes momentCardSwap {
  from { opacity: 0; transform: translateY(4px); }
  to   { opacity: 1; transform: translateY(0); }
}
.momentCardSwap { animation: momentCardSwap 280ms ease-out both; }

/* Stop card "just changed by AI" treatment — applied to the card while
   the stop is changed AND unviewed. Persistent (not a one-shot) so it
   stays discoverable: accent-tinted border + slow breathing ring. As
   soon as the user scrolls the stop into ≥50% view, the parent
   removes the class via viewedStops, and the card returns to its
   default 0.5px hairline border. */
@keyframes momentCardChangedBreathe {
  0%, 100% { box-shadow: 0 0 0 0   rgba(154,108,74,0.30), 0 1px 0 rgba(17,17,17,0.04); }
  50%      { box-shadow: 0 0 0 5px rgba(154,108,74,0.22), 0 1px 0 rgba(17,17,17,0.04); }
}
.momentCardChanged {
  border-color: var(--accent) !important;
  border-width: 1px !important;
  animation: momentCardChangedBreathe 2.6s ease-in-out infinite;
}

/* One-shot pulse layered on top of the persistent treatment — fires
   when a freshly changed stop crosses into view, then fades. Same
   accent palette as the persistent ring, just bolder + briefer. */
@keyframes momentCardPulse {
  0%   { outline-color: rgba(154,108,74,0.62); outline-width: 0px; }
  18%  { outline-color: rgba(154,108,74,0.50); outline-width: 4px; }
  55%  { outline-color: rgba(154,108,74,0.18); outline-width: 9px; }
  100% { outline-color: rgba(154,108,74,0.00); outline-width: 14px; }
}
.momentCardPulse {
  outline-style: solid;
  outline-offset: 2px;
  animation: momentCardPulse 1800ms ease-out 1;
}

/* Card Stack carousel — horizontal scroll-snap rail. Each card is a
   snap target; the next card peeks ~32px from the right edge to
   signal swipeability. Hides the native scrollbar.                  */
.momentCardRail {
  display: flex;
  gap: 12px;
  overflow-x: auto;
  overflow-y: visible;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
  padding-right: 32px; /* peek room for the right-most card */
}
.momentCardRail::-webkit-scrollbar { display: none; }
.momentCardRailItem {
  flex: 0 0 calc(100% - 32px);
  scroll-snap-align: start;
  scroll-snap-stop: always;
}

/* Inline calibration toast — slides up + fades in just above the
   chip row. Self-dismisses after ~1.8s via JS. */
@keyframes momentToast {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: translateY(0); }
}
.momentToast { animation: momentToast 220ms ease-out both; }

/* Persistent change summary — slides up from below the chip row
   once a calibration is applied. Sits in the bottom-sticky stack
   between the scroll content and the chip row. */
@keyframes momentChangeSummary {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}
.momentChangeSummary { animation: momentChangeSummary 240ms ease-out both; }

/* Inline animated ellipsis — three baseline-tight dots that pulse
   in sequence. Lives inline-text so it sits right after the last
   word with no orphan-gap. */
.momentEllipsis {
  display: inline;
  margin-left: 0;
  color: var(--ink-3);
  letter-spacing: -0.08em;
  font-weight: 600;
}
.momentEllipsis > span {
  display: inline;
  opacity: 0.25;
  animation: momentEllipsisDot 1.4s ease-in-out infinite;
}
.momentEllipsis > span:nth-child(2) { animation-delay: 0.20s; }
.momentEllipsis > span:nth-child(3) { animation-delay: 0.40s; }
@keyframes momentEllipsisDot {
  0%, 100% { opacity: 0.25; }
  50%      { opacity: 1; }
}

/* ── Live Tracker — additive tokens + pulse for ACTIVE/COMPLETED states.
   Only used inside the Plan view when `tracker` tweak is non-default.
   Default Plan view does not reference these. */
:root {
  --warm: #F4EFE5;                    /* warmer than --bg-soft for Now-playing zone */
  --warn: oklch(0.62 0.14 60);        /* amber — running over / conflict / missed */
}
@keyframes trackerPulse {
  0%, 100% { transform: scale(1);    opacity: 1;    }
  50%      { transform: scale(0.78); opacity: 0.85; }
}
@keyframes trackerPulseHalo {
  0%   { transform: scale(1);   opacity: 0.55; }
  70%  { transform: scale(2.6); opacity: 0;    }
  100% { transform: scale(2.6); opacity: 0;    }
}
.trackerPulseDot {
  position: relative;
  animation: trackerPulse 1.6s ease-in-out infinite;
}
.trackerPulseDot::after {
  content: ""; position: absolute; inset: 0;
  border-radius: 999px; background: inherit;
  animation: trackerPulseHalo 1.6s ease-out infinite;
  z-index: -1;
}
@keyframes momentLiveDot {
  0%, 100% { opacity: 0.55; }
  50%      { opacity: 1;    }
}
