/* ==========================================================================
   The Lair — Zone 1, The Gate.
   Loaded on the homepage only.
   ==========================================================================

   "Enter, not click."

   You arrive in a circle. The room wakes as you come in: the ring is drawn, the
   seven ignite one by one, Tara opens her eyes at the centre. Reach toward any
   dragon and the whole room answers — the light takes their colour and they
   speak their vow.

   The words you came to read sit INSIDE the ring. That is the move that lets
   this be atmospheric AND still put the value proposition in the first screen,
   rather than making the two fight (CLAUDE.md §9).

   WITHIN THE BRAND, NOT AROUND IT
   -------------------------------
   The background stays Warm Parchment. Always. No black, no charcoal, no "dark
   and mysterious" (CLAUDE.md §4) — which rules out the obvious way to do this.

   So the mystery comes from LIGHT, not from darkness. A warm pool of gold in the
   middle of a parchment page, the way an illuminated manuscript glows. Gold is
   the light; it is never the ink. Each dragon's colour lives in their ring, their
   aura and their ray — and never in a letter, because six of the seven fail WCAG
   AA as text on parchment.

   Everything below is decoration in the strict sense: strip every animation and
   every glow and the page still says what it needs to say, still reads, still
   works on a keyboard. That is the test motion has to pass.
   ========================================================================== */

/* The colour of the room.

   Gold when nobody is being attended to; whoever's colour when somebody is —
   Tara's Royal Purple included, because she is a Guardian too and the room should
   answer to her the way it answers to the seven.

   Registering it with @property is what makes it a COLOUR rather than a string,
   and a colour can be transitioned. Without this, the light would snap from gold
   to Luna's midnight blue in a single frame; with it, the whole room warms and
   cools. It is one line, and it is most of the magic.

   It is only ever used for LIGHT. Never for type — six of the seven fail WCAG AA
   as ink on parchment (CLAUDE.md §4). */
@property --room-color {
  syntax: "<color>";
  inherits: true;
  initial-value: #b89045;
}

.lair {
  position: relative;
  display: grid;
  place-items: center;
  padding-block: var(--space-12) var(--space-16);
  overflow: hidden;
  isolation: isolate;

  --room-color: var(--color-gold);
  transition: --room-color 700ms var(--ease);
}

/* --- The light -------------------------------------------------------------
   One pool, and it takes the colour of whoever has the room. Because
   --room-color is a registered colour it interpolates, so the gradient simply
   re-renders warmer or cooler each frame. No crossfading two stacked layers, no
   trickery — just the light changing.
   -------------------------------------------------------------------------- */

.lair__glow {
  position: absolute;
  inset: -25% -12%;
  z-index: -3;
  pointer-events: none;
  opacity: 0.9;
  transition: opacity var(--duration-slow) var(--ease);
  background: radial-gradient(
    55% 45% at 50% 44%,
    color-mix(in srgb, var(--room-color) 24%, transparent) 0%,
    color-mix(in srgb, var(--room-color) 10%, transparent) 40%,
    transparent 72%
  );
}

/* When somebody has the room, it leans in a little. */
.lair.is-attending .lair__glow {
  opacity: 1;
}

/* --- The floor -------------------------------------------------------------
   A ring on the ground. It draws itself as you arrive — a conic sweep, like a
   circle being inscribed rather than a border simply existing.
   -------------------------------------------------------------------------- */

.lair__floor {
  position: absolute;
  top: 50%;
  left: 50%;
  z-index: -1;
  width: min(78vw, 700px);
  aspect-ratio: 1;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  pointer-events: none;

  /* The stroke. A hairline read as an accident rather than a circle — this is a
     ring inscribed on a floor, and it should have some weight to it. */
  --ring-weight: 6px;

  /* Masked out of a conic gradient so it can be swept in.

     `closest-side` is doing real work here. A bare `radial-gradient(circle, …)`
     defaults to farthest-CORNER, so on a square element its 50% lands out at the
     diagonal — well outside the box — and the mask keeps essentially the whole
     disc. That is why this once rendered as a solid gold wedge rather than a
     ring. closest-side puts 100% exactly on the edge, which is where a ring
     lives. */
  background: conic-gradient(
    from -90deg,
    color-mix(in srgb, var(--room-color) 55%, transparent) 0turn,
    color-mix(in srgb, var(--room-color) 55%, transparent) var(--sweep, 0turn),
    transparent var(--sweep, 0turn)
  );
  -webkit-mask: radial-gradient(
    closest-side,
    transparent calc(100% - var(--ring-weight)),
    #000 calc(100% - var(--ring-weight))
  );
  mask: radial-gradient(
    closest-side,
    transparent calc(100% - var(--ring-weight)),
    #000 calc(100% - var(--ring-weight))
  );

  animation: floor-inscribe 1600ms var(--ease) 200ms forwards;
  transition: background var(--duration-slow) var(--ease);
}

@property --sweep {
  syntax: "<angle>";
  inherits: false;
  initial-value: 0turn;
}

@keyframes floor-inscribe {
  from {
    --sweep: 0turn;
  }
  to {
    --sweep: 1turn;
  }
}

/* A second, wider ring — barely there. Depth, not decoration. */
.lair__floor::after {
  content: "";
  position: absolute;
  inset: -9%;
  border: 1px solid var(--color-gold-soft);
  border-radius: 50%;
  opacity: 0.35;
}

@media (max-width: 899px) {
  .lair__floor {
    display: none;
  }
}

/* --- Motes -----------------------------------------------------------------
   Eight of them, drifting. Slow enough that you are not sure they are moving
   until you stop looking directly at them — which is the entire point, and also
   the line between atmosphere and a screensaver.
   -------------------------------------------------------------------------- */

.motes {
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  overflow: hidden;
}

.motes span {
  position: absolute;
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: var(--color-gold);
  opacity: 0;
  box-shadow: 0 0 8px 2px color-mix(in srgb, var(--color-gold) 45%, transparent);
  animation: mote-drift 18s linear infinite;
}

@keyframes mote-drift {
  0% {
    transform: translateY(20px) scale(0.6);
    opacity: 0;
  }
  15% {
    opacity: 0.5;
  }
  85% {
    opacity: 0.35;
  }
  100% {
    transform: translateY(-120px) scale(1);
    opacity: 0;
  }
}

