/* =============================================
   Traces glyphs — the wisp and the cairn

   Loaded by index.html ONLY. css/styles.css is loaded by ten pages
   including /daylight and /sunpath, both of which sit under page-weight
   gates; this section's styles have no business growing them.
   ============================================= */

/* --- The wisp --- */

/* Shorter than the 5.5s breath on purpose. Fading for the whole interval
   means the colour is never actually AT an energy — it is permanently
   mid-morph, and the name below it would be reading "gratitude" while the
   glyph sits halfway to compassion. Fading for half, then resting, keeps
   the word and the colour agreeing. */
.traces-card-icon--whispers {
  --wisp-fade: 2.6s;
  flex-direction: column;
  gap: var(--padding-xs);
}

.wisp-well {
  position: relative;
  display: block;
  width: 40px;
  height: 40px;
}

/* Same qualification as the cairn counter, and for the same reason:
   `.traces-card p` in styles.css outspecifies a bare class, so an
   unqualified rule here is parsed, matched, and discarded. */
.traces-card p.wisp-energy {
  margin: 0;
  min-height: 1.2em;
  max-width: none;
  font-family: var(--font-ui);
  font-size: 0.72rem;
  line-height: 1.4;
  letter-spacing: 0.04em;
  color: var(--ink-fog);
  transition: color var(--wisp-fade) ease-in-out;
}

/* The energy colour, as a soft halo behind the line work — never the
   line itself. The Swift property is named borderColor, and compassion,
   wonder, courage and lightness are all near-invisible as a thin stroke
   on parchment. */
/* The soft falloff is a MASK, not a gradient in the background.
   A custom property inside radial-gradient() is not interpolatable, so
   `transition: background` had nothing to animate — the gradient simply
   recomputed and the halo hard-cut to its new colour every 5.5s. Painting
   a flat background-color and shaping it with a mask gives the same
   result from a property that genuinely cross-fades. */
