/* =====================================================================
   styles-alive.css — Focus Immersion "alive" layer
   ---------------------------------------------------------------------
   Subtle motion, refined hovers, a soft living background, and the
   ambience/sound preference toggle. Loads AFTER styles.css.

   Design rule: elegant and warm, not animated. Two lenses —
     · a Harvard EAS professor: nothing gimmicky, motion is intentional
       and calm, never demands attention.
     · a 22-year-old in Seoul: never dusty or dead; a little warmth,
       a little modern polish, things respond when touched.

   Constraints honored:
     · GPU-friendly only — opacity / transform. No width/height/top/left
       transitions that reflow. No layout shift.
     · Nothing autoplays loudly; the living background is opt-in via the
       body[data-ambience="on"] flag set by alive.js (off by default).
     · prefers-reduced-motion disables ALL of it (block at the bottom).
   ===================================================================== */

/* ----- shared easing tokens (kept local so styles.css stays untouched) */
:root {
  --ease-calm: cubic-bezier(0.2, 0.7, 0.2, 1);
  --ease-soft: cubic-bezier(0.16, 0.8, 0.24, 1);
}

/* =====================================================================
   1 · SCROLL REVEAL
   Elements tagged with [data-reveal] by alive.js start slightly lowered
   and faded, then settle as they enter the viewport. Translation is tiny
   (0.7rem) so it reads as a settle, not a slide — and so it never shifts
   layout for content already on screen (those are revealed immediately).
   ===================================================================== */
[data-reveal] {
  opacity: 0;
  transform: translate3d(0, 0.7rem, 0);
  transition:
    opacity 0.9s var(--ease-calm),
    transform 0.9s var(--ease-calm);
  will-change: opacity, transform;
}
[data-reveal].is-revealed {
  opacity: 1;
  transform: translate3d(0, 0, 0);
}
/* Stagger children within a revealed group (set via --d on the element). */
[data-reveal] { transition-delay: var(--d, 0s); }

/* Once settled, drop will-change so we don't pin a compositor layer. */
[data-reveal].is-settled { will-change: auto; }

/* =====================================================================
   2 · A SOFT LIVING BACKGROUND  (opt-in: body[data-ambience="on"])
   Two extremely slow, low-amplitude motions:
     · the warm lamp-glow "breathes" (opacity + a few px of drift)
     · the base gradient hue drifts a hair, like a lamp warming a room
   Periods are 18–26s so nothing ever pulses. Off entirely by default.
   ===================================================================== */
body[data-ambience="on"] .warmth {
  animation: fi-breathe 22s var(--ease-calm) infinite;
}
body[data-ambience="on"] .halo {
  /* gentle secondary breath, out of phase with .warmth */
  animation: fi-breathe-alt 26s var(--ease-calm) infinite;
}
/* The whole page surface gets a barely-there hue drift. transform-free,
   uses background-position so it stays on the paint thread cheaply. */
body[data-ambience="on"] {
  background-size: 140% 140%, 140% 140%, 100% 100%;
  animation: fi-roomglow 30s ease-in-out infinite;
}

@keyframes fi-breathe {
  0%, 100% { opacity: 1;    transform: translate3d(0, 0, 0); }
  50%      { opacity: 0.78; transform: translate3d(0.6vmax, -0.6vmax, 0); }
}
@keyframes fi-breathe-alt {
  0%, 100% { transform: translate(-50%, -50%) scale(1); }
  50%      { transform: translate(-50%, -50%) scale(1.06); }
}
@keyframes fi-roomglow {
  0%, 100% { background-position: 8% -10%, 100% 108%, 0 0; }
  50%      { background-position: 13% -6%, 95% 104%, 0 0; }
}

/* A whisper of life even when ambience is OFF: the gold kicker mark
   glows very faintly. This is the one always-on touch — slow (9s),
   tiny opacity range — so the page never looks fully frozen. The
   professor lens permits it because it is calm; the Seoul lens wants it
   because a dead star is sad. Disabled under reduced-motion. */
.kicker-mark {
  animation: fi-emberglow 9s ease-in-out infinite;
}
@keyframes fi-emberglow {
  0%, 100% { opacity: 0.85; }
  50%      { opacity: 1; text-shadow: 0 0 0.5em rgba(196, 163, 92, 0.35); }
}

/* =====================================================================
   3 · REFINED HOVER MICRO-INTERACTIONS
   Small, intentional responses. We only touch transform/opacity/colour/
   box-shadow — never box geometry — to avoid reflow. Gated on
   (hover: hover) so touch devices don't get stuck-hover states.
   ===================================================================== */