.motes span:nth-child(1) { left: 12%; top: 68%; animation-delay: 0s; animation-duration: 19s; }
.motes span:nth-child(2) { left: 26%; top: 82%; animation-delay: -4s; animation-duration: 23s; }
.motes span:nth-child(3) { left: 41%; top: 74%; animation-delay: -9s; animation-duration: 17s; }
.motes span:nth-child(4) { left: 58%; top: 88%; animation-delay: -2s; animation-duration: 21s; }
.motes span:nth-child(5) { left: 71%; top: 70%; animation-delay: -13s; animation-duration: 25s; }
.motes span:nth-child(6) { left: 85%; top: 80%; animation-delay: -6s; animation-duration: 18s; }
.motes span:nth-child(7) { left: 33%; top: 60%; animation-delay: -15s; animation-duration: 24s; }
.motes span:nth-child(8) { left: 66%; top: 62%; animation-delay: -11s; animation-duration: 20s; }

/* --- The room --------------------------------------------------------------
   A little parallax on a pointer. Eight pixels, never more — enough that the
   room feels like it has depth, not so much that it feels like it is chasing
   you. Touch devices never get it.
   -------------------------------------------------------------------------- */

.lair__inner {
  position: relative;
  display: grid;
  justify-items: center;
  gap: var(--space-6);
  width: 100%;
  max-width: 100%;
  transform: translate3d(
    calc(var(--tilt-x, 0) * 8px),
    calc(var(--tilt-y, 0) * 8px),
    0
  );
  transition: transform 600ms var(--ease);
}

/* --- Tara ------------------------------------------------------------------
   Front and centre. Not one of the seven — the one who walks in with you, so
   she is larger, warmer, and the first thing you meet.
   -------------------------------------------------------------------------- */

.tara {
  display: grid;
  justify-items: center;
  gap: var(--space-3);
  text-decoration: none;
  z-index: 2;
  animation: rise 900ms var(--ease) 500ms backwards;
}

.tara__seal {
  position: relative;
  display: grid;
  place-items: center;
  width: 108px;
  height: 108px;
  border-radius: 50%;
  background: radial-gradient(
    circle at 50% 40%,
    var(--color-surface) 0%,
    var(--color-bg) 72%
  );
  border: 2px solid var(--color-gold);
  font-size: 2.75rem;
  line-height: 1;
  box-shadow:
    0 0 0 8px rgba(184, 144, 69, 0.1),
    0 0 40px rgba(184, 144, 69, 0.32),
    inset 0 0 20px rgba(184, 144, 69, 0.12);
  animation: tara-breathe 7s var(--ease) 1.4s infinite;
  transition: transform var(--duration-base) var(--ease);
}

.tara:hover .tara__seal,
.tara:focus-visible .tara__seal {
  transform: scale(1.05);
}

/* She breathes. Slowly. It is the only movement on the page that is not a
   response to something the visitor did, and it is what makes the room feel
   inhabited rather than drawn. */
@keyframes tara-breathe {
  0%,
  100% {
    box-shadow:
      0 0 0 8px rgba(184, 144, 69, 0.1),
      0 0 40px rgba(184, 144, 69, 0.3),
      inset 0 0 20px rgba(184, 144, 69, 0.12);
  }
  50% {
    box-shadow:
      0 0 0 14px rgba(184, 144, 69, 0.06),
      0 0 64px rgba(184, 144, 69, 0.45),
      inset 0 0 26px rgba(184, 144, 69, 0.18);
  }
}

/* When one of the seven has the room, Tara steps back. She does not compete with
   whoever is speaking.

   But NOT when she is the one speaking — hence :not(.is-attended). She is a
   Guardian too, and the room answers to her Royal Purple exactly the way it
   answers to Luna's midnight or Kai's teal. */
.lair.is-attending .tara:not(.is-attended) .tara__seal {
  opacity: 0.5;
  box-shadow:
    0 0 0 6px rgba(184, 144, 69, 0.06),
    0 0 24px rgba(184, 144, 69, 0.18);
}

/* Her turn. The seal takes her own colour and the breathing stops — she is not
   idling now, she is looking at you. */
.tara.is-attended .tara__seal {
  border-color: var(--room-color);
  animation: none;
  transform: scale(1.06);
  box-shadow:
    0 0 0 10px color-mix(in srgb, var(--room-color) 14%, transparent),
    0 0 52px color-mix(in srgb, var(--room-color) 45%, transparent),
    inset 0 0 26px color-mix(in srgb, var(--room-color) 16%, transparent);
}

.tara__seal,
.sigil__art {
  transition:
    opacity var(--duration-base) var(--ease),
    transform var(--duration-base) var(--ease),
    box-shadow var(--duration-base) var(--ease);
}

.tara__name {
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--color-text-soft);
}

.tara__pillar {
  font-family: var(--font-accent);
  font-size: var(--text-lg);
  color: var(--color-text-soft);
  line-height: 1;
}

/* --- The words -------------------------------------------------------------
   Inside the ring, and the reason the ring is allowed to exist at all.
   -------------------------------------------------------------------------- */

.lair__copy {
  position: relative;
  z-index: 2;
  display: grid;
  justify-items: center;
  gap: var(--space-5);
  max-width: 34ch;
  text-align: center;
  animation: rise 900ms var(--ease) 700ms backwards;
}

.lair__tagline {
  font-family: var(--font-accent);
  font-size: var(--text-xl);
  color: var(--color-text-soft);
  line-height: 1;
}

.lair__headline {
  font-size: var(--text-3xl);
  line-height: 1.12;
  text-wrap: balance;
}

.lair__lede {
  font-size: var(--text-lg);
  line-height: var(--leading-snug);
  color: var(--color-text-soft);
  text-wrap: pretty;
}

/* --- The whisper -----------------------------------------------------------
   A vow, held under the words. Tara's, until you reach toward one of the seven —
   then it becomes theirs.

   The height is reserved whether or not anything is showing, so the page never
   jumps when a dragon speaks. A layout that shifts under a cursor is the
   opposite of a room you can trust.
   -------------------------------------------------------------------------- */

.whisper {
  display: grid;
  place-items: center;
  min-height: 3.25rem;
  padding-inline: var(--space-4);
}

