/* proverb.to — an old stone well. Tokens first; everything derives.
   No control chrome exists: the card is the interface (see app.ts). */

:root {
  --ground: #23261a;
  --ground-2: #12140f;
  --ink: #ece7d8;
  --ink-soft: #9a9482;
  --gold: #b7a24a;
  --serif: "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, serif;
  --sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  /* Hold progress, written by app.ts; the words brighten on the inhale. */
  --gather: 0;
}

* {
  box-sizing: border-box;
  margin: 0;
}

html,
body {
  height: 100%;
}

body {
  background: radial-gradient(130% 100% at 50% 92%, var(--ground) 0%, var(--ground-2) 62%);
  color: var(--ink);
  font-family: var(--sans);
  overflow: hidden;
}

#well {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
  overflow: hidden;
}

/* The pool's glory overlay (bloom) sits over the stage canvas, inside #well. */
.pool-glory {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.wordmark {
  position: fixed;
  top: 1.25rem;
  left: 1.5rem;
  z-index: 1;
  font-family: var(--serif);
  font-size: 1.05rem;
  font-style: italic;
  letter-spacing: 0.06em;
  color: color-mix(in srgb, var(--gold) 60%, transparent);
  pointer-events: none;
}

/* The whole viewport takes the gesture — there is no smaller target to find. */
.stage {
  position: relative;
  z-index: 1;
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  padding: 1.5rem;
  touch-action: none;
  cursor: grab;
  -webkit-user-select: none;
  user-select: none;
}

.stage:active {
  cursor: grabbing;
}

/* Law 1: turn.ts drives --turn-rot/--turn-x/--turn-shadow directly, once per
   animation frame — never a CSS transition on transform here, since a
   transition would fight turn.ts's own eased tween instead of letting it
   own the timing (the fixed MIN_TURN_MS pace IS the law). The unset
   defaults (0deg / 0px / none) are a flat, resting page. Arrival is an
   opacity fade alone, so the base transform stays free for the turn. */
.card {
  max-width: 32rem;
  text-align: center;
  opacity: 0;
  transform: perspective(900px) rotateY(var(--turn-rot, 0deg)) translateX(var(--turn-x, 0px));
  transition: opacity 900ms ease, filter 400ms ease;
  filter: drop-shadow(0 0 calc(var(--gather) * 22px) color-mix(in srgb, var(--gold) 45%, transparent));
  box-shadow: var(--turn-shadow, none);
}

.card.risen {
  opacity: 1;
}

/* While the finger is down the card tracks it 1:1 — no easing in the way. */
.card.dragging {
  transition: filter 400ms ease;
}

/* Arrival hint: the card drifts once, teaching the gesture without a word. */
.card.hinting {
  animation: drift 900ms ease-in-out;
}

@keyframes drift {
  0%,
  100% {
    transform: none;
  }
  50% {
    transform: translateX(-14px);
  }
}

/* Carried: the light rises through the words once and settles. */
.card.carried {
  animation: carried 800ms ease-out;
}

@keyframes carried {
  0% {
    filter: drop-shadow(0 0 0 transparent);
  }
  35% {
    filter: drop-shadow(0 0 26px color-mix(in srgb, var(--gold) 70%, transparent));
    transform: translateY(-5px);
  }
  100% {
    filter: drop-shadow(0 0 0 transparent);
    transform: none;
  }
}

/* The breath let go with nothing in it: the hold was heard, honestly. */
.card.released {
  animation: released 800ms ease-out;
}

@keyframes released {
  0%,
  100% {
    opacity: 1;
    transform: none;
  }
  45% {
    opacity: 0.7;
    transform: translateY(3px);
  }
}

/* Law 5, the memory palace: keeping a saying collapses the card toward the very
   point in the water its coin drops to (--keep-dx/--keep-dy, written by app.ts
   from well.landingPoint), released as the coin over 480ms, then the class is
   dropped (app.ts's animationend) and the kept card fades back via .card's own
   opacity transition — still readable, now with its coin glinting below. Recall
   from the water is the opposite and instant (paint({instant}), no animation at
   all). ease-in so the words gather speed as they're drawn down into the well. */
.card.keeping {
  animation: keeping 480ms ease-in forwards;
}

@keyframes keeping {
  0% {
    transform: perspective(900px) translate(0, 0) scale(1);
    opacity: 1;
  }
  100% {
    transform: perspective(900px) translate(var(--keep-dx, 0px), var(--keep-dy, 0px)) scale(0.12);
    opacity: 0;
  }
}

/* The one word on the card that answers to touch: it tunes the water to its own
   kind. Styled as part of the writing, never as a control. */
.category {
  display: inline-block;
  font-size: 0.72rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin-bottom: 1.25rem;
  cursor: pointer;
  transition: color 300ms ease, text-shadow 300ms ease;
}

.category:hover {
  color: var(--gold);
}

/* Tuned: this kind is lit, and the water holds to it. */
.category.tuned {
  color: var(--gold);
  text-shadow: 0 0 14px color-mix(in srgb, var(--gold) 55%, transparent);
}

/* Kept: these words already have a coin in your well, on top of the same
   material shadow every saying carries (see .proverb below and tilt.ts). */
.card.kept .proverb {
  text-shadow:
    0 0 24px color-mix(in srgb, var(--gold) 28%, transparent),
    calc(var(--tilt-x, 0.6px)) calc(var(--tilt-y, 0.9px)) 8px rgba(0, 0, 0, 0.5);
}

/* Law 3: the words are material. tilt.ts writes --tilt-x/--tilt-y/--tilt-track
   at most once a frame from the device's orientation, low-pass filtered and
   scaled down for heavier sayings (see cardWeight) — the shadow drifts and the
   letters breathe as the card tilts. Every var default below is the same fixed,
   gentle look tilt.ts itself applies when the device offers nothing to read (no
   sensor, permission not granted, prefers-reduced-motion): the degraded state
   is designed, not an absence, and needs no JS at all to look intentional. The
   shadow is deep — light words on dark stone need the drop for depth. */
.proverb {
  font-family: var(--serif);
  font-size: clamp(1.6rem, 4.8vw, 2.5rem);
  line-height: 1.4;
  font-weight: 400;
  letter-spacing: calc(0em + var(--tilt-track, 0.01em));
  text-shadow: calc(var(--tilt-x, 0.6px)) calc(var(--tilt-y, 0.9px)) 8px rgba(0, 0, 0, 0.55);
}

/* Law 4: each phrase of the saying fades in on its own, a beat after the last
   (see unveil.ts). A kept card re-expanding from its coin paints the words
   directly, with no spans at all — instant is its own honest state. */
.phrase {
  display: inline-block;
  opacity: 0;
  transform: translateY(2px);
  transition: opacity 320ms ease-out, transform 320ms ease-out;
}

.phrase.lit {
  opacity: 1;
  transform: translateY(0);
}

/* The origin — where the saying comes from. It fades in only once the words
   have finished arriving (app.ts, on the final phrase; stoke's author step). */
.attribution {
  margin-top: 1.5rem;
  font-size: 0.95rem;
  color: var(--ink-soft);
  font-style: italic;
  opacity: 0;
  transition: opacity 320ms ease-out;
}

.attribution.lit {
  opacity: 1;
}

/* The gloss on the origin — proverb's one quiet second line, kept whisper-level:
   smaller, dimmer, unhurried. Present only when the card carries a note. */
.note {
  margin-top: 0.5rem;
  font-size: 0.82rem;
  letter-spacing: 0.01em;
  line-height: 1.5;
  color: var(--ink-soft);
  opacity: 0;
  transition: opacity 320ms ease-out;
}

.note.lit {
  opacity: 0.62;
}

/* Present to assistive tech and to the keyboard, invisible to the world. */
.sr-only button {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.sr-only button:focus-visible {
  position: fixed;
  bottom: 1rem;
  left: 50%;
  transform: translateX(-50%);
  width: auto;
  height: auto;
  clip: auto;
  padding: 0.55rem 1.3rem;
  border-radius: 999px;
  border: 1px solid var(--gold);
  background: var(--ground-2);
  color: var(--gold);
  font-family: var(--sans);
  font-size: 0.9rem;
  outline: none;
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--gold) 40%, transparent);
}

@media (prefers-reduced-motion: reduce) {
  .card,
  .card.hinting,
  .card.carried,
  .card.released,
  .card.keeping,
  .phrase,
  .attribution,
  .note {
    transition: none;
    animation: none;
  }

  /* turn.ts never writes --turn-rot/--turn-x in this mode (progress() is a
     no-op there) and drives a plain opacity crossfade for commit() instead
     — this is belt-and-suspenders so the card is flat even if some other
     path ever left a stale var behind. */
  .card {
    transform: none;
  }
}
