/* ===================================================================
   FUN·da·Mental — THE SUBMIT EFFECT
   A drop-in kit. Copy this whole fx/ folder into any FUN·da·Mental site,
   add:

       <link rel="stylesheet" href="fx/convo-fx.css">
       <script src="fx/convo-fx.js"></script>

   ...and call fxVanish(cardElement) when something is submitted.
   Nothing here depends on the Grant Garden. See fx/README.md.
   =================================================================== */

.card-sparkles { position: absolute; inset: 0; pointer-events: none; z-index: 40; }
/* The burst is pinned OVER the card rather than living inside it, so the
   card's own overflow:hidden — which the vanish needs, to collapse its
   height — cannot guillotine the sparkles at its edges. Sparkles spilling
   past the edge is most of the effect. */
.card-sparkles.fx-over {
  position: fixed;
  inset: auto;
  z-index: 12000;
}
.cs-spark {
  position: absolute;
  width: 26px; height: 26px;
  opacity: 0;
  transform: rotate(var(--d)) scale(0);
  animation: sparkPop calc(var(--moment, 1450ms) * .82) cubic-bezier(.16,1,.3,1) forwards;
}
.cs-spark svg { width: 100%; height: 100%; display: block; }
.cs-spark svg path {
  fill: none;
  stroke: var(--c-gold, #C49538);
  stroke-width: 1.4;
  stroke-linejoin: round;
  paint-order: stroke;
}
.cs-spark:nth-child(3n)   svg path { stroke: var(--c-teal, #307878); }
.cs-spark:nth-child(4n+1) svg path { stroke: #78B329; }
.cs-spark:nth-child(5n+2) svg path { stroke: #7A4380; }
/* Deesil: "if you can have the stars stay on a little longer that'd be
   cute — just a little longer is kind of cute."
   The middle of the curve now HOLDS at full strength instead of already
   drifting away, which is what actually makes it feel unhurried. The
   rotation is small now too, since the stars lean rather than tumble. */
@keyframes sparkPop {
  0%   { opacity: 0;   transform: rotate(var(--d)) scale(0)   translateY(0); }
  18%  { opacity: 1;   transform: rotate(var(--d)) scale(calc(var(--sc) * 1.06)) translateY(-4px); }
  28%  { opacity: 1;   transform: rotate(var(--d)) scale(var(--sc)) translateY(-5px); }
  72%  { opacity: 1;   transform: rotate(calc(var(--d) + 6deg)) scale(var(--sc)) translateY(-9px); }
  86%  { opacity: .92; transform: rotate(calc(var(--d) + 9deg)) scale(var(--sc)) translateY(-16px); }
  100% { opacity: 0;   transform: rotate(calc(var(--d) + 14deg)) scale(calc(var(--sc) * .62)) translateY(-34px); }
}

/* The history drawer — a closed folder at the bottom of the desk.
   Open it when you want it; otherwise it stays out of the way. */
.convo-history-drawer {
  margin: 18px 0 4px;
  border-top: 1.5px dashed rgba(154,143,120,.55);
  padding-top: 12px;
}
.chd-toggle {
  width: 100%;
  min-height: 46px;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 12px;
  background: #F6F1E2;
  border: 1.5px solid #C9BFA8;
  border-radius: 4px 9px 4px 8px;
  cursor: pointer;
  font-family: 'Chalkduster', cursive;
  font-size: .78rem;
  letter-spacing: .02em;
  color: #5A5245;
  transform: rotate(-.25deg);
  box-shadow: 1.5px 2px 0 rgba(42,37,32,.10);
  transition: transform .16s ease, box-shadow .16s ease, background .16s ease;
}
.chd-toggle:hover { background: #FBF6E8; transform: rotate(0) translateY(-1px); }
.chd-toggle:focus-visible { outline: 2.5px solid var(--c-teal); outline-offset: 2px; }
.chd-label { flex: 1; text-align: left; }
.chd-count {
  /* a count is a figure — matches .stat-num in the page */
  font-family: 'Gaposiss', 'Avenir Next', system-ui, sans-serif;
  font-size: .7rem;
  background: #EAE2CD;
  border: 1px solid #C9BFA8;
  border-radius: 20px;
  padding: 1px 8px;
  color: #6A6252;
}
.chd-arrow { transition: transform .22s cubic-bezier(.16,1,.3,1); font-size: .8rem; }
.chd-toggle.chd-open .chd-arrow { transform: rotate(180deg); }
.chd-body { padding-top: 10px; }
.chd-copy {
  font-family: 'Chalkduster', cursive;
  font-size: .72rem;
  min-height: 40px;
  padding: 8px 14px;
  background: #FDFBF3;
  border: 1.5px solid #C9BFA8;
  border-radius: 3px 8px 3px 7px;
  cursor: pointer;
  color: #6A6252;
  transform: rotate(.3deg);
}
.chd-copy:hover { background: #F6F1E2; }
.chd-copy:focus-visible { outline: 2.5px solid var(--c-teal); outline-offset: 2px; }

/* When a note lands in it while it is shut, the folder nudges — so it is
   discoverable without ever demanding attention. */
.convo-history-drawer.drawer-pinged .chd-toggle {
  animation: drawerPing 1.4s cubic-bezier(.16,1,.3,1);
}
@keyframes drawerPing {
  0%, 100% { transform: rotate(-.25deg); box-shadow: 1.5px 2px 0 rgba(42,37,32,.10); }
  18%      { transform: rotate(-1.4deg) translateY(-3px); box-shadow: 2px 4px 0 rgba(196,149,56,.42); background: #FBF3DC; }
  46%      { transform: rotate(.9deg)  translateY(0);     box-shadow: 1.5px 2px 0 rgba(196,149,56,.3); }
}

/* ===================================================================
   THE DESIGN LAB — pickers that look like slips on a desk, not a form.
   Each option is a torn paper chip with a pencilled tick box; the chosen
   one is taped down. Deesil is choosing, so the choosing has to feel
   like part of the same handmade world.
   =================================================================== */
/* The card is about what is still OPEN, not what was settled.

   Deesil: "you shouldn't be showing any more flower options — the emoji
   options have been selected. We should be advancing the design, the
   aesthetic, the clarity, the questions."

   A picker that keeps re-offering a decision he already made is the
   conversation going in a circle. Decided things collapse to one line he
   can reopen; the two open questions get big buttons that say what they
   do and invite a tap. */
.fx-lab { margin-top: 6px; }
.fx-headline {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 3px 0 11px;
  padding: 9px 11px;
  background: linear-gradient(175deg, #FBF3DC, #F5EBCF);
  border: 2px solid var(--c-gold, #C49538);
  border-radius: 5px 13px 6px 11px;
  font-family: 'Chalkduster', cursive;
  font-size: .84rem;
  color: #3A3A3A;
  transform: rotate(-.3deg);
  box-shadow: 2px 3px 0 rgba(196,149,56,.24);
}
.fx-sub {
  font-size: .69rem;
  color: #7A7060;
  margin: 1px 0 5px;
  font-style: italic;
}
.cc-section-label em { font-style: normal; text-decoration: underline; text-underline-offset: 2px; }

/* the two open questions get proper, tappable buttons */
/* Compact. Deesil: "the card is getting very big — I would love to have it
   be more compact so I can actually see more, instead of this long card.
   Any of the extra white space or filler padding."

   The options were stacked in tall blocks with the note underneath, which
   made nine of them into a scroll. They sit two or three across now with
   the note beside the label rather than below it, so the whole choice fits
   in a glance instead of a scroll. */
.fx-row-big { gap: 7px; padding-top: 8px; }
.fx-row-big .fx-chip {
  flex: 1 1 148px;
  min-height: 62px;
  padding: 8px 9px 22px 25px;
  border-width: 2px;
  box-shadow: 1.5px 2.5px 0 rgba(42,37,32,.12);
}
.fx-row-big .fx-chip-label { font-size: .84rem; line-height: 1.15; }
.fx-row-big .fx-chip-note  { font-size: .63rem; line-height: 1.3; }
.fx-row-big .fx-tick { top: 9px; width: 15px; height: 15px; }
/* the invitation to press it */
.fx-chip-play {
  position: absolute;
  left: 25px; bottom: 6px;
  font-family: 'EmbossT1', 'SF Mono', monospace;
  font-size: .6rem;
  letter-spacing: .07em;
  color: #6A5418;   /* utility grey, no brand meaning — was under the 4.5 floor */
  background: #F1E7CC;
  border: 1px solid #D8C79A;
  border-radius: 3px;
  padding: 2px 7px;
  transition: background .15s, color .15s;
}
.fx-row-big .fx-chip:hover .fx-chip-play { background: var(--c-gold, #C49538); color: #FDFBF3; }
.fx-row-big .fx-chip.fx-on .fx-chip-play { background: #E4D3A2; }

/* everything already decided, folded away */
.fx-settled {
  margin-top: 13px;
  border-top: 1.5px dashed rgba(154,143,120,.5);
  padding-top: 12px;
}
.fx-settled summary {
  cursor: pointer;
  list-style: none;
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  min-height: 44px;
  padding: 8px 10px;
  font-family: 'Chalkduster', cursive;
  font-size: .76rem;
  color: #6A6252;
  background: #F6F1E2;
  border: 1.5px solid #D8CFB8;
  border-radius: 4px 9px 4px 8px;
  transform: rotate(.25deg);
}
.fx-settled summary::-webkit-details-marker { display: none; }
.fx-settled summary::after { content: '▾'; margin-left: auto; }
.fx-settled[open] summary::after { content: '▴'; }
.fx-settled summary:hover { background: #FBF6E8; }
.fx-settled summary:focus-visible { outline: 2.5px solid var(--c-gold); outline-offset: 2px; }
.fx-settled-peek {
  flex-basis: 100%;
  font-size: .64rem;
  color: #5F5A4E;   /* utility grey, no brand meaning — was under the 4.5 floor */
  font-family: 'Avenir Next', system-ui, sans-serif;
}
.fx-settled-body { padding-top: 10px; }

@media (pointer: coarse) {
  .fx-row-big .fx-chip { min-height: 68px; flex-basis: calc(50% - 4px); }
}

.fx-row {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 5px;
  padding-top: 7px;   /* headroom for the tape to sit on the edge */
}
.fx-chip {
  position: relative;
  flex: 1 1 132px;
  min-width: 118px;
  min-height: 44px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0;
  padding: 6px 8px 6px 24px;
  background: #FDFBF3;
  border: 1.5px solid #C9BFA8;
  border-radius: 3px 8px 4px 7px;
  cursor: pointer;
  text-align: left;
  font-family: inherit;
  color: var(--c-ink, #2B2520);
  box-shadow: 1px 1.5px 0 rgba(42,37,32,.10);
  transform: rotate(-.35deg);
  transition: transform .16s ease, box-shadow .16s ease, background .16s ease;
}
.fx-chip:nth-child(even) { transform: rotate(.4deg); }
.fx-chip:hover  { transform: rotate(0deg) translateY(-1px); box-shadow: 1.5px 2.5px 0 rgba(42,37,32,.16); }
.fx-chip:active { transform: rotate(0deg) translateY(1px); box-shadow: 0 0 0 rgba(42,37,32,0); }
.fx-chip:focus-visible { outline: 2.5px solid var(--c-gold); outline-offset: 2px; }

/* the pencilled tick box */
.fx-tick {
  position: absolute;
  left: 7px; top: 9px;
  transform: rotate(-2deg);
  width: 14px; height: 14px;
  border: 1.6px solid #9A8F78;
  border-radius: 2px 3px 2px 4px;
  display: flex; align-items: center; justify-content: center;
  font-family: 'Chalkduster', cursive;
  font-size: .7rem;
  line-height: 1;
  color: #4A7A3A;
}
.fx-chip-label {
  font-family: 'Chalkduster', cursive;
  font-size: .78rem;
  line-height: 1.2;
}
.fx-chip-note {
  font-size: .66rem;
  line-height: 1.35;
  color: #615A4C;   /* utility grey, no brand meaning — was under the 4.5 floor */
}
/* the chosen one is taped down and reads warmer */
.fx-chip.fx-on {
  background: #FBF3DC;
  border-color: var(--c-gold);
  box-shadow: 1.5px 2.5px 0 rgba(196,149,56,.28);
}
.fx-chip.fx-on .fx-tick { border-color: #4A7A3A; background: #EAF3E2; }
/* WASHI TAPE — four patterns, all in shades of the gold.

   Deesil: "it's too small, and it's repeating exactly perfect on the
    other ones. It needs variety, slightly bigger and cute, and
    potentially become washi — striped, or a pattern of different shades
    of whatever colour we're selecting."

   The width, height, angle and offset come from washiVars() in the JS,
   derived from each chip's own name — so no two tabs match, and each one
   keeps the same tape every time rather than jittering on re-render.
   The stripes are here: four patterns, each built from two or three
   tones of the same gold so it reads as one roll of tape rather than
   four different colours. Semi-transparent, because washi is. */
/* The tape hugs the top EDGE rather than sitting on the words.

   Deesil: "I'm not a huge fan of the fact that you have the washy tape
   overlapping the text — it needs to be more off the text, but still hugging
   the edge of the selected box."

   It was two-thirds onto the chip, which put it straight through the label.
   Now only its bottom sliver touches the border, so it still reads as
   holding the chip down without sitting on anything you have to read. */
.fx-chip.fx-on::after {
  content: '';
  position: absolute;
  top: var(--tape-top, -13px);
  left: var(--tape-x, 30%);
  width: var(--tape-w, 54px);
  height: var(--tape-h, 18px);
  transform: rotate(var(--tape-rot, -4deg));
  border-radius: 1px;
  /* the torn ends, and the soft shadow of something laid on top */
  box-shadow: 0 1px 2px rgba(42,37,32,.14);
  opacity: .92;
  pointer-events: none;
  /* torn ends rather than scissor-straight ones */
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 2px, #000 calc(100% - 2px), transparent 100%);
          mask-image: linear-gradient(90deg, transparent 0, #000 2px, #000 calc(100% - 2px), transparent 100%);
}

/* 0 — diagonal stripes */
.fx-chip.washi-0.fx-on::after {
  background:
    repeating-linear-gradient(58deg,
      rgba(196,149,56,.46) 0 5px,
      rgba(212,165,72,.24) 5px 10px);
}
/* 1 — fine pinstripes */
.fx-chip.washi-1.fx-on::after {
  background:
    repeating-linear-gradient(90deg,
      rgba(196,149,56,.42) 0 2px,
      rgba(228,196,124,.2) 2px 6px);
}
/* 2 — dots on a wash */
.fx-chip.washi-2.fx-on::after {
  background:
    radial-gradient(rgba(160,118,36,.4) 1.4px, transparent 1.6px) 0 0 / 8px 8px,
    linear-gradient(180deg, rgba(212,165,72,.34), rgba(196,149,56,.26));
}
/* 3 — a plain wash with a torn grain along it */
.fx-chip.washi-3.fx-on::after {
  background:
    linear-gradient(172deg,
      rgba(228,196,124,.34) 0%,
      rgba(196,149,56,.4) 46%,
      rgba(212,165,72,.28) 100%);
}

.fx-preview-wrap { margin-top: 11px; text-align: center; }
.fx-preview-btn {
  font-family: 'Chalkduster', cursive;
  font-size: .8rem;
  padding: 9px 16px;
  min-height: 44px;
  background: #FDFBF3;
  color: var(--c-ink, #2B2520);
  border: 2px solid #8A7028;
  border-radius: 4px 10px 5px 9px;
  box-shadow: 2px 3px 0 rgba(138,112,40,.35);
  cursor: pointer;
  transform: rotate(-.5deg);
  transition: transform .14s ease, box-shadow .14s ease;
}
.fx-preview-btn:hover  { transform: rotate(0) translateY(-1px); box-shadow: 2.5px 4px 0 rgba(138,112,40,.4); }
.fx-preview-btn:active { transform: rotate(0) translateY(2px); box-shadow: 0 1px 0 rgba(138,112,40,.35); }
.fx-preview-btn:focus-visible { outline: 2.5px solid var(--c-gold); outline-offset: 3px; }
.fx-loop-btn { margin-left: 8px; }
.fx-loop-btn.fx-looping {
  background: #FBF3DC;
  border-color: var(--c-gold, #C49538);
  box-shadow: 2px 3px 0 rgba(196,149,56,.4);
  animation: loopPulse 1.6s ease-in-out infinite;
}
@keyframes loopPulse {
  0%, 100% { box-shadow: 2px 3px 0 rgba(196,149,56,.4); }
  50%      { box-shadow: 2px 3px 0 rgba(196,149,56,.75); }
}
@media (prefers-reduced-motion: reduce) {
  .fx-loop-btn.fx-looping { animation: none; }
}
.fx-hint { font-size: .66rem; color: #7A7060; margin-top: 5px; }

@media (pointer: coarse) {
  .fx-chip { min-height: 52px; flex-basis: 100%; }
  .fx-preview-btn { min-height: 48px; width: 100%; }
  .fx-loop-btn { margin-left: 0; margin-top: 8px; }
}

/* Every sparkle runs as a fraction of --moment, which is set from the
   real length of the chosen sound. Deesil: "we want to make sure it lasts
   as long as the sound effect, so it's not longer than the sound effect."
   Pick a different sound and the whole thing retimes itself. */

/* ============================================================
   FOUR WAYS THE STARS CAN ARRIVE
   ------------------------------------------------------------
   Deesil: "different effects of the revealing of the stars…
   give me a few options in that direction that give different
   varieties so I can choose one that I like."

   Same stars, same positions, same gold. Only the manner of
   arriving changes — which turns out to be most of what makes
   an effect feel like one thing rather than another.
   ============================================================ */

/* POP — springs in and turns as it goes. The original. */
/* (uses sparkPop / foamProp as defined below — no override needed) */

/* DRIFT — fades in gently and floats up. Slower, softer, dreamier. */
.card-sparkles.rv-drift .cs-star,
.card-sparkles.rv-drift .cs-spark:not(.cs-foam) {
  animation: sparkDrift calc(var(--moment, 1450ms) * 1.02) cubic-bezier(.22,.61,.36,1) forwards;
}
.card-sparkles.rv-drift .cs-foam {
  animation: foamDrift calc(var(--moment, 1450ms) * 1.08) cubic-bezier(.22,.61,.36,1) forwards;
}
@keyframes sparkDrift {
  0%   { opacity: 0;   transform: rotate(var(--d)) scale(.72) translateY(14px); }
  26%  { opacity: .95; transform: rotate(var(--d)) scale(1)   translateY(2px); }
  100% { opacity: 0;   transform: rotate(calc(var(--d) + 22deg)) scale(1.06) translateY(-52px); }
}
@keyframes foamDrift {
  0%   { opacity: 0;   transform: rotate(var(--d)) scale(.7)  translateY(16px); }
  24%  { opacity: 1;   transform: rotate(var(--d)) scale(1.02) translateY(2px); }
  100% { opacity: 0;   transform: rotate(calc(var(--d) * 1.4)) scale(1.1) translateY(-58px); }
}

/* FLASH — snaps in at full size all at once, then goes. Sharp and quick. */
.card-sparkles.rv-flash .cs-star,
.card-sparkles.rv-flash .cs-spark:not(.cs-foam) {
  animation: sparkFlash calc(var(--moment, 1450ms) * .68) cubic-bezier(.16,1,.3,1) forwards;
}
.card-sparkles.rv-flash .cs-foam {
  animation: sparkFlash calc(var(--moment, 1450ms) * .74) cubic-bezier(.16,1,.3,1) forwards;
}
@keyframes sparkFlash {
  0%   { opacity: 0; transform: rotate(var(--d)) scale(1.14); }
  9%   { opacity: 1; transform: rotate(var(--d)) scale(1); }
  55%  { opacity: 1; transform: rotate(var(--d)) scale(1); }
  100% { opacity: 0; transform: rotate(var(--d)) scale(.9); }
}

/* CASCADE — one after another in a run, like a sparkler catching.
   The sequencing is in the JS delays; this just gives each one a
   quicker, tighter arc so the run reads as a run. */
.card-sparkles.rv-cascade .cs-star,
.card-sparkles.rv-cascade .cs-spark:not(.cs-foam) {
  animation: sparkCascade calc(var(--moment, 1450ms) * .72) cubic-bezier(.16,1.3,.3,1) forwards;
}
.card-sparkles.rv-cascade .cs-foam {
  animation: sparkCascade calc(var(--moment, 1450ms) * .78) cubic-bezier(.16,1.3,.3,1) forwards;
}
@keyframes sparkCascade {
  0%   { opacity: 0;  transform: rotate(var(--d)) scale(0) translateY(6px); }
  18%  { opacity: 1;  transform: rotate(var(--d)) scale(1.15) translateY(-2px); }
  32%  { opacity: 1;  transform: rotate(var(--d)) scale(.98) translateY(0); }
  100% { opacity: 0;  transform: rotate(calc(var(--d) + 50deg)) scale(.55) translateY(-26px); }
}

@media (prefers-reduced-motion: reduce) {
  .card-sparkles[class*="rv-"] .cs-star,
  .card-sparkles[class*="rv-"] .cs-spark,
  .card-sparkles[class*="rv-"] .cs-foam { animation: none; opacity: 0; }
}

/* Foam stickers are PROPS, not drawings, so they move like objects.

   Deesil: "the foam emoji stickers are more like propped pieces — they
    fade in, expand large, different sizes, kind of appear and then jump
    in and out, slightly move in and out, and fade out with the effect."

   Which is exactly why they must not boil. A pencil star is redrawn
   every frame because a hand redrew it. A foam sticker is one physical
   thing somebody placed on the page — so it lands with a little
   overshoot, breathes, and lifts away. Same burst, different physics. */
.cs-spark.cs-foam {
  font-size: 20px;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  transform: rotate(var(--d)) scale(0);
  animation: foamProp calc(var(--moment, 1450ms) * .95) cubic-bezier(.16,1,.3,1) forwards;
  filter:
    drop-shadow(1.5px 0 0 #fff) drop-shadow(-1.5px 0 0 #fff)
    drop-shadow(0 1.5px 0 #fff) drop-shadow(0 -1.5px 0 #fff)
    drop-shadow(0 2px 3px rgba(42,37,32,.25));
}
@keyframes foamProp {
  0%   { opacity: 0;   transform: rotate(var(--d)) scale(.25) translateY(7px); }
  10%  { opacity: 1;   transform: rotate(var(--d)) scale(1.18) translateY(-2px); }   /* lands, overshoots */
  17%  { opacity: 1;   transform: rotate(var(--d)) scale(.96)  translateY(0); }      /* settles */
  38%  { opacity: 1;   transform: rotate(calc(var(--d) * 1.25)) scale(1.06) translateY(-4px); }
  74%  { opacity: 1;   transform: rotate(calc(var(--d) * .8))   scale(1.02) translateY(-2px); }  /* holds */
  88%  { opacity: .95; transform: rotate(calc(var(--d) * 1.1))  scale(1.06) translateY(-7px); }
  100% { opacity: 0;   transform: rotate(calc(var(--d) * 1.5))  scale(1.26) translateY(-28px); }
}

/* The whole card lifts, brightens and goes — rather than greying out.
   Height collapses separately so the cards below slide up into the gap. */
/* ============================================================
   THE GLITTER LEAVES UPWARD, AND CLEARS FROM BELOW
   ------------------------------------------------------------
   "As it transitions out you can have it drift up and fade from
   bottom to top — because the cards are moving up from below.
   Fade the lower emojis first and then slightly move up, where
   the fade is kind of like a white fade. So it plays with the
   visualisation of the cards moving up."

   The whole frame is travelling upward: the card leaves upward,
   the cards below rise into the gap. So the glitter goes the
   same way and clears from the bottom first, as if the rising
   deck is wiping it away rather than passing underneath it.

   --low is 0 at the top of the burst and 1 at the bottom, so a
   piece low in the frame gets a shorter life and goes first.
   The fade runs through white rather than straight to nothing,
   which is what makes it read as a sparkle dying instead of an
   element having its opacity turned down.
   ============================================================ */
.card-sparkles.go-drift-up .cs-star,
.card-sparkles.go-drift-up .cs-spark,
.card-sparkles.go-drift-soft .cs-star,
.card-sparkles.go-drift-soft .cs-spark {
  /* lower pieces finish sooner — the bottom-first clear */
  animation-duration: calc(var(--moment, 1450ms) * (0.92 - 0.34 * var(--low, .5)));
  animation-fill-mode: forwards;
}
.card-sparkles.go-drift-soft .cs-star,
.card-sparkles.go-drift-soft .cs-spark {
  animation-duration: calc(var(--moment, 1450ms) * (1.18 - 0.3 * var(--low, .5)));
  animation-timing-function: cubic-bezier(.22,.7,.3,1);
}
.card-sparkles.go-lift-fast .cs-star,
.card-sparkles.go-lift-fast .cs-spark {
  animation-duration: calc(var(--moment, 1450ms) * (0.66 - 0.26 * var(--low, .5)));
}

/* the drift itself — everything ends higher than it began, and the
   further down it started the further it travels to clear the frame */
.card-sparkles.go-drift-up .cs-star,
.card-sparkles.go-drift-soft .cs-star,
.card-sparkles.go-lift-fast .cs-star {
  animation-name: sparkRiseOut;
}
.card-sparkles.go-drift-up .cs-foam,
.card-sparkles.go-drift-soft .cs-foam,
.card-sparkles.go-lift-fast .cs-foam {
  animation-name: foamRiseOut;
}
@keyframes sparkRiseOut {
  0%   { opacity: 0; transform: rotate(var(--d)) scale(0) translateY(0); filter: none; }
  16%  { opacity: 1; transform: rotate(var(--d)) scale(calc(var(--sc) * 1.05)) translateY(-3px); }
  26%  { opacity: 1; transform: rotate(var(--d)) scale(var(--sc)) translateY(-5px); }
  58%  { opacity: 1; transform: rotate(calc(var(--d) + 5deg)) scale(var(--sc)) translateY(-14px); }
  /* the white fade — it brightens out rather than dimming away */
  /* The white fade is a whisper, not a blow-out. It only touches the last
     fifth, and it lifts the star barely — enough to read as a sparkle
     going out rather than a shape being dimmed, without losing the gold. */
  86%  { opacity: .5;  transform: rotate(calc(var(--d) + 8deg)) scale(calc(var(--sc) * 1.02)) translateY(calc(-30px - 26px * var(--low, .5)));
         filter: brightness(1.08); }
  100% { opacity: 0;  transform: rotate(calc(var(--d) + 11deg)) scale(calc(var(--sc) * .9)) translateY(calc(-48px - 44px * var(--low, .5)));
         filter: brightness(1.16); }
}
@keyframes foamRiseOut {
  0%   { opacity: 0; transform: rotate(var(--d)) scale(.25) translateY(7px); }
  11%  { opacity: 1; transform: rotate(var(--d)) scale(1.16) translateY(-2px); }
  19%  { opacity: 1; transform: rotate(var(--d)) scale(.97) translateY(0); }
  56%  { opacity: 1; transform: rotate(calc(var(--d) * 1.15)) scale(1.03) translateY(-10px); }
  84%  { opacity: .55; transform: rotate(calc(var(--d) * .9)) scale(1.06) translateY(calc(-26px - 24px * var(--low, .5))); }
  100% { opacity: 0;   transform: rotate(calc(var(--d) * 1.3)) scale(1.02) translateY(calc(-44px - 40px * var(--low, .5))); }
}

/* ============================================================
   THE RIPPLE — cards react before they move
   ------------------------------------------------------------
   "The card goes away and the cards below it kind of move out of
   the way a little bit, they adjust slightly, and then they get
   moved up… it's this cool little ripple effect, like the cards
   are slightly affected by its submission."

   The GIVE before the move is the whole trick. Cards that only
   slide up read as a list re-laying itself out. Cards that flinch
   first read as objects on a desk that felt something happen.
   Each one further down is a beat later, so it travels.
   ============================================================ */

/* SETTLE — a card just left. They dip, hang for a moment, and rise. */
.conv-card.card-settle,
.fx-card.card-settle {
  /* "the animation of them moving down needs to be more clean and smooth —
     it's too fast for the behaviour of the other cards." The multiplier is
     his choice; the curve is gentler at both ends so it eases rather than
     snaps. */
  animation: rippleSettle calc(var(--moment, 1450ms) * .62 * var(--ripple-mult, 1.55))
             cubic-bezier(.33,.06,.27,1) both;
}
@keyframes rippleSettle {
  0%   { transform: translateY(0) rotate(0deg); }
  22%  { transform: translateY(calc(5px * var(--ripple-depth, 1))) rotate(calc(.5deg * var(--ripple-depth, 1))); }
  46%  { transform: translateY(calc(3px * var(--ripple-depth, 1))) rotate(calc(-.3deg * var(--ripple-depth, 1))); }
  72%  { transform: translateY(calc(-2px * var(--ripple-depth, 1))) rotate(calc(.2deg * var(--ripple-depth, 1))); }
  100% { transform: translateY(0) rotate(0deg); }
}

/* RUMBLE — one is on its way. They shiver and open a space for it. */
.conv-card.card-rumble,
.fx-card.card-rumble {
  animation: rippleRumble calc(var(--moment, 1770ms) * .62 * var(--ripple-mult, 1.55))
             cubic-bezier(.33,.06,.27,1) both;
}
@keyframes rippleRumble {
  0%   { transform: translateY(0) rotate(0deg); }
  16%  { transform: translateY(calc(-2px * var(--ripple-depth, 1))) rotate(calc(-.4deg * var(--ripple-depth, 1))); }
  34%  { transform: translateY(calc(2px * var(--ripple-depth, 1)))  rotate(calc(.45deg * var(--ripple-depth, 1))); }
  52%  { transform: translateY(calc(6px * var(--ripple-depth, 1)))  rotate(calc(-.2deg * var(--ripple-depth, 1))); }
  76%  { transform: translateY(calc(3px * var(--ripple-depth, 1)))  rotate(0deg); }
  100% { transform: translateY(0) rotate(0deg); }
}

@media (prefers-reduced-motion: reduce) {
  .conv-card.card-settle, .conv-card.card-rumble,
  .fx-card.card-settle,   .fx-card.card-rumble { animation: none; }
}

/* THE FIRST TWO BEATS — anticipation, then being lit up.

   A pile of simultaneous things is a blur, not a moment. The card draws
   breath first, so you know something is coming; then the sparkles land
   ON it and it brightens, so it reads as being acted upon rather than
   merely covered by an overlay. Only after that does it leave. */
.conv-card.card-charging,
.fx-card.card-charging {
  animation: cardCharge calc(var(--moment, 1450ms) * .14) cubic-bezier(.4,0,.6,1) forwards;
}
@keyframes cardCharge {
  0%   { transform: scale(1); }
  100% { transform: scale(.982) translateY(1px); }   /* the breath in */
}
.conv-card.card-lit,
.fx-card.card-lit {
  animation: cardLit calc(var(--moment, 1450ms) * .24) cubic-bezier(.16,1.2,.3,1) forwards;
}
@keyframes cardLit {
  0%   { transform: scale(.982) translateY(1px); filter: brightness(1); }
  35%  { transform: scale(1.014) translateY(-2px); filter: brightness(1.09) saturate(1.06); }
  100% { transform: scale(1.004) translateY(-1px); filter: brightness(1.03); }
}

/* ============================================================
   THREE WAYS THE CARD LEAVES
   ------------------------------------------------------------
   Deesil: "I would love the effect of it going away to be a bit
   more smooth and kind of magical, and not quick — it shows the
   glitter, and then the card starts to glide away, and it sends
   off."

   The old one started leaving the instant the sparkles fired, so
   the two fought each other and the whole thing read as rushed.
   All three of these HOLD for the first third — glitter first,
   card still — and only then move. That pause is most of what
   makes it feel magical rather than fast.
   ============================================================ */
.fx-card.card-vanishing,
.conv-card.card-vanishing {
  pointer-events: none;
  overflow: hidden;
}

/* GLIDE — his own description. Settles, slides off to the side and
   lifts, the way a note is swept off a desk. */
.card-vanishing.exit-glide {
  animation: exitGlide calc(var(--moment, 1450ms) * .64) cubic-bezier(.36,0,.2,1) forwards;
}
@keyframes exitGlide {
  0%   { opacity: 1; transform: translate(0,0) rotate(0deg) scale(1); }
  30%  { opacity: 1; transform: translate(0,2px) rotate(-.6deg) scale(.995); }   /* holds while the glitter lands */
  48%  { opacity: 1; transform: translate(14px,-6px) rotate(1.2deg) scale(1.005); }
  100% { opacity: 0; transform: translate(120px,-46px) rotate(7deg) scale(.9); }
}

/* DISSOLVE — stays put and fades through its own sparkles. Softest. */
.card-vanishing.exit-dissolve {
  animation: exitDissolve calc(var(--moment, 1450ms) * .64) cubic-bezier(.4,0,.5,1) forwards;
}
@keyframes exitDissolve {
  0%   { opacity: 1;   filter: blur(0);     transform: scale(1); }
  32%  { opacity: 1;   filter: blur(0);     transform: scale(1); }
  60%  { opacity: .62; filter: blur(1.4px); transform: scale(1.012); }
  100% { opacity: 0;   filter: blur(5px);   transform: scale(1.04); }
}

/* ZOOM OFF — his own description, and now the default.

   "The sending one is like a ding ding ding... slowing down the sending
    off, kind of like the card zooming into the internet, kind of a thing.
    I don't know if that makes sense — it's just thinking of fun ways to
    describe it."

   It makes sense. A thing being SENT should get smaller and further away,
   not merely disappear. So it pulls back into the distance, gathering a
   little blur as it goes the way something does when it outruns your eye,
   and tilts as it recedes so you read depth rather than just shrinking. */
.card-vanishing.exit-zoom {
  animation: exitZoom calc(var(--moment, 1450ms) * .64) cubic-bezier(.5,0,.3,1) forwards;
  transform-origin: 50% 40%;
}
@keyframes exitZoom {
  0%   { opacity: 1; filter: blur(0);   transform: scale(1) translateY(0) rotate(0deg); }
  22%  { opacity: 1; filter: blur(0);   transform: scale(1.035) translateY(2px) rotate(-.3deg); }  /* leans in first */
  40%  { opacity: 1; filter: blur(.3px); transform: scale(.86) translateY(-6px) rotate(.6deg); }
  100% { opacity: 0; filter: blur(3.5px); transform: scale(.16) translateY(-34px) rotate(3deg); }
}

/* FOLD AWAY — folds flat, like paper going back into a drawer. */
.card-vanishing.exit-fold {
  animation: exitFold calc(var(--moment, 1450ms) * .64) cubic-bezier(.5,0,.28,1) forwards;
  transform-origin: 50% 50%;
}
@keyframes exitFold {
  0%   { opacity: 1; transform: perspective(900px) rotateX(0deg) scaleY(1); }
  24%  { opacity: 1; transform: perspective(900px) rotateX(-4deg) scaleY(1.01); }   /* lifts its edge */
  100% { opacity: 0; transform: perspective(900px) rotateX(78deg) scaleY(.35) translateY(-14px); }
}

/* LIFT OFF — sinks a touch, then rises and shrinks, as if carried up. */
.card-vanishing.exit-liftoff {
  animation: exitLiftoff calc(var(--moment, 1450ms) * .64) cubic-bezier(.34,0,.16,1) forwards;
}
@keyframes exitLiftoff {
  0%   { opacity: 1; transform: translateY(0) scale(1) rotate(0deg); }
  30%  { opacity: 1; transform: translateY(5px) scale(.992) rotate(-.4deg); }   /* gathers itself */
  46%  { opacity: 1; transform: translateY(-8px) scale(1.008) rotate(.5deg); }
  100% { opacity: 0; transform: translateY(-96px) scale(.7) rotate(2deg); }
}
.fx-card.card-collapsing,
.conv-card.card-collapsing {
  height: 0 !important;
  margin-top: 0;
  margin-bottom: 0;
  padding-top: 0;
  padding-bottom: 0;
  /* slower, and it starts only after the exit is under way — the cards
     below sliding up while the card is still sitting there was part of
     what made the whole thing feel hurried */
  /* rides the same clock as everything else, so the gap finishes closing
     as the last note of the sound lands rather than seconds afterwards */
  transition: height calc(var(--moment, 1450ms) * .46) cubic-bezier(.45,0,.3,1),
              margin calc(var(--moment, 1450ms) * .46) cubic-bezier(.45,0,.3,1),
              padding calc(var(--moment, 1450ms) * .46) cubic-bezier(.45,0,.3,1);
}

/* ============================================================
   FOUR WAYS A CARD FLIES IN
   ------------------------------------------------------------
   Deesil: "I really want to see the card flying in and flying
   out effect. What's the option for flying in with the glitter
   and what's the option for flying out with the glitter — the
   stars and the sparkles? Can you give me three or so varieties
   that I can select the best option?"

   Arriving had exactly one behaviour, which made it the poorer
   half of the pair. These mirror the exits, and all four run
   inside --moment so they finish with their own sound.
   ============================================================ */
.fx-card.card-arriving,
.conv-card.card-arriving {
  animation: cardArrive calc(var(--moment, 1770ms) * .7) cubic-bezier(.16,1,.3,1);
}

/* ZOOM IN — the mirror of Zoom off. Races in from far away and settles. */
.card-arriving.entry-zoomin {
  animation: entryZoomIn calc(var(--moment, 1770ms) * .7) cubic-bezier(.2,.9,.24,1);
  transform-origin: 50% 40%;
}
@keyframes entryZoomIn {
  0%   { opacity: 0; filter: blur(4px);   transform: scale(.14) translateY(-30px) rotate(-3deg); }
  46%  { opacity: 1; filter: blur(.4px);  transform: scale(1.05) translateY(4px) rotate(.8deg); }
  70%  { opacity: 1; filter: blur(0);     transform: scale(.985) translateY(-1px) rotate(-.3deg); }
  100% { opacity: 1; filter: blur(0);     transform: scale(1) translateY(0) rotate(0deg); }
}

/* UNFOLD — opens out of the sparkles like paper being laid down. */
.card-arriving.entry-unfold {
  animation: entryUnfold calc(var(--moment, 1770ms) * .74) cubic-bezier(.2,.9,.24,1);
  transform-origin: 50% 0%;
}
@keyframes entryUnfold {
  0%   { opacity: 0; transform: perspective(950px) rotateX(-72deg) scaleY(.4); }
  40%  { opacity: 1; transform: perspective(950px) rotateX(9deg)  scaleY(1.03); }
  68%  { opacity: 1; transform: perspective(950px) rotateX(-3deg) scaleY(.995); }
  100% { opacity: 1; transform: perspective(950px) rotateX(0deg)  scaleY(1); }
}

/* SWOOP IN — flies in from the side, overshoots, rocks into place. */
.card-arriving.entry-swoop {
  animation: entrySwoop calc(var(--moment, 1770ms) * .78) cubic-bezier(.18,.92,.22,1);
}
@keyframes entrySwoop {
  0%   { opacity: 0; transform: translate(-130px, 34px) rotate(-9deg) scale(.86); }
  44%  { opacity: 1; transform: translate(12px, -6px) rotate(2.4deg) scale(1.03); }
  66%  { opacity: 1; transform: translate(-4px, 2px) rotate(-1deg) scale(.995); }
  84%  { opacity: 1; transform: translate(1px, 0) rotate(.4deg) scale(1.002); }
  100% { opacity: 1; transform: translate(0,0) rotate(0deg) scale(1); }
}

/* DEVELOP — fades up out of the glitter, the softest of the four. */
.card-arriving.entry-develop {
  animation: entryDevelop calc(var(--moment, 1770ms) * .8) cubic-bezier(.32,.72,.3,1);
}
@keyframes entryDevelop {
  0%   { opacity: 0;   filter: blur(6px) brightness(1.3); transform: scale(1.04); }
  38%  { opacity: .55; filter: blur(2.4px) brightness(1.14); transform: scale(1.015); }
  100% { opacity: 1;   filter: blur(0) brightness(1); transform: scale(1); }
}
@keyframes cardArrive {
  0%   { opacity: 0; transform: scale(.93) translateY(18px) rotate(1.4deg); }
  45%  { opacity: 1; transform: scale(1.015) translateY(-3px) rotate(-.5deg); }
  100% { opacity: 1; transform: scale(1) translateY(0) rotate(-.25deg); }
}
@keyframes cardVanish {
  0%   { opacity: 1; transform: scale(1)    rotate(-.25deg); filter: brightness(1); }
  25%  { opacity: 1; transform: scale(1.02) rotate(.6deg);   filter: brightness(1.09); }
  100% { opacity: 0; transform: scale(.9)   rotate(-2.5deg) translateY(-26px); filter: brightness(1.2); }
}

/* the history drawer nudges to say the note landed in there */
.convo-history-drawer.drawer-pinged .ch-toggle {
  animation: drawerPing 1.5s cubic-bezier(.16,1,.3,1);
}

/* A note being filed. The slip lifts off the card, tilts like paper
   being set down, then travels up toward the history. */
.filed-slip {
  position: absolute;
  right: 18px;
  bottom: 46px;
  z-index: 30;
  pointer-events: none;
  font-family: 'Chalkduster', cursive;
  font-size: .74rem;
  color: #3C7A2A;
  background: linear-gradient(178deg, #FDFBF3, #EFF7E4);
  border: 2px solid rgba(120,179,41,.5);
  border-radius: 3px;
  padding: 6px 12px;
  box-shadow: 0 1px 0 rgba(255,255,255,.9) inset, 0 4px 10px rgba(42,37,32,.2);
  transform: rotate(-2deg);
  opacity: 0;
  animation: slipAppear .28s cubic-bezier(.16,1.5,.3,1) forwards;
}
.filed-slip .fs-emoji { margin-right: 3px; }
@keyframes slipAppear {
  from { opacity: 0; transform: translateY(8px) rotate(-6deg) scale(.9); }
  to   { opacity: 1; transform: translateY(0)  rotate(-2deg) scale(1); }
}
.filed-slip.flying {
  animation: slipFly .62s cubic-bezier(.5,-0.2,.7,1) forwards;
}
@keyframes slipFly {
  0%   { opacity: 1; transform: translateY(0) rotate(-2deg) scale(1); }
  35%  { opacity: 1; transform: translateY(-26px) rotate(5deg) scale(1.04); }
  100% { opacity: 0; transform: translateY(-190px) rotate(-11deg) scale(.55); }
}
/* the card gives a small nod as the note leaves it */
.fx-card.just-filed,
.conv-card.just-filed { animation: cardNod .7s cubic-bezier(.16,1,.3,1); }
@keyframes cardNod {
  0%   { transform: rotate(-.25deg) translateY(0); }
  30%  { transform: rotate(-.25deg) translateY(3px); }
  100% { transform: rotate(-.25deg) translateY(0); }
}
/* the new history entry arrives */
.convo-history .ch-entry.ch-landed {
  animation: entryLand 1.3s cubic-bezier(.16,1,.3,1);
}
@keyframes entryLand {
  0%   { transform: scale(.94) translateY(-10px); box-shadow: 0 6px 18px rgba(120,179,41,.4); border-left-color: #78B329; }
  40%  { transform: scale(1.01) translateY(0);   box-shadow: 0 3px 12px rgba(120,179,41,.3); border-left-color: #78B329; }
  100% { transform: scale(1) translateY(0); }
}
@media (prefers-reduced-motion: reduce) {
  .filed-slip, .filed-slip.flying,
  .fx-card.just-filed, .conv-card.just-filed,
  .convo-history .ch-entry.ch-landed,
  .cs-spark, .cs-star, .cs-foam,
  .card-sparkles[class*="go-"] .cs-star, .card-sparkles[class*="go-"] .cs-spark,
  .fx-card.card-vanishing,  .conv-card.card-vanishing,
  .card-vanishing.exit-glide, .card-vanishing.exit-dissolve, .card-vanishing.exit-liftoff,
  .card-vanishing.exit-zoom, .card-vanishing.exit-fold,
  .conv-card.card-charging, .conv-card.card-lit,
  .fx-card.card-charging, .fx-card.card-lit,
  .fx-card.card-arriving,   .conv-card.card-arriving,
  .card-arriving.entry-zoomin, .card-arriving.entry-unfold,
  .card-arriving.entry-swoop,  .card-arriving.entry-develop,
  .convo-history-drawer.drawer-pinged .chd-toggle { animation: none; }
  .cs-spark, .cs-star { opacity: 0; }
  .cs-star i { animation: none; }
  .fx-card.card-collapsing, .conv-card.card-collapsing { transition: none; }
  .filed-slip { opacity: 1; }
}

/* A cut-out star, and its boil.

   Three different drawings are stacked inside each star and shown one at
   a time on a steps(1) cycle, so the shape is genuinely being redrawn as
   you watch rather than scaled. That flicker between drawings is the
   whole difference between hand-drawn animation and a moving sticker —
   and it is why steps() matters here: any easing between the frames
   would smooth away the redraw and give the trick up. */
.cs-star {
  position: absolute;
  pointer-events: none;
  opacity: 0;
  transform: rotate(var(--d)) scale(0);
  animation: sparkPop calc(var(--moment, 1450ms) * .82) cubic-bezier(.16,1,.3,1) forwards;
  will-change: transform, opacity;
}
.cs-star i {
  position: absolute;
  inset: 0;
  background-repeat: no-repeat;
  background-position: center;
  background-size: contain;
  opacity: 0;
  animation-name: starBoil;
  animation-timing-function: steps(1, end);
  animation-iteration-count: infinite;
}
@keyframes starBoil {
  0%, 33.2%  { opacity: 1; }
  33.3%, 100% { opacity: 0; }
}

/* ============================================================
   ITEM M — SIX IDEAS OF WHAT PROGRESS LOOKS LIKE
   ------------------------------------------------------------
   Deesil has rejected the growth bar three times, and told me
   why another attempt is the wrong answer: "show me your best
   four to six cute options in a convo card, with a feedback
   field under each option so I can say what I like about each."

   And the reason underneath it: "the progress bar should feel
   like a kid's game — that's why he keeps rejecting it. It isn't
   fun, cute or exciting."

   So these are not six shades of one bar. Each is a different
   idea of what progress even IS. All render at 3 of 6 so they
   can be compared honestly.
   ============================================================ */
.gb-lab { margin-top: 6px; }
.gb-opt {
  margin-bottom: 14px;
  padding: 11px 12px 10px;
  background: #FDFBF3;
  border: 2px solid #D8CFB8;
  border-radius: 4px 12px 5px 10px;
  box-shadow: 1.5px 2.5px 0 rgba(42,37,32,.1);
  transform: rotate(-.2deg);
}
.gb-opt:nth-child(even) { transform: rotate(.25deg); }
.gb-opt-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 9px; margin-bottom: 8px; }
.gb-opt-name { font-family: 'Chalkduster', cursive; font-size: .88rem; color: #3A3A3A; }
.gb-opt-note { font-size: .68rem; color: #8A8070; flex: 1 1 100%; }
.gb-note { min-height: 40px !important; font-size: .78rem !important; }

.gb { margin: 4px 0 9px; }

/* 1 — SEED ROW: what is on the site now, for comparison */
.gb-row { display: flex; gap: 6px; align-items: center; justify-content: space-between; }
.gb-seed {
  /* fixed width, or flex:1 stretches the circles into ellipses */
  width: 38px; height: 38px; flex: 0 0 38px;
  display: flex; align-items: center; justify-content: center;
  font-size: 1.15rem;
  background: rgba(42,37,32,.04);
  border: 2px dashed rgba(42,37,32,.14);
  border-radius: 50%;
  color: #B8AE98;
}
.gb-seed.on {
  background: #F3F8EF;
  border-style: solid;
  border-color: #78B329;
  filter: drop-shadow(1.5px 0 0 #fff) drop-shadow(-1.5px 0 0 #fff) drop-shadow(0 1.5px 0 #fff) drop-shadow(0 -1.5px 0 #fff);
}

/* 2 — CLIMBING VINE: one continuous drawn line that grows */
.gb-vine { position: relative; height: 46px; }
.gb-vine svg { width: 100%; height: 46px; display: block; }
.gb-stem-bg { fill: none; stroke: rgba(42,37,32,.12); stroke-width: 3; stroke-linecap: round; stroke-dasharray: 5 7; }
.gb-stem    { fill: none; stroke: #78B329; stroke-width: 3.5; stroke-linecap: round;
              transition: stroke-dashoffset .6s cubic-bezier(.16,1,.3,1); }
.gb-leaf {
  position: absolute; left: var(--x); top: 2px;
  font-size: 1.05rem; opacity: .3;
  filter: grayscale(1);
  transition: opacity .3s, filter .3s;
}
.gb-leaf.on { opacity: 1; filter: none; }

/* 3 — FILLING JAR: the most literal, and the most kid-like */
.gb-jar { display: flex; align-items: center; gap: 11px; }
.gb-jar-glass {
  position: relative;
  width: 46px; height: 54px;
  background: rgba(255,255,255,.6);
  border: 2.5px solid #9A8F78;
  border-radius: 5px 5px 12px 12px;
  overflow: hidden;
  flex-shrink: 0;
}
.gb-jar-fill {
  position: absolute; bottom: 0; left: 0; right: 0;
  background: linear-gradient(180deg, #8FBF52, #6A9438 42%, #7A5A32);
  transition: height .6s cubic-bezier(.16,1,.3,1);
}
.gb-jar-top { position: absolute; top: 3px; left: 0; right: 0; text-align: center; font-size: 1.1rem; }
.gb-jar-label { font-family: 'Chalkduster', cursive; font-size: .78rem; color: #6A6252; }

/* 4 — STEPPING PATH: stones you walk, tilted like real ones */
.gb-path { display: flex; gap: 5px; align-items: center; padding: 4px 0; }
.gb-stone {
  flex: 1; height: 34px;
  display: flex; align-items: center; justify-content: center;
  background: #EFE9DA;
  border: 2px solid #C9BFA8;
  border-radius: 42% 58% 46% 54%;
  transform: translateY(var(--t)) rotate(-2deg);
  transition: background .3s, border-color .3s;
}
.gb-stone.on { background: #F3F8EF; border-color: #78B329; }
.gb-stone-e { font-size: 1.05rem; }

/* 5 — STICKER CHART: the actual kid's-game reference */
.gb-sticker { display: flex; gap: 5px; }
.gb-sq {
  flex: 1; height: 40px;
  display: flex; align-items: center; justify-content: center;
  font-size: 1.2rem;
  background: #FFFDF6;
  border: 2px solid #C9BFA8;
  border-radius: 3px 7px 3px 6px;
  box-shadow: 1px 1.5px 0 rgba(42,37,32,.09);
}
.gb-sq.on {
  background: #FBF3DC;
  border-color: var(--c-gold, #C49538);
  filter: drop-shadow(1.5px 0 0 #fff) drop-shadow(-1.5px 0 0 #fff) drop-shadow(0 1.5px 0 #fff) drop-shadow(0 -1.5px 0 #fff) drop-shadow(0 2px 3px rgba(42,37,32,.2));
  transform: rotate(-3deg);
}
.gb-sq.on:nth-child(even) { transform: rotate(4deg); }

/* 6 — SUNSHINE METER: warmth rising rather than distance covered */
.gb-thermo { display: flex; align-items: center; gap: 11px; }
.gb-tube {
  flex: 1; height: 16px;
  background: #EFE9DA;
  border: 2px solid #C9BFA8;
  border-radius: 20px;
  overflow: hidden;
}
.gb-tube > i {
  display: block; height: 100%;
  background: linear-gradient(90deg, #C9BFA8, #E8C25A 45%, #F0A93C);
  transition: width .6s cubic-bezier(.16,1,.3,1);
}
.gb-sun {
  font-size: calc(1.05rem + var(--w, .5) * .7rem);
  filter: drop-shadow(1.5px 0 0 #fff) drop-shadow(-1.5px 0 0 #fff) drop-shadow(0 1.5px 0 #fff) drop-shadow(0 -1.5px 0 #fff);
}

@media (pointer: coarse) {
  .gb-seed, .gb-stone, .gb-sq { min-height: 42px; }
}
@media (prefers-reduced-motion: reduce) {
  .gb-stem, .gb-jar-fill, .gb-tube > i, .gb-leaf, .gb-stone { transition: none; }
}


/* The submit button on a convo card. index.html raises this too, but the
   kit's stylesheet loads after it, so the last word has to be here — a
   sweep at 390px found it still at 40px when the rule lived only there. */
@media (pointer: coarse), (max-width: 600px) {
  .cc-copy { min-height: 46px; padding-top: 12px; padding-bottom: 12px; }
}

/* ============================================================
   THE WRITE-BACK ACTIONS — copy beside submit, on every card
   ------------------------------------------------------------
   Deesil: "all convo cards should have a copy button as well
   next to the submit button, just in case I want to copy the
   information before I submit it."

   He had asked for the big COPY ALL to go, and I removed copying
   altogether rather than moving it. This is the version he
   actually wanted: quiet, per-card, and sitting where the
   decision is made.
   ============================================================ */
.cc-actions {
  display: flex;
  gap: 7px;
  justify-content: flex-end;
  align-items: center;
  margin-top: 5px;
}
.cc-copybtn {
  font-family: 'EmbossT1', 'SF Mono', monospace;
  font-size: .66rem;
  letter-spacing: .05em;
  min-height: 44px;   /* was 40 — these are the card's primary controls */
  padding: 8px 13px;
  background: #FDFBF3;
  color: #6A6252;
  border: 1.5px solid #C9BFA8;
  border-radius: 3px 8px 3px 7px;
  cursor: pointer;
  box-shadow: 1px 1.5px 0 rgba(42,37,32,.1);
  transition: background .14s, transform .12s, box-shadow .12s;
  white-space: nowrap;
}
.cc-copybtn:hover  { background: #F6F1E2; transform: translateY(-1px); box-shadow: 1.5px 2.5px 0 rgba(42,37,32,.14); }
.cc-copybtn:active { transform: translateY(1px); box-shadow: 0 0 0 rgba(42,37,32,0); }
.cc-copybtn:focus-visible { outline: 2.5px solid var(--card-edge, #307878); outline-offset: 2px; }

/* who the card is addressed to.

   "The people responding to the cards with their specific names need to
   be aware that the cards are for them to submit." A card with a name on
   it is a card somebody owns. */
.cc-forwho {
  position: absolute;
  top: 10px; right: 12px;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-family: 'Chalkduster', cursive;
  font-size: .64rem;
  color: #6A6252;
  background: #EFE7D3;
  border: 1.5px solid #D8CFB8;
  border-radius: 3px 9px 3px 8px;
  padding: 3px 9px;
  transform: rotate(1.5deg);
  z-index: 3;
}

@media (pointer: coarse), (max-width: 600px) {
  .cc-copybtn { min-height: 46px; padding: 12px 14px; }
  .cc-actions { gap: 6px; }
}

/* The name box, sitting with copy and submit.

   "The people responding to the cards with their specific names need to be
   aware that the cards are for them to submit." A name typed once is
   remembered, so nobody types it twice — and the Master Gardener can
   finally tell who asked what. */
.cc-who {
  flex: 1 1 120px;
  min-width: 90px;
  min-height: 44px;   /* was 40 — these are the card's primary controls */
  padding: 8px 11px;
  background: #FDFBF3;
  border: 1.5px solid #C9BFA8;
  border-radius: 3px 8px 3px 7px;
  font-family: 'Chalkduster', cursive;
  font-size: .76rem;
  color: #3A3A3A;
}
.cc-who::placeholder { color: #A89E88; }
.cc-who:focus {
  outline: none;
  border-color: var(--card-color, #307878);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--card-color, #307878) 15%, transparent);
}
.cc-actions { flex-wrap: wrap; }

@media (pointer: coarse), (max-width: 600px) {
  .cc-who { min-height: 46px; flex-basis: 100%; }
}

/* ============================================================
   THE FUN PASS — the grant showing what it is
   ------------------------------------------------------------
   "A cute little arrangement of foam emojis that represent the
   grant… and a cute little Post-it note that gives a cute little
   'this grant is so perfect because of this and this and this
   reason' — showing the sparks that bring it together."

   Every emoji is earned from the grant's own data, and each one
   carries its reason in a title so it is not a mystery. They sit
   at slightly different angles and heights, the way a handful of
   stickers pressed on by somebody would.
   ============================================================ */
.gsc {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  margin: 5px 0 2px;
}
/* Sizes vary, they do not simply shrink. The first version stepped down
   1.05 -> 0.81rem, so the last mark in every cluster was the smallest and
   the whole thing read as a fade rather than a handful of stickers pressed
   on. Deesil: "much more variety of sizes and much larger sizes... not as
   many huge ones."

   Five hand-picked steps, largest second rather than first, so the eye does
   not read a ramp. Nothing drops below 1rem — under that an emoji stops
   being a drawing and becomes a smudge. */
.gsc-e {
  font-size: 1.12rem;
  line-height: 1;
  /* Rotation and baseline are hand-picked per position for the same reason
     the sizes are: a formula makes a ramp. The old calc() stepped a flat
     7deg each time (-10, -3, 4, 11, 18) and drifted the baseline 1px down
     each time, so every cluster on the page fanned open in the identical
     arc, like a hand of cards, and the last mark tipped a full 18deg —
     past anything the design system does with a sticker. These five sit
     inside the 2-8deg the reference actually uses and read as marks
     pressed on one at a time. Set on .gsc-e[--n] below, not here. */
  filter:
    drop-shadow(1.3px 0 0 #fff) drop-shadow(-1.3px 0 0 #fff)
    drop-shadow(0 1.3px 0 #fff) drop-shadow(0 -1.3px 0 #fff)
    drop-shadow(0 2px 2.5px rgba(42,37,32,.24));
  cursor: help;
}
.gsc-e[style*="--n:0"] { font-size: 1.12rem; transform: rotate(-6deg) translateY(0);    }
.gsc-e[style*="--n:1"] { font-size: 1.34rem; transform: rotate(4deg)  translateY(-1px); }
.gsc-e[style*="--n:2"] { font-size: 1.00rem; transform: rotate(-3deg) translateY(1px);  }
.gsc-e[style*="--n:3"] { font-size: 1.22rem; transform: rotate(7deg)  translateY(0);    }
.gsc-e[style*="--n:4"] { font-size: 1.06rem; transform: rotate(-2deg) translateY(-1px); }

.sr-only {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* the post-it. It only ever appears when the data supports three real
   reasons, so it never has to hedge. */
.why-fits {
  position: relative;
  margin: 2px 0 14px;
  padding: 16px 15px 13px;
  background: linear-gradient(178deg, #FBF3DC, #F5E9C8);
  border-radius: 2px 2px 4px 4px;
  box-shadow:
    0 1px 0 rgba(255,255,255,.6) inset,
    1px 3px 0 rgba(42,37,32,.1),
    0 8px 16px rgba(42,37,32,.07);
  transform: rotate(-.5deg);
}
/* the strip of tape holding it on */
.why-fits::before {
  content: '';
  position: absolute;
  top: -7px; left: 50%;
  width: 62px; height: 16px;
  margin-left: -31px;
  transform: rotate(-2.5deg);
  background: repeating-linear-gradient(58deg,
    rgba(196,149,56,.4) 0 5px, rgba(212,165,72,.18) 5px 10px);
  box-shadow: 0 1px 2px rgba(42,37,32,.12);
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 2px, #000 calc(100% - 2px), transparent 100%);
          mask-image: linear-gradient(90deg, transparent 0, #000 2px, #000 calc(100% - 2px), transparent 100%);
}
.wf-tape {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-family: 'EmbossT1', 'SF Mono', monospace;
  font-size: .62rem;
  letter-spacing: .1em;
  color: #8A7028;
  margin-bottom: 7px;
}
.wf-line { font-size: .83rem; line-height: 1.7; margin: .2rem 0; }

@media (prefers-reduced-motion: reduce) {
  /* must match the specificity of .gsc-e[style*="--n:N"] above (0,2,0) or
     it silently loses and reduced-motion users still get the tilts. */
  .gsc-e[style] { transform: none; }
}

/* ============================================================
   BRAIN BUDDY, PRESENT
   ------------------------------------------------------------
   "Brain Buddy hand-drawn and animated and visible throughout
   the site, being cute and supportive and helpful."

   One drawing, five moods, and the mood lives entirely in how he
   MOVES — a companion who holds the same expression whatever is
   happening is a sticker, not a companion.

   The white foam outline is what puts him ON the page rather than
   floating over it, the same treatment as every other sticker
   here.
   ============================================================ */
.bb-here {
  display: inline-block;
  height: auto;
  filter:
    drop-shadow(1.8px 0 0 #FDFBF3) drop-shadow(-1.8px 0 0 #FDFBF3)
    drop-shadow(0 1.8px 0 #FDFBF3) drop-shadow(0 -1.8px 0 #FDFBF3)
    drop-shadow(0 4px 6px rgba(42,37,32,.2));
  transform-origin: bottom center;
}

/* WAITING — a slow patient bob, the way somebody waits WITH you */
.bb-waiting { animation: bbWait 2.6s ease-in-out infinite; }
@keyframes bbWait {
  0%, 100% { transform: translateY(0) rotate(-1deg); }
  50%      { transform: translateY(-7px) rotate(1.5deg); }
}

/* SORRY — leans back and sags a little. Something went wrong and he
   knows it. Barely moves, because fussing would make it worse. */
.bb-sorry { animation: bbSorry 4.5s ease-in-out infinite; transform: rotate(-7deg); }
@keyframes bbSorry {
  0%, 100% { transform: rotate(-7deg) translateY(2px); }
  50%      { transform: rotate(-5deg) translateY(0); }
}

/* INVITING — leans in toward you, hopeful. For an empty garden that
   is waiting to be started. */
.bb-inviting { animation: bbInvite 3.2s ease-in-out infinite; }
@keyframes bbInvite {
  0%, 100% { transform: rotate(-2deg) translateY(0) scale(1); }
  45%      { transform: rotate(3deg) translateY(-5px) scale(1.03); }
}

/* CHEERING — an actual little jump. Only for something genuinely
   finished, so it never becomes wallpaper. */
.bb-cheering { animation: bbCheer 1.5s cubic-bezier(.28,.9,.3,1) infinite; }
@keyframes bbCheer {
  0%, 100% { transform: translateY(0) rotate(0deg) scale(1); }
  18%      { transform: translateY(-13px) rotate(-7deg) scale(1.06); }
  38%      { transform: translateY(0) rotate(4deg) scale(.97); }
  55%      { transform: translateY(-5px) rotate(-2deg) scale(1.02); }
  72%      { transform: translateY(0) rotate(0deg) scale(1); }
}

/* THINKING — a slow tilt from side to side, working something out */
.bb-thinking { animation: bbThink 5s ease-in-out infinite; }
@keyframes bbThink {
  0%, 100% { transform: rotate(-4deg); }
  50%      { transform: rotate(4deg); }
}

@media (prefers-reduced-motion: reduce) {
  .bb-here { animation: none !important; }
}

/* ===================================================================
   THE EIGHT GROWTH BARS
   -------------------------------------------------------------------
   Everything here obeys the four rules written above growthBarMarkup():
   it must look drawn, done steps must feel earned, steps to come must be
   inviting rather than absent, and each one gets a single moment of
   delight. The pencil filter (#sketch-accuracy) is what stops these
   reading as generated shapes.
   =================================================================== */
.gb2 {
  position: relative;
  margin: 4px 0 2px;
  padding: 12px 10px 10px;
  background:
    linear-gradient(178deg, #FDFBF3, #F7F1E2);
  border: 1.5px solid rgba(42,37,32,.10);
  border-radius: 4px;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.6), 0 2px 6px -4px rgba(42,37,32,.3);
}
.gb2-cap {
  display: block;
  margin-top: 7px;
  font-family: 'Chalkduster', cursive;
  font-size: .68rem;
  color: #6A6154;
  text-align: center;
}

/* ---------- 1 · THE PLANT GROWS ---------- */
.gb2-plant { text-align: center; }
.gb2-plant-svg { width: 100%; max-width: 210px; height: 118px; display: block; margin: 0 auto; }
.gb2-soil  { fill: #C9A87C; stroke: #8A6A46; stroke-width: 1.4; filter: url(#sketch-accuracy); }
.gb2-stem  { fill: none; stroke: #559C40; stroke-width: 3.4; stroke-linecap: round; filter: url(#sketch-accuracy); }
.gb2-leaf  { fill: #78B329; stroke: #3C7A2A; stroke-width: 1.2; filter: url(#sketch-accuracy); }
.gb2-leaf-g { animation: gbLeafIn .5s both cubic-bezier(.16,1,.3,1); animation-delay: var(--d, 0ms); }
@keyframes gbLeafIn { from { opacity: 0; transform: scale(.5) } to { opacity: 1; transform: scale(1) } }
/* the future, drawn in pencil so you can see where you are going */
.gb2-ghost { fill: none; stroke: rgba(85,156,64,.34); stroke-width: 2.2; stroke-dasharray: 3 5; stroke-linecap: round; }
.gb2-bloom { fill: #E8B84B; stroke: #B8862A; stroke-width: 1.6; }
.gb2-pot { position: absolute; left: 50%; bottom: 26px; transform: translateX(-50%); font-size: 1.5rem; opacity: 0; }
.gb2-sky { display: none; }

/* ---------- 2 · PUNCH CARD ---------- */
.gb2-punch-card {
  background: #FBF6E7;
  border: 1.5px dashed rgba(42,37,32,.28);
  border-radius: 3px;
  padding: 10px 12px 8px;
  filter: url(#sketch-accuracy);
}
.gb2-punch-title, .gb2-punch-foot {
  display: block; text-align: center;
  font-family: 'EmbossT1', 'SF Mono', monospace;
  font-size: .54rem; letter-spacing: .14em; color: #7A6A48;
}
.gb2-punch-foot { margin-top: 8px; opacity: .8; }
.gb2-holes { display: flex; justify-content: space-between; gap: 5px; margin: 9px 2px 0; }
.gb2-hole {
  flex: 1; aspect-ratio: 1; max-width: 38px;
  border-radius: 50%;
  border: 1.5px solid rgba(42,37,32,.22);
  display: grid; place-items: center;
  background: #FDFBF3;
}
/* a real hole: the dark of the page behind, with the paper edge catching light */
.gb2-hole.done {
  background: #6B5F4C;
  border-color: #4A4034;
  box-shadow:
    inset 0 2px 4px rgba(0,0,0,.55),
    inset 0 -1px 0 rgba(255,255,255,.18),
    0 1px 0 rgba(255,255,255,.7);
}
.gb2-hole-ghost { font-size: .84rem; opacity: .26; filter: grayscale(1); }

/* ---------- 3 · STICKER ALBUM ---------- */
.gb2-album {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: 6px;
}
.gb2-cell {
  aspect-ratio: 1;
  border: 1.5px dashed rgba(42,37,32,.2);
  border-radius: 3px;
  display: grid; place-items: center;
  background: rgba(255,255,255,.4);
}
.gb2-cell .gb2-cell-in { font-size: 1.15rem; opacity: .2; filter: grayscale(1); transition: none; }
/* earned: a foam sticker pressed on, never quite straight */
.gb2-cell.earned {
  border-style: solid;
  border-color: rgba(196,149,56,.42);
  background: #FFFDF6;
}
.gb2-cell.earned .gb2-cell-in {
  opacity: 1; filter: none;
  transform: rotate(var(--r, 0deg)) scale(1.12);
  filter:
    drop-shadow(1.6px 0 0 #fff) drop-shadow(-1.6px 0 0 #fff)
    drop-shadow(0 1.6px 0 #fff) drop-shadow(0 -1.6px 0 #fff)
    drop-shadow(0 2px 3px rgba(42,37,32,.34));
}

/* ---------- 4 · TRAIL MAP ---------- */
.gb2-trail { position: relative; }
.gb2-trail svg { width: 100%; height: 76px; display: block; }
.gb2-trail-bg   { fill: none; stroke: rgba(42,37,32,.2); stroke-width: 2.4; stroke-dasharray: 2 7; stroke-linecap: round; }
.gb2-trail-done { fill: none; stroke: #C4883A; stroke-width: 3; stroke-linecap: round; filter: url(#sketch-accuracy); }
.gb2-dot { fill: #FDFBF3; stroke: rgba(42,37,32,.3); stroke-width: 1.4; }
.gb2-dot.on { fill: #C4883A; stroke: #8A6320; }
.gb2-flag {
  position: absolute; left: calc(4% + var(--x, 0%)); top: 4px;
  font-size: 1.1rem;
  filter: drop-shadow(0 2px 2px rgba(42,37,32,.34));
  animation: gbFlag 2.6s ease-in-out infinite;
}
@keyframes gbFlag { 0%,100% { transform: rotate(-5deg) } 50% { transform: rotate(5deg) } }
.gb2-treasure { position: absolute; right: 6px; top: 8px; font-size: 1.2rem; }

/* ---------- 5 · SEED PACKET ---------- */
.gb2-packet-body {
  background: linear-gradient(178deg, #F3E5C4, #EAD9AE);
  border: 1.5px solid #C4A96A;
  border-radius: 3px 3px 5px 5px;
  padding: 9px 11px 11px;
  position: relative;
  /* the torn top edge — the delight */
  clip-path: polygon(0 6px, 5% 0, 12% 6px, 20% 1px, 29% 7px, 38% 1px, 47% 6px,
                     56% 0, 65% 6px, 74% 1px, 83% 7px, 92% 1px, 100% 6px,
                     100% 100%, 0 100%);
}
.gb2-packet-name {
  display: block; text-align: center;
  font-family: 'EmbossT1', 'SF Mono', monospace;
  font-size: .56rem; letter-spacing: .13em; color: #7A5A20;
  margin: 4px 0 9px;
}
.gb2-seals { display: flex; justify-content: space-between; gap: 5px; }
.gb2-seal {
  flex: 1; aspect-ratio: 1; max-width: 36px;
  border-radius: 50%;
  border: 1.5px dashed rgba(122,90,32,.34);
  display: grid; place-items: center;
  font-size: .92rem;
}
/* stamped: hot wax, pressed crooked */
.gb2-seal.stamped {
  border: none;
  background: radial-gradient(circle at 38% 32%, #C4544A, #9A3A32 68%);
  transform: rotate(var(--r, 0deg));
  box-shadow: inset 0 -2px 3px rgba(0,0,0,.32), inset 0 2px 2px rgba(255,255,255,.22), 0 1px 3px rgba(42,37,32,.34);
}

/* ---------- 6 · SUN ARC ---------- */
.gb2-sun { position: relative; overflow: hidden; padding-bottom: 6px; }
/* Two skies cross-faded. Interpolating HUE from dawn to noon passes
   through green, which is how a half-finished grant got a green sky. */
.gb2-sky-dawn, .gb2-sky-day { position: absolute; inset: 0; }
.gb2-sky-dawn {
  background: linear-gradient(180deg, #F6D2A8 0%, #FBE8D2 46%, #FDFBF3 86%);
}
.gb2-sky-day {
  background: linear-gradient(180deg, #A9D4EC 0%, #D6EAF4 46%, #FDFBF3 86%);
  transition: opacity .6s ease;
}
.gb2-sun svg { position: relative; width: 100%; height: 96px; display: block; }
.gb2-arc-bg { fill: none; stroke: rgba(42,37,32,.16); stroke-width: 2; stroke-dasharray: 3 6; }
.gb2-arc    { fill: none; stroke: #E8A93B; stroke-width: 3; stroke-linecap: round; filter: url(#sketch-accuracy); }
/* the sun now rides the arc as an SVG <text>, positioned in JS, because
   CSS sin() is not dependable enough to hang a design on */
.gb2-orb-t { filter: drop-shadow(0 0 6px rgba(232,169,59,.65)); }
.gb2-horizon {
  position: absolute; left: 8px; right: 8px; bottom: 26px; height: 1.5px;
  background: repeating-linear-gradient(90deg, rgba(42,37,32,.26) 0 5px, transparent 5px 10px);
}
.gb2-sun .gb2-cap { position: relative; }

/* ---------- 7 · UNDER THE SOIL ---------- */
.gb2-ground { position: relative; }
.gb2-air {
  height: 46px; display: grid; place-items: end center;
  background: linear-gradient(180deg, rgba(160,200,235,.22), transparent);
  border-radius: 3px 3px 0 0;
}
.gb2-flower { font-size: 1.5rem; animation: gbLeafIn .6s both; }
.gb2-line {
  height: 2px;
  background: repeating-linear-gradient(90deg, #8A6A46 0 6px, rgba(138,106,70,.4) 6px 11px);
}
.gb2-under {
  position: relative;
  height: 56px;
  background: linear-gradient(180deg, #C9A87C, #A8865C);
  border-radius: 0 0 4px 4px;
  overflow: hidden;
}
/* Real forking roots, drawn. The first pass used 2px white threads on a
   flat brown block: invisible, and it said nothing. */
.gb2-roots { position: absolute; inset: 0; width: 100%; height: 100%; }
.gb2-root-g { opacity: 0; transition: opacity .4s ease; }
.gb2-root-g.on { opacity: 1; animation: gbRootIn .55s both ease-out; animation-delay: var(--d, 0ms); }
@keyframes gbRootIn { from { opacity: 0; transform: translateY(-5px) } to { opacity: 1; transform: none } }
.gb2-root-main {
  fill: none; stroke: #FBF0DA; stroke-width: 2.6; stroke-linecap: round;
  opacity: .92; filter: url(#sketch-accuracy);
}
.gb2-root-fork {
  fill: none; stroke: #FBF0DA; stroke-width: 1.6; stroke-linecap: round;
  opacity: .74; filter: url(#sketch-accuracy);
}
.gb2-worm { position: absolute; right: 10px; bottom: 6px; font-size: .95rem; opacity: .8; }

/* ---------- 8 · THE JAR, PROPERLY ---------- */
.gb2-jar2 { text-align: center; }
.gb2-glass {
  position: relative;
  width: 74px; height: 92px;
  margin: 2px auto 0;
  /* neck, shoulder, body — the shape is what makes it a jar */
  border: 2px solid rgba(90,110,110,.5);
  border-radius: 6px 6px 16px 16px / 4px 4px 20px 20px;
  background: linear-gradient(100deg, rgba(214,236,236,.5), rgba(180,212,212,.24));
  overflow: hidden;
  box-shadow: inset 0 -6px 10px rgba(80,110,110,.18), 0 2px 5px -3px rgba(42,37,32,.4);
}
.gb2-lid {
  position: absolute; top: -1px; left: 50%; transform: translateX(-50%);
  width: 58px; height: 11px;
  background: linear-gradient(180deg, #B8863A, #8A6320);
  border: 1.5px solid #6A4A14;
  border-radius: 3px;
  z-index: 3;
}
.gb2-contents {
  position: absolute; left: 0; right: 0; bottom: 0;
  background: linear-gradient(180deg, #A8865C, #7A5C38);
  transition: height .6s cubic-bezier(.16,1,.3,1);
}
.gb2-shine {
  position: absolute; top: 16px; left: 9px;
  width: 9px; height: 46px;
  background: linear-gradient(180deg, rgba(255,255,255,.72), rgba(255,255,255,0));
  border-radius: 9px;
  z-index: 2;
}
.gb2-in-jar {
  position: absolute; left: 50%; bottom: 34%;
  transform: translateX(-50%);
  font-size: 1.35rem; z-index: 2;
  filter: drop-shadow(0 1px 2px rgba(42,37,32,.4));
}

@media (prefers-reduced-motion: reduce) {
  .gb2-leaf-g, .gb2-flag, .gb2-flower { animation: none; }
  .gb2-root, .gb2-contents { transition: none; }
}

/* ============================================================
   TAPPABLE CHOICES ON A CARD
   Deesil: "they need to be more interactive and engaging.
   They're convo cards, they're interactive."
   Foam stickers you press, not form controls. Selected reads as
   pressed IN — darker, sunk, and the key letter goes bold.
   ============================================================ */
.cc-options { margin: 2px 0 10px; }
.cc-options-label {
  font-family: 'EmbossT1', 'SF Mono', monospace;
  font-size: .58rem;
  letter-spacing: .07em;
  color: #8A8070;
  margin-bottom: 7px;
}
.cc-options-row { display: flex; flex-wrap: wrap; gap: 7px; }
.cc-opt {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 44px;
  padding: 8px 13px;
  background: #FDFBF3;
  border: 1.5px solid rgba(42,37,32,.18);
  border-radius: 5px 11px 5px 10px;
  cursor: pointer;
  font-size: .8rem;
  color: #3A3A3A;
  text-align: left;
  transform: rotate(-.3deg);
  box-shadow: 1px 1.5px 0 rgba(42,37,32,.1);
  transition: background .15s, box-shadow .15s, transform .15s, border-color .15s;
}
.cc-opt:nth-child(even) { transform: rotate(.4deg); }
.cc-opt:hover {
  background: #FFFDF6;
  transform: rotate(0) translateY(-1px);
  box-shadow: 1.5px 2.5px 0 rgba(42,37,32,.14);
}
.cc-opt:focus-visible { outline: 3px solid var(--card-edge, #307878); outline-offset: 2px; }
.cc-opt-key {
  font-family: 'EmbossT1', 'SF Mono', monospace;
  font-size: .66rem;
  letter-spacing: .04em;
  color: #8A8070;
}
/* pressed in: it took the card's own colour, and it sits down */
.cc-opt.selected {
  background: color-mix(in srgb, var(--card-color, #307878) 15%, #FDFBF3);
  border-color: color-mix(in srgb, var(--card-color, #307878) 55%, transparent);
  color: #2B2520;
  transform: rotate(0) translateY(1px);
  box-shadow: inset 0 1.5px 3px rgba(42,37,32,.14);
}
.cc-opt.selected .cc-opt-key { color: var(--card-edge, #1F5A5F); font-weight: 700; }
@media (prefers-reduced-motion: reduce) {
  .cc-opt, .cc-opt:hover { transition: none; transform: none; }
}
