/* Seal-dressing booth (seal.html) and Grape Ocean (ocean.html). Both link this file — same
   reasoning as seals.css being the one place that knows a seal badge is a picture: the seal
   figure, its effects and the tank are drawn the same way wherever they appear.

   Every colour here is one of site.css's own custom properties, so the booth follows the site's
   light/dark theme (the toggle stamps data-theme on <html>; there is no prefers-color-scheme
   fallback anywhere in this project, on purpose) instead of carrying a second palette. */

.seal-hint{color:var(--ink-soft); font-size:var(--fs-sealHint, .95rem); margin:8px 0;}
.seal-error{color:var(--pink); font-weight:700; min-height:1.3em; margin-top:8px; font-size:var(--fs-sealError, 1rem);}

/* Several rules below give an element its own `display` (flex/grid, for layout) on the same
   selector this page also toggles the HTML `hidden` attribute on — an attribute selector and a
   class selector of equal specificity is a coin flip, and here it kept losing (a "screen" that
   set display:grid stayed visible stacked under the next one; the mini tally showed 0/0 before
   unlock; an empty-state banner didn't disappear once seals existed). One page-wide override
   settles it in `hidden`'s favour everywhere, the same way site.css's own `.hidden` utility class
   already carries `!important` for exactly this reason. */
[hidden]{display:none !important;}

/* ------------------------------------------------------------ the seal figure */

/* 1000x664 is the art's own canvas (see seal-catalog.js) — every box the figure is drawn in
   keeps that 500/332 ratio so the drawing is never squashed, and the <svg> inside simply fills
   whatever box it is given. */
.seal-stage{width:300px; aspect-ratio:500/332; position:relative; margin:0 auto;}
.seal-stage-center{margin:10px auto;}
.seal-figure{width:100%; height:100%; position:relative; animation:seal-bob 2.8s ease-in-out infinite;}
.seal-figure-lg{width:270px; aspect-ratio:500/332; margin:0 auto;}
@keyframes seal-bob{0%,100%{transform:translateY(0);} 50%{transform:translateY(-7px);}}

/* ---- the legendary glow (sealLegendaryHtml) ----
   Automatic for anything in the top rarity tier. The aura is a sibling *behind* the figure, so
   the drawing needs its own stacking order to stay on top of it. */
.seal-figure > svg{position:relative; z-index:1;}
.seal-legend-glow{
  position:absolute; left:50%; top:52%; width:88%; aspect-ratio:1/1; z-index:0;
  transform:translate(-50%,-50%); pointer-events:none; border-radius:50%;
  background:radial-gradient(circle, rgba(255,205,70,.85) 0%, rgba(255,205,70,.38) 46%, rgba(255,205,70,0) 72%);
  animation:seal-legend-pulse 2.6s ease-in-out infinite;
}
@keyframes seal-legend-pulse{
  0%,100%{transform:translate(-50%,-50%) scale(.88); opacity:.72;}
  50%{transform:translate(-50%,-50%) scale(1.06); opacity:1;}
}
.seal-legend-stars{position:absolute; inset:0; z-index:2; pointer-events:none;}
.seal-legend-stars span{
  position:absolute; color:#ffd24a; font-size:clamp(11px, 4.5%, 22px); line-height:1;
  filter:drop-shadow(0 0 4px rgba(255,210,74,.9));
  animation:seal-legend-twinkle 1.9s ease-in-out infinite;
}
@keyframes seal-legend-twinkle{
  0%,100%{opacity:0; transform:scale(.4) rotate(0deg);}
  50%{opacity:1; transform:scale(1) rotate(22deg);}
}
/* The aura stays — it is what says "legendary" — but it stops breathing. */
@media (prefers-reduced-motion:reduce){
  .seal-legend-glow{animation:none; transform:translate(-50%,-50%) scale(1); opacity:.85;}
}

/* The effect layer floats around the seal rather than inside its <svg> — see sealEffectHtml().
   z-index:2 for the same reason .seal-legend-stars needs it just above: the body <svg> carries
   an explicit z-index:1 (for the legendary glow's own stacking, see that comment), and without
   a z-index here .seal-fx paints at its implicit auto/0 level — *behind* that svg. This was
   already wrong before any of the other effect fixes below: bubbles/sparkles have likely always
   rendered mostly hidden behind the seal's own body art, poking out only past its silhouette.
   `left`/`top` there are percentages of the stage, and .seal-bubble's own size is a %-of-width
   clamp() too (width/height percentages resolve against the containing box, so this genuinely
   shrinks at Ocean's ~110px badge instead of staying the booth-preview-sized 8px it used to be).
   .seal-spark used to size itself via `font-size` on the theory that the inner SVG's
   width="100%"/height="100%" would track it — it doesn't: a percentage width on a replaced
   element (the SVG) inside a box whose own width is auto (the span has no width, only
   font-size) has nothing definite to resolve against, so browsers fall back to sizing it off
   whatever ancestor box *does* have a definite width instead. Caught by the new aura effects
   below reusing this class for their sparkle glints and rendering a star bigger than the whole
   card. Fixed the same way every other icon effect here already sizes itself: an explicit
   `width` + `aspect-ratio`, not font-size. */
.seal-fx{position:absolute; inset:0; z-index:2; pointer-events:none;}
/* Bubbles, redone 2026-10-05 ("ไม่ขยับเลย"): the old 6% white dot bobbing 14% of its own size
   moved about a pixel at Ocean's badge size. Now a clear glossy bubble — a tinted rim, a shine
   spot and a faint rainbow sheen — that drifts up about two of its own heights with a sway,
   then pops (swells and fades). Still stays around her rather than flying off the stage.
   Transform/opacity only, so it's cheap enough to keep moving on every seal (see the
   effects-budget exemption under .ocean-seal:not(.fx-on)). */