.whisper__text {
  font-family: var(--font-accent);
  font-size: var(--text-xl);
  line-height: 1.25;
  color: var(--color-text-soft);
  transition:
    opacity var(--duration-base) var(--ease),
    transform var(--duration-base) var(--ease);
}

.whisper.is-changing .whisper__text {
  opacity: 0;
  transform: translateY(4px);
}

.whisper__who {
  display: block;
  margin-top: var(--space-1);
  font-family: var(--font-body);
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--color-text-faint);
}

.lair__actions {
  display: grid;
  gap: var(--space-3);
  width: 100%;
  max-width: 22rem;
}

.lair__note {
  font-size: var(--text-sm);
  color: var(--color-text-faint);
}

@media (min-width: 640px) {
  .lair__actions {
    display: flex;
    justify-content: center;
    max-width: none;
  }
}

/* --- The seven -------------------------------------------------------------
   A halo on a phone. A circle on a real screen.
   -------------------------------------------------------------------------- */

/* R7 — on a phone the seven are a SWIPEABLE strip, not a wrapping pile.

   Kate: "the mobile version is tough on the eyeballs… a swipeable carousel of the
   dragons." A 7-item flex-wrap stacked three rows of cramped sigils under the copy;
   a horizontal scroll-snap track shows them one-and-a-bit at a time and invites a
   thumb. Only the track scrolls — never the page (the parent clips x). From 900px
   up this is all replaced by the ring (below). */
.seven {
  display: flex;
  flex-wrap: nowrap;
  gap: var(--space-5);
  margin-top: var(--space-8);
  padding: var(--space-2) var(--space-5) var(--space-4);
  width: 100%;
  max-width: 100%;
  overflow-x: auto;
  scroll-snap-type: x proximity;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}

.seven::-webkit-scrollbar {
  display: none;
}

.seven .sigil {
  scroll-snap-align: center;
  flex: 0 0 auto;
  width: 6rem; /* room for the pillar label under a 60px face, no cramped wrap */
}

/* The <li> owns the position. The <a> owns the look — keeping those apart is
   what lets the desktop circle absolutely-position the item without fighting the
   link's own layout. */
.sigil {
  --sigil-size: 60px;
  width: var(--sigil-size);
}

/* On a phone there is no circle to travel out to, so they simply arrive: a fade
   and a small swell, one after another around the halo.

   The animation lives on the LINK, not on the <li>. That distinction is the
   whole bug that was showing on the homepage — see the note above `emerge`. */
.sigil__link {
  display: grid;
  justify-items: center;
  gap: var(--space-2);
  text-decoration: none;
  text-align: center;
  animation: ignite 700ms var(--ease) backwards;
  animation-delay: calc(900ms + var(--i) * 90ms);
}

.sigil__art {
  position: relative;
  display: grid;
  place-items: center;
  width: var(--sigil-size);
  height: var(--sigil-size);
  border-radius: 50%;
  background: var(--color-surface);
  /* The dragon's colour. A ring and an aura — never ink. */
  border: 2px solid var(--dragon-color);
  box-shadow:
    0 0 0 5px color-mix(in srgb, var(--dragon-color) 12%, transparent),
    0 0 22px color-mix(in srgb, var(--dragon-color) 28%, transparent);
  font-size: 1.5rem;
  line-height: 1;
}

.sigil__link:hover .sigil__art,
.sigil__link:focus-visible .sigil__art {
  transform: scale(1.14) translateY(-2px);
  box-shadow:
    0 0 0 9px color-mix(in srgb, var(--dragon-color) 18%, transparent),
    0 0 40px color-mix(in srgb, var(--dragon-color) 55%, transparent);
}

/* When one dragon is being attended to, the others recede. Not hidden — just
   quieter, the way a room goes still when somebody speaks. */
.lair.is-attending .sigil:not(.is-attended) .sigil__art {
  opacity: 0.4;
}

.lair.is-attending .sigil:not(.is-attended) .sigil__name,
.lair.is-attending .sigil:not(.is-attended) .sigil__pillar {
  opacity: 0.5;
}

/* The real artwork landed, and it did NOT drop straight in — see the long note on
   `.seal img` in atmosphere.css for the full story.

   Short version: the tall 1024x1536 dragons rendered 80x120 inside an 80x80 seal,
   because `height: 100%` has nothing definite to resolve against in a
   content-sized grid row and quietly became `auto`. Rosemary, Luna, Aspen and
   Haven hung out of their own sigils and over their own names; Kai, Nova and Valor
   were square or landscape and fitted by accident.

   aspect-ratio squares the box regardless of the source; overflow: hidden on the
   sigil is the guarantee. */
.sigil__art {
  overflow: hidden;
}

.sigil__art img,
.tara__seal img {
  width: 100%;
  height: 100%;
  aspect-ratio: 1;
  border-radius: 50%;
  object-fit: cover;
  object-position: 50% 28%; /* the face, not the belly */
}

/* Tara only ever showed an emoji here until her v2 art arrived, so her seal — a
   circle like the others — had no rule to clip the image to it. Without this her
   portrait rendered as a rectangle, and because the v2 adult art is exported on a
   white background (the hatchlings are transparent; the adults are not), that
   rectangle showed as a white box on the parchment. Same overflow + cover the ring
   dragons already use: the circular seal hides the white corners exactly as it
   does for the other seven. (If Kate re-exports the adults with transparency, this
   still holds — it just clips a transparent image instead.) */
.tara__seal {
  overflow: hidden;
}

/* Tara's horns and face sit at the TOP of her portrait. Her background is now
   transparent (knocked out), so the seal's own gradient shows cleanly behind her —
   no white patch, no zoom needed to hide one. Just bias the crop up so the whole
   head, horns included, sits in the circle. */
.tara__seal img {
  object-position: 50% 12%;
}

/* Navy ink, always. The dragon's colour is in the ring above, never in the
   letters — Aspen is 1.6:1 as text on parchment. */
.sigil__name {
  font-size: var(--text-xs);
  font-weight: 700;
  color: var(--color-text);
  line-height: 1.2;
  transition: opacity var(--duration-base) var(--ease);
}

.sigil__pillar {
  display: none; /* no room on a phone; revealed in the circle */
  font-size: 0.6875rem;
  color: var(--color-text-faint);
  line-height: 1.2;
  transition: opacity var(--duration-base) var(--ease);
}

