/* ============================================================================
   democraci matters — the living torch.

   The flat art (assets/democraciMattersFooterLogo.png) is a green→cyan gradient
   torch on transparency. This component uses that PNG's ALPHA as a mask and
   fills the silhouette with a slow aurora, so the colour drifts inside the mark
   instead of sitting still. Same idea and same palette family as the Orealis
   ring (orealis-logo.css on the personal site) — the two marks should read as
   coming from the same hand.

   Usage (set --size on .dm-torch to scale the whole thing):

     <span class="dm-torch" style="--size:150px">
       <span class="dm-torch__glow" aria-hidden="true"></span>
       <span class="dm-torch__fill" aria-hidden="true">
         <i class="dt1"></i><i class="dt2"></i><i class="dt3"></i>
         <i class="dt4"></i><i class="dt5"></i><i class="dt6"></i>
         <i class="dt7"></i><i class="dt8"></i><i class="dt9"></i>
       </span>
       <img class="dm-torch__flat" src="assets/democraciMattersFooterLogo.png" alt="" />
     </span>

   ⚠ Two things are load-bearing, both learned on the Orealis mark:

   1. THE BLUR LIVES ON EACH BLOB, NEVER ON THE MASKED PARENT. A parent that is
      both filtered and masked gets promoted to a cached composited layer, and a
      cached layer FREEZES its moving children — the aurora just stops.
   2. The fill needs `isolation: isolate` so the `screen` blobs blend against
      the torch's own base gradient rather than punching through to the page.
   ========================================================================== */

.dm-torch {
  --size: 140px;
  /* Tempo: lower = faster. The Orealis ring drifts at 1 because it is ambient
     and sits in a corner; this mark is a FLAME held full-screen, so it wants
     visibly quicker, larger movement or it just reads as a static gradient. */
  --au-t: 0.42;
  --torch-art: url("assets/democraciMattersFooterLogo.png");

  position: relative;
  flex: none;
  display: inline-block;
  width: var(--size);
  /* The art is 1226 × 1179, so height is width × 0.9617. Hard-coding the ratio
     keeps the mask aligned at every size without an intrinsic-size dependency. */
  height: calc(var(--size) * 0.9617);
  isolation: isolate;
}

/* ----- The masked fill: base gradient + drifting light ----- */
.dm-torch__fill {
  position: absolute;
  inset: 0;
  isolation: isolate; /* see note 2 above */

  -webkit-mask-image: var(--torch-art);
  mask-image: var(--torch-art);
  -webkit-mask-size: contain;
  mask-size: contain;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;

  /* The resting colour of the mark. GREEN-DOMINANT on purpose: the original art
     ran to full cyan down the handle, and a blue mark on a civic site gets read
     as a party colour. Blue survives only as a teal note at the very base, for
     depth — it never becomes the impression the mark leaves. */
  background: linear-gradient(
    168deg,
    #bef264 0%,
    #86efac 14%,
    #4ade80 32%,
    #22c55e 52%,
    #10b981 72%,
    #14b8a6 90%,
    #2dd4bf 100%
  );
}

/* ----- Volume -----
   Without these the mark reads as light shot through a stencil: a flat fill in
   the shape of a torch. These two layers give it a body. The multiply pass
   darkens both flanks so the flame and the handle round away from the viewer
   like solid objects; the screen pass lays a soft sheen down the lit side.
   Together they turn a silhouette into a form.
   Light comes from the upper left. */
.dm-torch__fill::before,
.dm-torch__fill::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
}

/* Shading — dark, light, dark across the width = cylindrical volume. */
.dm-torch__fill::before {
  z-index: 2;
  mix-blend-mode: multiply;
  background:
    linear-gradient(
      96deg,
      rgba(2, 26, 16, 0.62) 0%,
      rgba(2, 26, 16, 0.2) 16%,
      rgba(2, 26, 16, 0) 40%,
      rgba(2, 26, 16, 0.06) 58%,
      rgba(2, 26, 16, 0.42) 82%,
      rgba(2, 26, 16, 0.72) 100%
    ),
    /* a little weight at the foot so it sits rather than floats */
    linear-gradient(to bottom, transparent 62%, rgba(2, 26, 16, 0.34) 100%);
}

/* Specular — the sheen of a rounded surface, plus a hot spot on the flame.
   TINTED, not white, and kept weak. `screen` drives everything toward white, so
   a white highlight on top of the aurora bleaches the mark to pale mint and the
   green disappears. A lime-tinted highlight adds the same sense of a lit,
   curved surface while the colour survives. */