.seal-bubble{
  position:absolute; width:clamp(7px, 10%, 22px); aspect-ratio:1/1; border-radius:50%;
  background:
    radial-gradient(circle at 32% 28%, #fff 0 13%, rgb(255 255 255/.4) 22%, transparent 34%),
    radial-gradient(circle at 70% 75%, rgb(255 190 230/.45), transparent 42%),
    radial-gradient(circle, rgb(210 240 255/.12) 0 55%, rgb(120 205 245/.38) 100%);
  border:1.5px solid rgb(70 175 225/.75);
  transform:translate(-50%,-50%); opacity:0;
  animation:seal-bubrise 3.4s ease-in-out infinite;
}
@keyframes seal-bubrise{
  0%{opacity:0; transform:translate(-50%,-50%) translate(0,0) scale(.45);}
  12%{opacity:1; transform:translate(-50%,-50%) translate(0,-15%) scale(.85);}
  40%{transform:translate(-50%,-50%) translate(-35%,-90%) scale(1);}
  70%{opacity:1; transform:translate(-50%,-50%) translate(30%,-170%) scale(1);}
  82%{opacity:.9; transform:translate(-50%,-50%) translate(0,-210%) scale(1.05);}
  90%{opacity:.6; transform:translate(-50%,-50%) translate(0,-215%) scale(1.45);}
  100%{opacity:0; transform:translate(-50%,-50%) translate(0,-215%) scale(1.7);}
}
@media (prefers-reduced-motion:reduce){ .seal-bubble{animation:none; opacity:1;} }
/* A cling, not a rise: she wears these, they don't leave — a small in-place bob/fade rather
   than travelling off the top of the stage (the old keyframe rose 180px, which is several
   stage-heights at Ocean's badge size and read as bubbles flying away instead of worn art). */
@keyframes seal-bubcling{
  0%,100%{transform:translate(-50%,-50%) translateY(0) scale(.82); opacity:.5;}
  50%{transform:translate(-50%,-50%) translateY(-14%) scale(1); opacity:1;}
}
.seal-spark{
  position:absolute; width:clamp(9px, 4.2%, 18px); aspect-ratio:1/1; transform:translate(-50%,-50%);
  animation:seal-twinkle 1.6s ease-in-out infinite;
}
@keyframes seal-twinkle{
  0%,100%{opacity:0; transform:translate(-50%,-50%) scale(.4) rotate(0deg);}
  50%{opacity:1; transform:translate(-50%,-50%) scale(1) rotate(20deg);}
}

/* hearts + grapes: the same cling idiom as bubbles (reuses seal-bubcling), just a different
   drawn icon at a different size — see SEAL_EFFECT_ICONS in seal-catalog.js. */
.seal-heart, .seal-grape{
  position:absolute; transform:translate(-50%,-50%);
  animation:seal-bubcling 2.6s ease-in-out infinite;
}
.seal-heart{width:clamp(9px, 7%, 20px); aspect-ratio:32/28;}
.seal-grape{width:clamp(8px, 6.5%, 18px); aspect-ratio:28/34;}

.seal-butterfly{
  position:absolute; width:clamp(11px, 9%, 26px); aspect-ratio:32/22;
  animation:seal-flutter 3.6s ease-in-out infinite;
}
/* Loops around its own spawn point rather than crossing the stage — every offset here is a
   transform:translate(%), which resolves against the butterfly's *own* (already stage-relative)
   size, so the loop itself scales down at Ocean's small badge instead of overshooting it. */
@keyframes seal-flutter{
  0%,100%{transform:translate(-50%,-50%) translate(0,0) rotate(-6deg);}
  25%{transform:translate(-50%,-50%) translate(60%,-70%) rotate(6deg);}
  50%{transform:translate(-50%,-50%) translate(10%,-130%) rotate(-4deg);}
  75%{transform:translate(-50%,-50%) translate(-60%,-55%) rotate(8deg);}
}

/* confetti / snow / petals: fall straight down through the stage. The travel animates `top`
   (a real percentage of the containing box) rather than transform:translateY — translateY's
   percentage resolves against the *element's own* height, which is what made the old bubble
   rise-and-fade unusable at more than one stage size (see the note above .seal-fx). Horizontal
   position is left at its per-instance inline `left`, untouched by any keyframe here, rather
   than swaying — animating that the same correct way would need `left` in every keyframe stop
   instead of transform:translateX, and a straight fall already reads fine. */
.seal-confetti-fx{
  position:absolute; top:-12%; width:clamp(3px, 2.6%, 8px); aspect-ratio:7/11; border-radius:1px;
  animation:seal-confetti-fall 2.6s linear infinite;
}
.seal-confetti-fx-pink{background:var(--pink);}
.seal-confetti-fx-yellow{background:var(--yellow);}
.seal-confetti-fx-mint{background:var(--mint);}
.seal-confetti-fx-lilac{background:var(--lilac);}
@keyframes seal-confetti-fall{
  0%{top:-12%; opacity:0; transform:rotate(0deg);}
  8%{opacity:1;}
  100%{top:112%; opacity:0; transform:rotate(340deg);}
}
.seal-snow{
  position:absolute; top:-8%; width:clamp(3px, 3.2%, 8px); aspect-ratio:1/1; border-radius:50%;
  background:#fff; box-shadow:0 0 3px rgba(255,255,255,.9);
  animation:seal-snow-fall 4.2s linear infinite;
}
@keyframes seal-snow-fall{
  0%{top:-8%; opacity:0;} 10%{opacity:.95;} 100%{top:108%; opacity:0;}
}
.seal-petal{
  position:absolute; top:-10%; width:clamp(7px, 6%, 18px); aspect-ratio:1/1;
  animation:seal-petal-fall 4s ease-in-out infinite;
}
@keyframes seal-petal-fall{
  0%{top:-10%; opacity:0; transform:rotate(0deg);}
  10%{opacity:1;}
  50%{top:45%; transform:rotate(160deg);}
  100%{top:112%; opacity:0; transform:rotate(320deg);}
}

.seal-shootingstar{
  position:absolute; width:clamp(16px, 11%, 36px); height:2px; border-radius:2px;
  background:linear-gradient(90deg, transparent, #fff 60%, var(--yellow));
  transform-origin:0% 50%; animation:seal-shootingstar-go 2.4s ease-in infinite;
}
/* translateX(%) here is relative to the star's own (already stage-relative) width, so the
   streak length scales down with it rather than overshooting a small stage. */
@keyframes seal-shootingstar-go{
  0%{opacity:0; transform:rotate(28deg) scaleX(0);}
  6%{opacity:1; transform:rotate(28deg) scaleX(1) translateX(0);}
  28%{opacity:0; transform:rotate(28deg) scaleX(1) translateX(-160%);}
  100%{opacity:0;}
}

/* rainbow: the one effect drawn *behind* the figure instead of floating in front of it — see
   the z-index:2 note above .seal-fx, and sealEffectHtml()'s rainbow branch for why it gets its
   own sibling wrapper instead of living inside .seal-fx. */
.seal-fx-back{position:absolute; inset:0; z-index:0; pointer-events:none;}
.seal-rainbow{
  position:absolute; left:50%; bottom:22%; width:78%; aspect-ratio:2/1; transform:translateX(-50%);
  border-radius:50% 50% 0 0; border:4px solid transparent;
  border-top-color:var(--pink); border-left-color:var(--yellow); border-right-color:var(--mint);
  opacity:.85; animation:seal-rainbow-fade 2.8s ease-in-out infinite;
}
@keyframes seal-rainbow-fade{
  0%,100%{opacity:.6; transform:translateX(-50%) scale(.97);}
  50%{opacity:1; transform:translateX(-50%) scale(1);}
}

/* ---- the eight aura effects (fire/lightning/space/candy/angel/demon/gold/sleep) ----
   Each pairs a small tinted glow (.seal-aura-glow, a modifier class per aura) with 2-4 particles
   in front. Went through three shape/size passes: a full-bleed circle copying the legendary
   aura's 88% ("ไม่น่ารักเลย" — not cute at all), a shrink to 56% that undershot ("ขอใหญ่กว่านี้
   ได้มั้ย" — bigger, please), then 78% as a plain circle. The plain-circle READ as "a shape
   sitting behind the seal" no matter the size — what a user-supplied reference site
   (living.monet3rdonelasttime.com) did differently was never the size, it was an irregular
   (not perfectly round) blob plus a scatter of twinkling motes, which is what actually reads as
   "light" instead of "shape". Two offset ellipses per colour, rather than one centred circle,
   is what makes it irregular; the motes are .seal-ministar spans laid down alongside it in
   sealEffectHtml. Still anchored low (top:56%, not 52%) so it stays a glow *behind* the seal
   rather than a halo centered on its face. */
.seal-aura-glow{
  position:absolute; left:47%; top:56%; width:82%; aspect-ratio:1/1;
  transform:translate(-50%,-50%); pointer-events:none; opacity:.8; filter:blur(1px);
  animation:seal-aura-pulse 3s ease-in-out infinite;
}
@keyframes seal-aura-pulse{
  0%,100%{transform:translate(-50%,-50%) scale(.94); opacity:.65;}
  50%{transform:translate(-50%,-50%) scale(1.06); opacity:.9;}
}
.seal-aura-fire{background:
  radial-gradient(ellipse 60% 50% at 40% 55%, rgba(255,138,61,.88) 0%, rgba(255,138,61,0) 70%),
  radial-gradient(ellipse 45% 55% at 62% 42%, rgba(255,190,120,.55) 0%, rgba(255,190,120,0) 72%);}
@media (prefers-reduced-motion:reduce){
  .seal-aura-glow{animation:none; transform:translate(-50%,-50%) scale(1); opacity:.75;}
}
/* ^ .seal-aura-glow now only serves the retired fire aura (kept so seals saved with it still
   draw). Every other aura moved to the layered light below on 2026-09-25. */

/* ---- layered aura light (.seal-na) ----
   Replaced the single blob after a side-by-side demo: one blob, however irregular, still read as
   "a patch of colour behind the seal". Four layers instead, all sized in % so they shrink with
   Ocean's 110px badge (blur is done with long gradient falloffs / blur *inside* SVG viewBoxes,
   never filter:blur(px), which wouldn't scale):
     bloom — wide + faint, breathes     core — tight + bright, slowly morphs
     pool  — tinted light on the ground under the belly     tex — the aura's own personality
   plus motes: coloured with a white heart, rising and fading. The old motes were plain white
   dots, which vanished on the booth's white card. Each aura sets --a (main) and --b (core) as
   "r g b" triplets.
   The box is shifted down 9.5% of the stage: the body is bottom-aligned in the 1000x664 stage
   (it's 538 tall, so it spans 19%-100%), and every % below was tuned on a vertically centred
   body — this keeps them landing on the same part of the seal. */
.seal-na{position:absolute; left:0; right:0; top:9.5%; height:100%; z-index:0; pointer-events:none;}
.seal-na > *{position:absolute; pointer-events:none;}
.seal-na-bloom{left:50%; top:56%; width:128%; height:128%; transform:translate(-50%,-50%);
  background:radial-gradient(closest-side, rgb(var(--a)/.50), rgb(var(--a)/.20) 55%, rgb(var(--a)/0));
  animation:seal-na-breathe 4.6s ease-in-out infinite;}
.seal-na-core{left:50%; top:58%; width:92%; height:84%; transform:translate(-50%,-50%);
  background:radial-gradient(closest-side, rgb(var(--b)/.95), rgb(var(--a)/.55) 50%, rgb(var(--a)/0));
  animation:seal-na-morph 7s ease-in-out infinite;}
.seal-na-pool{left:50%; top:93%; width:96%; height:20%; transform:translate(-50%,-50%);
  background:radial-gradient(closest-side, rgb(var(--a)/.55), rgb(var(--a)/0));
  animation:seal-na-breathe 4.6s ease-in-out infinite;}
@keyframes seal-na-breathe{0%,100%{transform:translate(-50%,-50%) scale(.95); opacity:.8;} 50%{transform:translate(-50%,-50%) scale(1.05); opacity:1;}}
@keyframes seal-na-morph{
  0%,100%{transform:translate(-50%,-50%) scale(1,1) rotate(0deg);}
  33%{transform:translate(-48%,-52%) scale(1.07,.94) rotate(5deg);}
  66%{transform:translate(-52%,-49%) scale(.95,1.06) rotate(-4deg);}
}
@keyframes seal-na-spin{to{transform:translate(-50%,-50%) rotate(360deg);}}
.seal-na-mote{width:clamp(3px, 2.6%, 8px); aspect-ratio:1/1; border-radius:50%; left:var(--x); top:var(--y);
  background:radial-gradient(circle, #fff 0 32%, rgb(var(--m, var(--a))) 58%, rgb(var(--m, var(--a))/0) 74%);
  filter:drop-shadow(0 0 2px rgb(var(--m, var(--a))/.9));
  transform:translate(-50%,-50%); opacity:0; animation:seal-na-rise var(--d,3.6s) ease-out infinite; animation-delay:var(--t,0s);}
@keyframes seal-na-rise{
  0%{opacity:0; top:var(--y); transform:translate(-50%,-50%) scale(.5);}
  20%{opacity:1;}
  60%{transform:translate(-20%,-50%) scale(1);}
  100%{opacity:0; top:calc(var(--y) - 26%); transform:translate(-80%,-50%) scale(.4);}
}
.seal-na-tex{left:50%; top:54%; width:118%; height:118%; transform:translate(-50%,-50%);
  -webkit-mask-image:radial-gradient(closest-side, #000 35%, transparent 100%); mask-image:radial-gradient(closest-side, #000 35%, transparent 100%);}

/* space: slow nebula swirl + pinprick stars */
.seal-na-space{--a:118 88 214; --b:176 150 255;}
.seal-tex-space{background:conic-gradient(from 0deg, rgb(118 88 214/0), rgb(118 88 214/.6), rgb(92 170 255/.45), rgb(255 130 200/.35), rgb(176 150 255/.55), rgb(118 88 214/0));
  animation:seal-na-spin 22s linear infinite;}
.seal-na-star{width:clamp(2px, 1.4%, 4px); aspect-ratio:1; border-radius:50%; background:#fff; box-shadow:0 0 0 1px rgb(var(--a)/.7), 0 0 4px rgb(var(--b));
  transform:translate(-50%,-50%); animation:seal-ministar-twinkle 2.2s ease-in-out infinite;}
/* candy: three pastel puffs swirling like cotton candy */
.seal-na-candy{--a:255 140 185; --b:255 214 230;}
.seal-tex-candy{background:
    radial-gradient(circle at 28% 40%, rgb(255 150 195/.8) 0 14%, transparent 34%),
    radial-gradient(circle at 72% 38%, rgb(150 225 205/.8) 0 14%, transparent 34%),
    radial-gradient(circle at 52% 76%, rgb(255 226 130/.75) 0 14%, transparent 34%);
  animation:seal-na-spin 14s linear infinite;}
/* angel + gold: turning light rays (gold faster, and shimmering) */
.seal-na-angel{--a:255 204 110; --b:255 246 214;}
.seal-tex-angel{background:repeating-conic-gradient(from 0deg, rgb(255 226 150/.7) 0deg 5deg, rgb(255 226 150/0) 9deg 22deg);
  -webkit-mask-image:radial-gradient(closest-side, transparent 18%, #000 42%, transparent 100%); mask-image:radial-gradient(closest-side, transparent 18%, #000 42%, transparent 100%);
  animation:seal-na-spin 40s linear infinite;}
.seal-na-gold{--a:255 190 40; --b:255 236 150;}
.seal-tex-gold{background:repeating-conic-gradient(from 10deg, rgb(255 205 70/.75) 0deg 4deg, rgb(255 205 70/0) 8deg 30deg);
  -webkit-mask-image:radial-gradient(closest-side, transparent 20%, #000 44%, transparent 100%); mask-image:radial-gradient(closest-side, transparent 20%, #000 44%, transparent 100%);
  animation:seal-na-spin 18s linear infinite, seal-na-shimmer 1.8s ease-in-out infinite alternate;}
@keyframes seal-na-shimmer{from{opacity:.55;} to{opacity:1;}}
/* demon: dark smoke puffs rolling up */
.seal-na-demon{--a:190 40 70; --b:255 90 110;}
.seal-na-smoke{width:46%; aspect-ratio:1; border-radius:50%; left:var(--x); top:62%;
  background:radial-gradient(closest-side, rgb(70 18 50/.6), rgb(70 18 50/0)); transform:translate(-50%,-50%) scale(.6); opacity:0;
  animation:seal-na-smoke 4.2s ease-out infinite; animation-delay:var(--t);}
@keyframes seal-na-smoke{0%{opacity:0; top:62%; transform:translate(-50%,-50%) scale(.5);} 25%{opacity:.9;} 100%{opacity:0; top:18%; transform:translate(-50%,-50%) scale(1.25);}}
/* lightning: light only in the instant the bolts strike (same 2.4s as seal-bolt-flash) */
.seal-na-lightning{--a:120 170 255; --b:255 246 140;}
.seal-na-lightning .seal-na-bloom, .seal-na-lightning .seal-na-core, .seal-na-lightning .seal-na-pool{animation:seal-na-strike 2.4s linear infinite;}
@keyframes seal-na-strike{0%,78%,100%{opacity:0;} 82%{opacity:1;} 85%{opacity:.25;} 88%{opacity:.9;} 96%{opacity:0;}}
/* sleep: moonlight breathing slowly */
.seal-na-sleep{--a:120 150 230; --b:205 220 255;}
.seal-na-sleep .seal-na-bloom, .seal-na-sleep .seal-na-core, .seal-na-sleep .seal-na-pool{animation:seal-na-breathe 7s ease-in-out infinite;}

/* ---- light-only auras (no drawn icons at all) ---- */
.seal-na-aurora{--a:70 220 170; --b:170 255 220;}
.seal-na-band{left:50%; width:150%; height:34%; transform:translate(-50%,-50%) skewY(-8deg); border-radius:50%;
  -webkit-mask-image:radial-gradient(closest-side, #000 30%, transparent 100%); mask-image:radial-gradient(closest-side, #000 30%, transparent 100%);
  background:linear-gradient(90deg, rgb(60 230 160/0), rgb(60 230 160/.8) 25%, rgb(80 200 255/.75) 50%, rgb(180 110 255/.7) 75%, rgb(180 110 255/0));
  background-size:200% 100%; animation:seal-na-wave 6s ease-in-out infinite, seal-na-slide 9s linear infinite;}
.seal-na-band.b2{height:26%; opacity:.75; animation-duration:7.5s, 12s; animation-direction:alternate, reverse;
  background:linear-gradient(90deg, rgb(180 110 255/0), rgb(200 120 255/.7) 30%, rgb(60 230 160/.75) 65%, rgb(60 230 160/0));}
@keyframes seal-na-wave{0%,100%{transform:translate(-50%,-50%) skewY(-8deg) scaleY(1);} 50%{transform:translate(-46%,-56%) skewY(7deg) scaleY(1.25);}}
@keyframes seal-na-slide{to{background-position:-200% 0;}}

.seal-na-holo{--a:190 170 255; --b:230 245 255;}
.seal-tex-holo{background:conic-gradient(from 0deg, #ffb3d9, #ffe9a8, #b5f5d8, #a8dcff, #d7b8ff, #ffb3d9);
  opacity:.85; animation:seal-na-spin 10s linear infinite;}
.seal-na-holo .seal-na-bloom, .seal-na-holo .seal-na-pool{animation:seal-na-breathe 4.6s ease-in-out infinite, seal-na-hue 6s linear infinite;}
@keyframes seal-na-hue{to{filter:hue-rotate(360deg);}}

/* neon: the one aura that lights the seal itself — a rim-light traced off the body's own alpha
   by drop-shadow on its <svg>. :has() so sealFigureHtml needs no neon special case. */
.seal-na-neon{--a:255 80 200; --b:120 240 255;}
.seal-na-neon .seal-na-bloom{opacity:.55; animation:seal-na-breathe 4.6s ease-in-out infinite, seal-na-hue 4s linear infinite reverse;}
.seal-figure:has(> .seal-na-neon) > svg{animation:seal-na-rim 4s linear infinite;}
@keyframes seal-na-rim{
  0%,100%{filter:drop-shadow(0 0 2px #ff4fc8) drop-shadow(0 0 7px #ff4fc8) drop-shadow(0 0 16px rgb(255 79 200/.6));}
  33%{filter:drop-shadow(0 0 2px #3fe8ff) drop-shadow(0 0 7px #3fe8ff) drop-shadow(0 0 16px rgb(63 232 255/.6));}
  66%{filter:drop-shadow(0 0 2px #a974ff) drop-shadow(0 0 7px #a974ff) drop-shadow(0 0 16px rgb(169 116 255/.6));}
}

.seal-na-sea{--a:40 180 230; --b:170 240 255;}
.seal-tex-sea{background:
    radial-gradient(circle, transparent 42%, rgb(200 250 255/.9) 50%, transparent 58%) 0 0/34% 34%,
    radial-gradient(circle, transparent 40%, rgb(120 220 255/.8) 48%, transparent 56%) 17% 17%/26% 26%;
  animation:seal-na-drift 5s linear infinite;}
.seal-tex-sea.b{opacity:.7; animation-duration:7s; animation-direction:reverse;}
@keyframes seal-na-drift{to{background-position:34% 34%, -9% 43%;}}

.seal-na-sunset{--a:255 120 120; --b:255 214 120;}
.seal-tex-sunset{background:linear-gradient(180deg, rgb(150 90 220/.7), rgb(255 110 150/.75) 40%, rgb(255 170 80/.85) 70%, rgb(255 220 120/.6));
  animation:seal-na-breathe 6s ease-in-out infinite;}
.seal-tex-sunrays{background:repeating-conic-gradient(from -90deg at 50% 70%, rgb(255 220 150/.6) 0deg 3deg, rgb(255 220 150/0) 6deg 16deg);
  -webkit-mask-image:radial-gradient(closest-side, transparent 25%, #000 45%, transparent 100%); mask-image:radial-gradient(closest-side, transparent 25%, #000 45%, transparent 100%);
  animation:seal-na-spin 60s linear infinite;}

.seal-na-prism{--a:200 210 255; --b:255 255 255;}
.seal-na-beam{left:50%; top:48%; width:150%; height:3.5%; border-radius:50%;
  background:linear-gradient(90deg, transparent, #ff6b8b 20%, #ffc76b 35%, #7dffb0 50%, #6bc8ff 65%, #b98bff 80%, transparent);
  opacity:0; animation:seal-na-sweep 4.8s ease-in-out infinite; animation-delay:var(--t);}
@keyframes seal-na-sweep{
  0%{opacity:0; transform:translate(-50%,-50%) rotate(var(--r)) scaleX(.4);}
  30%{opacity:.95;}
  60%{opacity:0; transform:translate(-50%,-50%) rotate(calc(var(--r) + 14deg)) scaleX(1.05);}
  100%{opacity:0;}
}
.seal-na-glint{width:clamp(7px, 6%, 18px); aspect-ratio:1; left:var(--x); top:var(--y); transform:translate(-50%,-50%) scale(0);
  background:radial-gradient(circle, #fff 0 12%, transparent 13%), conic-gradient(from 45deg, transparent 0 20deg, #fff 45deg, transparent 70deg 110deg, #fff 135deg, transparent 160deg 200deg, #fff 225deg, transparent 250deg 290deg, #fff 315deg, transparent 340deg);
  -webkit-mask-image:radial-gradient(circle, #000 20%, transparent 70%); mask-image:radial-gradient(circle, #000 20%, transparent 70%);
  filter:drop-shadow(0 0 3px rgb(160 200 255)); animation:seal-na-glint 2.4s ease-in-out infinite; animation-delay:var(--t);}
@keyframes seal-na-glint{0%,100%{transform:translate(-50%,-50%) scale(0) rotate(0);} 45%{transform:translate(-50%,-50%) scale(1) rotate(45deg);} 70%{transform:translate(-50%,-50%) scale(0) rotate(90deg);}}

.seal-na-firefly{--a:150 210 90; --b:230 255 150;}
.seal-na-firefly .seal-na-bloom{animation:none; opacity:.5;}
.seal-na-firefly .seal-na-core{animation:none; opacity:.3;}
.seal-na-ff{width:clamp(4px, 3.2%, 9px); aspect-ratio:1; border-radius:50%; left:var(--x); top:var(--y); transform:translate(-50%,-50%);
  background:radial-gradient(circle, #fffbd0 0 25%, rgb(210 255 110) 45%, rgb(210 255 110/0) 72%);
  filter:drop-shadow(0 0 4px rgb(200 255 90));
  animation:seal-na-wander var(--d) ease-in-out infinite, seal-na-blink calc(var(--d) / 2.3) ease-in-out infinite; animation-delay:var(--t);}
@keyframes seal-na-wander{
  0%,100%{left:var(--x); top:var(--y);}
  25%{left:calc(var(--x) + 6%); top:calc(var(--y) - 7%);}
  50%{left:calc(var(--x) - 3%); top:calc(var(--y) - 12%);}
  75%{left:calc(var(--x) - 7%); top:calc(var(--y) - 3%);}
}
@keyframes seal-na-blink{0%,100%{opacity:.15;} 50%{opacity:1;}}

/* ---- love auras: the hearts are *light* — an SVG heart blurred inside its own viewBox (so the
   blur scales with the stage) used as a background image, not a drawn icon ---- */
.seal-na-heartbeat, .seal-na-heartbokeh, .seal-na-sweet{--a:255 110 160; --b:255 220 232;
  --heart-soft:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='-8 -8 48 44'%3E%3Cdefs%3E%3Cfilter id='b' x='-50%25' y='-50%25' width='200%25' height='200%25'%3E%3CfeGaussianBlur stdDeviation='2.6'/%3E%3C/filter%3E%3CradialGradient id='g' cx='50%25' cy='42%25' r='62%25'%3E%3Cstop offset='0' stop-color='%23fff2f6'/%3E%3Cstop offset='.45' stop-color='%23ff8fb5'/%3E%3Cstop offset='1' stop-color='%23ff4f8b' stop-opacity='.2'/%3E%3C/radialGradient%3E%3C/defs%3E%3Cpath filter='url(%23b)' fill='url(%23g)' d='M16 26S3 18 3 9.7C3 4.8 6.7 2.3 10.4 2.3c2.6 0 4.7 1.4 5.6 3.3.9-1.9 3-3.3 5.6-3.3C25.3 2.3 29 4.8 29 9.7 29 18 16 26 16 26Z'/%3E%3C/svg%3E");
  --heart-ring:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='-8 -8 48 44'%3E%3Cdefs%3E%3Cfilter id='b' x='-50%25' y='-50%25' width='200%25' height='200%25'%3E%3CfeGaussianBlur stdDeviation='.9'/%3E%3C/filter%3E%3C/defs%3E%3Cpath filter='url(%23b)' fill='none' stroke='%23ff6f9f' stroke-width='1.6' d='M16 26S3 18 3 9.7C3 4.8 6.7 2.3 10.4 2.3c2.6 0 4.7 1.4 5.6 3.3.9-1.9 3-3.3 5.6-3.3C25.3 2.3 29 4.8 29 9.7 29 18 16 26 16 26Z'/%3E%3C/svg%3E");
  --heart-bokeh:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 40 36'%3E%3Cdefs%3E%3Cfilter id='b' x='-50%25' y='-50%25' width='200%25' height='200%25'%3E%3CfeGaussianBlur stdDeviation='1.1'/%3E%3C/filter%3E%3C/defs%3E%3Cpath filter='url(%23b)' fill='%23ff8fb5' fill-opacity='.85' stroke='%23fff' stroke-opacity='.8' stroke-width='1.4' d='M16 26S3 18 3 9.7C3 4.8 6.7 2.3 10.4 2.3c2.6 0 4.7 1.4 5.6 3.3.9-1.9 3-3.3 5.6-3.3C25.3 2.3 29 4.8 29 9.7 29 18 16 26 16 26Z'/%3E%3C/svg%3E");
  --heart-glint:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 40 36'%3E%3Cpath fill='%23fff' d='M16 26S3 18 3 9.7C3 4.8 6.7 2.3 10.4 2.3c2.6 0 4.7 1.4 5.6 3.3.9-1.9 3-3.3 5.6-3.3C25.3 2.3 29 4.8 29 9.7 29 18 16 26 16 26Z'/%3E%3C/svg%3E");
}
/* heartbeat: a big soft heart of light beating lub-dub, sending out heart-shaped ripples */
.seal-na-heart{left:50%; top:38%; width:74%; aspect-ratio:48/44; transform:translate(-50%,-50%);
  background:var(--heart-soft) center/contain no-repeat; animation:seal-na-beat 1.6s ease-out infinite;}
.seal-na-hring{left:50%; top:38%; width:74%; aspect-ratio:48/44; transform:translate(-50%,-50%); opacity:0;
  background:var(--heart-ring) center/contain no-repeat; animation:seal-na-ripple 1.6s ease-out infinite; animation-delay:var(--t,0s);}
.seal-na-heartbeat .seal-na-bloom, .seal-na-heartbeat .seal-na-pool{animation:seal-na-beat 1.6s ease-out infinite;}
@keyframes seal-na-beat{
  0%,100%{transform:translate(-50%,-50%) scale(1);}
  10%{transform:translate(-50%,-50%) scale(1.12);}
  22%{transform:translate(-50%,-50%) scale(1);}
  32%{transform:translate(-50%,-50%) scale(1.07);}
  48%{transform:translate(-50%,-50%) scale(1);}
}
@keyframes seal-na-ripple{0%{opacity:.9; transform:translate(-50%,-50%) scale(1);} 70%,100%{opacity:0; transform:translate(-50%,-50%) scale(1.6);}}
/* heart bokeh: soft out-of-focus hearts drifting up and away */
.seal-na-hbokeh{left:var(--x); top:var(--y); width:var(--s); aspect-ratio:40/36; transform:translate(-50%,-50%); opacity:0;
  background:var(--heart-bokeh) center/contain no-repeat; filter:hue-rotate(var(--h,0deg)) drop-shadow(0 0 3px rgb(255 120 170/.7));
  animation:seal-na-hfloat var(--d) ease-in-out infinite; animation-delay:var(--t);}
@keyframes seal-na-hfloat{
  0%{opacity:0; top:var(--y); transform:translate(-50%,-50%) rotate(-8deg) scale(.6);}
  20%{opacity:.95;}
  50%{transform:translate(-30%,-50%) rotate(8deg) scale(1);}
  100%{opacity:0; top:calc(var(--y) - 34%); transform:translate(-70%,-50%) rotate(-6deg) scale(.85);}
}
/* sweet: pink-peach-lavender swirl with tiny heart glints popping */
.seal-tex-sweet{background:conic-gradient(from 0deg, rgb(255 140 180/.75), rgb(255 190 160/.6), rgb(210 170 255/.65), rgb(255 160 210/.7), rgb(255 140 180/.75));
  animation:seal-na-spin 16s linear infinite;}
.seal-na-hglint{left:var(--x); top:var(--y); width:clamp(5px, 4.5%, 13px); aspect-ratio:40/36; transform:translate(-50%,-50%) scale(0);
  background:var(--heart-glint) center/contain no-repeat;
  filter:drop-shadow(0 0 2px #ff6f9f) drop-shadow(0 0 5px rgb(255 111 159/.7));
  animation:seal-na-hpop 2.6s ease-in-out infinite; animation-delay:var(--t);}
@keyframes seal-na-hpop{0%,100%{transform:translate(-50%,-50%) scale(0);} 40%{transform:translate(-50%,-50%) scale(1.1);} 60%{transform:translate(-50%,-60%) scale(.9);} 80%{transform:translate(-50%,-70%) scale(0);}}

/* ---- set added 2026-09-25: soap bubbles / blossom / birthday / halloween / crown. Same rule as
   the love set — whatever looks like an object (flower, balloon, ghost, crown) is drawn as soft
   light in a data-URI SVG, not a hard-outlined icon. ---- */
@keyframes seal-na-flicker{0%,100%{opacity:1;} 18%{opacity:.78;} 32%{opacity:.96;} 51%{opacity:.74;} 68%{opacity:1;} 84%{opacity:.84;}}

/* soap: iridescent bubbles drifting up, wobbling, then popping */
/* The five below run a little brighter than the older auras (asked for "สดใสกว่านี้"): more
   saturated tokens, plus a saturate() on the whole light box. */
.seal-na-soap, .seal-na-blossom, .seal-na-birthday, .seal-na-halloween, .seal-na-crown{filter:saturate(1.45) brightness(1.04);}
.seal-na-soap{--a:95 160 255; --b:225 240 255;}
.seal-tex-soap{background:conic-gradient(from 0deg, rgb(255 120 190/.75), rgb(255 215 80/.65), rgb(90 225 170/.7), rgb(90 180 255/.75), rgb(180 120 255/.75), rgb(255 120 190/.75));
  animation:seal-na-spin 14s linear infinite;}
.seal-na-sbub{left:var(--x); top:var(--y); width:var(--s); aspect-ratio:1; border-radius:50%; transform:translate(-50%,-50%); opacity:0;
  background:radial-gradient(circle at 33% 30%, rgb(255 255 255/.95) 0 9%, transparent 11%), radial-gradient(circle, rgb(255 255 255/.14) 0 58%, rgb(255 255 255/.5) 70%, transparent 72%);
  filter:drop-shadow(0 0 2px rgb(150 190 255/.8));
  animation:seal-na-sbub var(--d) ease-in-out infinite; animation-delay:var(--t);}
.seal-na-sbub::before{content:''; position:absolute; inset:0; border-radius:50%;
  background:conic-gradient(from 0deg, #ff8fc6, #ffd96b, #7fe8b8, #7cc8ff, #b98cff, #ff8fc6);
  -webkit-mask-image:radial-gradient(circle, transparent 60%, #000 65%, #000 69%, transparent 72%); mask-image:radial-gradient(circle, transparent 60%, #000 65%, #000 69%, transparent 72%);
  animation:seal-na-turn 3s linear infinite;}
@keyframes seal-na-turn{to{rotate:360deg;}}
@keyframes seal-na-sbub{
  0%{opacity:0; top:var(--y); transform:translate(-50%,-50%) scale(.4);}
  15%{opacity:1; transform:translate(-50%,-50%) scale(1);}
  45%{transform:translate(-30%,-50%) scale(1.04,.96);}
  75%{transform:translate(-68%,-50%) scale(.97,1.03);}
  86%{opacity:1; top:calc(var(--y) - 22%); transform:translate(-50%,-50%) scale(1);}
  92%{opacity:.7; transform:translate(-50%,-50%) scale(1.3);}
  100%{opacity:0; top:calc(var(--y) - 23%); transform:translate(-50%,-50%) scale(1.5);}
}

/* blossom: a big soft flower of light slowly turning and opening, tiny flowers popping */
.seal-na-blossom{--a:255 95 165; --b:255 235 190;
  --flower:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='-8 -8 56 56'%3E%3Cdefs%3E%3Cfilter id='b' x='-50%25' y='-50%25' width='200%25' height='200%25'%3E%3CfeGaussianBlur stdDeviation='2.4'/%3E%3C/filter%3E%3CradialGradient id='g' cx='50%25' cy='50%25' r='55%25'%3E%3Cstop offset='0' stop-color='%23fffbe6'/%3E%3Cstop offset='.35' stop-color='%23ffc2dc'/%3E%3Cstop offset='1' stop-color='%23ff7fb0' stop-opacity='.35'/%3E%3C/radialGradient%3E%3C/defs%3E%3Cg filter='url(%23b)' fill='url(%23g)'%3E%3Cellipse cx='20' cy='9.5' rx='7' ry='10' transform='rotate(0 20 20)'/%3E%3Cellipse cx='20' cy='9.5' rx='7' ry='10' transform='rotate(72 20 20)'/%3E%3Cellipse cx='20' cy='9.5' rx='7' ry='10' transform='rotate(144 20 20)'/%3E%3Cellipse cx='20' cy='9.5' rx='7' ry='10' transform='rotate(216 20 20)'/%3E%3Cellipse cx='20' cy='9.5' rx='7' ry='10' transform='rotate(288 20 20)'/%3E%3Ccircle cx='20' cy='20' r='6' fill='%23fff3b8'/%3E%3C/g%3E%3C/svg%3E");
  --flower-glint:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 40 40'%3E%3Cg fill='%23fff'%3E%3Cellipse cx='20' cy='9.5' rx='7' ry='10' transform='rotate(0 20 20)'/%3E%3Cellipse cx='20' cy='9.5' rx='7' ry='10' transform='rotate(72 20 20)'/%3E%3Cellipse cx='20' cy='9.5' rx='7' ry='10' transform='rotate(144 20 20)'/%3E%3Cellipse cx='20' cy='9.5' rx='7' ry='10' transform='rotate(216 20 20)'/%3E%3Cellipse cx='20' cy='9.5' rx='7' ry='10' transform='rotate(288 20 20)'/%3E%3C/g%3E%3Ccircle cx='20' cy='20' r='5' fill='%23ffe07a'/%3E%3C/svg%3E");}
.seal-na-flower{left:50%; top:44%; width:100%; aspect-ratio:1; transform:translate(-50%,-50%);
  background:var(--flower) center/contain no-repeat; opacity:.9; animation:seal-na-open 9s ease-in-out infinite;}
.seal-na-flower.f2{width:58%; opacity:.8; filter:hue-rotate(-28deg); animation-duration:7s; animation-direction:reverse;}
@keyframes seal-na-open{0%,100%{transform:translate(-50%,-50%) rotate(0deg) scale(.9);} 50%{transform:translate(-50%,-50%) rotate(36deg) scale(1.05);}}
.seal-na-fglint{left:var(--x); top:var(--y); width:clamp(6px, 5%, 14px); aspect-ratio:1; transform:translate(-50%,-50%) scale(0);
  background:var(--flower-glint) center/contain no-repeat; filter:drop-shadow(0 0 2px #ff7fb0) drop-shadow(0 0 5px rgb(255 127 176/.7));
  animation:seal-na-hpop 2.8s ease-in-out infinite; animation-delay:var(--t);}

/* birthday: warm candlelight that flickers, balloons of light floating up, confetti glints */
.seal-na-birthday{--a:255 150 60; --b:255 240 180;}
.seal-na-birthday .seal-na-core{animation:seal-na-morph 7s ease-in-out infinite, seal-na-flicker 1.6s ease-in-out infinite;}
.seal-na-balloon{left:var(--x); top:95%; width:clamp(9px, 8%, 24px); aspect-ratio:24/42; transform:translate(-50%,-50%); opacity:0;
  background:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 42'%3E%3Cdefs%3E%3CradialGradient id='g' cx='36%25' cy='30%25' r='70%25'%3E%3Cstop offset='0' stop-color='%23fff'/%3E%3Cstop offset='.25' stop-color='%23ffb3cf'/%3E%3Cstop offset='1' stop-color='%23ff5f95'/%3E%3C/radialGradient%3E%3C/defs%3E%3Cellipse cx='12' cy='12' rx='9.5' ry='11.5' fill='url(%23g)' fill-opacity='.92'/%3E%3Cpath d='M10.3 23.2h3.4L12 26Z' fill='%23ff5f95'/%3E%3Cpath d='M12 26q-3 4 0 8t0 8' fill='none' stroke='%23fff' stroke-opacity='.85' stroke-width='1.1'/%3E%3C/svg%3E") center/contain no-repeat;
  filter:hue-rotate(var(--h,0deg)) drop-shadow(0 0 4px rgb(255 200 220/.9));
  animation:seal-na-balloon var(--d) ease-in-out infinite; animation-delay:var(--t);}
@keyframes seal-na-balloon{
  0%{opacity:0; top:95%; transform:translate(-50%,-50%) rotate(-6deg);}
  15%{opacity:.95;}
  50%{transform:translate(-25%,-50%) rotate(7deg);}
  82%{opacity:.9;}
  100%{opacity:0; top:-4%; transform:translate(-65%,-50%) rotate(-5deg);}
}
.seal-na-conf{left:var(--x); top:var(--y); width:clamp(3px, 2.2%, 7px); aspect-ratio:1/2; border-radius:1px; opacity:0;
  background:rgb(var(--c)); box-shadow:0 0 4px rgb(var(--c)/.9);
  animation:seal-na-conf 2.6s ease-in-out infinite; animation-delay:var(--t);}
@keyframes seal-na-conf{
  0%{opacity:0; transform:translate(-50%,-50%) rotate(0deg) scale(.5);}
  25%{opacity:1;}
  100%{opacity:0; top:calc(var(--y) + 14%); transform:translate(-50%,-50%) rotate(280deg) scale(1);}
}

/* halloween: pumpkin-orange light flickering under a purple mist, little ghosts of light */
.seal-na-halloween{--a:255 120 10; --b:255 205 100;}
.seal-na-halloween .seal-na-core{animation:seal-na-morph 7s ease-in-out infinite, seal-na-flicker 1.2s ease-in-out infinite;}
.seal-tex-halloween{background:
    radial-gradient(circle at 30% 34%, rgb(140 70 225/.72) 0 16%, transparent 38%),
    radial-gradient(circle at 72% 40%, rgb(105 40 180/.62) 0 14%, transparent 36%),
    radial-gradient(circle at 50% 78%, rgb(255 115 25/.55) 0 14%, transparent 36%);
  animation:seal-na-spin 16s linear infinite;}
.seal-na-ghost{left:var(--x); top:72%; width:var(--s); aspect-ratio:38/42; transform:translate(-50%,-50%); opacity:0;
  background:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 38 42'%3E%3Cdefs%3E%3Cfilter id='b' x='-50%25' y='-50%25' width='200%25' height='200%25'%3E%3CfeGaussianBlur stdDeviation='.9'/%3E%3C/filter%3E%3C/defs%3E%3Cpath filter='url(%23b)' fill='%23fff' fill-opacity='.92' d='M3 31V14a12 12 0 0 1 24 0v17l-4-3-4 4-4-4-4 4-4-4Z'/%3E%3Cellipse cx='11' cy='15' rx='1.8' ry='2.4' fill='%235b3a86'/%3E%3Cellipse cx='19' cy='15' rx='1.8' ry='2.4' fill='%235b3a86'/%3E%3Cellipse cx='15' cy='20.5' rx='1.6' ry='1.2' fill='%235b3a86' fill-opacity='.7'/%3E%3C/svg%3E") center/contain no-repeat;
  filter:drop-shadow(0 0 4px rgb(190 140 255/.95));
  animation:seal-na-ghost var(--d) ease-in-out infinite; animation-delay:var(--t);}
@keyframes seal-na-ghost{
  0%{opacity:0; top:72%; transform:translate(-50%,-50%) scale(.7);}
  20%{opacity:.9;}
  45%{transform:translate(-85%,-50%) scale(.95) rotate(-6deg);}
  75%{opacity:.85; transform:translate(-20%,-50%) scale(1) rotate(5deg);}
  100%{opacity:0; top:6%; transform:translate(-50%,-50%) scale(1.05);}
}

/* crown: ice-blue light with silver rays, a glowing gold crown bobbing on the seal's head */
/* ice-queen blue with silver-white rays (picked from 7 colour candidates 2026-09-26); the crown
   itself stays gold. */
.seal-na-crown{--a:80 170 255; --b:235 250 255;}
.seal-tex-crown{background:repeating-conic-gradient(from 5deg, rgb(215 240 255/.9) 0deg 4deg, rgb(215 240 255/0) 8deg 26deg);
  -webkit-mask-image:radial-gradient(closest-side, transparent 20%, #000 44%, transparent 100%); mask-image:radial-gradient(closest-side, transparent 20%, #000 44%, transparent 100%);
  animation:seal-na-spin 30s linear infinite;}
.seal-na-crown .seal-na-glint{filter:drop-shadow(0 0 3px rgb(255 200 70));}
.seal-crown-light{position:absolute; width:clamp(16px, 17%, 52px); aspect-ratio:40/30; transform:translate(-50%,-50%) rotate(-10deg);
  background:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 40 30'%3E%3Cdefs%3E%3ClinearGradient id='g' x1='0' y1='0' x2='0' y2='1'%3E%3Cstop offset='0' stop-color='%23fff6c2'/%3E%3Cstop offset='.55' stop-color='%23ffd04a'/%3E%3Cstop offset='1' stop-color='%23f0a318'/%3E%3C/linearGradient%3E%3C/defs%3E%3Cg stroke='%23c47e0c' stroke-width='1.3' stroke-linejoin='round'%3E%3Cpath d='M5 23 3 8l9 7 8-11 8 11 9-7-2 15Z' fill='url(%23g)'/%3E%3Crect x='4.5' y='21.5' width='31' height='5.5' rx='2' fill='%23ffd04a'/%3E%3Ccircle cx='3' cy='7.5' r='2.1' fill='%23fff6c2'/%3E%3Ccircle cx='20' cy='3.4' r='2.3' fill='%23fff6c2'/%3E%3Ccircle cx='37' cy='7.5' r='2.1' fill='%23fff6c2'/%3E%3C/g%3E%3Ccircle cx='20' cy='24.2' r='2.1' fill='%23ff6f9f'/%3E%3Ccircle cx='11.5' cy='24.2' r='1.6' fill='%236fc8ff'/%3E%3Ccircle cx='28.5' cy='24.2' r='1.6' fill='%237fd6a0'/%3E%3Cpath d='M9 14.5 11 16' stroke='%23fff' stroke-width='1.4' stroke-linecap='round'/%3E%3C/svg%3E") center/contain no-repeat;
  filter:drop-shadow(0 0 3px rgb(255 214 90)) drop-shadow(0 0 8px rgb(255 190 60/.7));
  animation:seal-crown-bob 3s ease-in-out infinite;}
@keyframes seal-crown-bob{0%,100%{transform:translate(-50%,-50%) rotate(-10deg);} 50%{transform:translate(-50%,-64%) rotate(-6deg);}}

/* fire / candy / gold / planet clings: same cling idiom as bubbles (reuses seal-bubcling), just
   a different drawn icon at a different size. */
.seal-flame{position:absolute; width:clamp(9px, 7%, 20px); aspect-ratio:22/30; transform:translate(-50%,-50%); animation:seal-bubcling 2.4s ease-in-out infinite;}
.seal-candy{position:absolute; width:clamp(9px, 7%, 20px); aspect-ratio:26/34; transform:translate(-50%,-50%); animation:seal-bubcling 2.8s ease-in-out infinite;}
.seal-coin{position:absolute; width:clamp(9px, 7%, 19px); aspect-ratio:1/1; transform:translate(-50%,-50%); animation:seal-bubcling 2.6s ease-in-out infinite;}
.seal-planet{position:absolute; width:clamp(12px, 9%, 24px); aspect-ratio:32/24; transform:translate(-50%,-50%); animation:seal-bubcling 3.4s ease-in-out infinite;}

.seal-ministar{
  position:absolute; width:clamp(3px, 2.4%, 6px); aspect-ratio:1/1; border-radius:50%;
  background:#fff; box-shadow:0 0 3px rgba(255,255,255,.9); transform:translate(-50%,-50%);
  animation:seal-ministar-twinkle 2s ease-in-out infinite;
}
@keyframes seal-ministar-twinkle{0%,100%{opacity:.2; transform:translate(-50%,-50%) scale(.6);} 50%{opacity:1; transform:translate(-50%,-50%) scale(1.15);}}

.seal-bolt{position:absolute; width:clamp(7px, 5.5%, 15px); aspect-ratio:20/30; transform:translate(-50%,-50%); animation:seal-bolt-flash 2.4s ease-in-out infinite;}
@keyframes seal-bolt-flash{
  0%,78%,100%{opacity:0; transform:translate(-50%,-50%) scale(.6);}
  84%{opacity:1; transform:translate(-50%,-50%) scale(1.15);}
  92%{opacity:.3; transform:translate(-50%,-50%) scale(.9);}
}

.seal-halo{position:absolute; width:clamp(16px, 13%, 34px); aspect-ratio:30/16; transform:translate(-50%,0); animation:seal-halo-bob 3.2s ease-in-out infinite;}
@keyframes seal-halo-bob{0%,100%{transform:translate(-50%,0) translateY(0);} 50%{transform:translate(-50%,0) translateY(-14%);}}

.seal-feather{
  position:absolute; top:-8%; width:clamp(6px, 5%, 14px); aspect-ratio:20/30;
  animation:seal-feather-fall 5.2s ease-in-out infinite;
}
@keyframes seal-feather-fall{
  0%{top:-8%; opacity:0; transform:rotate(-10deg);}
  10%{opacity:.9;}
  50%{top:46%; transform:rotate(14deg);}
  100%{top:104%; opacity:0; transform:rotate(-8deg);}
}

.seal-wing{
  position:absolute; width:clamp(11px, 9%, 26px); aspect-ratio:34/20;
  animation:seal-flutter 2.6s ease-in-out infinite;
}

.seal-zzz{
  position:absolute; width:clamp(8px, 6.5%, 18px); aspect-ratio:1/1; transform:translate(-50%,-50%);
  animation:seal-zzz-rise 3.4s ease-in infinite;
}
@keyframes seal-zzz-rise{
  0%{transform:translate(-50%,-50%) translateY(0) scale(.7); opacity:0;}
  15%{opacity:.9;}
  100%{transform:translate(-50%,-50%) translateY(-160%) scale(1.2); opacity:0;}
}

@media (prefers-reduced-motion:reduce){
  .seal-figure{animation:none;}
}

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

.seal-btn{
  display:inline-flex; align-items:center; justify-content:center; gap:8px;
  font-family:inherit; font-weight:700; font-size:var(--fs-sealBtn, .95rem); cursor:pointer; text-decoration:none;
  border:var(--bw) solid var(--line); border-radius:14px; padding:13px 26px;
  background:var(--grape); color:#fff; box-shadow:var(--shadow-hard);
  transition:transform .08s ease, box-shadow .08s ease;
}
.seal-btn:active{transform:translate(3px,3px); box-shadow:none;}
.seal-btn.secondary{background:var(--paper); color:var(--ink);}
.seal-btn.pink{background:var(--pink); color:#3a1020;}
.seal-btn.ghost{background:transparent; border-color:var(--line-soft); color:var(--ink-soft); box-shadow:none;}
.seal-btn:disabled{opacity:.45; cursor:not-allowed; transform:none; box-shadow:var(--shadow-hard);}
.seal-linkbtn{
  border:0; background:none; color:var(--ink-soft); font-family:inherit; font-size:var(--fs-sealBtn, .85rem);
  text-decoration:underline; cursor:pointer; margin-top:14px;
}

/* ------------------------------------------------------------ mini admin tally */

.seal-admin-mini{
  display:flex; gap:18px; flex-wrap:wrap; justify-content:center;
  margin:0 auto 18px; padding:8px 16px; max-width:560px;
  border:var(--bw) dashed var(--line); border-radius:12px; background:var(--paper-2);
  font-size:var(--fs-sealMiniStats, .92rem); color:var(--ink-soft);
}
.seal-admin-mini b{color:var(--ink); font-family:var(--font-pixel); font-size:.85rem;}

/* ------------------------------------------------------------ screens */

#sealBooth{max-width:920px; margin:0 auto;}

.seal-screen{
  background:var(--paper); border:var(--bw) solid var(--line); border-radius:var(--radius);
  box-shadow:var(--shadow-hard);
}
.seal-center-card{padding:34px 24px; text-align:center; position:relative;}
.seal-pixel-title{
  font-family:var(--font-pixel); font-size:var(--fs-sealSectionTitle, .95rem); line-height:1.9; margin:14px 0 8px;
}
.seal-pixel-title.celebrate{color:var(--grape-deep);}
.seal-pixel-name{font-family:var(--font-pixel); font-size:var(--fs-sealPixelName, .85rem); margin:6px 0 10px; word-break:break-word;}
.seal-lead{color:var(--ink-soft); max-width:42ch; margin:0 auto 22px; font-size:var(--fs-sealLead, .98rem); line-height:1.75;}
.seal-lock-emoji{font-size:2.6rem; margin-bottom:4px;}
#boothPw{
  font-family:inherit; text-align:center; padding:12px 16px; width:min(260px, 80vw);
  border:var(--bw) solid var(--line); border-radius:12px; background:var(--paper-2); color:var(--ink);
  margin:4px 0 4px;
}
.seal-joined{font-weight:800; margin:2px 0 6px; font-size:var(--fs-sealJoined, 1rem);}
.seal-nav{display:flex; justify-content:space-between; gap:10px; margin-top:18px; flex-wrap:wrap;}
.seal-nav.center{justify-content:center;}
/* Empty most of the time, so it takes no room until it has something to say. */
.seal-blocked{margin:10px 0 0; color:var(--pink-deep, #c2416a); font-weight:700; font-size:var(--fs-sealError, .92rem);}
.seal-blocked:empty{display:none;}

/* ------------------------------------------------------------ dressing screen */

.seal-customize{padding:18px; display:grid; grid-template-columns:280px 1fr; gap:20px;}
@media (max-width:720px){ .seal-customize{grid-template-columns:1fr;} }

.seal-preview-pane{display:flex; flex-direction:column; align-items:center;}

/* ---- little reactions (seal-booth.js: pokeSeal / cheerSeal / randomLook / paintNameTag) ----
   .poked and .cheer replace the figure's seal-bob loop for one play, then the bob comes back
   on its own when the class-driven animation ends (they're one-shot, not infinite). */
#introSeal, #stageSeal, #nameSeal, #reviewSeal, #celebrateSeal{cursor:pointer;}
.seal-figure.poked{transform-origin:50% 100%; animation:seal-poke .55s cubic-bezier(.3,1.6,.5,1);}
@keyframes seal-poke{0%{transform:scale(1,1);} 25%{transform:scale(1.14,.82);} 55%{transform:scale(.94,1.08);} 100%{transform:scale(1,1);}}
.seal-figure.cheer{transform-origin:50% 100%; animation:seal-cheer .8s ease-in-out;}
@keyframes seal-cheer{0%,100%{transform:rotate(0) translateY(0);} 20%{transform:rotate(-6deg) translateY(-8%);} 45%{transform:rotate(5deg) translateY(-4%);} 70%{transform:rotate(-3deg) translateY(-2%);}}
.seal-pop-heart{
  position:absolute; z-index:3; width:12%; aspect-ratio:32/28; pointer-events:none;
  background:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 28'%3E%3Cpath d='M16 26S3 18 3 9.7C3 4.8 6.7 2.3 10.4 2.3c2.6 0 4.7 1.4 5.6 3.3.9-1.9 3-3.3 5.6-3.3C25.3 2.3 29 4.8 29 9.7 29 18 16 26 16 26Z' fill='%23ff8fb5' stroke='%23141414' stroke-width='2'/%3E%3C/svg%3E") center/contain no-repeat;
  animation:seal-pop-heart 1.1s ease-out forwards;
}
@keyframes seal-pop-heart{
  0%{transform:translate(-50%,-50%) scale(.3); opacity:0;}
  20%{opacity:1; transform:translate(-50%,-50%) scale(1.1);}
  100%{transform:translate(calc(-50% + var(--dx)),-260%) scale(.8) rotate(var(--rot)); opacity:0;}
}
.seal-puff{
  position:absolute; z-index:3; left:50%; top:55%; width:90%; aspect-ratio:1; border-radius:50%; pointer-events:none;
  background:radial-gradient(circle, rgba(255,255,255,.95) 0 18%, rgba(255,255,255,0) 19%) 0 0/22% 22%, radial-gradient(closest-side, rgba(255,255,255,.9), rgba(255,255,255,0));
  transform:translate(-50%,-50%) scale(.3); animation:seal-puff .6s ease-out forwards;
}
@keyframes seal-puff{0%{opacity:1; transform:translate(-50%,-50%) scale(.3);} 100%{opacity:0; transform:translate(-50%,-50%) scale(1.25);}}
.seal-random-btn{margin-top:12px; font-size:var(--fs-sealBtn, .9rem);}
.seal-poke-hint{margin:6px 0 0; font-size:.78rem; color:var(--ink-soft);}
.seal-nametag{
  position:absolute; left:50%; top:-4%; z-index:4; transform:translateX(-50%); white-space:nowrap;
  font-weight:800; font-size:1rem; padding:2px 14px; border-radius:999px;
  background:#fff; color:#2a2433; border:2px solid #141414; box-shadow:2px 2px 0 #141414;
}
@media (prefers-reduced-motion:reduce){ .seal-figure.poked, .seal-figure.cheer{animation:none;} }

.seal-steps{display:flex; gap:6px; overflow-x:auto; padding-bottom:6px; margin-bottom:14px; max-width:100%;}
.seal-step-dot{
  flex:0 0 auto; width:34px; height:34px; border-radius:50%;
  border:2.5px solid var(--line-soft); background:var(--paper); color:var(--ink-soft);
  display:flex; align-items:center; justify-content:center; font-size:var(--fs-sealStepDot, .8rem); font-weight:700;
}
.seal-step-dot.done{background:var(--mint); border-color:var(--line); color:var(--ink);}
.seal-step-dot.now{background:var(--grape); border-color:var(--line); color:#fff;}

.seal-price-total{
  position:relative; width:100%; margin-bottom:14px; padding:10px 18px; text-align:center;
  background:var(--yellow); border:var(--bw) solid var(--line); border-radius:16px;
  box-shadow:var(--shadow-hard);
}
.seal-price-total.narrow{max-width:240px; margin:0 auto 14px;}
.seal-price-label{font-size:var(--fs-sealPriceLabel, .7rem); color:#4a3a10; opacity:.85;}
.seal-price-amount{font-family:var(--font-pixel); font-size:var(--fs-sealPriceAmount, 1.3rem); font-weight:800; color:#2c2205; line-height:1.6;}
.seal-price-amount.pulse{animation:seal-pulse .3s ease;}
@keyframes seal-pulse{0%{transform:scale(1);} 40%{transform:scale(1.18);} 100%{transform:scale(1);}}
.seal-floatplus{
  position:absolute; top:-6px; right:14px; font-weight:800; color:var(--grape-deep); font-size:.95rem;
  animation:seal-floatup .9s ease-out forwards; pointer-events:none;
}
@keyframes seal-floatup{0%{transform:translateY(0); opacity:1;} 100%{transform:translateY(-38px); opacity:0;}}

.seal-options-pane{min-width:0;}
.seal-cat-tabs{display:flex; flex-wrap:wrap; gap:6px; margin-bottom:14px;}
.seal-cat-tab{
  border:2px solid var(--line-soft); background:var(--paper); border-radius:10px;
  padding:7px 10px; font-family:inherit; font-size:var(--fs-sealCatTab, .8rem); font-weight:600; color:var(--ink-soft);
  cursor:pointer;
}
.seal-cat-tab.active{border-color:var(--line); background:var(--grape-soft); color:var(--grape-deep);}

.seal-item-grid{display:grid; grid-template-columns:repeat(auto-fill, minmax(118px, 1fr)); gap:10px;}
.seal-item-card{
  display:flex; flex-direction:column; align-items:center; gap:4px; text-align:center;
  border:2.5px solid var(--line-soft); border-radius:14px; padding:10px 8px;
  background:var(--paper); color:var(--ink); font-family:inherit; cursor:pointer;
}
.seal-item-card.selected{border-color:var(--line); background:var(--grape-soft); box-shadow:var(--shadow-hard);}
.seal-item-swatch{
  width:40px; height:40px; border-radius:50%; border:2.5px solid var(--line);
  display:flex; align-items:center; justify-content:center; font-size:1.15rem;
}
/* A thumbnail of the actual drawing. The art is a wide figure on a transparent canvas, so it
   is fitted whole into a wider pill rather than cropped into the emoji circle — a centre-crop
   of a costume is usually just its middle, which all look alike. */
.seal-item-swatch.art{
  width:66px; height:44px; border-radius:12px; overflow:hidden;
  background:var(--paper-2); padding:2px;
}
.seal-item-swatch.art img{width:100%; height:100%; object-fit:contain; display:block;}
.seal-item-name{font-size:var(--fs-sealItemName, .78rem); font-weight:600; line-height:1.35; word-break:break-word;}
.seal-item-price{font-size:var(--fs-sealItemPrice, .72rem); color:var(--ink-soft);}
.seal-rarity-tag{font-size:var(--fs-sealRarityTag, .64rem); padding:1px 8px; border-radius:99px; font-weight:700;}
.rarity-base{background:var(--grape-soft); color:var(--grape-deep);}
.rarity-common{background:#e7edf0; color:#5b6975;}
.rarity-special{background:#dff5ec; color:#1f8f6b;}
.rarity-rare{background:#efe6ff; color:#7a4fd6;}
.rarity-legendary{background:#fff3d2; color:#a3760a;}

/* ------------------------------------------------------------ name / review / qr */

.seal-name-input{
  font-family:var(--font-pixel); font-size:var(--fs-sealNameInput, 1rem); text-align:center; padding:14px;
  border:var(--bw) solid var(--line); border-radius:14px; width:min(280px, 80vw);
  background:var(--paper-2); color:var(--ink);
}
.seal-review-list{text-align:left; max-width:360px; margin:18px auto;}
.seal-review-row{
  display:flex; justify-content:space-between; gap:12px; padding:8px 0;
  border-bottom:1.5px dashed var(--line-soft); font-size:var(--fs-sealReviewRow, .92rem);
}
.seal-review-row.total{
  border-bottom:0; border-top:var(--bw) solid var(--line); margin-top:6px; padding-top:10px;
  font-weight:800; font-size:var(--fs-sealReviewRow, 1.05rem);
}
.seal-qr-box{
  width:200px; margin:16px auto; padding:10px; background:#fff;
  border:var(--bw) solid var(--line); border-radius:14px;
}
.seal-qr-box img{display:block; width:100%; border-radius:4px;}
.seal-lockrow{margin-top:20px; display:flex; flex-direction:column; align-items:center; gap:10px;}
.seal-confirm-warn{font-size:var(--fs-sealHint, .85rem); color:var(--orange); font-weight:700; margin:0 0 8px;}

.seal-confetti-host{position:relative; height:0;}
.seal-confetti{position:absolute; font-size:1.25rem; animation:seal-fall 1.8s ease-in forwards;}
@keyframes seal-fall{
  0%{transform:translateY(-20px) rotate(0deg); opacity:1;}
  100%{transform:translateY(160px) rotate(200deg); opacity:0;}
}

/* ================================================================ Grape Ocean

   A snowy shore, not open water — seals waddle along a ground band near the bottom of the tank
   (see GROUND_TOP/GROUND_BOTTOM in ocean.js) rather than drifting through the whole box, which
   is what used to read as swimming. .ocean-hero gives the shared .page-hero title/subtitle
   their own sizing keys, same reason pet.css re-points them for /pet.html: without it, this
   page's font slider would silently retune Ranking's title too (they'd otherwise both fall
   back to --fs-rankTitle/--fs-rankSubtitle). */

.ocean-hero h1{font-size:var(--fs-oceanPageTitle, 2.3rem);}
.ocean-hero .subtitle{font-size:var(--fs-oceanPageSubtitle, 1.5rem);}

/* seal.html (the booth) gets the same treatment, for the same reason: .page-hero is shared
   markup, so an override needs .seal-hero's extra class or this page's slider would silently
   retune whichever other page's slider currently owns the bare .page-hero h1/.subtitle rule. */
.seal-hero h1{font-size:var(--fs-sealPageTitle, 2.3rem);}
.seal-hero .subtitle{font-size:var(--fs-sealPageSubtitle, 1.5rem);}

/* The tank and the name/amount roster beside it, side by side. No explicit height anywhere on
   .ocean-roster: flex's own default (align-items:stretch) is what makes it match the tank's
   height, which is itself only ever set by aspect-ratio — so the roster's height still tracks
   the tank correctly if that ratio, or the page's width, ever changes. */
/* contain:size (2026-10-03): without it a long roster counted toward the row's height, and the
   stretch then pulled the tank taller than 16:9 with it. Now the list scrolls inside instead. */
.ocean-layout{display:flex; gap:16px;}
.ocean-layout .ocean-tank{flex:1; min-width:0;}
.ocean-roster{
  width:250px; flex:0 0 250px; min-width:0; min-height:0; contain:size;
  display:flex; flex-direction:column; gap:10px;
  background:var(--paper); border:var(--bw) solid var(--line); border-radius:var(--radius);
  box-shadow:var(--shadow-hard); padding:12px;
}
/* Same pill as Participants' own search box (.part-search, site.css) for visual consistency,
   but sized by this page's own slider rather than Participants' — same reasoning as .ocean-hero
   overriding the shared .page-hero rule just above: two classes on the input, seal.css loads
   after site.css, so this rule's font-size wins the tie without needing !important. */
/* .part-search's own `flex:1 1 220px` assumes the row layout it was written for (Participants'
   tab bar) — inside .ocean-roster's *column* flex, that same shorthand reads as "grow along the
   column," which is what stretched this into a tall oval instead of a normal input row. */
.ocean-search{flex:0 0 auto; font-size:var(--fs-oceanRoster, .95rem);}
.ocean-roster-list{flex:1; min-height:0; overflow-y:auto; display:flex; flex-direction:column; gap:6px;}
.ocean-roster-row{
  display:flex; justify-content:space-between; align-items:baseline; gap:8px;
  padding:6px 8px; border-radius:8px; background:var(--paper-2);
  font-size:var(--fs-oceanRoster, .85rem);
}
/* Not var(--font-pixel) — that stack is 'Press Start 2P','DBHelvethaicaMonX',monospace, and
   Press Start 2P draws its (Latin-only) glyphs much larger relative to its own em-box than
   DBHelvethaicaMonX draws Thai ones, so an English name and a Thai name at the identical
   font-size come out wildly different sizes the moment they sit in the same list — exactly
   what happened here ("pond" dwarfing "อุ๋ง" right below it). The ordinary body font this
   inherits doesn't have that Latin/Thai mismatch. */
.ocean-roster-row b{font-weight:700; color:var(--grape-deep); word-break:break-word; font-size:1em;}
.ocean-roster-row span{white-space:nowrap; color:var(--ink-soft); font-weight:700;}
.ocean-roster-empty{color:var(--ink-soft); font-size:var(--fs-oceanRoster, .85rem); text-align:center; padding:12px 4px;}
@media (max-width:860px){
  .ocean-layout{flex-direction:column;}
  .ocean-roster{width:100%; flex:none; height:280px;}
}
/* Room switcher, top-centre of the tank in the sky (ocean.js oceanSetRoom) — at the bottom it
   sat on the seals' name tags. On a narrow tank the pixel title gives way to it. */
.ocean-rooms{
  position:absolute; left:50%; top:10px; transform:translateX(-50%); z-index:6000;
  display:flex; gap:6px; padding:4px; border-radius:999px;
  background:rgba(255,255,255,.7); border:2px solid var(--line);
}
.ocean-rooms[hidden]{display:none;}
.ocean-room-btn{
  border:0; border-radius:999px; padding:4px 12px; background:transparent; color:#123;
  font:inherit; font-size:var(--fs-oceanHud, .78rem); font-weight:700; white-space:nowrap; cursor:pointer;
}
.ocean-room-btn.on{background:var(--grape); color:#fff;}
.ocean-fs-fake .ocean-rooms{top:calc(10px + env(safe-area-inset-top));}
@media (max-width:640px){
  .ocean-title{display:none;}
  /* the "รวม (n)" tab already says how many — the ❤️ count gives up its corner to the tabs */
  .ocean-tank.has-rooms .ocean-hud{display:none;}
  .ocean-rooms{left:12px; transform:none; gap:2px; padding:3px;}
  .ocean-room-btn{padding:3px 8px;}
}
.ocean-roster-list{scrollbar-width:thin;}
.ocean-seal.ocean-away{display:none;}
/* Effects budget (ocean.js oceanFxRotate): only .fx-on seals' auras animate; the rest hold a
   still frame, which costs nothing per frame. Phones (.ocean-lite) also freeze the animated
   bits drawn inside the backdrop SVG — those repaint the whole scene every frame — while the
   snow and stars (HTML, composited) keep going. */
.ocean-seal:not(.fx-on) .seal-figure *:not(.seal-bubble), .ocean-seal:not(.fx-on) .seal-figure *::before,
.ocean-lite .osc-layer svg *{animation-play-state:paused !important;}
.ocean-tank.ocean-room-swap .osc-layer, .ocean-tank.ocean-room-swap .ocean-seal{animation:ocean-room-in .45s ease;}
@keyframes ocean-room-in{from{opacity:0;}}

/* Search results reach into the tank too, not just the list — the point of naming someone is
   finding them *in the ocean*, not just reading a number off a sidebar. Toggled per-seal in
   ocean.js's renderOceanRoster() against the same filtered set the list itself renders. */
.ocean-seal.dimmed{opacity:.22; transition:opacity .2s ease;}
.ocean-seal.matched .ocean-seal-body{animation:ocean-seal-ping 1s ease-in-out infinite;}
@keyframes ocean-seal-ping{
  0%,100%{filter:drop-shadow(0 0 0 rgba(255,205,70,0));}
  50%{filter:drop-shadow(0 0 10px rgba(255,205,70,.95));}
}
@media (prefers-reduced-motion:reduce){
  .ocean-seal.matched .ocean-seal-body{animation:none; filter:drop-shadow(0 0 8px rgba(255,205,70,.95));}
}

.ocean-tank{
  position:relative; width:100%; aspect-ratio:16/9; border-radius:var(--radius); overflow:hidden;
  border:var(--bw) solid var(--line); box-shadow:var(--shadow-hard);
  background:linear-gradient(180deg,#bfe6fb 0%,#eaf7ff 55%,#ffffff 58%,#ffffff 100%);
  /* Seals stack by y*10 (550-800); isolate keeps that inside the tank, or they'd paint over
     page-level overlays like the photo modal (z-index 90). */
  isolation:isolate;
}
:root[data-theme="dark"] .ocean-tank{
  background:linear-gradient(180deg,#0d1c33 0%,#16263f 55%,#26324a 58%,#3a4560 100%);
}
/* Fills the actual screen rather than being capped by the aspect-ratio box that fits it into
   the page layout — the border/radius go with it, since a full-bleed tank with a frame drawn
   around empty page margin would look broken. */
.ocean-tank:fullscreen{width:100vw; height:100vh; aspect-ratio:auto; border-width:0; border-radius:0;}
/* Phones without the Fullscreen API (iPhone): ocean.js pins the tank over the page instead.
   100dvh so Safari's collapsing toolbar doesn't leave a strip of page under the tank. */
.ocean-tank.ocean-fs-fake{
  position:fixed; inset:0; z-index:80; width:100vw; height:100vh; height:100dvh;
  aspect-ratio:auto; border-width:0; border-radius:0; box-shadow:none;
}
.ocean-fs-lock, .ocean-fs-lock body{overflow:hidden;}
.ocean-fs-fake .ocean-hud, .ocean-fs-fake .ocean-title, .ocean-fs-fake .ocean-fullscreen-btn{
  top:calc(10px + env(safe-area-inset-top));
}
.ocean-fs-fake .ocean-fullscreen-btn{width:38px; height:38px; font-size:18px;}
.ocean-hud{
  position:absolute; top:10px; left:12px; z-index:5;
  background:rgba(255,255,255,.85); border:2px solid var(--line); border-radius:10px;
  padding:5px 10px; font-size:var(--fs-oceanHud, .78rem); font-weight:700; color:#123;
}
.ocean-title{
  position:absolute; top:10px; right:50px; z-index:5;
  font-family:var(--font-pixel); font-size:var(--fs-oceanTankTitle, .7rem); color:#fff;
  text-shadow:0 2px 0 rgba(0,0,0,.25);
}
:root[data-theme="dark"] .ocean-title{color:#eef6ff;}
.ocean-fullscreen-btn{
  position:absolute; top:10px; right:12px; z-index:6; width:30px; height:30px; padding:0;
  display:flex; align-items:center; justify-content:center; font-size:15px; line-height:1;
  background:rgba(255,255,255,.85); border:2px solid var(--line); border-radius:10px;
  color:#123; cursor:pointer;
}
/* The painted scene behind everything (ocean-scenes.js). Replaced the old snow mounds and the
   tank's own gradient as the "ground-level decor", 2026-09-25. The scenes carry their own
   colours, so dark theme doesn't restyle them — the night scene is what dark looks like here. */
.osc-layer{position:absolute; inset:0; z-index:0; pointer-events:none;}
.osc-layer > svg{position:absolute; inset:0; width:100%; height:100%; display:block;}
.osc-fx{position:absolute; inset:0; overflow:hidden;}
/* flakes/stars live in the scene layer, so they pass behind the seals */
/* Each flake is a full-height column whose dot sits at its top, and the column slides down by
   its own (= the tank's) height — a transform, where animating `top` re-laid-out the tank for
   every flake on every frame (2026-10-03 phone lag). */
.osc-flake{position:absolute; top:0; height:100%; animation:osc-fall linear infinite; will-change:transform;}
.osc-flake::before{content:''; display:block; aspect-ratio:1; border-radius:50%; background:#fff; box-shadow:0 0 0 1px rgba(170,210,235,.5);}
@keyframes osc-fall{from{transform:translateY(-3%);} to{transform:translate(40px,103%);}}
.osc-star{position:absolute; aspect-ratio:1; border-radius:50%; background:#fffbe6; box-shadow:0 0 4px #fff; animation:osc-twinkle 2.6s ease-in-out infinite;}
.osc-box{transform-box:fill-box; transform-origin:50% 50%;}
.osc-drift{animation:osc-drift linear infinite;}
@keyframes osc-drift{from{transform:translateX(-260px);} to{transform:translateX(1860px);}}
.osc-bob{animation:osc-bob 4s ease-in-out infinite;}
@keyframes osc-bob{0%,100%{transform:translateY(0) rotate(-1deg);} 50%{transform:translateY(-6px) rotate(1deg);}}
.osc-wave{stroke-dasharray:30 26; animation:osc-wave 3s linear infinite;}
@keyframes osc-wave{to{stroke-dashoffset:-112;}}
.osc-lap{animation:osc-lap 4.5s ease-in-out infinite;}
@keyframes osc-lap{0%,100%{transform:translateY(0);} 50%{transform:translateY(10px);}}
.osc-twinkle{animation:osc-twinkle 2.4s ease-in-out infinite;}
@keyframes osc-twinkle{0%,100%{opacity:.25;} 50%{opacity:1;}}
.osc-flag{transform-origin:0 50%; animation:osc-flag 1.6s ease-in-out infinite;}
@keyframes osc-flag{0%,100%{transform:skewY(-4deg) scaleX(1);} 50%{transform:skewY(5deg) scaleX(.9);}}
.osc-spin{animation:osc-spin 40s linear infinite;}
@keyframes osc-spin{to{transform:rotate(360deg);}}
.osc-sway{animation:osc-sway 4s ease-in-out infinite;}
@keyframes osc-sway{0%,100%{transform:rotate(-2deg);} 50%{transform:rotate(2deg);}}
.osc-aurora{animation:osc-aurora 7s ease-in-out infinite;}
@keyframes osc-aurora{0%,100%{transform:translateX(0) scaleY(1); opacity:.75;} 50%{transform:translateX(-40px) scaleY(1.25); opacity:1;}}
.osc-gull{animation:osc-gull 9s ease-in-out infinite;}
@keyframes osc-gull{0%,100%{transform:translate(0,0);} 50%{transform:translate(80px,-20px);}}
@media (prefers-reduced-motion:reduce){ .osc-layer *{animation:none !important;} }
/* night: seals get a faint moonlit rim, name tags go dark so they don't glare */
.ocean-tank.osc-night .ocean-seal .seal-figure > svg{filter:brightness(.92) drop-shadow(0 0 3px rgba(200,210,255,.55));}
.ocean-tank.osc-night .ocean-seal .mini-tag{background:rgba(30,30,70,.75); color:#eef0ff;}
.ocean-tank.osc-night .ocean-empty, .ocean-tank.osc-night .ocean-title{color:#eef0ff;}
.ocean-empty{
  position:absolute; inset:0; display:flex; align-items:center; justify-content:center;
  color:#123; font-size:var(--fs-oceanEmpty, .95rem); text-align:center; padding:20px;
  text-shadow:0 1px 0 rgba(255,255,255,.6);
}
:root[data-theme="dark"] .ocean-empty{color:#eef6ff; text-shadow:0 2px 0 rgba(0,0,0,.25);}
/* left/top stay 0 — ocean.js moves her with a px translate (no layout per frame). */
.ocean-seal{position:absolute; left:0; top:0; width:var(--ocean-seal-w, 110px); text-align:center; will-change:transform;}
/* The transform target: translate/flip/depth-scale are written here every frame by ocean.js's
   place(). Never on .ocean-seal itself (that also carries the name tag below) — flipping the
   whole card used to mirror the tag's text along with the art. */
.ocean-seal-body{position:relative; width:100%; will-change:transform;}
.ocean-seal .seal-figure{aspect-ratio:500/332; height:auto;}
/* The gait is now written by ocean.js every frame (waddle / galumph / scoot-and-slide, plus
   idle actions) onto .ocean-seal-pose — a wrapper between the flipped body and the figure.
   Three levels because each carries its own transform: body = flip + depth scale, pose = the
   gait (with a moving transform-origin: galumph pivots on the tail, then the nose), figure =
   nothing. The figure's own booth bob animation is switched off here — a CSS animation beats
   any inline transform, so leaving it on would fight the pose. Replaced the CSS-only
   ocean-seal-waddle loop, 2026-09-25. */
.ocean-seal{cursor:pointer;}
/* its own layer, so the art (and its night-time drop-shadow) is painted once and only moved */
.ocean-seal-pose{position:relative; transform-origin:50% 100%; will-change:transform;}
.ocean-seal .seal-figure{animation:none;}
.ocean-emote{
  position:absolute; left:50%; top:-8px; z-index:5; transform:translateX(-50%); pointer-events:none;
  font-weight:800; font-size:1.05rem; line-height:1; color:#6b4fd6;
  text-shadow:1px 1px 0 #fff,-1px -1px 0 #fff,1px -1px 0 #fff,-1px 1px 0 #fff,0 2px 0 #fff;
  animation:ocean-emote 1.45s ease-out forwards;
}
.ocean-emote.note{color:#e0568a;}
.ocean-emote.heart{width:18px; aspect-ratio:32/28;
  background:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 28'%3E%3Cpath d='M16 26S3 18 3 9.7C3 4.8 6.7 2.3 10.4 2.3c2.6 0 4.7 1.4 5.6 3.3.9-1.9 3-3.3 5.6-3.3C25.3 2.3 29 4.8 29 9.7 29 18 16 26 16 26Z' fill='%23ff8fb5' stroke='%23141414' stroke-width='2'/%3E%3C/svg%3E") center/contain no-repeat;}
.ocean-emote.heart.big{width:26px;}
@keyframes ocean-emote{
  0%{opacity:0; transform:translate(-50%,0) scale(.5);}
  18%{opacity:1; transform:translate(-50%,-25%) scale(1.15);}
  100%{opacity:0; transform:translate(calc(-50% + var(--dx,0px)),-190%) scale(1);}
}
/* ---- feeding (ocean.js oceanDropFish) ---- */
.ocean-tank{cursor:pointer;}
.ocean-fish{position:absolute; width:4.5%; min-width:26px; aspect-ratio:48/30; transform:translate(-50%,-100%); pointer-events:none;}
.ocean-fish-fall{animation:ocean-fish-fall .7s cubic-bezier(.4,0,.8,.4) both;}
.ocean-fish-flop{transform-origin:50% 100%; animation:ocean-fish-flop .5s ease-in-out .7s infinite alternate;}
@keyframes ocean-fish-fall{0%{transform:translateY(-900%) rotate(-40deg);} 75%{transform:translateY(0) rotate(10deg);} 88%{transform:translateY(-35%) rotate(-6deg);} 100%{transform:translateY(0) rotate(0);}}
@keyframes ocean-fish-flop{from{transform:rotate(-10deg) scaleX(1);} to{transform:rotate(12deg) scaleX(-1);}}
.ocean-fish.eaten{transition:transform .35s ease-in, opacity .35s ease-in; transform:translate(-50%,-100%) scale(0); opacity:0;}
.ocean-fish.gone{transition:opacity .5s; opacity:0;}

/* ---- photo booth (ocean-photo.js) ---- the modal itself borrows site.css's .share-modal */
.ocean-snap-chip{
  position:absolute; left:50%; top:-30px; z-index:6; transform:translateX(-50%); white-space:nowrap;
  font:inherit; font-weight:700; font-size:.78rem; padding:3px 10px; border-radius:999px;
  background:#fff; color:#23202b; border:2px solid #141414; box-shadow:2px 2px 0 #141414;
  cursor:pointer; animation:ocean-chip-in .25s ease-out;
}
@keyframes ocean-chip-in{from{opacity:0; transform:translate(-50%,6px);} to{opacity:1; transform:translate(-50%,0);}}
.ocean-roster-snap{
  flex:none; font-size:.9rem; line-height:1; padding:3px 6px; border-radius:8px; cursor:pointer;
  background:var(--paper); border:2px solid var(--line-soft); color:var(--ink);
}
.ocean-roster-snap:hover{border-color:var(--line);}
.ocean-roster-row span{margin-left:auto;}
.sp-modal{width:min(620px,100%);}
.sp-frame{border:var(--bw) solid var(--line); border-radius:16px; overflow:hidden; background:var(--paper-2); margin-bottom:12px;}
.sp-frame canvas{display:block; width:100%; height:auto; aspect-ratio:16/9;}
.sp-scenes{display:flex; flex-wrap:wrap; justify-content:center; gap:6px; margin-bottom:14px;}
.sp-scene{
  font:inherit; font-weight:700; font-size:.82rem; padding:5px 12px; border-radius:999px; cursor:pointer;
  background:var(--paper); color:var(--ink); border:2px solid var(--line-soft);
}
.sp-scene[aria-pressed="true"]{background:var(--grape-soft); border-color:var(--line); box-shadow:2px 2px 0 var(--line);}
.sp-gif{margin-top:12px;}
.sp-gif img{display:block; width:100%; border-radius:12px; border:2px solid var(--line);}
.sp-note{min-height:1.2em; color:var(--ink-soft); font-size:.88rem;}

.ocean-puff{position:absolute; aspect-ratio:1; border-radius:50%; background:#fff; box-shadow:0 0 0 1px rgba(170,205,230,.7); transform:translate(-50%,-50%); pointer-events:none; animation:ocean-puff .8s ease-out forwards;}
.ocean-tank.osc-beach .ocean-puff{background:#f6dca2; box-shadow:none;}
.ocean-tank.osc-night .ocean-puff{background:#e6e8fb;}
@keyframes ocean-puff{from{opacity:.95; transform:translate(-50%,-50%) scale(.5);} to{opacity:0; transform:translate(-50%,-150%) scale(1.9);}}
.ocean-seal .mini-tag{
  display:inline-block; margin-top:2px; padding:1px 7px; border-radius:8px;
  background:rgba(255,255,255,.9); color:#123; font-size:var(--fs-oceanTag, .66rem); font-weight:700;
}
/* The featured seal (ocean.js oceanMakeStar, picked in /admin/ocean.html): --star-k times the
   size, a soft spotlight pooled under her and a gold name tag. */
.ocean-seal.ocean-star{width:calc(var(--ocean-seal-w, 110px) * var(--star-k, 1.8));}
.ocean-star::before{
  content:''; position:absolute; left:50%; top:calc(var(--ocean-seal-w, 110px) * var(--star-k, 1.8) * .58);
  width:140%; aspect-ratio:3/1; transform:translate(-50%,-50%); z-index:-1; pointer-events:none;
  background:radial-gradient(closest-side, rgb(255 246 190/.95), rgb(255 214 110/.55) 50%, rgb(255 214 110/0));
}
.ocean-star .mini-tag{
  font-size:calc(var(--fs-oceanTag, .66rem) * 1.35); padding:2px 10px; color:#5a3a00;
  background:linear-gradient(180deg, #fff3b8, #ffd45e); border:1.5px solid #c48a12;
  box-shadow:0 2px 0 rgb(196 138 18/.45);
}
.ocean-star .mini-tag::before{content:'👑 ';}
.ocean-tank.osc-night .ocean-star .mini-tag{color:#5a3a00; background:linear-gradient(180deg, #fff3b8, #ffd45e);}
/* Featured-seal extras (ocean.js, content.ocean.starFx) — all transform/opacity animations. */
.ocean-confetti{position:absolute; inset:0; z-index:5000; pointer-events:none; overflow:hidden;}
.ocean-confetti i{position:absolute; top:0; width:7px; height:11px; border-radius:2px; opacity:0;
  animation:ocean-conf-fall 3s cubic-bezier(.3,.6,.5,1) forwards;}
@keyframes ocean-conf-fall{
  0%{opacity:1; transform:translate(0,-20px) rotate(0);}
  85%{opacity:1;}
  100%{opacity:0; transform:translate(var(--sx,0),calc(var(--tank-h, 480px) * .9)) rotate(540deg);}
}
.ocean-star-banner{
  position:absolute; left:50%; top:24%; z-index:5001; pointer-events:none; white-space:nowrap;
  padding:8px 20px; border-radius:999px; border:2.5px solid #141414; box-shadow:3px 3px 0 #141414;
  background:linear-gradient(180deg, #fff6c8, #ffd45e); color:#5a3a00; font-weight:800;
  font-size:clamp(.95rem, 3.2vw, 1.5rem);
  animation:ocean-banner 2.8s ease forwards;
}
@keyframes ocean-banner{
  0%{opacity:0; transform:translate(-50%,0) scale(.3);}
  14%{opacity:1; transform:translate(-50%,0) scale(1.12);}
  22%,82%{opacity:1; transform:translate(-50%,0) scale(1);}
  100%{opacity:0; transform:translate(-50%,-14px) scale(.95);}
}
.ocean-star-say{
  position:absolute; left:50%; bottom:100%; z-index:6; pointer-events:none; white-space:nowrap;
  padding:5px 12px; border-radius:14px; border:2px solid #141414; background:#fff; color:#23202b;
  font-weight:700; font-size:calc(var(--fs-oceanTag, .66rem) * 1.4);
  opacity:0; transform:translate(-50%,6px) scale(.6); transform-origin:50% 100%;
}
.ocean-star-say::after{content:''; position:absolute; left:50%; top:100%; width:10px; height:10px; background:#fff;
  border-right:2px solid #141414; border-bottom:2px solid #141414; transform:translate(-50%,-55%) rotate(45deg);}
.ocean-star-say.show{animation:ocean-say 3.2s ease forwards;}
@keyframes ocean-say{
  0%{opacity:0; transform:translate(-50%,6px) scale(.6);}
  10%{opacity:1; transform:translate(-50%,0) scale(1.06);}
  16%,85%{opacity:1; transform:translate(-50%,0) scale(1);}
  100%{opacity:0; transform:translate(-50%,-6px) scale(.95);}
}
.ocean-burst{position:absolute; left:50%; top:40%; z-index:7; pointer-events:none; font-size:1.25rem; line-height:1;
  animation:ocean-burst 1.1s cubic-bezier(.2,.7,.3,1) forwards;}
@keyframes ocean-burst{
  0%{opacity:1; transform:translate(-50%,-50%) scale(.4);}
  70%{opacity:1;}
  100%{opacity:0; transform:translate(calc(-50% + var(--dx)), calc(-50% + var(--dy))) scale(1.15);}
}
.ocean-roster-row.star{background:linear-gradient(180deg, #fff6c8, #ffe28a); border:1.5px solid #e0a82a;}
.ocean-roster-row.star b{color:#7a4f00;}
/* smaller seals on a phone-width tank get a slightly smaller tag to match */
.ocean-lite .ocean-seal:not(.ocean-star) .mini-tag{font-size:calc(var(--fs-oceanTag, .66rem) * .85); padding:0 5px;}
