/* ============================================================================
   The summoning ritual
   ----------------------------------------------------------------------------
   Four beats: charge, tell, burst, reveal. The tell is the one that matters —
   the light turns the colour of the best card in the pull before any card is
   visible, so the player knows something good is coming before they know what
   it is. That gap is the entire feeling the screen exists to produce.

   Depends on tokens.css and kit.css.
   ========================================================================== */

.sm-stage {
  position: absolute;
  inset: 0;
  z-index: var(--z-overlay);
  display: grid;
  place-items: center;
  overflow: hidden;
  background: radial-gradient(70% 50% at 50% 55%, #1a1526 0%, #07080e 72%);
  --tell: var(--r-r);
  --tell-glow: rgba(255, 255, 255, 0.3);
}

/* --- beat 1: the circle wakes --------------------------------------------- */

/* The art is painted in three-quarter perspective, so the disc is an ellipse.
   Spinning that in 2D reads as an object tumbling end over end rather than a
   circle turning on the ground — the motion lives in the motes and the glow
   instead. Nudged up because the painted mass sits low in its own frame. */
.sm-circle {
  position: absolute;
  top: 46%;
  left: 50%;
  width: 260px;
  height: 260px;
  transform: translate(-50%, -50%) scale(0.86);
  background-size: contain;
  background-position: center;
  background-repeat: no-repeat;
  opacity: 0;
  transition:
    opacity 500ms var(--ease-out),
    transform 700ms var(--ease-out),
    filter 400ms var(--ease-out);
}

.sm-stage.is-charging .sm-circle {
  opacity: 1;
  transform: translate(-50%, -50%) scale(1);
  animation: sm-breathe-circle 2.6s ease-in-out infinite;
}

@keyframes sm-breathe-circle {
  0%, 100% { transform: translate(-50%, -50%) scale(1); }
  50% { transform: translate(-50%, -50%) scale(1.035); }
}

/* Motes converging on the circle. Each starts on its own bearing and falls
   inward; the stagger is what makes it read as gathering rather than as a
   ring appearing. */
.sm-motes {
  position: absolute;
  top: 46%;
  left: 50%;
  width: 0;
  height: 0;
}

.sm-motes i {
  position: absolute;
  width: 7px;
  height: 7px;
  margin: -3.5px;
  border-radius: 50%;
  background: var(--tell);
  box-shadow: 0 0 10px 3px var(--tell-glow);
  opacity: 0;
}

.sm-stage.is-charging .sm-motes i {
  animation: sm-converge 1.5s var(--ease-in) infinite;
  animation-delay: var(--d);
  rotate: var(--a);
}

@keyframes sm-converge {
  0% { opacity: 0; translate: 230px 0; scale: 0.4; }
  26% { opacity: 1; }
  100% { opacity: 0; translate: 10px 0; scale: 1.3; }
}

/* --- beat 2: the tell ------------------------------------------------------ */

.sm-stage.is-telling .sm-circle {
  filter:
    drop-shadow(0 0 28px var(--tell-glow))
    drop-shadow(0 0 70px var(--tell-glow));
}

.sm-stage.is-telling::before {
  content: '';
  position: absolute;
  inset: 0;
  background: radial-gradient(48% 36% at 50% 50%, var(--tell-glow), transparent 70%);
  animation: sm-swell 600ms var(--ease-out) forwards;
}

@keyframes sm-swell {
  from { opacity: 0; transform: scale(0.6); }
  to { opacity: 1; transform: scale(1); }
}

/* --- beat 3: burst --------------------------------------------------------- */

.sm-stage.is-bursting .sm-circle {
  animation: sm-burst 520ms var(--ease-out) forwards;
}

@keyframes sm-burst {
  0% { transform: translate(-50%, -50%) scale(1); }
  40% { transform: translate(-50%, -50%) scale(1.22); }
  100% { transform: translate(-50%, -50%) scale(2.6); opacity: 0; }
}

.sm-stage.is-bursting::after {
  content: '';
  position: absolute;
  inset: 0;
  background: #fff;
  animation: sm-flash 520ms var(--ease-out) forwards;
}

@keyframes sm-flash {
  0% { opacity: 0; }
  22% { opacity: 0.86; }
  100% { opacity: 0; }
}

.sm-skip {
  position: absolute;
  right: var(--s4);
  top: max(var(--s4), env(safe-area-inset-top));
  min-height: var(--tap);
  padding: 0 var(--s4);
  border: 0;
  border-radius: var(--rad-pill);
  background: rgba(255, 255, 255, 0.12);
  color: var(--text-muted);
  font-family: var(--font-display);
  cursor: pointer;
}

/* --- beat 4: the reveal ----------------------------------------------------- */

.sm-reveal {
  position: relative;
  z-index: 2;
  display: grid;
  gap: var(--s4);
  width: min(430px, 100%);
  padding: var(--s4);
  animation: kit-rise var(--t-base) var(--ease-out);
}

.sm-reveal-title {
  margin: 0;
  text-align: center;
  font-family: var(--font-display);
  font-size: var(--fz-display);
  color: var(--gold-200);
  text-shadow: 0 3px 0 rgba(0, 0, 0, 0.7);
}

.sm-grid {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 6px;
}
.sm-grid:has(> :nth-child(1):last-child) { grid-template-columns: 1fr; justify-items: center; }
.sm-grid:has(> :nth-child(1):last-child) .sm-card { width: 150px; }

/* The card itself: a 3D flip, so turning one is a physical act rather than a
   crossfade. The back is the same for every card — that is the point. */
.sm-card {
  position: relative;
  aspect-ratio: 3 / 4;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  transform-style: preserve-3d;
  transition: transform 460ms var(--ease-back);
  animation: sm-deal 420ms var(--ease-back) backwards;
  animation-delay: calc(var(--i) * 70ms);
}

@keyframes sm-deal {
  0% { opacity: 0; transform: translateY(-120px) scale(0.5) rotate(-12deg); }
  100% { opacity: 1; transform: none; }
}

.sm-card.flipped { transform: rotateY(180deg); }

.sm-card-back,
.sm-card-front {
  position: absolute;
  inset: 0;
  display: grid;
  border-radius: var(--rad-sm);
  backface-visibility: hidden;
  overflow: hidden;
}

.sm-card-back {
  place-items: center;
  color: var(--gold-200);
  background:
    radial-gradient(70% 60% at 50% 30%, #2f2748, #14101f),
    var(--panel-face);
  box-shadow: inset 0 0 0 2px var(--gold-800), var(--cast-sm);
}

.sm-card-front {
  transform: rotateY(180deg);
  grid-template-rows: 1fr auto auto;
  background: var(--rar-bed, var(--r-r-bed));
  box-shadow: inset 0 0 0 2px var(--rar, var(--r-r)), var(--cast-sm);
}

.sm-card.r-r   { --rar: var(--r-r);   --rar-bed: var(--r-r-bed);   --rar-glow: var(--r-r-glow); }
.sm-card.r-s   { --rar: var(--r-s);   --rar-bed: var(--r-s-bed);   --rar-glow: var(--r-s-glow); }
.sm-card.r-sr  { --rar: var(--r-sr);  --rar-bed: var(--r-sr-bed);  --rar-glow: var(--r-sr-glow); }
.sm-card.r-ssr { --rar: var(--r-ssr); --rar-bed: var(--r-ssr-bed); --rar-glow: var(--r-ssr-glow); }
.sm-card.r-ur  { --rar: var(--r-ur);  --rar-bed: var(--r-ur-bed);  --rar-glow: var(--r-ur-glow); }

.sm-card.r-ssr.flipped .sm-card-front,
.sm-card.r-ur.flipped .sm-card-front {
  box-shadow: inset 0 0 0 2px var(--rar), inset 0 0 18px var(--rar-glow), 0 0 16px var(--rar-glow);
}

.sm-card-art {
  background-size: auto 118%;
  background-position: center 8%;
  background-repeat: no-repeat;
}

.sm-card-name {
  padding: 2px 3px;
  font-size: 0.56rem;
  line-height: 1.1;
  text-align: center;
  color: var(--text-cream);
  background: rgba(6, 8, 14, 0.8);
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}

.sm-card-new,
.sm-card-dupe {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 2px;
  padding: 1px 0;
  font-size: 0.56rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.sm-card-new { color: #10210f; background: var(--success); }
.sm-card-dupe { color: var(--text-muted); background: rgba(6, 8, 14, 0.9); text-transform: none; }

.sm-reveal-actions { display: flex; gap: var(--s2); }

/* --- the showcase ----------------------------------------------------------- */

.sm-show {
  position: absolute;
  inset: 0;
  z-index: var(--z-toast);
  display: grid;
  place-items: center;
  overflow: hidden;
  background: radial-gradient(60% 50% at 50% 50%, rgba(28, 20, 44, 0.96), rgba(5, 6, 12, 0.98));
  animation: kit-fade 180ms var(--ease-out);
}

/* Rays behind the figure, turning slowly. The genre's own grammar for
   "this one is rare". */
.sm-show-rays {
  position: absolute;
  width: 170vmax;
  height: 170vmax;
  background: repeating-conic-gradient(
    from 0deg,
    var(--ray, rgba(255, 210, 130, 0.17)) 0deg 7deg,
    transparent 7deg 15deg);
  animation: sm-rays 22s linear infinite;
}
.sm-show.r-ssr { --ray: rgba(255, 110, 110, 0.22); }
.sm-show.r-ur { --ray: rgba(255, 70, 110, 0.26); }
@keyframes sm-rays { from { rotate: 0deg; } to { rotate: 360deg; } }

.sm-show-art {
  position: relative;
  max-height: 56vh;
  filter: drop-shadow(0 16px 30px rgba(0, 0, 0, 0.8));
  animation: sm-show-art 700ms var(--ease-back);
}
@keyframes sm-show-art {
  0% { opacity: 0; transform: scale(0.72) translateY(40px); }
  100% { opacity: 1; transform: none; }
}

.sm-show-text {
  position: absolute;
  bottom: 12%;
  display: grid;
  justify-items: center;
  gap: 2px;
  padding: 0 var(--s6);
  text-align: center;
  animation: kit-rise 500ms var(--ease-out) 240ms backwards;
}

.sm-show-tier {
  padding: 1px 12px;
  border-radius: var(--rad-pill);
  font-size: var(--fz-tiny);
  font-weight: 800;
  letter-spacing: 0.12em;
  color: var(--ink-900);
  background: var(--r-ur);
}
.sm-show.r-ssr .sm-show-tier { background: var(--r-ssr); color: #fff; }

.sm-show-name {
  font-family: var(--font-display);
  font-size: var(--fz-display);
  color: var(--gold-100);
  text-shadow: 0 3px 0 rgba(0, 0, 0, 0.8), 0 0 28px rgba(255, 200, 110, 0.5);
}
.sm-show-meta { font-size: var(--fz-small); color: var(--text-muted); text-transform: capitalize; }
.sm-show-line {
  max-width: 30ch;
  font-size: var(--fz-small);
  color: var(--text-dim);
  font-style: italic;
}

@media (prefers-reduced-motion: reduce) {
  .sm-circle, .sm-motes i, .sm-show-rays, .sm-card, .sm-show-art { animation: none; }
  .sm-card { transition-duration: 1ms; }
}

/* --- the banner -------------------------------------------------------------
   A place rather than a photograph with a caption: the portal lit behind, a
   hero standing in front of it, and the text on a plate at the foot where it
   cannot sit on top of a face. */

.sm-banner {
  position: relative;
  /* Sized against the screen, not fixed. The banner is the best thing on
     this page and it should be as large as it can be WITHOUT pushing the
     rates and history controls off the bottom — at a flat 268px the page
     overflowed by 129px on a 390x844 phone and the secondary row was
     unreachable without scrolling. 30vh keeps it dominant at every size
     and bounded at the small end. */
  height: clamp(170px, 25vh, 240px);
  margin-bottom: var(--s3);
  border-radius: var(--rad-lg);
  overflow: hidden;
  box-shadow:
    inset 0 0 0 var(--frame-w) var(--gold-800),
    var(--bevel),
    var(--shelf-md) var(--gold-800),
    var(--cast-md);
}

.sm-banner-bg {
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: center;
  filter: saturate(0.9) brightness(0.72);
}

/* Light welling up from behind the figure, slowly breathing. */
.sm-banner-glow {
  position: absolute;
  inset: auto 0 -22% 0;
  height: 76%;
  background: radial-gradient(52% 70% at 50% 100%, rgba(255, 206, 128, 0.5), transparent 72%);
  animation: sm-banner-glow 4.6s ease-in-out infinite;
}
@keyframes sm-banner-glow {
  0%, 100% { opacity: 0.75; transform: scaleY(1); }
  50% { opacity: 1; transform: scaleY(1.07); }
}

.sm-banner-star {
  position: absolute;
  bottom: 44px;
  left: 50%;
  translate: -50% 0;
  height: 212px;
  transform-origin: 50% 100%;
  filter: drop-shadow(0 10px 18px rgba(0, 0, 0, 0.7));
}

.sm-banner-plate {
  position: absolute;
  inset: auto 0 0 0;
  display: grid;
  gap: 1px;
  padding: var(--s4) var(--s3) var(--s2);
  background: linear-gradient(180deg, transparent, rgba(6, 8, 14, 0.94) 48%);
}

.sm-banner-name {
  font-family: var(--font-display);
  font-size: var(--fz-title);
  color: var(--gold-200);
  text-shadow: 0 2px 0 rgba(0, 0, 0, 0.7);
}
.sm-banner-blurb { font-size: var(--fz-small); color: var(--text-muted); }
.sm-banner-deal {
  justify-self: start;
  margin-top: 4px;
  padding: 1px 9px;
  border-radius: var(--rad-pill);
  font-size: var(--fz-tiny);
  color: #10210f;
  background: var(--success);
}

/* --- cost buttons ------------------------------------------------------------ */

.sm-costs { display: grid; gap: var(--s2); margin-bottom: var(--s3); }
.sm-cost { display: flex; gap: var(--s2); }
.sm-cost .kit-btn.secondary { flex: 0 0 auto; padding: 0 var(--s3); }

.sm-price {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  margin-left: var(--s2);
  padding: 2px 8px 2px 4px;
  border-radius: var(--rad-pill);
  background: rgba(40, 24, 4, 0.22);
  font-family: var(--font-num);
  font-size: var(--fz-small);
}

.sm-note { margin: 0 0 var(--s2); font-size: var(--fz-small); color: var(--text-dim); }

/* --- the near miss ----------------------------------------------------------
   The tell climbs the rarity ladder and, one time in four, goes one rung too
   far before falling back. While it is up there the light flares and the
   circle holds its breath — a half-second of "maybe" that costs nothing,
   because the pull was decided before the first frame was drawn.

   Nothing here can change an outcome. The animation reads the result; it
   does not produce it. That distinction is what keeps this an honest piece
   of theatre rather than a tease. */

.sm-stage.is-nearmiss .sm-circle {
  animation: sm-nearmiss 420ms var(--ease-out);
}
@keyframes sm-nearmiss {
  0%   { transform: scale(1); filter: brightness(1); }
  35%  { transform: scale(1.08); filter: brightness(1.5) saturate(1.3); }
  100% { transform: scale(1); filter: brightness(1); }
}

/* The motes surge outward with it, so the flare reads as the circle trying
   to reach a higher rarity rather than as a lighting change. */
.sm-stage.is-nearmiss .sm-motes > i {
  animation-duration: 240ms;
  filter: brightness(1.6);
}

/* The tell colour transitions rather than cutting, which is what makes a
   climb read as a climb. */
.sm-circle { transition: box-shadow var(--t-quick) var(--ease-out); }

/* --- pity, as a bar with marks ----------------------------------------------
   It used to be the line "7 / 10". A counter states a fact; a bar with the
   guarantee marked on it shows how close you are, and closeness is the thing
   that decides whether there is an eleventh pull. */

.sm-pity { display: grid; gap: var(--s2); }

.sm-pity-row {
  display: grid;
  grid-template-columns: 4.5rem 1fr auto;
  align-items: center;
  gap: var(--s2);
  font-size: var(--fz-small);
}

.sm-pity-label { color: var(--text-muted); }

.sm-pity-track {
  position: relative;
  height: 10px;
  border-radius: var(--rad-pill);
  background: var(--panel-sunken);
  box-shadow: var(--carve);
  overflow: hidden;
}

.sm-pity-fill {
  display: block;
  height: 100%;
  border-radius: inherit;
  background: linear-gradient(90deg, var(--pity-c, var(--gold-400)), var(--pity-c, var(--gold-200)));
  transition: width var(--t-base) var(--ease-out);
}

/* Inside ten of the guarantee the bar starts breathing. That is the moment
   the player is deciding whether to stop, and it is the only moment this
   screen is allowed to lean on them. */
.sm-pity-row.is-close .sm-pity-fill { animation: sm-pity-pulse 1.4s ease-in-out infinite; }
@keyframes sm-pity-pulse {
  0%, 100% { filter: brightness(1); }
  50%      { filter: brightness(1.35); }
}

.sm-pity-n {
  font-size: var(--fz-tiny);
  color: var(--text-dim);
  white-space: nowrap;
}
.sm-pity-row.is-close .sm-pity-n { color: var(--gold-200); }

/* The free pull. Above the priced rows, because the one thing that costs
   nothing should not be read past two prices to be found. */
.sm-free {
  margin-bottom: var(--s2);
  animation: sm-free-breathe 2.8s var(--ease-out) infinite;
}
.sm-free .sm-price { opacity: 0.75; text-transform: uppercase; }
@keyframes sm-free-breathe {
  0%, 100% { filter: brightness(1); }
  50% { filter: brightness(1.1); }
}
@media (prefers-reduced-motion: reduce) { .sm-free { animation: none; } }

/* Soft pity made visible.

   The tick marks where the rate starts climbing; the row warms once it has.
   Both are drawn from the same numbers the roll uses, so the bar cannot show
   one thing while the dice do another. */
.sm-pity-mark {
  position: absolute;
  top: -2px;
  bottom: -2px;
  left: var(--pity-soft, 75%);
  width: 2px;
  border-radius: 1px;
  background: color-mix(in srgb, var(--pity-c) 70%, transparent);
}
.sm-pity-track { position: relative; overflow: visible; }

/* Past the tick, the number is the thing to look at. */
.sm-pity-row.is-warming .sm-pity-n {
  color: var(--pity-c, var(--gold-200));
  font-weight: 800;
}
.sm-pity-row.is-warming .sm-pity-fill {
  animation: sm-warm 1.9s var(--ease-out) infinite;
}
@keyframes sm-warm {
  0%, 100% { filter: brightness(1); }
  50% { filter: brightness(1.28); }
}
@media (prefers-reduced-motion: reduce) {
  .sm-pity-row.is-warming .sm-pity-fill { animation: none; }
}

/* ===========================================================================
   §14.5, second pass
   --------------------------------------------------------------------------
   The banner names who is standing on it; the pity meter counts pulls
   rather than reciting a percentage that never moves; one button per pull
   size; and the reference material goes behind controls instead of down
   the page.
   ========================================================================= */

/* --- the featured hero ---------------------------------------------------- */

.sm-banner-cast { position: absolute; inset: 0; pointer-events: none; }

/* Each rotation swaps the node, so the entrance rides on the new child. */
.sm-banner-star.is-in { animation: sm-star-in 520ms var(--ease-out) both; }
@keyframes sm-star-in {
  from { opacity: 0; transform: translateY(10px) scale(0.98); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .sm-banner-star.is-in { animation: none; }
}

.sm-banner-hero { display: grid; gap: 3px; margin-top: 2px; }

.sm-banner-hname {
  font-family: var(--font-display);
  font-size: var(--fz-body);
  color: var(--text-cream);
  text-shadow: 0 2px 0 rgba(0, 0, 0, 0.7);
}

.sm-banner-htags { display: flex; align-items: center; gap: var(--s2); }

/* Rarity as a coloured chip rather than coloured text: at this size the
   tint alone was not surviving the painted background behind it. */
.sm-rar-chip {
  padding: 0 7px;
  border-radius: var(--rad-pill);
  font-size: var(--fz-tiny);
  font-weight: 800;
  letter-spacing: 0.04em;
  color: #07090f;
  background: var(--rar, var(--gold-300));
  box-shadow: 0 1px 0 rgba(0, 0, 0, 0.5);
}

.sm-fac-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: var(--fz-tiny);
  color: var(--text-muted);
  text-shadow: 0 1px 0 rgba(0, 0, 0, 0.7);
}

/* --- one button per pull size --------------------------------------------- */

/* The price sits at the right end of the same control rather than in a
   second button beside it. Two buttons asked for a currency decision on
   every summon whose answer is always "tokens while you have them". */
.sm-pull { display: flex; align-items: center; justify-content: center; gap: var(--s3); }
.sm-pull-label { font-family: var(--font-display); }

/* The spent free pull keeps its row and carries the countdown. An absent
   row answers "is there a free pull today" with silence. */
.sm-free.is-spent {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: 40px;
  padding: 0 var(--s3);
  border: 1px dashed var(--line);
  border-radius: var(--rad-md);
  background: var(--panel-sunken);
  color: var(--text-dim);
  font-size: var(--fz-small);
  animation: none;
}

/* --- the pity card -------------------------------------------------------- */

.sm-pity-card {
  display: grid;
  gap: var(--s2);
  margin-bottom: var(--s3);
  padding: var(--s3);
  border: 1px solid var(--line);
  border-radius: var(--rad-md);
  background: var(--panel-sunken);
  box-shadow: var(--carve);
}

.sm-pity-head { display: flex; align-items: baseline; gap: var(--s2); }

/* The number that matters, in the size that says so. */
.sm-pity-big {
  font-family: var(--font-display);
  font-size: 1.7rem;
  line-height: 1;
  color: var(--gold-200);
  text-shadow: 0 2px 0 rgba(0, 0, 0, 0.6);
}
.sm-pity-cap { font-size: var(--fz-small); color: var(--text-muted); }

.sm-pity-foot {
  display: flex;
  justify-content: space-between;
  font-size: var(--fz-tiny);
  color: var(--text-dim);
}

.sm-pity-card.is-warming .sm-pity-big { color: var(--warn); }
.sm-pity-card.is-close .sm-pity-big { color: var(--alert); }
.sm-pity-card.is-close .sm-pity-fill { animation: sm-pity-pulse 1.4s ease-in-out infinite; }

/* The soft-pity mark: where the rate leaves its base. */
.sm-pity-mark {
  position: absolute;
  top: 0;
  bottom: 0;
  left: var(--pity-soft, 75%);
  width: 2px;
  background: rgba(255, 255, 255, 0.45);
}

/* --- secondary controls --------------------------------------------------- */

/* Three framed icons, not three full-width bars. Rates and history are
   reference: read once, then never again until something changes. */
.sm-tools {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--s2);
}

.sm-tool {
  display: grid;
  justify-items: center;
  gap: 3px;
  padding: var(--s2) var(--s1);
  border: 0;
  background: none;
  color: var(--text-muted);
  font-size: var(--fz-tiny);
  cursor: pointer;
}

.sm-tool-face {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border: 2px solid var(--gold-800);
  border-radius: var(--rad-sm);
  background: var(--panel-sunken);
  box-shadow: var(--carve), 0 2px 0 rgba(0, 0, 0, 0.5);
  color: var(--gold-200);
}
.sm-tool:hover .sm-tool-face { border-color: var(--gold-300); }
.sm-tool:active .sm-tool-face { transform: translateY(2px); box-shadow: var(--carve); }

/* --- the rates sheet ------------------------------------------------------ */

.sm-rates { display: grid; gap: 2px; }

.sm-rate-row {
  display: grid;
  grid-template-columns: 2.6rem 1fr auto;
  align-items: center;
  gap: var(--s2);
  padding: var(--s2) var(--s2);
  border-radius: var(--rad-sm);
  background: var(--panel-sunken);
  font-size: var(--fz-small);
}
/* Not in the pool at all: stated, not omitted. */
.sm-rate-row.is-out { opacity: 0.72; }

.sm-rate-chip {
  justify-self: start;
  min-width: 2.2rem;
  padding: 1px 0;
  border-radius: var(--rad-sm);
  font-size: var(--fz-tiny);
  font-weight: 800;
  text-align: center;
  color: #07090f;
  background: var(--rar, var(--text-dim));
}

.sm-rate-name { color: var(--text-muted); }
.sm-rate-pct { color: var(--text-cream); }

.sm-note { margin: 0; font-size: var(--fz-tiny); color: var(--text-dim); }

.sm-hist-row { display: flex; align-items: center; gap: var(--s2); font-size: var(--fz-small); }
.sm-hist-pills { display: flex; gap: 3px; flex-wrap: wrap; }

/* The page has to end at the bottom of the screen. These are the measured
   trims that get it there, each taken from somewhere the space was not
   doing any work. */
.sm-banner-star { bottom: 30px; height: min(190px, 24vh); }
.sm-banner-plate { padding: var(--s3) var(--s3) var(--s2); }
.sm-costs { gap: 6px; margin-bottom: var(--s2); }
.sm-pull { min-height: 46px; }
.sm-pull.lg { min-height: 54px; }
.sm-free { margin-bottom: var(--s2); min-height: 44px; }
.sm-pity-card { gap: 6px; padding: var(--s2) var(--s3); margin-bottom: var(--s2); }
.sm-pity-big { font-size: 1.45rem; }
.sm-tool { padding: var(--s1) var(--s1); }
.sm-tool-face { width: 40px; height: 40px; }
.sm-banner { margin-bottom: var(--s2); }
.sm-banner-star { height: min(165px, 20vh); }
.sm-tool { padding: 2px var(--s1); gap: 2px; }

/* ===========================================================================
   §14.7, second pass — the reveal
   --------------------------------------------------------------------------
   The pull happens at the shrine, the cards fill the screen they are on,
   the backs are worth looking at, and the buttons change when the job
   changes.
   ========================================================================= */

/* The shrine stays behind the reveal. A flat gradient threw away the place
   the summon was performed in at the moment the player looks hardest. */
.sm-stage-bg {
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: center 38%;
  opacity: 0.55;
  filter: saturate(0.85);
}
.sm-stage-bg::after {
  content: '';
  position: absolute;
  inset: 0;
  background: radial-gradient(72% 54% at 50% 48%, rgba(10, 8, 18, 0.1), rgba(5, 6, 12, 0.93) 76%);
}

/* --- cards fill the screen -------------------------------------------------
   `width: min(430px, 100%)` on a 390px phone left the ten-pull grid under
   240px wide: ten cards across half the screen with the rest unused. The
   reveal is the most important thing the game shows and it was the
   smallest. ~85% of the width, in two rows of five. */
.sm-reveal {
  width: min(560px, 94%);
  gap: var(--s3);
  padding: var(--s3);
}

.sm-grid { gap: 8px; width: 100%; }

/* A ten-pull is two rows of five, and the second row is OFFSET — a 2x5
   block reads as a spreadsheet, a staggered one as a hand of cards.
   The offset is a MARGIN, not a transform: `transform` is what the flip
   itself animates, so a stagger written that way silently replaced the
   rotation and the whole second row stayed face-down after "Flip all". */
.sm-grid.is-ten { grid-template-columns: repeat(5, 1fr); }
.sm-grid.is-ten > :nth-child(n + 6) { margin-left: 9%; margin-right: -9%; }

/* --- the backs carry the rarity --------------------------------------------
   Face-down is not nothing. R says nothing, S shows a faint edge, SR
   pulses, and an SSR glows, shakes and throws embers. None of it is a
   guess: the pull resolved before the first frame, so the back is showing
   something already true rather than predicting it. */

.sm-card.back-s .sm-card-back {
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--r-s) 55%, transparent);
}

.sm-card.back-sr .sm-card-back {
  box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--r-sr) 75%, transparent);
  animation: sm-back-pulse 1.5s ease-in-out infinite;
}
@keyframes sm-back-pulse {
  0%, 100% { box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--r-sr) 55%, transparent); }
  50% {
    box-shadow:
      inset 0 0 0 2px var(--r-sr),
      0 0 14px color-mix(in srgb, var(--r-sr) 60%, transparent);
  }
}