@media (hover: hover) {

  /* Word-table rows: a warm wash already exists in styles.css; add a
     faint left gold tick that fades in, and lift the gold accent words. */
  .word-table tbody tr {
    transition: background 0.3s var(--ease-calm), box-shadow 0.3s var(--ease-calm);
  }
  .word-table tbody tr:hover {
    box-shadow: inset 2px 0 0 rgba(196, 163, 92, 0.55);
  }
  .word-table tbody tr:hover .rank {
    color: var(--gold);
  }

  /* Metric tiles: the big italic number warms and rises a hair. */
  .metric { transition: background 0.4s var(--ease-calm); }
  .metric-number {
    transition: color 0.4s var(--ease-calm), transform 0.4s var(--ease-soft);
    transform: translate3d(0, 0, 0);
  }
  .metric:hover { background: rgba(196, 163, 92, 0.05); }
  .metric:hover .metric-number {
    color: var(--gold);
    transform: translate3d(0, -0.12rem, 0);
  }

  /* Viz donut slices: lift the hovered slice outward very slightly.
     (styles.css already handles opacity; we add a gentle pop.) */
  .viz-slice { transition: opacity 0.3s ease, transform 0.35s var(--ease-soft); }
  .viz-slice:hover { transform: scale(1.018); }

  /* Heat cells: warm fill on hover, in addition to the gold outline. */
  .viz-heat-cell { transition: outline 0.2s ease, opacity 0.25s ease, background 0.25s ease; }
  .viz-heat-cell:hover { background: rgba(196, 163, 92, 0.06); }

  /* Specimen index rows (homepage): the existing padding shift is nice;
     add a soft gold underglow on the native script as it warms. */
  .tongue:hover .native { text-shadow: 0 0 0.6em rgba(196, 163, 92, 0.18); }

  /* Inline prose / footer links: animated gold underline grow-in.
     Implemented with background-size (composited) — no layout change. */
  .prose a,
  .masthead-note a,
  .study-nav a,
  .study-footer a,
  .next-langs a {
    background-image: linear-gradient(var(--gold), var(--gold));
    background-repeat: no-repeat;
    background-position: 0 100%;
    background-size: 0% 1px;
    transition: background-size 0.4s var(--ease-calm), color 0.25s ease;
  }
  .prose a:hover,
  .masthead-note a:hover,
  .study-nav a:hover,
  .study-footer a:hover,
  .next-langs a:hover {
    background-size: 100% 1px;
  }
}

/* =====================================================================
   4 · FOCUS STATES WITH CHARACTER
   Keyboard focus gets a calm gold ring plus a soft outer glow, so it is
   unmistakable but never harsh. Applies on top of existing :focus-visible
   rules in styles.css.
   ===================================================================== */
a:focus-visible,
button:focus-visible,
input:focus-visible,
[tabindex]:focus-visible,
.tongue-overlay:focus-visible,
.lang-chip:focus-visible,
.viz-slice:focus-visible,
.viz-leg:focus-visible {
  outline: 1px solid var(--gold);
  outline-offset: 0.3rem;
  border-radius: 2px;
  box-shadow: 0 0 0 4px rgba(196, 163, 92, 0.14);
  transition: box-shadow 0.25s var(--ease-calm), outline-offset 0.25s var(--ease-calm);
}

/* =====================================================================
   5 · PREFERENCES TOGGLE UI  (built by alive.js)
   A quiet control pinned bottom-right. Closed = a small gold-dot button;
   open = a slim panel with two switches. Understated, glassy, on-brand.
   ===================================================================== */
.fi-prefs {
  position: fixed;
  right: clamp(1rem, 3vw, 2rem);
  bottom: clamp(1rem, 3vw, 2rem);
  z-index: 40;
  font-family: var(--disp);
  color: var(--cream);
}

/* round trigger */
.fi-prefs-toggle {
  display: grid;
  place-items: center;
  width: 2.6rem;
  height: 2.6rem;
  padding: 0;
  color: var(--cream-dim);
  background: rgba(11, 10, 8, 0.66);
  border: 1px solid var(--rule-strong);
  border-radius: 50%;
  cursor: pointer;
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  transition: color 0.25s ease, border-color 0.25s ease, transform 0.4s var(--ease-soft), box-shadow 0.3s ease;
}
.fi-prefs-toggle:hover {
  color: var(--gold);
  border-color: var(--gold);
  box-shadow: 0 0 0 5px rgba(196, 163, 92, 0.1);
}
/* a small breathing dot in the trigger when ambience is on */
.fi-prefs-toggle .fi-glyph {
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  background: var(--cream-faint);
  transition: background 0.3s ease;
}
body[data-ambience="on"] .fi-prefs-toggle .fi-glyph {
  background: var(--gold);
  animation: fi-dotpulse 4.5s ease-in-out infinite;
}
@keyframes fi-dotpulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(196, 163, 92, 0.45); }
  50%      { box-shadow: 0 0 0 0.35rem rgba(196, 163, 92, 0); }
}

