/*
 * Comic pop tag -- a hand-lettered speech-bubble badge that pops itself on,
 * one letter at a time. Recreated from the pop-art stock clip so the same
 * beat can carry any word ("Boom!", "New", "50mg") instead of the one word
 * the footage was rendered with, at any size, in any colourway, without
 * shipping a 450KB video per tag.
 *
 * Drop-in: this file plus comic-pop.js. No build step, no dependencies.
 * The display face (or whatever --pop-font names) has to be loaded by the host page.
 */

.pop-tag {
  /* Type */
  /* Follows the brand token when theme.css is present. The literal stays as the
     fallback because this stylesheet is meant to drop into a page on its own --
     see the standalone note above. */
  --pop-font: var(--font-display, "Boom Display", "Arial Black", sans-serif);
  --pop-size: 3.4rem;
  --pop-track: -.012em;

  /* Ink and paper */
  --pop-ink: #0d0a10;
  --pop-paper: #ffffff;
  --pop-paper-shade: #ece2f0;

  /* Letter fill: light at the cap line, saturated at the baseline, sampled
     off the reference frames rather than guessed. */
  --pop-fill-1: #d9a9d2;
  --pop-fill-2: #b671b0;
  --pop-fill-3: #93469c;

  /* Halftone. The dot grid is em-based so the screen scales with the type
     instead of turning into mush at 6rem and noise at 1rem. */
  --pop-dot: #9f56a3;
  --pop-dot-faint: rgba(159, 86, 163, .32);
  --pop-dot-grid: .155em;

  /* Line weights. Both are em-based; comic-pop.js reads the resolved pixel
     value back off the SVG so the bubble geometry stays in step. */
  --pop-stroke: .105em;
  --pop-letter-stroke: .058em;

  /* The hard offset shadow sits down-left, as it does in the reference. */
  --pop-shadow: #17111c;
  --pop-shadow-x: -.11em;
  --pop-shadow-y: .1em;

  /* Room under the word for the tail to hang into. */
  --pop-tail-space: .34em;

  /* Pose and timing */
  --pop-tilt: -5deg;
  --pop-delay: 0ms;
  --pop-bubble-ms: 260ms;
  --pop-letter-ms: 300ms;
  --pop-letter-step: 88ms;

  position: relative;
  display: inline-block;
  padding: .3em .42em .46em;
  font-family: var(--pop-font);
  font-size: var(--pop-size);
  font-weight: 400;
  line-height: .92;
  text-transform: uppercase;
  letter-spacing: var(--pop-track);
  transform: rotate(var(--pop-tilt));
  /* The bubble is what the tail hangs off, so the tail's own height has to
     come out of the box rather than out of the word. */
  padding-bottom: calc(.46em + var(--pop-tail-space));
}

/* The bubble is generated at the element's real pixel size, so the viewBox
   maps 1:1 and nothing about the stroke or the tail gets stretched. The
   offset shadow is allowed to paint outside the box on purpose. */
.pop-tag-bubble {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
  pointer-events: none;
}

.pop-tag-bubble stop:first-child { stop-color: var(--pop-paper); }
.pop-tag-bubble stop:last-child { stop-color: var(--pop-paper-shade); }

.pop-tag-shadow {
  fill: var(--pop-shadow);
  transform: translate(var(--pop-shadow-x), var(--pop-shadow-y));
}

/* No `fill` here on purpose: comic-pop.js points the path at a per-instance
   gradient via the fill *attribute*, and a CSS declaration would outrank it. */
.pop-tag-body {
  stroke: var(--pop-ink);
  stroke-width: var(--pop-stroke);
  stroke-linejoin: round;
}

.pop-tag-word {
  position: relative;
  display: block;
  white-space: nowrap;
  text-align: center;
}

/*
 * Each letter is drawn twice in the same place: a fat stroked copy
 * underneath for the outline, a gradient-and-halftone copy on top for the
 * fill. -webkit-text-stroke centres its stroke on the glyph edge, so the
 * inner half is covered by the fill copy and only the outer half reads --
 * which is why --pop-letter-stroke is doubled below.
 *
 * The element's own text stays transparent purely to reserve the layout box,
 * so the two pseudo-elements can be positioned out of flow and line up
 * exactly on top of each other.
 */
.pop-tag-letter {
  position: relative;
  display: inline-block;
  color: transparent;
  transform: rotate(var(--pop-rot, 0deg)) translateY(var(--pop-shift, 0em));
  transform-origin: 50% 70%;
}

.pop-tag-letter::before,
.pop-tag-letter::after {
  content: attr(data-char);
  position: absolute;
  top: 0;
  left: 0;
  white-space: pre;
}

.pop-tag-letter::before {
  color: var(--pop-ink);
  -webkit-text-stroke: calc(var(--pop-letter-stroke) * 2) var(--pop-ink);
  paint-order: stroke fill;
}