/* --- The rays --------------------------------------------------------------
   A thread from Tara to each of the seven. The vows made visible.

   They use the SAME angle maths as the sigils — same --i, same --count, same
   --radius — so they cannot drift out of alignment with the thing they point at.
   That is the whole reason to compute the ring in CSS rather than in JS.
   -------------------------------------------------------------------------- */

.rays {
  display: none;
}

/* --- The arrival -----------------------------------------------------------
   THE BUG THIS EXISTS TO FIX.

   A sigil is placed on the ring with `transform`. The old entrance animated
   `transform` as well — and an animation's transform WINS over the element's own.
   So for 700ms every dragon sat at dead centre, stacked under the headline, and
   then snapped out to its place. That flash of seven dragons under the copy was
   not a design choice. It was a collision.

   The fix is to animate the RADIUS instead of the transform. --radius is a
   registered custom property (@property below), so it interpolates, and the
   transform that reads it stays untouched. The dragons travel outward from Tara
   along their own thread — invisible for the first two-thirds of the journey, and
   materialising only as they near the place they are going to stand.

   You do not see them leave. You see them arrive.
   -------------------------------------------------------------------------- */

@property --radius {
  syntax: "<length>";
  inherits: false;
  initial-value: 0px;
}

@keyframes emerge {
  0% {
    --radius: 0px;
    opacity: 0;
  }
  62% {
    opacity: 0;
  }
  100% {
    --radius: var(--rim);
    opacity: 1;
  }
}

/* The thread draws itself alongside them. Note the rotate() is repeated inside
   the keyframe: a transform in an animation replaces the whole transform, so
   omitting it would flatten every ray to horizontal for the duration — the exact
   same mistake, one element over. */
@keyframes ray-draw {
  from {
    transform: rotate(var(--angle)) scaleX(0);
    opacity: 0;
  }
  to {
    transform: rotate(var(--angle)) scaleX(1);
    opacity: 0.35;
  }
}

