/* ============================================================================
   Option A - the shipping stylesheet.

   Single source of truth for the pure CSS/SVG tier. Both the three-glyph demo
   and the 21-glyph field link this file, so the two can never drift apart.
   Everything reacts to two custom properties written by proximity.js:
     --charge  0..1 induction level
     --surge   0..1 click shockwave amplitude
   ========================================================================= */

.glyph { overflow: visible; }

/* ---- IDLE ---------------------------------------------------------------
   The base layer is always drawn, recessed and monochrome, so an unpowered
   glyph reads as engraved metal rather than as nothing at all. */
.glyph-base [data-layer] > * {
  stroke: var(--dim);
  stroke-width: 1.1px;
  opacity: .85;
}
.glyph-base [data-fill="core"] { fill: var(--dim); stroke: none; opacity: .85; }

/* ---- CHARGE -------------------------------------------------------------
   The trace layer rides exactly on top of the base. dashoffset retracts the
   whole path at rest and draws it in as charge rises, so the current visibly
   rushes along lines that were already there. */

/* A cold glyph pays for no filter at all. Three stacked drop-shadows are the
   expensive part of this tier, so they exist only while charged. This is the
   single most important rule once the glyph count passes about a dozen. */
.cell:not(.live) .glyph-trace { filter: none; }

.glyph-trace {
  filter:
    drop-shadow(0 0 calc(1px + 2px  * var(--charge)) var(--core))
    drop-shadow(0 0 calc(3px + 13px * var(--charge)) var(--glow))
    drop-shadow(0 0 calc(8px + 34px * var(--charge)) var(--ambient));
  transition: filter .12s linear;
}

.glyph-trace [data-layer] > * {
  stroke: var(--glow);
  stroke-width: calc(1.2px + 1.2px * var(--charge));
  stroke-dasharray: 1;
  stroke-dashoffset: calc(1 - var(--charge));
  transition: stroke-width .1s linear, stroke-dashoffset .22s ease-out;
}

/* Staggered ignition using nothing but transition-delay:
   outer ring leads, mid follows, core lands last. */
.glyph-trace [data-layer="outer"] > * { transition-delay: 0s; }
.glyph-trace [data-layer="mid"]   > * { transition-delay: .05s; }
.glyph-trace [data-layer="core"]  > * { transition-delay: .11s; }

.glyph-trace [data-fill="core"] {
  stroke: none;
  fill: var(--core);
  fill-opacity: var(--charge);
}

/* ---- MOTION -------------------------------------------------------------- */
.glyph {
  animation: breathe 5.5s ease-in-out infinite;
  transform-origin: 50% 50%;
  scale: calc(1 + var(--charge) * .03 + var(--surge, 0) * .10);
  transition: scale .18s cubic-bezier(.2, 1.6, .4, 1);
}
@keyframes breathe {
  0%, 100% { opacity: .82; }
  50%      { opacity: 1; }
}

/* Micro-vibration during induction. A separate keyframe rather than a
   JS-driven transform, so it costs nothing on the main thread. */
.cell.buzzing .glyph {
  animation: breathe 5.5s ease-in-out infinite, buzz .09s steps(2) infinite;
}
@keyframes buzz {
  0%   { translate: calc(var(--charge) * -0.7px) calc(var(--charge) *  0.5px); }
  100% { translate: calc(var(--charge) *  0.7px) calc(var(--charge) * -0.5px); }
}

/* ---- CLICK SHOCKWAVE ----------------------------------------------------- */
.cell { position: relative; --surge: 0; }
.cell::after {
  content: "";
  position: absolute; top: 50%; left: 50%;
  width: 44px; height: 44px; margin: -22px 0 0 -22px;
  border: 2px solid var(--glow); border-radius: 50%;
  pointer-events: none;
  scale: calc(1 + var(--surge) * 7);
  opacity: calc(var(--surge) * .85);
  transition: scale .1s linear, opacity .1s linear;
}

@media (prefers-reduced-motion: reduce) {
  .glyph, .cell.buzzing .glyph { animation: none; }
  .glyph *, .glyph-trace, .glyph { transition-duration: .01s; }
}