.pop-tag-letter::after {
  color: transparent;
  background-image:
    radial-gradient(circle, var(--pop-dot) 42%, transparent 44%),
    radial-gradient(circle, var(--pop-dot) 36%, transparent 38%),
    radial-gradient(circle, var(--pop-dot) 30%, transparent 32%),
    radial-gradient(circle, var(--pop-dot) 24%, transparent 26%),
    radial-gradient(circle, var(--pop-dot-faint) 20%, transparent 22%),
    linear-gradient(
      180deg,
      var(--pop-fill-1) 0%,
      var(--pop-fill-2) 54%,
      var(--pop-fill-3) 100%
    );
  /* Four repeat-x rows of increasing radius stacked toward the baseline is
     what makes it read as a halftone screen rather than as dots on text --
     real screens grow their dots into the shadows. */
  background-size:
    var(--pop-dot-grid) var(--pop-dot-grid),
    var(--pop-dot-grid) var(--pop-dot-grid),
    var(--pop-dot-grid) var(--pop-dot-grid),
    var(--pop-dot-grid) var(--pop-dot-grid),
    var(--pop-dot-grid) var(--pop-dot-grid),
    100% 100%;
  background-position: 0 99%, 0 88%, 0 77%, 0 66%, 0 0, 0 0;
  background-repeat: repeat-x, repeat-x, repeat-x, repeat-x, repeat, no-repeat;
  -webkit-background-clip: text;
  background-clip: text;
}

.pop-tag-space {
  display: inline-block;
  width: .26em;
}

/*
 * Animation. JS only arms elements it is actually going to animate, so a tag
 * that never gets observed -- no IntersectionObserver, reduced motion, script
 * blocked -- stays visible in its finished state instead of flashing or
 * disappearing.
 */
.pop-tag.is-armed .pop-tag-bubble,
.pop-tag.is-armed .pop-tag-letter {
  opacity: 0;
}

.pop-tag.is-armed.is-live .pop-tag-bubble {
  animation: pop-tag-bubble var(--pop-bubble-ms)
    cubic-bezier(.22, 1.44, .38, 1) var(--pop-delay) both;
}

.pop-tag.is-armed.is-live .pop-tag-letter {
  animation: pop-tag-letter var(--pop-letter-ms)
    cubic-bezier(.18, 1.6, .4, 1)
    calc(var(--pop-delay) + 170ms + var(--pop-i, 0) * var(--pop-letter-step))
    both;
}

/* The reference never fully settles -- it keeps a slow breath on it. Held
   off until the last letter has landed. */
.pop-tag.is-armed.is-live {
  animation: pop-tag-breathe 3.6s ease-in-out
    calc(var(--pop-delay) + 900ms) infinite both;
}

@keyframes pop-tag-bubble {
  from {
    opacity: 0;
    transform: scale(.14) translateY(.06em);
  }
  60% { opacity: 1; }
  to {
    opacity: 1;
    transform: scale(1) translateY(0);
  }
}

@keyframes pop-tag-letter {
  from {
    opacity: 0;
    transform: rotate(var(--pop-rot, 0deg))
      translateY(var(--pop-shift, 0em)) scale(.08);
  }
  55% { opacity: 1; }
  to {
    opacity: 1;
    transform: rotate(var(--pop-rot, 0deg))
      translateY(var(--pop-shift, 0em)) scale(1);
  }
}

@keyframes pop-tag-breathe {
  0%, 100% { transform: rotate(var(--pop-tilt)) scale(1); }
  38% { transform: rotate(calc(var(--pop-tilt) + 1.1deg)) scale(1.013); }
  72% { transform: rotate(calc(var(--pop-tilt) - .7deg)) scale(.996); }
}

@media (prefers-reduced-motion: reduce) {
  .pop-tag.is-armed .pop-tag-bubble,
  .pop-tag.is-armed .pop-tag-letter {
    opacity: 1;
  }
  .pop-tag.is-armed.is-live,
  .pop-tag.is-armed.is-live .pop-tag-bubble,
  .pop-tag.is-armed.is-live .pop-tag-letter {
    animation: none;
  }
}

/* ---- Colourways ------------------------------------------------------- */

/* The house purple. These read --brand-deep from theme.css so the tag
   follows a re-skin instead of drifting away from it; the literal is the
   fallback for demos/pop-tag/, which loads this file without theme.css. */
.pop-tag--boom {
  --pop-fill-1: #e8e3f6;
  --pop-fill-2: #a096ce;
  --pop-fill-3: var(--brand-deep, #6158a6);
  --pop-dot: var(--brand-deep, #6158a6);
  --pop-dot-faint: rgba(97, 88, 166, .3);
}

.pop-tag--amber {
  --pop-fill-1: #ffe6a8;
  --pop-fill-2: #f0b821;
  --pop-fill-3: #c07a06;
  --pop-dot: #b8710a;
  --pop-dot-faint: rgba(184, 113, 10, .3);
}

.pop-tag--red {
  --pop-fill-1: #ffc3ad;
  --pop-fill-2: #d9524b;
  --pop-fill-3: #8f1d24;
  --pop-dot: #8f1d24;
  --pop-dot-faint: rgba(143, 29, 36, .3);
}

/* Reads on a dark panel: the bubble goes to ink and the outline to paper. */
.pop-tag--night {
  --pop-ink: #f4eefa;
  --pop-paper: #17111c;
  --pop-paper-shade: #0a070d;
  --pop-shadow: var(--brand-deep, #6158a6);
}