@keyframes rise {
  from {
    opacity: 0;
    transform: translateY(14px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@keyframes ignite {
  from {
    opacity: 0;
    transform: scale(0.7);
  }
  to {
    opacity: 1;
    transform: scale(1);
  }
}

/* --- The circle, on a real screen ------------------------------------------ */

@media (min-width: 900px) {
  /* --rim is where the dragons stand, and the floor ring is drawn at exactly the
     same radius — so the seven are standing ON the circle rather than near it.
     One number, one circle.

     It lives on .lair rather than on .lair__inner because the floor is a SIBLING
     of the inner and needs the same value. */
  .lair {
    /* Wide enough that the bottom of the ring clears the buttons and the
       free-to-begin note. The copy sets this number — pull the ring in and the
       dragons land on the words. */
    --rim: min(40vw, 405px);
    padding-block: var(--space-8);
  }

  .lair__floor {
    width: calc(var(--rim) * 2);
  }

  /* The box has to be big enough to HOLD the ring, or .lair's overflow:hidden
     shears the top and bottom dragons off. A sigil is about 150px tall with its
     name and pillar under it, so the box needs the radius plus half of that on
     every side — hence the +80. Tie it to --rim rather than typing a number, so
     the two can never drift apart again. */
  .lair__inner {
    width: min(92vw, calc((var(--rim) + 80px) * 2));
    aspect-ratio: 1;
    place-content: center;
    gap: var(--space-4);
  }

  /* Tighter inside the circle than outside it. Every line the copy grows is a
     line the ring has to grow to clear, and the ring is bounded by the screen. */
  .lair__copy {
    max-width: 42ch;
    gap: var(--space-4);
  }

  .lair__headline {
    font-size: var(--text-2xl);
  }

  .lair__lede {
    font-size: var(--text-base);
  }

  .whisper {
    min-height: 2.75rem;
  }

  .seven,
  .rays {
    display: block;
    margin: 0;
    max-width: none;
  }

  /* Each sigil sits on the rim. --i and --count come from the template, so the
     ring re-spaces itself if Kate ever activates an eighth dragon — nothing here
     assumes there are seven.

     Item 0 lands at -90°: straight up, above the tagline. With an odd roster that
     leaves the GAP at the bottom — which is where it belongs, because the bottom
     of the copy is where the buttons, the free-to-begin note and the scroll cue
     all live. Put the gap at the top instead and a dragon lands on the call to
     action, which is exactly what it was doing. */
  .sigil,
  .ray {
    --step: calc(360deg / var(--count));
    --angle: calc(var(--i) * var(--step) - 90deg);
    --radius: var(--rim); /* --rim is inherited from .lair. One number, one circle. */
    position: absolute;
    top: 50%;
    left: 50%;
  }

  .sigil {
    --sigil-size: 84px;
    width: max-content;
    margin: 0;

    /* This transform is never animated. The entrance animates --radius, which
       this reads — so the dragon travels out along its own thread without the
       animation ever taking the transform away from it. */
    transform: translate(-50%, -50%)
      rotate(var(--angle))
      translate(var(--radius))
      rotate(calc(-1 * var(--angle)));

    animation:
      emerge 1100ms var(--ease) backwards,
      sigil-drift 9s var(--ease) infinite;
    animation-delay: calc(500ms + var(--i) * 110ms), calc(2400ms + var(--i) * -1.3s);
  }

  /* The link's own entrance is a mobile-only thing — in the circle, the <li>
     handles arrival and the link must not fade a second time on top of it. */
  .sigil__link {
    animation: none;
  }

  .sigil__pillar {
    display: block;
  }

  .ray {
    z-index: -1;
    width: var(--radius);
    height: 1px;
    transform-origin: 0 50%;
    transform: rotate(var(--angle));
    background: linear-gradient(
      to right,
      transparent 0%,
      color-mix(in srgb, var(--dragon-color) 30%, transparent) 30%,
      color-mix(in srgb, var(--dragon-color) 45%, transparent) 100%
    );
    opacity: 0.35;
    /* Drawn a beat behind its dragon, so the thread trails them out rather than
       arriving first and waiting. */
    animation: ray-draw 1100ms var(--ease) backwards;
    animation-delay: calc(600ms + var(--i) * 110ms);
    transition: opacity var(--duration-base) var(--ease);
  }

  /* The thread to whoever is speaking brightens; the rest fade back. */
  .lair.is-attending .ray {
    opacity: 0.1;
  }

  .lair.is-attending .ray.is-attended {
    opacity: 0.9;
  }

  /* Tara's turn is the exception: every thread is hers, so they all light. The
     room does not pick one of her children — it shows you that she holds all of
     them. */
  .lair.is-attending-tara .ray {
    opacity: 0.5;
  }

  /* They drift, gently, and out of step with one another. Alive, not animated. */
  @keyframes sigil-drift {
    0%,
    100% {
      margin-top: 0;
    }
    50% {
      margin-top: -8px;
    }
  }

  .tara__seal {
    width: 116px;
    height: 116px;
    font-size: 3.25rem;
  }
}

/* No wide-screen override. There used to be one, and it set --radius directly —
   which quietly broke the entrance: `emerge` ends on var(--rim), the declared
   value was 380px, and the moment the animation stopped filling, every dragon
   jumped. --ring already caps at 860px on its own. One number, one circle. */

/* --- Motion is decoration, and decoration is the first thing to go -----------
   Everything below is still legible, still clickable, still keyboard-navigable.
   Nothing moves; nothing is lost. That is the bar motion has to clear.
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  .lair__floor,
  .tara,
  .tara__seal,
  .sigil,
  .sigil__link,
  .ray,
  .lair__copy,
  .motes span {
    animation: none;
  }

  /* The entrance animated --radius, so switching it off leaves the dragons where
     the animation would have STARTED them: at zero, piled on top of Tara. Put
     them where they belong. Same for the floor ring, which is drawn by a sweep. */
  .sigil,
  .ray {
    --radius: var(--rim);
  }

  .lair__floor {
    --sweep: 1turn;
  }

  .motes {
    display: none;
  }

  .lair__inner {
    transform: none;
    transition: none;
  }

  /* The room may still change colour — that is information, not motion, and it is
     how somebody knows which Guardian they are pointing at. It simply arrives
     instantly. */
  .lair {
    transition: none;
  }

  .sigil__link:hover .sigil__art,
  .sigil__link:focus-visible .sigil__art,
  .tara:hover .tara__seal,
  .tara:focus-visible .tara__seal,
  .tara.is-attended .tara__seal {
    transform: none;
  }
}

/* ==========================================================================
   Below the lair.

   The room opens onto the rest of the page. Everything down here is a real thing
   from the database — the five crest tiers with their actual week gates, the four
   memberships with their actual prices. A homepage that describes a product in
   prose the product cannot back up is a brochure.
   ========================================================================== */

/* --- Dragon's Grace --------------------------------------------------------
   The emotional centre of the whole product, so it gets a panel of its own and
   the page slows down around it.

   "Miss a day and a dragon covers you" is the single sentence most likely to
   make somebody stay. It is not a feature; it is the argument.
   -------------------------------------------------------------------------- */

.grace {
  position: relative;
  padding: var(--space-10) var(--space-6);
  border: 1px solid var(--color-gold-soft);
  border-radius: var(--radius-lg);
  background:
    radial-gradient(
      70% 90% at 50% 0%,
      var(--color-gold-wash) 0%,
      transparent 70%
    ),
    var(--color-surface);
  overflow: hidden;
}

.grace::before {
  content: "";
  position: absolute;
  top: -40%;
  left: 50%;
  width: 120%;
  aspect-ratio: 1;
  transform: translateX(-50%);
  border-radius: 50%;
  border: 1px solid var(--color-gold-soft);
  opacity: 0.35;
  pointer-events: none;
}

.grace__body {
  position: relative;
  max-width: 52ch;
  margin-inline: auto;
  text-align: center;
}

.grace__body > * + * {
  margin-top: var(--space-4);
}

.grace__quote {
  padding: var(--space-5);
  border-left: 0;
  border-top: 1px solid var(--color-gold-soft);
  border-bottom: 1px solid var(--color-gold-soft);
  font-size: var(--text-2xl);
  color: var(--color-text);
}

@media (min-width: 768px) {
  .grace {
    padding: var(--space-16) var(--space-10);
  }
}

/* --- The ladder ------------------------------------------------------------
   Hatchling to Dragon Master. A rising line, not a list — the whole point of the
   crest system is that it takes six months, and a flat list of five bullets does
   not say that.
   -------------------------------------------------------------------------- */

.ladder {
  position: relative;
  display: grid;
  gap: var(--space-4);
  padding-left: var(--space-8);
}

/* The thread they hang from. */
.ladder::before {
  content: "";
  position: absolute;
  top: 12px;
  bottom: 12px;
  left: 19px;
  width: 2px;
  border-radius: var(--radius-full);
  background: linear-gradient(
    to bottom,
    var(--color-gold),
    var(--color-gold-soft) 70%,
    transparent
  );
}

.rung {
  position: relative;
  display: flex;
  gap: var(--space-4);
  padding: var(--space-5);
  background: var(--color-surface);
  border: 1px solid var(--color-line);
  border-radius: var(--radius-md);
}

.rung__mark {
  position: absolute;
  left: calc(-1 * var(--space-8) + 4px);
  top: var(--space-5);
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: var(--color-bg);
  border: 2px solid var(--color-gold);
  font-size: 0.9rem;
  line-height: 1;
  box-shadow: 0 0 0 4px var(--color-bg);
}

.rung__body > * + * {
  margin-top: var(--space-2);
}

.rung__when {
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--color-text-faint);
}

.rung__name {
  font-size: var(--text-xl);
}

.rung__meaning {
  color: var(--color-text-soft);
}

/* Each rung sits a little further in than the last. Six months of climbing,
   rendered as an actual climb rather than a bulleted list. */
@media (min-width: 768px) {
  .rung {
    margin-left: calc(var(--i) * 22px);
  }

  .ladder__note {
    margin-top: var(--space-6);
    margin-left: calc(4 * 22px);
  }
}

.ladder__note {
  margin-top: var(--space-5);
}

/* --- The free list --------------------------------------------------------- */

/* What a Wanderer gets. Two columns, no markers.

   It borrows .tier-card__benefits for its layout, which brings a gold dot with
   it — and a bullet in front of centred text is a bullet floating in space, since
   there is no left edge for it to sit against any more. The format stays; the
   dots go. */
.free-list {
  border-top: 1px solid var(--color-line);
  margin-top: var(--space-6);
  padding-top: var(--space-6);
}

.free-list li {
  padding-left: 0;
}

.free-list li::before {
  display: none;
}

@media (min-width: 640px) {
  .free-list {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: var(--space-3) var(--space-8);
  }
}

/* ==========================================================================
   R3 — more magic in the hero.

   Kate: "floating particles throughout the landing page circle like stars," and
   "Tara should shimmer a little to show the life inside of her."
   ========================================================================== */

/* The base .motes drift up from the floor of the ring. These fill the UPPER arc
   too, so the whole circle reads as full of stars rather than just its base. Same
   drift animation, seeded across the top half. */
.motes--dense span:nth-child(9)  { left: 20%; top: 24%; animation-delay: -3s;  animation-duration: 22s; }
.motes--dense span:nth-child(10) { left: 44%; top: 16%; animation-delay: -8s;  animation-duration: 26s; }
.motes--dense span:nth-child(11) { left: 63%; top: 22%; animation-delay: -1s;  animation-duration: 19s; }
.motes--dense span:nth-child(12) { left: 78%; top: 34%; animation-delay: -12s; animation-duration: 24s; }
.motes--dense span:nth-child(13) { left: 15%; top: 44%; animation-delay: -6s;  animation-duration: 20s; }
.motes--dense span:nth-child(14) { left: 88%; top: 50%; animation-delay: -16s; animation-duration: 27s; }
.motes--dense span:nth-child(15) { left: 52%; top: 40%; animation-delay: -10s; animation-duration: 21s; }
.motes--dense span:nth-child(16) { left: 34%; top: 34%; animation-delay: -14s; animation-duration: 23s; }

/* Tara breathes already (a glow pulse). The shimmer is a second, faster thing: a
   soft sheen that sweeps across her once every few seconds, clipped to the seal
   circle by its own overflow:hidden. Candlelight, not chrome — the brand forbids
   glossy (§4), so the highlight is low and the sweep is slow. */
.tara__seal--living::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: linear-gradient(
    115deg,
    transparent 34%,
    rgba(255, 255, 255, 0.26) 48%,
    transparent 62%
  );
  transform: translateX(-130%);
  animation: tara-shimmer 6.5s var(--ease) infinite;
  pointer-events: none;
  z-index: 2;
}

