/* HORO-BEAT sim theme: FX = the decorative layer of NIGHT PARADE (washi grain, sumi wash, the printed patterns, gold
   sheen, lantern glow, foil, the night city) + the styles of the overlays fx.js creates (press shine, card ghosts,
   ripples, brush banners) + the keyframes. Everything decorative here is scoped to body:not(.hb-perf); Performance
   mode (perf.css) also empties the texture tokens and hides .deco. Lanes put their own decorative paint in an
   @layer hb-fx block scoped the same way (DESIGN.md §7). Motion personality: "paper and flame" - paper things (cards,
   plaques, scrolls) are slapped down and settle; flame things (lanterns, 人魂, neon) flicker and drift. Idle loops
   animate transform / opacity only. NEVER gate any of this on prefers-reduced-motion. */

@layer hb-fx {
  /* ------------------------------------------------------------------ page + chrome textures */
  body:not(.hb-perf) { background-image: var(--tex-grain); }
  body:not(.hb-perf) .hb-panel { background-image: var(--tex-grain); }

  /* ------------------------------------------------------------------ buttons: a gold-leaf sheen sweeps across on hover;
     the lantern button glows */
  body:not(.hb-perf) .hb-btn--primary { background-image: radial-gradient(120% 140% at 50% 0%, rgba(255,190,120,.35), transparent 60%); }
  body:not(.hb-perf) .hb-btn--primary::before, body:not(.hb-perf) .hb-btn:not(.hb-btn--ghost):not(.hb-btn--danger):not(.hb-btn--danger-solid):not(.hb-btn--tama)::before {
    content: ""; position: absolute; z-index: -1; top: 0; bottom: 0; left: -40%; width: 30%; pointer-events: none;
    background: linear-gradient(100deg, transparent, rgba(255,236,190,.28), transparent); transform: translateX(-120%) skewX(-18deg); }
  body:not(.hb-perf) .hb-btn:not([disabled]):hover::before, body:not(.hb-perf) .hb-btn.is-hover::before { animation: hb-sheen 700ms var(--hb-ease-brush) 1; }
  body:not(.hb-perf) .hb-btn--primary:not([disabled]):hover, body:not(.hb-perf) .hb-btn--primary.is-hover { box-shadow: inset 0 1px 0 rgba(255,214,170,.45), 0 2px 0 var(--hb-shu-lo), 0 0 22px var(--hb-shu-glow); }
  body:not(.hb-perf) .hb-seg > button[aria-pressed="true"], body:not(.hb-perf) .hb-seg > button.is-on, body:not(.hb-perf) .hb-seg > button[aria-selected="true"] { background-image: linear-gradient(180deg, var(--hb-kin-hi), var(--hb-kin) 55%, #a87d26); }
  body:not(.hb-perf) .hb-crest.is-on, body:not(.hb-perf) [aria-current="page"] > .hb-crest { box-shadow: 0 0 14px var(--hb-shu-glow); }

  /* ------------------------------------------------------------------ card furniture */
  /* SR / DR foil: a periodic gold band pattern (115deg, 29.0018 px along the gradient = 32 px across) slides by exactly
     one period, forever, so the loop point cannot show; transform only (compositor). fx.js keeps every idle loop on one
     clock, so a re-rendered tag (the printing strip on every hover) continues in phase instead of restarting. */
  body:not(.hb-perf) .hb-rar--sr, body:not(.hb-perf) .hb-rar--dr { position: relative; overflow: hidden; isolation: isolate; }
  body:not(.hb-perf) .hb-rar--sr::before, body:not(.hb-perf) .hb-rar--dr::before { content: ""; position: absolute; z-index: -1; top: -2px; bottom: -2px; left: -34px; right: -2px; pointer-events: none;
    background: repeating-linear-gradient(115deg, #a87a1e 0, #f6dc92 11.6px, #c99a3a 16px, #8a641c 23.2px, #a87a1e 29.0018px); animation: hb-foil 3s linear infinite; }
  body:not(.hb-perf) .hb-typetab { background-image: var(--pat-seigaiha); background-size: 12px 6px; background-position: 0 calc(100% + 2px); background-repeat: repeat-x; }   /* (2 px lower: the waves run under the frame, clear of the letters) */
  /* a lit line mark floats as one (its numeral stays in its ball: EBM 2026-11-08, numbers off centre in circles) and its
     tail sways about the ball's own centre (the mask's arc: 10 / 15 of 24), so the ball stays round the numeral */
  body:not(.hb-perf) .hb-lmark.is-lit { animation: hb-bob 2.4s var(--hb-ease-sway) infinite alternate; }
  body:not(.hb-perf) .hb-lmark.is-lit > .hb-dama { filter: drop-shadow(0 0 5px var(--hb-tama-glow)); transform-origin: 41.667% 62.5%; animation: hb-sway-tail 2.4s var(--hb-ease-sway) infinite alternate; }
  body:not(.hb-perf) .hb-dama.is-lit { filter: drop-shadow(0 0 5px var(--hb-tama-glow)); animation: hb-float 2.4s var(--hb-ease-sway) infinite alternate; }

  /* the card-text box: the colour's tint on both edges, its printed pattern fading in from the left (plain washi: no fibre
     texture, its feTurbulence fibres read as dark horizontal streaks) */
  body:not(.hb-perf) .hb-cardtext {
    background-image: linear-gradient(90deg, var(--c-pale) 0%, color-mix(in srgb, var(--c-pale) 35%, var(--hb-washi)) 26%, var(--hb-washi) 50%, var(--hb-washi) 74%, color-mix(in srgb, var(--c-pale) 70%, var(--hb-washi)) 100%);
    box-shadow: 0 0 0 1.5px var(--c), 0 0 0 3.5px #140a06, 0 10px 24px rgba(0,0,0,.45); }
  body:not(.hb-perf) .hb-cardtext::before { content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none; background: var(--c-pat);
    -webkit-mask-image: linear-gradient(90deg, #000 0%, rgba(0,0,0,.55) 22%, transparent 46%); mask-image: linear-gradient(90deg, #000 0%, rgba(0,0,0,.55) 22%, transparent 46%); }

  /* ------------------------------------------------------------------ menus, windows, toasts */
  body:not(.hb-perf) .hb-ddmenu:not(.is-page) { background-image: var(--tex-grain); }
  body:not(.hb-perf) .hb-window__brocade { background-image: var(--pat-seigaiha), linear-gradient(180deg, #2b1f17, #21170f); background-size: 16px 8px, auto; }
  body:not(.hb-perf) .hb-window__page { background-image: var(--tex-grain); }
  body:not(.hb-perf) .hb-toast__plate { background-image: linear-gradient(180deg, color-mix(in srgb, var(--plate) 55%, #fff4d0), var(--plate) 40%, color-mix(in srgb, var(--plate) 70%, #000)); }
  body:not(.hb-perf) .hb-cartouche { background-image: var(--tex-fibre), linear-gradient(180deg, #d9482a, #b52f1a); background-blend-mode: multiply, normal; }
  @media (max-width: 600px) { body:not(.hb-perf) .hb-window__brocade { background: none; } }

  /* ------------------------------------------------------------------ THE NIGHT CITY (UI.nightCity(): moon, 霞 mist
     outlined in gold, the skyline with lit windows, a pagoda, a torii, power lines, a lantern string, two neon signs,
     floating 人魂). All .deco; the host sets position: relative + overflow: hidden and the scene fills it. */
  .hb-night { position: absolute; inset: 0; z-index: 0; overflow: hidden; pointer-events: none; }
  .hb-night__sky { position: absolute; left: 0; right: 0; top: 50%; height: 560px; margin-top: -280px; }
  body:not(.hb-perf) .hb-night { background: radial-gradient(60% 75% at 74% 42%, rgba(255,214,160,.10), transparent 62%), linear-gradient(180deg, #08060c 0%, #110b12 38%, #211010 72%, #3a170c 100%); }
  body:not(.hb-perf) .hb-night::after { content: ""; position: absolute; inset: 0; z-index: 3; background: var(--tex-grain); }
  .hb-moon { position: absolute; z-index: 0; left: calc(50% + 150px); top: 50px; width: 330px; height: 330px; border-radius: 50%; opacity: .9;
    background: radial-gradient(circle at 42% 38%, #fbf3dc 0, #efe0bb 58%, #d8c393 100%); box-shadow: 0 0 60px 12px rgba(250,230,180,.22), 0 0 180px 50px rgba(250,200,140,.10); }
  .hb-mist { position: absolute; z-index: 1; left: calc(50% + 40px); top: 210px; width: 600px; height: 150px; animation: hb-drift 22s var(--hb-ease-sway) infinite alternate; }
  .hb-city { position: absolute; z-index: 1; left: 0; right: 0; bottom: 0; width: 100%; height: 230px;
    -webkit-mask-image: linear-gradient(90deg, rgba(0,0,0,.4), rgba(0,0,0,.4) 40%, #000 60%); mask-image: linear-gradient(90deg, rgba(0,0,0,.4), rgba(0,0,0,.4) 40%, #000 60%); }
  .hb-wire { position: absolute; z-index: 2; left: 0; top: 0; width: 100%; height: 90px; }
  .hb-lantern { position: absolute; z-index: 2; width: 30px; height: 45px; transform-origin: 50% 0; animation: hb-sway 5.2s var(--hb-ease-sway) infinite alternate; }
  .hb-lantern > svg { width: 100%; height: 100%; overflow: visible; }
  .hb-lantern::after { content: ""; position: absolute; left: 50%; top: 58%; width: 120px; height: 120px; margin: -60px 0 0 -60px; border-radius: 50%; background: radial-gradient(circle, rgba(255,140,60,.32), transparent 65%); animation: hb-flicker 3.1s linear infinite; }
  .hb-lantern:nth-child(2n) { animation-duration: 6.4s; animation-delay: -2s; }
  .hb-lantern:nth-child(3n)::after { animation-delay: -1.3s; }
  .hb-neon { position: absolute; z-index: 1; right: 64px; top: 168px; padding: 12px 7px; writing-mode: vertical-rl; border: 2px solid rgba(158,240,222,.7); border-radius: 4px; color: #e6fffa; font: 400 30px/1 var(--hb-font-neon);
    text-shadow: 0 0 3px #9ef0de, 0 0 12px #4fd9c2, 0 0 30px rgba(79,217,194,.65); box-shadow: 0 0 16px rgba(79,217,194,.35), inset 0 0 14px rgba(79,217,194,.25); animation: hb-neon 7s steps(1) infinite; }
  .hb-neon--shu { right: 128px; top: 252px; padding: 8px 5px; border-color: rgba(255,138,82,.7); color: #ffe6d8; font-size: 17px;
    text-shadow: 0 0 3px #ff8a52, 0 0 12px #ff5a2a, 0 0 26px rgba(255,90,42,.6); box-shadow: 0 0 14px rgba(255,90,42,.35), inset 0 0 10px rgba(255,90,42,.25); animation-delay: -3s; }
  .hb-wisp { position: absolute; z-index: 4; width: 24px; height: 24px; color: var(--hb-tama); filter: drop-shadow(0 0 6px var(--hb-tama-glow)) drop-shadow(0 0 14px var(--hb-tama-glow)); animation: hb-float 4.6s var(--hb-ease-sway) infinite alternate; }
  .hb-wisp--2 { animation-duration: 5.8s; animation-delay: -2s; }
  .hb-wisp--3 { animation-duration: 3.9s; animation-delay: -1s; }
  @media (max-width: 600px) {
    .hb-night__sky { top: 0; bottom: 0; height: auto; margin-top: 0; }
    .hb-moon { left: calc(50% - 125px); top: auto; bottom: 40px; width: 250px; height: 250px; }
    .hb-mist { left: -80px; top: auto; bottom: 40px; width: 520px; height: 130px; }
    .hb-neon { display: none; }
    .hb-lantern { width: 22px; height: 33px; }
    .hb-wisp--1, .hb-wisp--3 { display: none; }
  }

  /* ------------------------------------------------------------------ the press shine (fx.js), BZ's module in our light:
     a lantern glow, a gold ring and a rising 人魂 wisp, tinted by the pressed card's colour (--shine) */
  .hb-shine { position: fixed; z-index: 2147483600; width: 0; height: 0; pointer-events: none; }
  .hb-shine > i { position: absolute; left: 0; top: 0; display: block; border-radius: 50%; will-change: transform, opacity; mix-blend-mode: screen; animation: .44s cubic-bezier(.2,.7,.3,1) both; }
  .hb-shine > i.hb-shine__glow { width: 48px; height: 48px; margin: -24px 0 0 -24px; background: radial-gradient(circle, rgba(255,240,214,.85), rgba(255,150,80,.38) 40%, transparent 70%); animation-name: hb-shine-glow; }
  .hb-shine > i.hb-shine__ring { width: 30px; height: 30px; margin: -15px 0 0 -15px; border: 1.5px solid rgba(255,236,190,.8); box-shadow: 0 0 8px var(--shine, rgba(201,154,58,.7)), inset 0 0 6px var(--shine, rgba(201,154,58,.5)); animation-name: hb-shine-ring; }
  .hb-shine > i.hb-shine__dama { width: 14px; height: 14px; margin: -7px 0 0 -7px; border-radius: 0; background-color: var(--shine, var(--hb-tama)); -webkit-mask: var(--hb-dama) center / contain no-repeat; mask: var(--hb-dama) center / contain no-repeat; animation-name: hb-shine-dama; }
  .hb-shine > i.hb-shine__px { width: 4px; height: 4px; margin: -2px 0 0 -2px; border-radius: 0; background: var(--shine, var(--hb-kin-hi)); animation-name: hb-shine-px; }

  /* ------------------------------------------------------------------ overlays fx.js builds */
  .hb-fxlayer { position: fixed; inset: 0; z-index: 700; pointer-events: none; overflow: hidden; }
  .hb-ghost { position: fixed; left: 0; top: 0; margin: 0; pointer-events: none; transform-origin: 50% 50%; will-change: transform, opacity, filter; }
  .hb-ghost > img, .hb-ghost > .hb-cimg { width: 100%; height: 100%; border-radius: var(--hb-r-print); }
  .hb-fx-hidden { opacity: 0; }
  .hb-ripple { position: fixed; border-radius: 50%; pointer-events: none; border: 2px solid var(--c, var(--hb-kin)); box-shadow: 0 0 14px color-mix(in srgb, var(--c, var(--hb-kin)) 70%, transparent); }
  .hb-px { position: fixed; width: 6px; height: 6px; pointer-events: none; background: var(--c, var(--hb-kin)); box-shadow: 0 0 6px var(--c, var(--hb-kin)); }
  .hb-float { position: fixed; pointer-events: none; color: var(--c-text, var(--hb-kin-hi)); font: italic 900 var(--hb-fs-22)/1 var(--hb-font-num); -webkit-text-stroke: .17em #140a06; paint-order: stroke fill; white-space: nowrap; }
  .hb-flash { position: fixed; pointer-events: none; border-radius: 6px; box-shadow: 0 0 0 2px var(--hb-kin-hi), 0 0 18px var(--c, var(--hb-kin)), inset 0 0 14px rgba(255,240,200,.5); }

  /* ------------------------------------------------------------------ BANNER: a sumi brush plate carries the round /
     phase / trigger / result; its words are stamped on. Markup (fx.js HBFX.banner): .hb-banner > .hb-banner__ink
     (> i.hb-banner__halo + i.hb-banner__smear) + .hb-banner__txt > [.hb-banner__seal] [.hb-trig] [.hb-banner__round >
     small] .hb-banner__phase. The stroke is raster art (ui/img/plate-wide.webp, plate-sm.webp, + their -halo masks;
     painted by scripts/gen-plates.py), tinted per kind: --plate-ink (the stroke), --plate-rim (the glow round it),
     --plate-word (the words). Sizes follow the plate's width (--plate-w). Performance mode (perf.css): the same stroke,
     flat and static, no glow. The images come in as data: URLs (--hb-plate-*, theme/plates.css, written by
     scripts/embed-plates.mjs): a mask image must pass CORS, and Chrome refuses a file:// one, so a page opened
     straight from disk would have no plates. */
  .hb-banner { --plate-w: min(720px, 100vw); --plate-ink: #0c0807; --plate-rim: rgba(255,128,60,.34); --plate-word: #fff4e4;
    position: fixed; left: 50%; top: var(--hb-banner-y, 38%); z-index: 760; display: grid; place-items: center; width: var(--plate-w);
    aspect-ratio: 1600 / 340; translate: -50% -50%; pointer-events: none; }
  .hb-banner--sm { --plate-w: min(540px, 100vw); aspect-ratio: 1200 / 250; }
  .hb-banner__ink, .hb-banner__ink > i { position: absolute; inset: 0; }
  .hb-banner__smear { background-color: var(--plate-ink); -webkit-mask: var(--hb-plate-wide) center / 100% 100% no-repeat; mask: var(--hb-plate-wide) center / 100% 100% no-repeat; }
  .hb-banner--sm .hb-banner__smear { -webkit-mask-image: var(--hb-plate-sm); mask-image: var(--hb-plate-sm); }
  .hb-banner__halo { background-color: var(--plate-rim); -webkit-mask: var(--hb-plate-wide-halo) center / 100% 100% no-repeat; mask: var(--hb-plate-wide-halo) center / 100% 100% no-repeat; }
  .hb-banner--sm .hb-banner__halo { -webkit-mask-image: var(--hb-plate-sm-halo); mask-image: var(--hb-plate-sm-halo); }
  body:not(.hb-perf) .hb-banner__smear::after { content: ""; position: absolute; inset: 0; background: var(--hb-plate-wide) center / 100% 100% no-repeat; mix-blend-mode: screen; opacity: var(--plate-sheen, 1); }
  body:not(.hb-perf) .hb-banner--sm .hb-banner__smear::after { background-image: var(--hb-plate-sm); }
  /* the words: on the stroke's dense core (a little left of centre: the loaded head is heavier than the flick); an ink
     outline in the plate's own colour keeps every letter whole over a dry-brush streak */
  .hb-banner__txt { position: relative; display: flex; align-items: center; gap: .42em; margin-right: 7%; white-space: nowrap; scale: var(--fit, 1);
    font-size: calc(var(--plate-w) * .047); }
  .hb-banner--sm .hb-banner__txt { font-size: calc(var(--plate-w) * .05); margin-right: 6%; }
  .hb-banner__phase { color: var(--plate-word); font: 800 1em/1.15 var(--hb-font-display); letter-spacing: .045em;
    -webkit-text-stroke: .16em var(--plate-ink); paint-order: stroke fill; }
  .hb-banner__round { display: inline-flex; align-items: baseline; gap: .12em; color: #fff; font: italic 900 1.9em/1 var(--hb-font-num);
    -webkit-text-stroke: .1em var(--plate-ink); paint-order: stroke fill; }
  .hb-banner__round small { color: var(--hb-kin-text); font: 800 max(11px, .24em)/1 var(--hb-font-ui); font-style: normal; letter-spacing: .2em; -webkit-text-stroke: 0; translate: 0 -.9em; }
  .hb-banner__seal { display: grid; place-items: center; width: 1.75em; height: 1.75em; border-radius: 3px; background: var(--hb-shu); color: #fff; font: 800 .74em/1 var(--hb-font-display);
    rotate: -6deg; box-shadow: inset 0 0 0 2px rgba(255,220,190,.35); }
  .hb-banner__txt > .hb-trig { width: 1.8em; height: 1.8em; font-size: .7em; box-shadow: 0 0 0 .12em var(--plate-ink); }
  body:not(.hb-perf) .hb-banner__phase, body:not(.hb-perf) .hb-banner__round { text-shadow: 0 .05em 0 rgba(0,0,0,.5); }
  /* the result words: bigger, a little tracking (the old .3em split DEFEAT into loose letters) */
  .hb-banner--win .hb-banner__phase, .hb-banner--lose .hb-banner__phase, .hb-banner--draw .hb-banner__phase { font-size: 1.42em; letter-spacing: .14em; margin-right: -.14em; }
  :lang(ja) .hb-banner--win .hb-banner__phase, :lang(ja) .hb-banner--lose .hb-banner__phase, :lang(ja) .hb-banner--draw .hb-banner__phase { letter-spacing: .1em; margin-right: -.1em; }
  /* the kinds: win = gold leaf, lose = a cold blue-black, draw = pale usuzumi, a trigger = its card colour's deep ink */
  .hb-banner--win { --plate-ink: #c8962f; --plate-rim: rgba(255,214,120,.5); --plate-word: #1b0f08; --plate-sheen: .75; }
  .hb-banner--win .hb-banner__phase { -webkit-text-stroke-color: #f1d48a; }
  body:not(.hb-perf) .hb-banner--win .hb-banner__phase { text-shadow: 0 .04em 0 rgba(255,244,214,.55); }
  .hb-banner--lose { --plate-ink: #0a1017; --plate-rim: rgba(126,166,206,.26); --plate-word: #e8eff7; }
  .hb-banner--draw { --plate-ink: #2b2723; --plate-rim: rgba(232,222,200,.2); --plate-word: #f4ede1; }
  .hb-banner--color { --plate-ink: var(--c-deep-2); --plate-rim: color-mix(in srgb, var(--c) 46%, transparent); --plate-word: var(--c-text); }
  /* phones: the plate fills the width and stands a little taller, so the words can be bigger (24 px on a 390 px phone,
     the old plate's 26 px less the room the brush needs; a long name, ラストオーバートリガー, shrinks to fit via --fit) */
  @media (max-width: 600px) {
    .hb-banner { aspect-ratio: 1600 / 420; }
    .hb-banner--sm { --plate-w: 100vw; aspect-ratio: 1200 / 300; }
    .hb-banner__txt, .hb-banner--sm .hb-banner__txt { font-size: calc(var(--plate-w) * .062); }
  }

  /* ------------------------------------------------------------------ the card landing (play / overbeat): HBFX.land adds
     .is-land to a card; it drops from above at -9°, overshoots, settles, and a gold ink ring ripples out */
  body:not(.hb-perf) .is-land { animation: hb-land var(--hb-dur-land) var(--hb-ease-stamp) both; }

  /* ------------------------------------------------------------------ THE BATTLE FLOURISHES (fx.js ink / slash / petals /
     words; the play lane's cues: the ram, a unit down / destroyed, a heart down / destroyed, OVER BEAT). After three
     frames of the official explainer video (reference/fx-*.webp): black sumi splats, one brush slash, brush lettering
     with a white glow, pink cherry blossoms and small rings. Every piece is an <i class="hb-fl" data-fl="kind"> in the
     fx layer: fixed, no pointer events, one animation, then removed. The art is raster (scripts/gen-ink.py ->
     ui/img/ink-*.webp, sakura.webp, obt-*.webp), used as PLAIN background images, never as a mask: a page opened from
     disk shows them too. Black ink would vanish on the night board's dark mats, so each blot stands on a pale smoke
     (lantern-lit paper; the reference has the same pale cloud behind its ink): a gradient here, not baked into the
     files (smooth, and the files stay small). Performance mode never makes them (the cue queue is off) and perf.css
     hides .hb-fl in case the mode is switched while one is on the screen. */
  .hb-fl { position: fixed; display: block; margin: 0; pointer-events: none; will-change: transform, opacity; }
  .hb-ink { background: center / contain no-repeat; }
  .hb-ink--burst { background-image: url("../img/ink-burst.webp"); }
  .hb-ink--blob { background-image: url("../img/ink-blob.webp"); }
  .hb-ink--splash { background-image: url("../img/ink-splash.webp"); }
  .hb-ink--heavy { background-image: url("../img/ink-heavy.webp"); }
  .hb-ink--drops { background-image: url("../img/ink-drops.webp"); }
  .hb-slash { background: url("../img/ink-slash.webp") center / 100% 100% no-repeat; }
  /* the smoke: its own piece, the same box and motion as its blot, at the BOTTOM of the layer (under every blot: one
     blot's smoke never greys another's ink) */
  .hb-smoke { background: radial-gradient(closest-side, rgba(255,243,226,.5), rgba(255,243,226,.24) 48%, rgba(255,243,226,0) 100%) center / 78% 78% no-repeat; }
  .hb-smoke--blob { background-size: 96% 96%; }
  .hb-smoke--splash { background-position: 34% 50%; background-size: 70% 70%; }
  .hb-smoke--heavy { background-size: 92% 92%; }
  .hb-smoke--drops { background-image: radial-gradient(closest-side, rgba(255,243,226,.24), rgba(255,243,226,0)); background-size: 96% 96%; }
  .hb-smoke--slash { background-image: radial-gradient(closest-side, rgba(255,243,226,.5), rgba(255,243,226,.22) 55%, rgba(255,243,226,0)); background-position: 42% 50%; background-size: 96% 170%; }
  .hb-petal { background: url("../img/sakura.webp") 0 0 / 500% 100% no-repeat; }
  .hb-petal[data-i="1"] { background-position: 25% 0; }
  .hb-petal[data-i="2"] { background-position: 50% 0; }
  .hb-petal[data-i="3"] { background-position: 75% 0; }
  .hb-petal[data-i="4"] { background-position: 100% 0; }
  .hb-ring { box-sizing: border-box; border: 2px solid #fff; border-radius: 50%; box-shadow: 0 0 0 1.5px rgba(58,38,44,.62), inset 0 0 0 1.5px rgba(58,38,44,.62); }
  /* OVER BEAT: the lettering (its tight white rim is in the art) on a wide soft glow; 日本語 has OVER BEAT spaced beneath */
  .hb-obt { display: grid; justify-items: center; }
  .hb-obt::before { content: ""; position: absolute; z-index: -1; inset: -30% -5% -42%; background: radial-gradient(closest-side, rgba(255,250,244,.56), rgba(255,246,236,.3) 50%, rgba(255,246,236,0) 100%); }
  .hb-obt__ink { display: block; width: 100%; height: 100%; background: url("../img/obt-ja.webp") center / 100% 100% no-repeat; }
  .hb-obt--en .hb-obt__ink { background-image: url("../img/obt-en.webp"); }
  .hb-obt__sub { position: absolute; left: 0; right: 0; top: 96%; margin-right: -.62em; text-align: center; white-space: nowrap; color: #332c2c;
    font: 800 calc(var(--obt-w) * .058)/1 var(--hb-font-headtext); letter-spacing: .62em;
    text-shadow: 0 0 2px #fff, 0 0 2px #fff, 0 0 3px #fff, 0 0 7px #fff, 0 0 14px rgba(255,255,255,.85); }
  /* the clash of a line's battle (play-fx.js ram: .hb-clash--ram): no lacquer box, the totals written large in the card
     numerals over one sumi stroke (the banner's small plate, tokens --hb-plate-sm*), the winner's the big one */
  .hb-clash--ram { --cs: clamp(30px, 4.3vw, 60px); gap: calc(var(--cs) * .2); padding: calc(var(--cs) * .16) calc(var(--cs) * .7) calc(var(--cs) * .16) calc(var(--cs) * .5);
    background: none; border: 0; border-radius: 0; box-shadow: none; }
  body:not(.hb-perf) .hb-clash--ram { box-shadow: none; }
  .hb-clash--ram::before, .hb-clash--ram::after { content: ""; position: absolute; z-index: -1; inset: -30% -9% -30% -7%; }
  .hb-clash--ram::before { background-color: rgba(255,243,226,.6); -webkit-mask: var(--hb-plate-sm-halo) center / 100% 100% no-repeat; mask: var(--hb-plate-sm-halo) center / 100% 100% no-repeat; }
  .hb-clash--ram::after { background-color: #0c0807; -webkit-mask: var(--hb-plate-sm) center / 100% 100% no-repeat; mask: var(--hb-plate-sm) center / 100% 100% no-repeat; }
  .hb-clash--ram > b { color: #fff; font: italic 900 calc(var(--cs) * .8)/1 var(--hb-font-pownum); -webkit-text-stroke: .13em #0c0807; paint-order: stroke fill; }
  .hb-clash--ram > b.is-win { color: #fff8e6; font-size: var(--cs); }
  .hb-clash--ram > b.is-lose { color: #a59c94; font-size: calc(var(--cs) * .56); }
  body:not(.hb-perf) .hb-clash--ram > b { text-shadow: 0 .05em 0 rgba(0,0,0,.55); }
  body:not(.hb-perf) .hb-clash--ram > b.is-win { text-shadow: 0 .05em 0 rgba(0,0,0,.55), 0 0 .5em rgba(255,206,120,.75); }
  body:not(.hb-perf) .hb-clash--ram > b.is-lose { text-shadow: none; }
  .hb-clash--ram > .hb-clash__vs { width: calc(var(--cs) * .56); height: calc(var(--cs) * .56); font-size: calc(var(--cs) * .3); }

  /* ------------------------------------------------------------------ keyframes */
  @keyframes hb-sheen { from { transform: translateX(-120%) skewX(-18deg); } to { transform: translateX(560%) skewX(-18deg); } }
  @keyframes hb-foil { from { transform: translateX(0); } to { transform: translateX(32px); } }
  @keyframes hb-float { from { transform: translateY(0) rotate(-4deg); } to { transform: translateY(-7px) rotate(4deg); } }
  @keyframes hb-bob { from { translate: 0 0; } to { translate: 0 -7px; } }
  @keyframes hb-sway-tail { from { transform: rotate(-4deg); } to { transform: rotate(4deg); } }
  @keyframes hb-sway { from { transform: rotate(-3.5deg); } to { transform: rotate(3.5deg); } }
  @keyframes hb-flicker { 0%, 100% { opacity: 1; } 8% { opacity: .82; } 11% { opacity: .97; } 37% { opacity: .9; } 41% { opacity: 1; } 63% { opacity: .78; } 66% { opacity: .95; } 88% { opacity: .88; } }
  @keyframes hb-neon { 0%, 100% { opacity: 1; } 71% { opacity: .35; } 72% { opacity: 1; } 74% { opacity: .5; } 75% { opacity: 1; } }
  @keyframes hb-drift { from { transform: translateX(0); } to { transform: translateX(-60px); } }
  @keyframes hb-breathe { from { opacity: .35; } to { opacity: 1; } }
  @keyframes hb-land { 0% { opacity: 0; transform: translateY(-90px) rotate(-9deg) scale(1.16); } 60% { opacity: 1; transform: translateY(3px) rotate(1.5deg) scale(.97); } 100% { opacity: 1; transform: none; } }
  @keyframes hb-shine-glow { from { transform: scale(.35); opacity: 1; } 55% { opacity: .9; } to { transform: scale(1.15); opacity: 0; } }
  @keyframes hb-shine-ring { from { transform: scale(.3); opacity: .95; } to { transform: scale(1.9); opacity: 0; } }
  @keyframes hb-shine-dama { from { transform: translateY(0) scale(.4); opacity: 1; } to { transform: translateY(-22px) scale(1); opacity: 0; } }
  @keyframes hb-shine-px { from { transform: translate(0, 0) scale(1); opacity: 1; } to { transform: translate(var(--dx), var(--dy)) scale(.6); opacity: 0; } }
}