/* panel */
.fi-prefs-panel {
  position: absolute;
  right: 0;
  bottom: calc(100% + 0.7rem);
  width: min(20rem, calc(100vw - 2rem));
  padding: 1.1rem 1.15rem 1rem;
  background: rgba(11, 10, 8, 0.92);
  border: 1px solid var(--rule-strong);
  border-radius: 4px;
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
  box-shadow: 0 14px 40px rgba(0, 0, 0, 0.5);
  /* closed state */
  opacity: 0;
  transform: translate3d(0, 0.5rem, 0) scale(0.98);
  transform-origin: bottom right;
  pointer-events: none;
  transition: opacity 0.3s var(--ease-calm), transform 0.3s var(--ease-soft);
}
.fi-prefs.is-open .fi-prefs-panel {
  opacity: 1;
  transform: translate3d(0, 0, 0) scale(1);
  pointer-events: auto;
}

.fi-prefs-title {
  margin: 0 0 0.15rem;
  color: var(--cream-faint);
  font-size: 0.64rem;
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
}
.fi-prefs-sub {
  margin: 0 0 0.9rem;
  color: var(--cream-faint);
  font-size: 0.78rem;
  font-style: italic;
  line-height: 1.5;
}

.fi-pref-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.6rem 0;
  border-top: 1px solid var(--rule);
}
.fi-pref-copy { min-width: 0; }
.fi-pref-name {
  display: block;
  color: var(--cream);
  font-size: 0.98rem;
  line-height: 1.2;
}
.fi-pref-desc {
  display: block;
  margin-top: 0.12rem;
  color: var(--cream-faint);
  font-size: 0.72rem;
  font-style: italic;
  line-height: 1.4;
}

/* the switch — a calm gold-on-cream toggle, transform-driven knob */
.fi-switch {
  position: relative;
  flex: none;
  width: 2.6rem;
  height: 1.5rem;
  padding: 0;
  background: rgba(236, 227, 211, 0.08);
  border: 1px solid var(--rule-strong);
  border-radius: 1rem;
  cursor: pointer;
  transition: background 0.3s var(--ease-calm), border-color 0.3s var(--ease-calm);
}
.fi-switch::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 0.2rem;
  width: 1rem;
  height: 1rem;
  margin-top: -0.5rem;
  background: var(--cream-dim);
  border-radius: 50%;
  transition: transform 0.3s var(--ease-soft), background 0.3s ease;
}
.fi-switch[aria-checked="true"] {
  background: rgba(196, 163, 92, 0.22);
  border-color: var(--gold);
}
.fi-switch[aria-checked="true"]::after {
  transform: translate3d(1.05rem, 0, 0);
  background: var(--gold);
}

/* playback-volume slider row */
.fi-vol-row { align-items: center; }
.fi-vol-slider {
  -webkit-appearance: none; appearance: none;
  width: 5.2rem; height: 3px; border-radius: 2px;
  background: linear-gradient(to right, var(--gold) 85%, rgba(236,227,211,0.14) 85%);
  outline: none; cursor: pointer; flex-shrink: 0;
}
.fi-vol-slider::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 13px; height: 13px; border-radius: 50%;
  background: var(--gold); cursor: pointer;
  box-shadow: 0 0 6px rgba(196,163,92,0.5); transition: transform 0.15s;
}
.fi-vol-slider::-webkit-slider-thumb:hover { transform: scale(1.2); }
.fi-vol-slider::-moz-range-thumb {
  width: 13px; height: 13px; border-radius: 50%; border: none;
  background: var(--gold); cursor: pointer; box-shadow: 0 0 6px rgba(196,163,92,0.5);
}

.fi-prefs-foot {
  margin: 0.7rem 0 0;
  color: var(--cream-faint);
  font-size: 0.66rem;
  letter-spacing: 0.04em;
  line-height: 1.5;
}

/* keep the control clear of the sticky search bar visual weight on small
   screens by nudging it up a touch when a study search bar is present */
@media (max-width: 460px) {
  .fi-prefs { right: 0.9rem; bottom: 0.9rem; }
}

/* =====================================================================
   6 · REDUCED MOTION — disable EVERYTHING above.
   We mirror the strong reset already in styles.css and additionally make
   every reveal element fully visible and static. The preference panel
   still opens/closes (just without the slide), which is a usability,
   not a decorative, animation — but we keep it instant for safety.
   ===================================================================== */
@media (prefers-reduced-motion: reduce) {
  [data-reveal] {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
  }
  .kicker-mark,
  body[data-ambience="on"] .warmth,
  body[data-ambience="on"] .halo,
  body[data-ambience="on"],
  .fi-prefs-toggle .fi-glyph,
  body[data-ambience="on"] .fi-prefs-toggle .fi-glyph {
    animation: none !important;
  }
  .fi-prefs-panel,
  .fi-prefs.is-open .fi-prefs-panel,
  .fi-switch,
  .fi-switch::after,
  .fi-prefs-toggle {
    transition: none !important;
  }
  /* hover micro-interactions that move things: neutralise the transforms,
     keep the colour cues (colour change is not motion). */
  .metric:hover .metric-number,
  .viz-slice:hover { transform: none !important; }
}