@keyframes tara-shimmer {
  0%,
  72% {
    transform: translateX(-130%);
  }
  100% {
    transform: translateX(130%);
  }
}

/* ==========================================================================
   R2 — Meet the Seven. The roster that opens.

   Each Guardian starts collapsed — just their face, name and pillar. Open one and
   it speaks: its vow, who it is, its colour rising as the accent border and ring.
   One open at a time (roster.js). It is a real <button> + a real panel, so it
   works with the keyboard and degrades to plain links if the JS never runs.
   ========================================================================== */

.roster {
  max-width: 720px;
  margin: var(--space-10) auto 0;
  display: grid;
  gap: var(--space-3);
}

.roster__item {
  --dragon-color: var(--color-gold);
  background: var(--color-surface);
  border: 1px solid var(--color-line);
  border-radius: var(--radius-md);
  overflow: hidden;
  transition:
    border-color var(--duration-base) var(--ease),
    box-shadow var(--duration-base) var(--ease);
}

.roster__item.is-open {
  border-color: color-mix(in srgb, var(--dragon-color) 55%, var(--color-line));
  box-shadow:
    0 0 0 1px color-mix(in srgb, var(--dragon-color) 40%, transparent),
    var(--shadow-md);
}

.guardian {
  width: 100%;
  display: flex;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-3) var(--space-4);
  background: transparent;
  border: 0;
  cursor: pointer;
  text-align: left;
  font: inherit;
  color: inherit;
}

.guardian:focus-visible {
  outline: 2px solid var(--dragon-color);
  outline-offset: -3px;
}

.guardian__face {
  position: relative;
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 60px;
  height: 60px;
  border-radius: 50%;
  background: radial-gradient(circle at 50% 38%, var(--color-surface), var(--color-bg));
  border: 2px solid color-mix(in srgb, var(--dragon-color) 60%, transparent);
  font-size: 1.6rem;
  transition:
    box-shadow var(--duration-base) var(--ease),
    transform var(--duration-base) var(--ease);
}

/* The portrait is clipped to a circle by its own radius, so the face itself does
   NOT clip — the signature particles (R6) need to drift up out of it. */
.guardian__face img {
  width: 100%;
  height: 100%;
  /* Without this the portrait art keeps its 2:3 ratio inside the centred grid
     (height:100% has no definite row to resolve against), rendering 56x84 — an
     ellipse that spills out of the circle. aspect-ratio squares it. Same bug and
     same fix as `.seal img` in atmosphere.css. */
  aspect-ratio: 1;
  border-radius: 50%;
  object-fit: cover;
  object-position: 50% 28%;
}

.guardian:hover .guardian__face,
.guardian:focus-visible .guardian__face {
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--dragon-color) 18%, transparent);
}

.guardian__id {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.guardian__name {
  font-size: var(--text-lg);
  font-weight: 700;
}

.guardian__pillar {
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--color-text-soft);
}

/* A + that becomes a − when open. Drawn, not a glyph, so it takes the dragon's
   colour and animates cleanly. */
.guardian__cue {
  flex: 0 0 auto;
  position: relative;
  width: 22px;
  height: 22px;
}

.guardian__cue::before,
.guardian__cue::after {
  content: "";
  position: absolute;
  background: var(--dragon-color, var(--color-gold));
  border-radius: 2px;
}

.guardian__cue::before {
  left: 2px;
  right: 2px;
  top: 10px;
  height: 2px;
}

.guardian__cue::after {
  top: 2px;
  bottom: 2px;
  left: 10px;
  width: 2px;
  transition: transform var(--duration-base) var(--ease);
}

.guardian[aria-expanded="true"] .guardian__cue::after {
  transform: scaleY(0);
}

.guardian__panel {
  padding: 0 var(--space-5) var(--space-5);
}

.guardian__panel > * + * {
  margin-top: var(--space-3);
}

.roster__item.is-open .guardian__panel {
  animation: guardian-open var(--duration-base) var(--ease);
}