.sm-card.back-ssr .sm-card-back,
.sm-card.back-ur .sm-card-back {
  box-shadow:
    inset 0 0 0 2px var(--r-ssr),
    0 0 18px color-mix(in srgb, var(--r-ssr) 70%, transparent);
}
/* The shake is on the CARD, not the face, so it survives the flip
   transform being replaced. */
.sm-card.back-ssr:not(.flipped),
.sm-card.back-ur:not(.flipped) { animation: sm-card-shake 1.9s ease-in-out infinite; }
@keyframes sm-card-shake {
  0%, 62%, 100% { transform: none; }
  68% { transform: translateX(-2px) rotate(-1.4deg); }
  74% { transform: translateX(2px) rotate(1.4deg); }
  80% { transform: translateX(-1px) rotate(-0.7deg); }
  86% { transform: none; }
}

.sm-card-embers {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
}
.sm-card-embers i {
  position: absolute;
  bottom: -6px;
  left: var(--x);
  width: 3px;
  height: 3px;
  border-radius: 50%;
  background: var(--r-ssr, #ff9a3c);
  box-shadow: 0 0 6px var(--r-ssr, #ff9a3c);
  animation: sm-ember 2.2s linear infinite;
  animation-delay: calc(var(--k) * 340ms);
}
@keyframes sm-ember {
  0% { opacity: 0; transform: translateY(0) scale(0.6); }
  18% { opacity: 1; }
  100% { opacity: 0; transform: translateY(-78px) scale(1.15); }
}

/* A flipped card stops advertising and stops moving. */
.sm-card.flipped { animation: none; }

@media (prefers-reduced-motion: reduce) {
  .sm-card.back-sr .sm-card-back,
  .sm-card.back-ssr:not(.flipped),
  .sm-card.back-ur:not(.flipped),
  .sm-card-embers i { animation: none; }
}

/* --- actions ---------------------------------------------------------------
   Two sets, one at a time: turn them or skip; then pull again or leave. */
.sm-reveal-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s2);
  align-items: stretch;
}
.sm-reveal-actions > .kit-btn { flex: 1 1 auto; min-height: 44px; }
.sm-reveal-actions > .kit-btn.block { flex: 1 1 100%; }

/* "NEW" as a ribbon across the corner rather than a word in the plate. */
.sm-card-new {
  position: absolute;
  z-index: 3;
  top: 7px;
  left: -20px;
  width: 74px;
  padding: 1px 0;
  rotate: -38deg;
  text-align: center;
  font-size: 0.5rem;
  font-weight: 800;
  letter-spacing: 0.08em;
  color: #07210f;
  background: var(--success);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.6);
}

/* On a tablet the phone-sized banner leaves the page short: the clamp
   that keeps it from pushing the controls off a 640px screen also stops
   it using a 1112px one, and the screen measured 72% full. The ceiling
   lifts where there is room for it. */
@media (min-width: 700px) {
  .sm-banner { height: clamp(260px, 34vh, 400px); }
  .sm-banner-star { height: min(320px, 29vh); }
  .sm-pity-card { padding: var(--s3); }
  .sm-tool-face { width: 52px; height: 52px; }
}