.wisp-aura {
  position: absolute;
  inset: -14px;
  border-radius: 50%;
  background-color: var(--wisp-energy, transparent);
  -webkit-mask-image: radial-gradient(circle, #000 0%, transparent 68%);
  mask-image: radial-gradient(circle, #000 0%, transparent 68%);
  opacity: 0.55;
  transition: background-color var(--wisp-fade) ease-in-out;
  pointer-events: none;
}

/* The band the glyph colour is remapped into — dark enough to read on
   parchment, light enough to read on the night palette. JS reads these
   and hands them to TracesGlyphs.glyphColorFor(). */
.wisp {
  --wisp-l-min: 30;
  --wisp-l-max: 54;
  position: relative;
  display: block;
  color: var(--rust);
  transition: color var(--wisp-fade) ease-in-out;
  animation: wisp-breathe 5.5s ease-in-out infinite;
}

[data-theme="dark"] .wisp {
  --wisp-l-min: 52;
  --wisp-l-max: 78;
}

@keyframes wisp-breathe {
  0%, 100% { transform: scale(1);    opacity: 0.92; }
  50%      { transform: scale(1.04); opacity: 1;    }
}

@media (prefers-reduced-motion: reduce) {
  .wisp { animation: none; transition: none; }
  .wisp-aura { transition: none; }
  .traces-card p.wisp-energy { transition: none; }
}

/* --- The cairn --- */

.traces-card-icon--cairns {
  flex-direction: column;
  gap: var(--padding-xs);
}

.cairn-stack {
  position: relative;
  display: block;
  width: 96px;
  height: 96px;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: transform 0.2s ease;
}

.cairn-stack:hover { transform: translateY(-2px); }

.cairn-stack:focus-visible {
  outline: 2px solid var(--moss);
  outline-offset: 4px;
  border-radius: var(--radius-sm);
}

/* The pile wrapper exists so the settle and the tier wipe live on
   different elements. Both are `animation` on the same property, and on
   one element the more specific settle wins outright — the wipe then
   never runs and the tier change silently becomes an instant swap. */
.cairn-pile {
  position: absolute;
  inset: 0;
  display: block;
  transform-origin: 50% 95.5%;   /* the shared ground line, not the box */
}

.cairn-layer {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
}

/* Qualified deliberately. The counter is a <p> inside .traces-card, and
   `.traces-card p` in styles.css is more specific than a bare
   .cairn-counter — so every one of these declarations was being thrown
   away and the readout rendered as body copy in the display serif, at
   the same size as the paragraph below it. It is a caption, not prose. */
.traces-card p.cairn-counter {
  margin: 0;
  min-height: 1.2em;
  max-width: none;
  font-family: var(--font-ui);
  font-size: 0.72rem;
  line-height: 1.4;
  letter-spacing: 0.04em;
  color: var(--ink-fog);
  opacity: 0;
  transition: opacity 0.6s ease;
}

.traces-card p.cairn-counter.is-visible { opacity: 1; }

/* --- Placement motion --- */

/* The stone falls on a heavy-in ease and does NOT decelerate at the
   bottom. Real things arrive; they do not ease into the ground. */
.falling-stone {
  position: absolute;
  left: 50%;
  top: var(--stone-land, 62%);
  width: 12px;
  height: 7px;
  margin-left: -6px;
  border-radius: 50%;
  /* A lit top-left so it reads as a rounded stone rather than a flat
     pill. The energy colour is the body of the stone, not a label on it. */
  background:
    radial-gradient(ellipse at 34% 28%, rgba(255, 255, 255, 0.5) 0%, rgba(255, 255, 255, 0) 58%),
    var(--stone-energy, var(--stone));
  opacity: 0;
  pointer-events: none;
  animation: stone-drop 260ms cubic-bezier(.55, .06, .68, .19) forwards;
}

@keyframes stone-drop {
  0%   { transform: translateY(-30px) scale(0.9); opacity: 0;   }
  25%  {                                          opacity: 0.9; }
  100% { transform: translateY(0) scale(1);       opacity: 0;   }
}

/* The settle. This is the detail that carries the whole feature: the
   pile compresses on impact and springs back. Mass is communicated by
   what the receiving object does, never by the falling one. */
.cairn-stack.is-settling .cairn-pile {
  animation: cairn-settle 180ms ease-out;
}

@keyframes cairn-settle {
  0%   { transform: scaleY(1);     }
  35%  { transform: scaleY(0.985); }
  100% { transform: scaleY(1);     }
}

.dust {
  position: absolute;
  bottom: 4.5%;
  left: 50%;
  width: 3px;
  height: 3px;
  border-radius: 50%;
  background: var(--fog);
  opacity: 0;
  pointer-events: none;
  animation: dust-kick 400ms ease-out forwards;
}

@keyframes dust-kick {
  0%   { opacity: 0.55; transform: translate(0, 0) scale(1); }
  100% { opacity: 0;    transform: translate(var(--dx), 4px) scale(0.4); }
}

/* --- Tier change --- */

/* Bottom-to-top reveal, never a cross-fade. Cairns grow upward, so an
   upward wipe reads as the new pile assembling out of the ground rather
   than one image dissolving into another. That single choice is what
   makes seven unrelated paintings feel like one object that grew. */
.cairn-layer--over.is-wiping {
  animation: cairn-wipe 500ms ease-out forwards;
}

@keyframes cairn-wipe {
  0%   { clip-path: inset(100% 0 0 0); }
  100% { clip-path: inset(0 0 0 0);    }
}

/* sacred and eternal carry radial glows. They arrive LATE — the pile
   assembles first, and then it begins to shine. */
.cairn-stack.is-glowing::after {
  content: '';
  position: absolute;
  inset: -18%;
  border-radius: 50%;
  background: radial-gradient(circle, var(--dawn) 0%, transparent 62%);
  opacity: 0;
  pointer-events: none;
  animation: cairn-glow-arrive 900ms ease-in 500ms forwards;
}

@keyframes cairn-glow-arrive {
  0%   { opacity: 0;    }
  100% { opacity: 0.28; }
}

/* The 108th stone. Everything holds: the glow comes up over 2.4s rather
   than 900ms, and the wisp stops cycling (in JS) so the aura settles on
   whichever energy was breathing when the last stone landed. */
.cairn-stack.is-eternal::after {
  animation: cairn-glow-arrive 2400ms ease-in forwards;
}

@media (prefers-reduced-motion: reduce) {
  .cairn-stack, .cairn-counter { transition: none; }
  .cairn-stack.is-eternal::after { animation: none; opacity: 0.28; }
  .falling-stone, .dust { display: none; }
  .cairn-stack.is-settling .cairn-pile { animation: none; }
  .cairn-layer--over.is-wiping { animation: none; clip-path: none; }
  .cairn-stack.is-glowing::after { animation: none; opacity: 0.28; }
}