@keyframes guardian-open {
  from {
    opacity: 0;
    transform: translateY(-6px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

.guardian__vow {
  font-size: var(--text-xl);
  color: var(--color-text);
}

.guardian__story {
  color: var(--color-text-soft);
  max-width: 58ch;
}

.roster__overseer {
  margin-top: var(--space-6);
  text-align: center;
  color: var(--color-text-soft);
}

/* ==========================================================================
   Kate's story (R1) — the bridge to /meet-kate, sitting above pricing.
   ========================================================================== */

.story {
  max-width: 62ch;
  margin-inline: auto;
  padding: var(--space-8) var(--space-6);
  text-align: center;
  border-top: 1px solid var(--color-gold-soft);
  border-bottom: 1px solid var(--color-gold-soft);
}

.story__body > * + * {
  margin-top: var(--space-4);
}

.story__actions {
  margin-top: var(--space-6);
}

/* ==========================================================================
   R6 — each Guardian's signature flourish on hover.

   Kate: "hover over Rosemary and tiny leaves float up… Haven and little hearts
   drift upwards… Luna and stars sparkle… Nova her compass shimmers… Valor two
   circles combine for the infinity circle… Aspen a tree grows taller… Kai his
   muscles flex… Tara she blinks at you."

   The effect is chosen by data-slug on the <li> — a CSS registry keyed on the
   DB slug, never a hardcoded name branch in JS or a template. Every one is pure
   decoration: aria-hidden, never blocks the button, and silent under
   prefers-reduced-motion (the whole block is gated at the bottom).
   ========================================================================== */

.guardian__fx {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 3;
}

.guardian__fx i {
  position: absolute;
  left: 50%;
  top: 46%;
  font-size: 0.8rem;
  line-height: 1;
  font-style: normal;
  opacity: 0;
  transform: translate(-50%, -50%);
}

/* --- Drifting particles: Rosemary (leaves), Haven (hearts), Luna (stars) ---- */
@keyframes fx-rise {
  0% {
    opacity: 0;
    transform: translate(calc(-50% + var(--dx, 0px)), -30%) scale(0.5) rotate(0deg);
  }
  30% {
    opacity: 1;
  }
  100% {
    opacity: 0;
    transform: translate(calc(-50% + var(--dx, 0px)), -220%) scale(1) rotate(var(--rot, 0deg));
  }
}

.roster__item[data-slug="rosemary"] .guardian:hover .guardian__fx i,
.roster__item[data-slug="haven"] .guardian:hover .guardian__fx i,
.roster__item[data-slug="luna"] .guardian:hover .guardian__fx i,
.roster__item[data-slug="rosemary"] .guardian:focus-visible .guardian__fx i,
.roster__item[data-slug="haven"] .guardian:focus-visible .guardian__fx i,
.roster__item[data-slug="luna"] .guardian:focus-visible .guardian__fx i {
  animation: fx-rise 1.5s var(--ease) infinite;
}

.guardian__fx i:nth-child(1) { --dx: -14px; --rot: -40deg; animation-delay: 0s; }
.guardian__fx i:nth-child(2) { --dx: 2px; --rot: 30deg; animation-delay: 0.35s; }
.guardian__fx i:nth-child(3) { --dx: 14px; --rot: 50deg; animation-delay: 0.7s; }

/* Colour EMOJI, deliberately — they render in their own colours, so R6 needs no
   `color:` fills. That keeps the brand rules intact: a dragon hex hardcoded in a
   stylesheet, or --dragon-color used as a text fill, is exactly what the brand
   tests forbid (both fail WCAG AA as ink). */
.roster__item[data-slug="rosemary"] .guardian__fx i::before { content: "\1F343"; } /* 🍃 */
.roster__item[data-slug="haven"] .guardian__fx i::before { content: "\1F497"; } /* 💗 */
.roster__item[data-slug="luna"] .guardian__fx i::before { content: "\2728"; } /* ✨ */

/* --- Nova: the compass turns ----------------------------------------------- */
.roster__item[data-slug="nova"] .guardian__fx i:nth-child(1) {
  --dx: 0;
  top: 50%;
  font-size: 1.5rem;
}
.roster__item[data-slug="nova"] .guardian__fx i:nth-child(1)::before { content: "\1F9ED"; } /* compass */
.roster__item[data-slug="nova"] .guardian:hover .guardian__fx i:nth-child(1),
.roster__item[data-slug="nova"] .guardian:focus-visible .guardian__fx i:nth-child(1) {
  animation: fx-spin 2.4s linear infinite;
}
@keyframes fx-spin {
  from { opacity: 1; transform: translate(-50%, -50%) rotate(0deg); }
  to { opacity: 1; transform: translate(-50%, -50%) rotate(360deg); }
}

/* --- Valor: two become infinity -------------------------------------------- */
.roster__item[data-slug="valor"] .guardian__fx i:nth-child(1) { top: 50%; font-size: 1.6rem; }
.roster__item[data-slug="valor"] .guardian__fx i:nth-child(1)::before { content: "\221E"; } /* ∞ — inherits navy ink */
.roster__item[data-slug="valor"] .guardian:hover .guardian__fx i:nth-child(1),
.roster__item[data-slug="valor"] .guardian:focus-visible .guardian__fx i:nth-child(1) {
  animation: fx-infinity 1.8s var(--ease) infinite;
}
@keyframes fx-infinity {
  0% { opacity: 0; transform: translate(-50%, -50%) scaleX(0.2); }
  40% { opacity: 1; transform: translate(-50%, -50%) scaleX(1.1); }
  60% { transform: translate(-50%, -50%) scaleX(0.95); }
  100% { opacity: 0.85; transform: translate(-50%, -50%) scaleX(1); }
}

/* --- Aspen: a tree grows ---------------------------------------------------- */
.roster__item[data-slug="aspen"] .guardian__fx i:nth-child(1) { top: 62%; font-size: 1.5rem; transform-origin: bottom center; }
.roster__item[data-slug="aspen"] .guardian__fx i:nth-child(1)::before { content: "\1F332"; } /* evergreen */
.roster__item[data-slug="aspen"] .guardian:hover .guardian__fx i:nth-child(1),
.roster__item[data-slug="aspen"] .guardian:focus-visible .guardian__fx i:nth-child(1) {
  animation: fx-grow 1.6s var(--ease) infinite;
}
@keyframes fx-grow {
  0% { opacity: 0; transform: translate(-50%, -40%) scale(0.3); transform-origin: bottom; }
  40% { opacity: 1; }
  100% { opacity: 0.9; transform: translate(-50%, -55%) scale(1); transform-origin: bottom; }
}

/* --- Kai: a flex — the face gives a small impact pulse + a spark ------------ */
.roster__item[data-slug="kai"] .guardian:hover .guardian__face,
.roster__item[data-slug="kai"] .guardian:focus-visible .guardian__face {
  animation: fx-flex 0.9s var(--ease) infinite;
}
@keyframes fx-flex {
  0%, 100% { transform: scale(1); }
  40% { transform: scale(1.08); }
}
.roster__item[data-slug="kai"] .guardian__fx i:nth-child(1) { top: 30%; left: 74%; font-size: 0.9rem; }
.roster__item[data-slug="kai"] .guardian__fx i:nth-child(1)::before { content: "\2728"; } /* spark */
.roster__item[data-slug="kai"] .guardian:hover .guardian__fx i:nth-child(1),
.roster__item[data-slug="kai"] .guardian:focus-visible .guardian__fx i:nth-child(1) {
  animation: fx-pop 0.9s var(--ease) infinite;
}
@keyframes fx-pop {
  0%, 100% { opacity: 0; transform: translate(-50%, -50%) scale(0.4); }
  40% { opacity: 1; transform: translate(-50%, -50%) scale(1); }
}

/* --- Tara: she blinks — a soft twinkle at the eye -------------------------- */
.roster__item[data-slug="tara"] .guardian__fx i:nth-child(1) { top: 34%; left: 40%; font-size: 0.8rem; }
.roster__item[data-slug="tara"] .guardian__fx i:nth-child(1)::before { content: "\2728"; } /* ✨ */
.roster__item[data-slug="tara"] .guardian:hover .guardian__fx i:nth-child(1),
.roster__item[data-slug="tara"] .guardian:focus-visible .guardian__fx i:nth-child(1) {
  animation: fx-twinkle 1.4s var(--ease) infinite;
}
@keyframes fx-twinkle {
  0%, 100% { opacity: 0; transform: translate(-50%, -50%) scale(0.3); }
  50% { opacity: 1; transform: translate(-50%, -50%) scale(1); }
}

@media (prefers-reduced-motion: reduce) {
  .tara__seal--living::after {
    animation: none;
    opacity: 0;
  }

  .roster__item.is-open .guardian__panel {
    animation: none;
  }

  .guardian__cue::after {
    transition: none;
  }

  /* R6 flourishes are delight-only — silent when motion is reduced. */
  .guardian__fx i,
  .guardian__fx i:nth-child(1),
  .guardian:hover .guardian__face,
  .guardian:focus-visible .guardian__face {
    animation: none !important;
  }
}

/* --- Dragon's Grace, illustrated (R9) -------------------------------------- */
.grace--illustrated {
  display: grid;
  gap: var(--space-6);
  align-items: center;
}

.grace__art {
  display: grid;
  place-items: center;
}

.grace-illustration {
  width: min(220px, 68%);
  height: auto;
}

.grace--illustrated .grace__body {
  text-align: center;
  margin-inline: auto;
}

@media (min-width: 768px) {
  .grace--illustrated {
    grid-template-columns: 220px 1fr;
    gap: var(--space-10);
  }

  .grace--illustrated .grace__body {
    text-align: left;
    margin-inline: 0;
  }

  .grace--illustrated .grace__quote {
    /* left-aligned layout: the quote's centred border rules would look odd */
    border-left: 3px solid var(--color-gold-soft);
    border-top: 0;
    border-bottom: 0;
    padding-block: var(--space-2);
  }
}

/* ==========================================================================
   Revision 2 — Kate sooner (K1), social proof (K2).
   ========================================================================== */

/* K1 — the brief Kate hello, above the dragons. Photo beside a short "why", or
   stacked and centred on a phone. The photo is blank-safe: a labelled placeholder
   circle until she uploads one. */
.kate-intro {
  display: grid;
  gap: var(--space-6);
  align-items: center;
  max-width: 880px;
  margin-inline: auto;
  text-align: center;
}

.kate-intro__photo {
  justify-self: center;
  display: grid;
  place-items: center;
  width: 160px;
  height: 160px;
  border-radius: 50%;
  overflow: hidden;
  background: radial-gradient(circle at 50% 38%, var(--color-surface), var(--color-bg));
  border: 2px solid var(--color-gold-soft);
}

.kate-intro__photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.kate-intro__placeholder {
  padding: var(--space-3);
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--color-text-faint);
  text-align: center;
}

.kate-intro__body > * + * {
  margin-top: var(--space-4);
}

@media (min-width: 768px) {
  .kate-intro {
    grid-template-columns: 160px 1fr;
    gap: var(--space-10);
    text-align: left;
  }
}

/* K2 — testimonials. Real words only (the model enforces consent). */
.testimonials {
  display: grid;
  gap: var(--space-5);
  margin-top: var(--space-8);
}

@media (min-width: 768px) {
  .testimonials {
    grid-template-columns: repeat(2, 1fr);
  }
}

.testimonial {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  padding: var(--card-pad);
  background: var(--color-surface);
  border: 1px solid var(--color-line);
  border-left: 3px solid var(--dragon-color, var(--color-gold));
  border-radius: var(--radius-md);
}

.testimonial__quote {
  font-size: var(--text-lg);
  line-height: var(--leading-snug);
}

.testimonial__who {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin-top: auto;
}

.testimonial__photo {
  flex: 0 0 auto;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  object-fit: cover;
}

.testimonial__name {
  font-weight: 700;
}

/* K2 — community wins, pulled live from the Victory Wall. */
.wins-strip {
  margin-top: var(--space-10);
}

.wins-strip__list {
  display: grid;
  gap: var(--space-4);
  margin-top: var(--space-5);
}

@media (min-width: 640px) {
  .wins-strip__list {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (min-width: 1024px) {
  .wins-strip__list {
    grid-template-columns: repeat(4, 1fr);
  }
}

.win-chip {
  padding: var(--space-4);
  background: var(--color-surface-sunk);
  border-radius: var(--radius-md);
  border-top: 2px solid var(--dragon-color, var(--color-gold));
  font-size: var(--text-sm);
}

.win-chip > * + * {
  margin-top: var(--space-2);
}