.dm-torch__fill::after {
  z-index: 3;
  mix-blend-mode: screen;
  background:
    radial-gradient(26% 40% at 36% 62%, rgba(190, 242, 100, 0.26) 0%, transparent 74%),
    radial-gradient(18% 13% at 40% 22%, rgba(236, 252, 203, 0.34) 0%, transparent 72%);
}

.dm-torch__fill i {
  position: absolute;
  display: block;
  border-radius: 50%;
  mix-blend-mode: screen;
  filter: blur(max(6px, calc(var(--size) * 0.085))); /* per-blob — see note 1 */
  will-change: transform, opacity;
}

/* SATURATED mid-tones, not pastels. Under `screen`, a pale blob lands on white
   and the mark goes colourless; a saturated green blob lands on brighter green.
   Only one teal is kept, low and near the base, so there is depth without the
   mark reading as blue. */
.dm-torch__fill .dt1 {
  width: 78%; height: 62%; left: -4%; top: -2%;
  background: radial-gradient(circle at 50% 50%, #4ade80 0%, transparent 68%);
  animation: dt-drift-a calc(5.4s * var(--au-t)) ease-in-out infinite;
}
.dm-torch__fill .dt2 {
  width: 70%; height: 58%; left: 34%; top: 4%;
  background: radial-gradient(circle at 50% 50%, #a3e635 0%, transparent 68%);
  opacity: 0.8;
  animation: dt-drift-b calc(6.8s * var(--au-t)) ease-in-out infinite;
  animation-delay: -2s;
}
.dm-torch__fill .dt3 {
  width: 66%; height: 66%; left: 20%; top: 34%;
  background: radial-gradient(circle at 50% 50%, #16a34a 0%, transparent 66%);
  animation: dt-drift-c calc(8.1s * var(--au-t)) ease-in-out infinite;
  animation-delay: -3s;
}
.dm-torch__fill .dt4 {
  width: 60%; height: 70%; left: -2%; top: 40%;
  background: radial-gradient(circle at 50% 50%, #22c55e 0%, transparent 66%);
  animation: dt-drift-b calc(6.1s * var(--au-t)) ease-in-out infinite reverse;
  animation-delay: -3.5s;
}
.dm-torch__fill .dt5 {
  /* the single teal — kept to the lower half and dimmed */
  width: 56%; height: 60%; left: 44%; top: 52%;
  background: radial-gradient(circle at 50% 50%, #14b8a6 0%, transparent 64%);
  opacity: 0.72;
  animation: dt-drift-a calc(7.3s * var(--au-t)) ease-in-out infinite reverse;
  animation-delay: -2.5s;
}
.dm-torch__fill .dt6 {
  /* A HAIR of warmth, no more. At any real strength the yellow sits on top of
     the green, desaturates it, and the whole flame goes washed-out and pale —
     it should register as heat you can barely name, not as a colour. */
  width: 30%; height: 30%; left: 36%; top: 14%;
  background: radial-gradient(circle at 50% 50%, #fbbf24 0%, transparent 60%);
  opacity: 0.16;
  animation: dt-drift-c calc(9.4s * var(--au-t)) ease-in-out infinite;
  animation-delay: -4.5s;
}
/* The blue, deliberately confined to the BASE of the handle: it adds depth
   where the eye reads shadow, and never reaches the flame — so the mark's
   impression stays green. */
.dm-torch__fill .dt7 {
  width: 62%; height: 46%; left: 18%; top: 66%;
  background: radial-gradient(circle at 50% 50%, #0ea5e9 0%, transparent 66%);
  opacity: 0.6;
  animation: dt-drift-b calc(7.6s * var(--au-t)) ease-in-out infinite;
  animation-delay: -1.2s;
}
/* Flicker pair — fast, up at the flame. GREEN and TEAL, not yellow: these are
   the two brightest, fastest layers, so whatever colour they carry is the
   colour the flame appears to be. */
.dm-torch__fill .dt8 {
  width: 34%; height: 40%; left: 33%; top: 6%;
  background: radial-gradient(circle at 50% 60%, #34d399 0%, transparent 64%);
  transform-origin: 50% 100%;
  filter: blur(max(4px, calc(var(--size) * 0.05)));
  animation: dt-flicker calc(2.9s * var(--au-t)) ease-in-out infinite;
}
.dm-torch__fill .dt9 {
  width: 40%; height: 46%; left: 30%; top: 2%;
  background: radial-gradient(circle at 50% 60%, #5eead4 0%, transparent 62%);
  transform-origin: 50% 100%;
  filter: blur(max(5px, calc(var(--size) * 0.06)));
  animation: dt-flicker calc(3.7s * var(--au-t)) ease-in-out infinite;
  animation-delay: -1.1s;
}

/* ----- The bleed: a soft, unmasked halo so the mark sits in the dark rather
   than being pasted on top of it. No moving children, so a filter here is safe. */
.dm-torch__glow {
  position: absolute;
  inset: -18%;
  z-index: -1;
  pointer-events: none;
  background: radial-gradient(
    46% 42% at 50% 34%,
    rgba(74, 222, 128, 0.5) 0%,
    rgba(16, 185, 129, 0.26) 46%,
    transparent 74%
  );
  filter: blur(calc(var(--size) * 0.14));
  animation: dt-breathe calc(7s * var(--au-t)) ease-in-out infinite;
}

/* ----- Fallback: the flat art, shown only where masking is unavailable ----- */
.dm-torch__flat {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
}
@supports (mask-image: url("#")) or (-webkit-mask-image: url("#")) {
  .dm-torch__flat { display: none; }
}
/* …and if masking is missing, there is nothing to fill, so hide the aurora. */
@supports not ((mask-image: url("#")) or (-webkit-mask-image: url("#"))) {
  .dm-torch__fill { display: none; }
}

/* Wider travel and an extra beat per cycle compared with the Orealis ring — the
   light has to visibly climb and fall inside the silhouette, the way a flame
   does, rather than breathe in place. */
@keyframes dt-drift-a {
  0%   { transform: translate(-20%, 16%)  scale(0.88); opacity: 0.55; }
  26%  { transform: translate(14%, -8%)   scale(1.3);  opacity: 1; }
  52%  { transform: translate(-12%, -20%) scale(1.02); opacity: 0.78; }
  76%  { transform: translate(18%, 10%)   scale(1.2);  opacity: 0.95; }
  100% { transform: translate(-20%, 16%)  scale(0.88); opacity: 0.55; }
}
@keyframes dt-drift-b {
  0%   { transform: translate(16%, 12%)   scale(1.14); opacity: 0.92; }
  30%  { transform: translate(-18%, -14%) scale(0.84); opacity: 0.6; }
  58%  { transform: translate(12%, -22%)  scale(1.32); opacity: 1; }
  82%  { transform: translate(-8%, 6%)    scale(0.96); opacity: 0.74; }
  100% { transform: translate(16%, 12%)   scale(1.14); opacity: 0.92; }
}
@keyframes dt-drift-c {
  0%   { transform: translate(-16%, 18%)  scale(0.9);  opacity: 0.8; }
  34%  { transform: translate(14%, -16%)  scale(1.34); opacity: 1; }
  62%  { transform: translate(20%, 8%)    scale(1.0);  opacity: 0.62; }
  86%  { transform: translate(-6%, -10%)  scale(1.18); opacity: 0.9; }
  100% { transform: translate(-16%, 18%)  scale(0.9);  opacity: 0.8; }
}

/* The flicker: fast, small, and always UPWARD — this is what stops the mark
   reading as a slow gradient wash and starts it reading as combustion. */
@keyframes dt-flicker {
  0%   { transform: translate(0, 6%)    scaleY(0.9)  scaleX(1.04); opacity: 0.35; }
  18%  { transform: translate(-5%, -2%) scaleY(1.18) scaleX(0.92); opacity: 0.75; }
  37%  { transform: translate(4%, 3%)   scaleY(0.96) scaleX(1.06); opacity: 0.45; }
  59%  { transform: translate(-3%, -6%) scaleY(1.26) scaleX(0.88); opacity: 0.82; }
  78%  { transform: translate(5%, 1%)   scaleY(1.02) scaleX(1.02); opacity: 0.5; }
  100% { transform: translate(0, 6%)    scaleY(0.9)  scaleX(1.04); opacity: 0.35; }
}
@keyframes dt-breathe {
  0%, 100% { opacity: 0.72; transform: scale(1); }
  50%      { opacity: 1;    transform: scale(1.06); }
}

@media (prefers-reduced-motion: reduce) {
  .dm-torch__fill i,
  .dm-torch__glow { animation: none; }
}
