@font-face { font-family: "SA Hall"; font-style: normal; font-weight: 400; font-display: block; src: url("/assets/sa/hall-calligraphy.woff2") format("woff2"); }
/* 03 / 04 / 06 / 07 / 08 / 09 layered altar stage (web/scene-altar.js). Every selector is scoped to .sa-* or
   body.sa-page, which only the six themes render; templates 01 / 02 / 05 never match. Canvas: 390 × 740 units. */

body.sa-page { --sa-ink: #222a2e; --sa-slate: #1b2226; --sa-slate-2: #252e33; --sa-line: #3a464c; --sa-gold: #e2c48a; --sa-paper: #f6f3ee;
  background: var(--sa-slate); color: var(--sa-ink); }
body.sa-page .mode { display: none; }
body.sa-page main#app { max-width: 520px; padding: 0; margin: 0 auto; min-height: 0; }
@media (min-width: 701px) { body.sa-page main#app { max-width: 1440px; } }
body.sa-page footer { background: var(--sa-slate); color: #8d9a9c; border-top: 1px solid var(--sa-line); text-align: center; padding: 22px 16px 86px; font-size: 12px; }
body.sa-page footer a { color: #8d9a9c; }

/* ---------------------------------------------------------------- brand bar (collapsible; WeChat default collapsed) */
body.sa-page .top { position: relative; z-index: 40; height: 44px; min-height: 0; padding: 0 16px; display: flex; align-items: center; justify-content: center; box-sizing: border-box;
  background: linear-gradient(#20282c, #192024); border-bottom: 1px solid #323d42; box-shadow: 0 1px 0 rgba(226, 196, 138, .12) inset; }
body.sa-page .top .brand { display: flex; align-items: baseline; gap: 10px; font-family: "Memorial Serif", serif; font-size: 19px; letter-spacing: 6px; color: var(--sa-gold); line-height: 1; text-decoration: none; text-shadow: 0 1px 0 rgba(0, 0, 0, .5); margin: 0; }
body.sa-page .top .brand span { display: inline; margin: 0; font-size: 10.5px; letter-spacing: 3px; color: #a8a089; padding-left: 10px; border-left: 1px solid #4b585d; }
body.sa-page .top #nav, body.sa-page .top #identity { display: none; }
.sa-brand-toggle { display: none; }
html.sa-doc body.sa-page .top { overflow: visible; transition: height .32s cubic-bezier(.3, .7, .2, 1), border-bottom-width .32s step-end, box-shadow .32s; }
html.sa-doc body.sa-page .top .brand { transition: opacity .2s ease .1s, transform .32s cubic-bezier(.3, .7, .2, 1), visibility 0s; }
html.sa-doc.sa-brand-collapsed body.sa-page .top { height: 0; border-bottom-width: 0; box-shadow: none; transition: height .32s cubic-bezier(.3, .7, .2, 1), border-bottom-width .32s step-start, box-shadow .32s; }
html.sa-doc.sa-brand-collapsed body.sa-page .top .brand { opacity: 0; transform: translateY(-18px); visibility: hidden; pointer-events: none; transition: opacity .14s ease, transform .32s cubic-bezier(.3, .7, .2, 1), visibility 0s .32s; }
html.sa-doc body.sa-page .top .sa-brand-toggle { all: unset; box-sizing: border-box; position: absolute; z-index: 41; right: 4px; top: 100%; width: 44px; height: 44px; display: grid; place-items: center; cursor: pointer;
  -webkit-tap-highlight-color: transparent; transform: translateY(-44px); transition: transform .32s cubic-bezier(.3, .7, .2, 1); }
html.sa-doc.sa-brand-collapsed body.sa-page .top .sa-brand-toggle { transform: translateY(0); }
.sa-brand-toggle i { box-sizing: border-box; width: 34px; height: 22px; display: grid; place-items: center; border-radius: 11px; background: linear-gradient(#262f34, #1a2124); border: 1px solid rgba(214, 186, 130, .42);
  box-shadow: 0 1px 0 rgba(255, 236, 200, .08) inset, 0 2px 6px rgba(0, 0, 0, .3); transition: transform .32s cubic-bezier(.3, .7, .2, 1), border-radius .32s, background .32s; }
.sa-brand-toggle svg { width: 12px; height: 7px; fill: none; stroke: #d6b678; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; transition: transform .32s cubic-bezier(.3, .7, .2, 1); }
html.sa-doc.sa-brand-collapsed .sa-brand-toggle i { transform: translateY(-11px); height: 24px; border-radius: 0 0 11px 11px; border-top-width: 0; background: linear-gradient(rgba(26, 33, 36, .9), rgba(32, 40, 44, .82)); }
html.sa-doc.sa-brand-collapsed .sa-brand-toggle svg { transform: translateY(2px) rotate(180deg); }
.sa-brand-toggle:focus-visible i { box-shadow: 0 0 0 1.5px #e2c48a, 0 2px 6px rgba(0, 0, 0, .3); }
@media (min-width: 701px) { html.sa-doc body.sa-page .top .sa-brand-toggle { display: none; } }

/* ---------------------------------------------------------------- stage, frame, canvas */
.sa-sanctuary { position: relative; margin: 0; padding: 0; background: #1d2226; }
.sa-flame-defs { position: absolute; width: 0; height: 0; }
.sa-stage { position: relative; width: 100%; height: 684px; overflow: hidden; --k: 1; --ox: 0px; background: #1d2226; }
.sa-stage::before { content: ""; position: absolute; inset: -20px; pointer-events: none; z-index: 0;
  background: var(--sa-far-m) 50% 0 / 100% auto no-repeat, #1d2226; filter: blur(16px) brightness(.6); }
/* Preview geometry is a scaled mobile stage, independent of the family viewport. */
.sa-family-preview { width: 100%; pointer-events: none; overflow: hidden; }
.hall-summary > .sa-family-preview { width: 132px; flex: 0 0 132px; }
.sa-family-preview .sa-stage { min-height: 0; border: 0; border-radius: 0; }
.sa-frame { position: absolute; left: 0; top: 0; width: 390px; height: 740px; transform-origin: 0 0; transform: translateX(var(--ox)) scale(var(--k)); z-index: 1; }
.sa-canvas { position: absolute; left: 0; top: 0; width: 390px; height: 740px; }
.sa-canvas img, .sa-far-d img { display: block; -webkit-user-drag: none; user-select: none; max-width: none; }
.sa-far-d { display: none; }
.sa-far, .sa-near { position: absolute; inset: 0; pointer-events: none; }
.sa-far img { position: absolute; left: 0; top: 0; width: 390px; height: 740px; }
.sa-near img { position: absolute; }
.sa-far { z-index: 0; } .sa-near { z-index: 3; }
.sa-near-lit { position: absolute; z-index: 4; pointer-events: none; opacity: 0; transition: opacity 1.4s ease .3s; }
.sa-stage.has-annual .sa-near-lit { opacity: 1; }
/* desktop: a 1200 × 600 unit window of the wide environment; the altar canvas sits at u 0 (frame x 405), v −60 */
.sa-stage.sa-desk .sa-frame { width: 1200px; height: 600px; }
.sa-stage.sa-desk .sa-far-d { display: block; position: absolute; inset: 0; z-index: 0; }
.sa-stage.sa-desk .sa-far-d img { width: 1200px; height: 600px; }
.sa-stage.sa-desk .sa-canvas { left: 405px; top: -60px; }
.sa-stage.sa-desk .sa-far { display: none; }
.sa-stage.sa-desk::before { display: none; }

.sa-air { position: absolute; inset: 0; z-index: 2; pointer-events: none; }

/* ---------------------------------------------------------------- identity on the stele / tablet panel */
.sa-identity { position: absolute; z-index: 6; display: flex; flex-direction: column; align-items: center; box-sizing: border-box; padding-top: 7px; }
.sa-photo-frame { position: relative; flex: none; width: 88px; height: 117.33px; padding: 2.6px; box-sizing: border-box;
  background: linear-gradient(160deg, #e9d2a0, #a8813f 45%, #dcbb7a 70%, #8a6430);
  box-shadow: 0 0 0 .6px rgba(20, 12, 4, .8), 0 3px 8px rgba(0, 0, 0, .55); }
.sa-photo-frame::after { content: ""; position: absolute; inset: 2.6px; box-shadow: 0 0 0 .5px rgba(40, 24, 8, .7) inset, 0 0 8px rgba(0, 0, 0, .28) inset; pointer-events: none; }
.sa-photo { display: block; width: 100%; height: 100%; object-fit: cover; object-position: 50% 22%; filter: saturate(.9) contrast(1.02); }
.sa-photo.portrait-wide { object-position: 50% 30%; }
.sa-photo-empty { display: grid; place-items: center; color: #e8d3a0; font-family: "Memorial Serif", serif; font-size: 30px; background: #2b2a28; }
.sa-inscription { width: 100%; text-align: center; margin-top: 7px; }
.sa-inscription h1 { margin: 0; font-family: "Memorial Serif", serif; font-weight: 500; font-size: 17px; line-height: 21px; letter-spacing: 5px; padding-left: 5px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; color: var(--sa-name, #ecd6a4); text-shadow: 0 1px 1px rgba(0, 0, 0, .65); }
.sa-dates { margin: 3px 0 0; display: flex; flex-direction: column; align-items: center; gap: 0; font-family: "Memorial Serif", serif; font-size: 10.5px; line-height: 13px; letter-spacing: .8px;
  color: var(--sa-dates, #d2bd93); text-shadow: 0 1px 1px rgba(0, 0, 0, .6); }
.sa-dates i { display: block; width: 18px; height: 1px; margin: 3px 0 3px; background: currentColor; opacity: .5; font-size: 0; line-height: 0; overflow: hidden; }
.sa-portrait-row { display: flex; align-items: center; justify-content: center; gap: 4px; }
.sa-fixed-col { margin: 0; width: 14px; display: flex; flex-direction: column; align-items: center; gap: 2px; font-family: "Memorial Serif", serif; font-size: 11.5px; line-height: 13px; color: var(--sa-fixed, #d8c296); text-shadow: 0 1px 1px rgba(0, 0, 0, .6); }
.sa-fixed-col span { display: block; }
.sa-fixed { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; margin: 0; font-family: "Memorial Serif", serif; font-size: 11px; line-height: 14px; letter-spacing: 2px; padding-left: 2px; white-space: nowrap;
  color: var(--sa-fixed, #d8c296); text-shadow: 0 1px 1px rgba(0, 0, 0, .6); }

/* ---------------------------------------------------------------- lettering (plaque, couplets, stele head) */
.sa-boards { position: absolute; inset: 0; z-index: 6; pointer-events: none; }
.sa-boards p { margin: 0; display: flex; font-family: "SA Hall", "Memorial Serif", serif; line-height: 1; }
.sa-boards span { display: block; color: transparent; -webkit-background-clip: text; background-clip: text;
  background-image: var(--sa-letter, linear-gradient(176deg, #fff1c8 0%, #e9c983 30%, #c8994e 58%, #f2d697 76%, #a9783a 100%));
  filter: drop-shadow(0 .7px 0 rgba(20, 8, 2, .95)) drop-shadow(0 0 2.5px rgba(255, 190, 110, .16)); }
.sa-plaque, .sa-couplet { position: absolute; display: grid; place-items: center; }
.sa-couplet p { flex-direction: column; align-items: center; }
.sa-engrave span { background-image: none; color: var(--sa-engrave, #3c4044); filter: drop-shadow(0 .8px 0 rgba(255, 255, 255, .28)) drop-shadow(0 -.5px 0 rgba(0, 0, 0, .45)); }

/* ---------------------------------------------------------------- warmth of candles / lamps, grade, vignette */
.sa-warm { position: absolute; inset: 0; z-index: 8; pointer-events: none; mix-blend-mode: soft-light; opacity: 0; transition: opacity 1.6s ease var(--candle-delay, 0s);
  background: radial-gradient(150px 120px at var(--cl, 113px) 360px, var(--warm), transparent 70%), radial-gradient(150px 120px at var(--cr, 277px) 360px, var(--warm), transparent 70%); }
.sa-stage.has-candle .sa-warm { opacity: .85; }
.sa-grade { position: absolute; inset: 0; z-index: 14; pointer-events: none; }
.sa-vignette { position: absolute; inset: 0; z-index: 15; pointer-events: none;
  background: radial-gradient(130% 92% at 50% 44%, transparent 62%, rgba(10, 12, 18, .30) 100%), linear-gradient(transparent 86%, rgba(12, 14, 18, .2)); }
.sa-stage.sa-desk .sa-vignette, .sa-stage.sa-desk .sa-grade { display: none; }
.sa-stage.sa-desk .sa-frame::after { content: ""; position: absolute; inset: 0; z-index: 16; pointer-events: none;
  background: radial-gradient(70% 90% at 50% 46%, transparent 55%, rgba(8, 10, 14, .42) 100%); }

/* ---------------------------------------------------------------- censer + offerings */
.sa-censer { position: absolute; z-index: 10; pointer-events: none; }
.sa-censer > img, .sa-item > img { display: block; width: 100%; height: 100%; }
.ritual-effects { position: absolute; inset: 0; pointer-events: none; z-index: 7; }
.sa-offerings { position: absolute; inset: 0; }
.sa-item { position: absolute; }
.sa-cast, .sa-bouquet { position: absolute; max-width: none; pointer-events: none; }
.sa-bouquet { filter: var(--sa-bouquet, none); }
.sa-flowers { z-index: 7; pointer-events: none; }
.sa-candle { z-index: 9; }
.sa-lamp { z-index: 11; }
.sa-fruit { z-index: 12; }

/* incense: three sticks in the ash at the censer mouth; length follows the 24 h burn */
.sa-incense { z-index: 12; width: 40px; height: 60px; clip-path: inset(-80px -24px 0 -24px); --full: var(--sa-stick, 46px); --handle: .3; --burn: 1;
  --len: calc(var(--full) * (var(--handle) + (1 - var(--handle)) * var(--burn))); }
.sa-ash { position: absolute; left: 3px; bottom: -.6px; width: 34px; height: 4.4px; border-radius: 50%;
  background: radial-gradient(closest-side, #a59e95, #847d75 60%, rgba(90, 86, 80, .6) 85%, transparent); }
.sa-stick { position: absolute; bottom: .9px; left: 19.2px; width: 1.7px; height: var(--len); transform-origin: 50% 100%; border-radius: .8px .8px 0 0;
  background:
    linear-gradient(90deg, rgba(0, 0, 0, .55), rgba(0, 0, 0, 0) 30%, rgba(255, 220, 190, .32) 45%, rgba(0, 0, 0, 0) 60%, rgba(0, 0, 0, .6)),
    linear-gradient(to top, #7a160c 0, #b02a18 calc(var(--full) * var(--handle) - 1px), #6a2412 calc(var(--full) * var(--handle)), #8a3418 55%, #6c2814); }
.sa-stick.s1 { transform: translateX(-4.6px) rotate(-5deg); height: calc(var(--len) * .92); }
.sa-stick.s2 { transform: rotate(.6deg); }
.sa-stick.s3 { transform: translateX(4.8px) rotate(4.4deg); height: calc(var(--len) * .88); }
.sa-ember { position: absolute; left: -.1px; right: -.1px; top: -2.4px; height: 3.5px; border-radius: 1px 1px .3px .3px;
  background: linear-gradient(to top, #ff7a24 0, #ffb04a .9px, #d65a22 1.4px, #8c8178 1.8px, #b5aca2 3px, #9b9288 100%);
  box-shadow: 0 1.4px 1.6px -.2px rgba(255, 110, 30, .75); animation: sa-ember 2.2s ease-in-out infinite; }
.sa-stick.s1 .sa-ember { animation-duration: 2.7s; } .sa-stick.s3 .sa-ember { animation-duration: 1.9s; }
@keyframes sa-ember { 0%, 100% { filter: brightness(1); } 50% { filter: brightness(1.25); } }
/* Filmed smoke is behind the independent portrait/glyph layer (z=6), above
   the scene (z=3/4). Keep the root/texture intact instead of cutting at text. */
.sa-smoke { position: absolute; inset: 0; z-index: 5; pointer-events: none; opacity: 0; }
.sa-stage.has-incense .sa-smoke { animation: sa-smoke-in 2.4s ease var(--smoke-delay, 0s) both; }
@keyframes sa-smoke-in { from { opacity: 0; } to { opacity: 1; } }
.sa-smoke canvas { filter: blur(.8px); }

.sa-flame-wrap { position: absolute; width: 7px; height: 17.5px; margin: -16.8px 0 0 -3.5px; transform-origin: 50% 96%; }
.sa-flame-wrap::before { content: ""; position: absolute; left: 50%; top: 58%; width: 32px; height: 36px; margin: -18px 0 0 -16px; border-radius: 50%; pointer-events: none;
  background: radial-gradient(closest-side, rgba(255, 214, 140, .45), rgba(255, 170, 90, .12) 55%, transparent); mix-blend-mode: screen; }
.sa-flame { position: absolute; left: 0; top: 0; width: 100%; height: 100%; overflow: visible; transform-origin: 50% 94%; animation: sa-flicker 2.6s ease-in-out infinite; }
.sa-candle-right .sa-flame { animation-duration: 3.1s; animation-delay: -1.2s; }
.sa-candle-light { position: absolute; width: 112px; height: 112px; margin: -56px 0 0 -56px; border-radius: 50%; pointer-events: none;
  background: radial-gradient(closest-side, rgba(255, 190, 110, .28), rgba(255, 160, 80, .08) 50%, transparent 100%); mix-blend-mode: screen; animation: sa-glow 3.4s ease-in-out infinite; }
.sa-lamp-light { position: absolute; width: 64px; height: 64px; margin: -32px 0 0 -32px; border-radius: 50%; pointer-events: none; mix-blend-mode: screen;
  background: radial-gradient(closest-side, rgba(255, 196, 120, .42), rgba(255, 170, 90, .12) 55%, transparent); animation: sa-glow 3s ease-in-out infinite; }
.sa-lamp-right .sa-lamp-light { animation-duration: 3.4s; animation-delay: -1s; }
.sa-annual-on { position: absolute; inset: 0; pointer-events: none; }
@keyframes sa-flicker {
  0%, 100% { transform: scale(1, 1) skewX(0deg); opacity: .97; } 18% { transform: scale(.95, 1.07) skewX(-2.4deg); opacity: 1; }
  33% { transform: scale(1.03, .95) skewX(1.4deg); opacity: .93; } 52% { transform: scale(.96, 1.09) skewX(2.6deg); opacity: 1; }
  71% { transform: scale(1.01, .97) skewX(-1.2deg); opacity: .95; } 86% { transform: scale(.99, 1.03) skewX(.7deg); opacity: .98; } }
@keyframes sa-glow { 0%, 100% { opacity: .88; } 40% { opacity: 1; } 65% { opacity: .8; } }

/* ---------------------------------------------------------------- entrances (once; renewals stay settled) */
.sa-incense .sa-stick { animation: sa-enter-insert 1s calc(var(--d, 0s) + var(--i, 0s)) cubic-bezier(.25, .8, .3, 1) both; }
.sa-stick.s1 { --i: .12s; } .sa-stick.s3 { --i: .24s; }
.sa-incense .sa-ash { animation: sa-enter-fade .5s var(--d, 0s) ease-out both; }
.sa-incense .sa-ember { animation: sa-enter-ember .8s calc(var(--d, 0s) + .95s + var(--i, 0s)) ease-out both, sa-ember 2.2s calc(var(--d, 0s) + 2s) ease-in-out infinite; }
.sa-candle { animation: sa-enter-rise .9s var(--d, 0s) cubic-bezier(.2, .7, .2, 1) both; }
.sa-candle-right { --j: .18s; animation-delay: calc(var(--d, 0s) + .18s); }
.sa-candle .sa-flame-wrap { animation: sa-enter-ignite .8s calc(var(--d, 0s) + var(--j, 0s) + .75s) cubic-bezier(.3, 1.4, .5, 1) both; }
.sa-candle .sa-candle-light { animation: sa-enter-glow 1.2s calc(var(--d, 0s) + var(--j, 0s) + .8s) ease-out both, sa-glow 3.4s calc(var(--d, 0s) + 2.2s) ease-in-out infinite; }
.sa-lamp { animation: sa-enter-rise .8s var(--d, 0s) cubic-bezier(.2, .7, .2, 1) both; }
.sa-lamp .sa-lamp-light { animation: sa-enter-glow 1s calc(var(--d, 0s) + .6s) ease-out both, sa-glow 3s calc(var(--d, 0s) + 1.6s) ease-in-out infinite; }
.sa-flowers { animation: sa-enter-flowers 1.1s var(--d, 0s) cubic-bezier(.2, .7, .2, 1) both; }
.sa-flowers-right { animation-delay: calc(var(--d, 0s) + .16s); }
.sa-fruit { animation: sa-enter-fruit 1s var(--d, 0s) cubic-bezier(.2, .8, .25, 1) both; }
.sa-fruit-right { animation-delay: calc(var(--d, 0s) + .16s); }
.is-settled, .is-settled .sa-stick, .is-settled .sa-ash, .is-settled .sa-flame-wrap { animation: none !important; }
.is-settled .sa-ember { animation: sa-ember 2.2s ease-in-out infinite !important; }
.is-settled .sa-candle-light { animation: sa-glow 3.4s ease-in-out infinite !important; }
.is-settled .sa-lamp-light { animation: sa-glow 3s ease-in-out infinite !important; }
@keyframes sa-enter-insert { 0% { opacity: 0; translate: 0 -20px; } 35% { opacity: 1; } 100% { opacity: 1; translate: 0 0; } }
@keyframes sa-enter-ember { 0% { opacity: 0; filter: brightness(.4); } 100% { opacity: 1; filter: brightness(1); } }
@keyframes sa-enter-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes sa-enter-rise { from { opacity: 0; translate: 0 5px; } to { opacity: 1; translate: 0 0; } }
@keyframes sa-enter-ignite { 0% { opacity: 0; transform: scale(.15, .1); } 100% { opacity: 1; transform: none; } }
@keyframes sa-enter-glow { from { opacity: 0; } to { opacity: .9; } }
@keyframes sa-enter-flowers { 0% { opacity: 0; translate: 0 -5px; } 30% { opacity: 1; } 100% { opacity: 1; translate: 0 0; } }
@keyframes sa-enter-fruit { 0% { opacity: 0; translate: 0 -6px; } 28% { opacity: 1; } 100% { opacity: 1; translate: 0 0; } }

/* ---------------------------------------------------------------- right rail: 上香 点烛 献花 供果, 年 at the bottom */
.sa-rail { position: absolute; z-index: 20; right: 0; top: calc(var(--rail-top, 96px) * var(--k)); width: 50px; padding: 5px 0 6px 2px; box-sizing: border-box;
  display: flex; flex-direction: column; gap: 2px; align-items: center;
  background: linear-gradient(90deg, rgba(16, 20, 24, .46), rgba(16, 20, 24, .7)); border: 1px solid rgba(222, 192, 134, .42); border-right: 0; border-radius: 24px 0 0 24px;
  box-shadow: -3px 4px 14px rgba(0, 0, 0, .32), 0 1px 0 rgba(255, 236, 200, .1) inset; -webkit-backdrop-filter: blur(6px) saturate(1.1); backdrop-filter: blur(6px) saturate(1.1); }
.sa-rail button { all: unset; box-sizing: border-box; width: 48px; min-height: 50px; display: flex; flex-direction: column; align-items: center; gap: 1px; cursor: pointer; padding: 1px 0; border-radius: 9px; -webkit-tap-highlight-color: transparent; }
.sa-rail-pic { width: 36px; height: 36px; border-radius: 50%; display: grid; place-items: center; overflow: hidden;
  background: radial-gradient(85% 80% at 50% 30%, #4e5b5f, #20282c 75%); box-shadow: 0 0 0 1px rgba(232, 202, 142, .78) inset, 0 0 0 2.5px rgba(20, 24, 28, .55), 0 2px 4px rgba(0, 0, 0, .35); }
.sa-rail-pic img { width: 34px; height: 34px; }
.sa-rail-pic b { font-family: "Memorial Serif", serif; font-weight: 500; font-size: 19px; line-height: 1; color: transparent; padding-top: 1px;
  background: linear-gradient(176deg, #fff3cf, #ecd08f 45%, #c9994f 80%); -webkit-background-clip: text; background-clip: text; filter: drop-shadow(0 1px 0 rgba(0, 0, 0, .6)); }
.sa-rail-year { margin-top: 3px; padding-top: 4px !important; border-top: 1px solid rgba(222, 192, 134, .28) !important; border-radius: 0 0 9px 9px !important; }
.sa-rail-year .sa-rail-pic { background: radial-gradient(85% 80% at 50% 30%, #5a3f2a, #2a1c14 75%); }
.sa-rail-label { font-family: "Memorial Serif", serif; font-size: 11px; line-height: 12px; letter-spacing: 1px; color: #efdfb8; padding-left: 1px; text-shadow: 0 1px 1px rgba(0, 0, 0, .6); }
.sa-rail button:active .sa-rail-pic, .sa-rail button:focus-visible .sa-rail-pic { box-shadow: 0 0 0 1.5px #e2c48a inset, 0 0 0 3px rgba(226, 196, 138, .2); }
.sa-rail button.is-on .sa-rail-label::after { content: ""; display: inline-block; width: 4px; height: 4px; border-radius: 50%; background: #f0b062; margin-left: 2px; vertical-align: 2px; box-shadow: 0 0 4px rgba(255, 160, 70, .9); }
.sa-stage.sa-desk .sa-rail { right: max(0px, calc((100% - 1200px * var(--k)) / 2)); top: 50%; transform: translateY(-50%); }

/* ---------------------------------------------------------------- one-click sweep (on the altar front) */
.sa-sweep { all: unset; box-sizing: border-box; position: absolute; z-index: 20; left: 195px; top: var(--sweep-top, 548px); transform: translateX(-50%);
  width: 168px; height: 46px; border-radius: 23px; cursor: pointer; text-align: center; padding-left: 24px;
  display: flex; flex-direction: column; justify-content: center; align-items: center; gap: 1px;
  background: radial-gradient(120% 140% at 50% 0%, rgba(70, 58, 40, .84), rgba(26, 24, 22, .9) 70%); color: #f3e4c2;
  box-shadow: 0 0 0 1px rgba(236, 204, 140, .9) inset, 0 0 0 3.5px rgba(18, 16, 14, .45), 0 0 14px rgba(255, 196, 120, .26), 0 6px 14px rgba(0, 0, 0, .4);
  -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px); -webkit-tap-highlight-color: transparent; }
.sa-sweep::before { content: ""; position: absolute; inset: 3.5px; border-radius: 20px; border: .6px solid rgba(236, 204, 140, .38); pointer-events: none; }
.sa-sweep-mark { position: absolute; left: 13px; top: 50%; width: 24px; height: 24px; margin-top: -12px; border-radius: 50%;
  background: radial-gradient(circle at 50% 38%, #f8e3ae, #c99c54 60%, #8c6630); box-shadow: 0 0 0 1px rgba(20, 16, 10, .5), 0 0 9px rgba(255, 190, 110, .45); }
.sa-sweep-mark::before, .sa-sweep-mark::after { content: ""; position: absolute; left: 50%; bottom: 6px; width: 1.4px; height: 10px; margin-left: -.7px; background: #4a2a14; border-radius: 1px; box-shadow: -3.6px 1px 0 #4a2a14, 3.6px 1px 0 #4a2a14; }
.sa-sweep-mark::after { bottom: 16px; height: 2px; background: #ff9a40; box-shadow: -3.6px 1px 0 #ff9a40, 3.6px 1px 0 #ff9a40, 0 0 3px #ffb060; }
.sa-sweep b { font-family: "Memorial Serif", serif; font-weight: 500; font-size: 16px; line-height: 20px; letter-spacing: 5px; padding-left: 5px;
  color: transparent; background: linear-gradient(176deg, #fff3cf, #ecd08f 45%, #c9994f 80%); -webkit-background-clip: text; background-clip: text; filter: drop-shadow(0 1px 0 rgba(0, 0, 0, .6)); }
.sa-sweep small { font-size: 9.5px; line-height: 12px; letter-spacing: 1px; color: #d6c093; }
.sa-sweep:active { filter: brightness(1.12); }
.sa-sweep[disabled] { opacity: .82; cursor: default; }
.sa-sweep-progress { position: absolute; z-index: 21; left: 195px; top: calc(var(--sweep-top, 548px) - 40px); transform: translateX(-50%); display: flex; align-items: center; gap: 6px;
  padding: 6px 13px; border-radius: 16px; background: rgba(22, 28, 32, .88); box-shadow: 0 0 0 1px rgba(226, 196, 138, .4) inset, 0 4px 12px rgba(0, 0, 0, .3);
  font-family: "Memorial Serif", serif; font-size: 12px; color: #9aa3a3; white-space: nowrap; -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px); }
.sa-sweep-progress[hidden] { display: none; }
.sa-sweep-progress i { font-style: normal; color: #59656a; }
.sa-sweep-progress span { transition: color .35s; }
.sa-sweep-progress span.now { color: #ffcf8a; text-shadow: 0 0 6px rgba(255, 160, 70, .55); }
.sa-sweep-progress span.done { color: #eadcbc; }
.sa-sweep-progress.is-done { padding: 7px 14px 7px 10px; color: #f3e4c2; animation: sa-done-in .45s cubic-bezier(.2, .8, .3, 1) both; }
.sa-sweep-progress.is-done b { width: 14px; height: 14px; border-radius: 50%; background: #b38a4a; position: relative; flex: none; }
.sa-sweep-progress.is-done b::after { content: ""; position: absolute; left: 4.6px; top: 2.6px; width: 3.4px; height: 6.4px; border: solid #fff6de; border-width: 0 1.5px 1.5px 0; transform: rotate(42deg); }
.sa-sweep-progress.is-done span { color: #f3e4c2; }
.sa-sweep-progress.is-leaving { opacity: 0; transition: opacity .6s ease; }
@keyframes sa-done-in { from { opacity: 0; translate: 0 4px; } to { opacity: 1; translate: 0 0; } }

/* ---------------------------------------------------------------- tool bar: 祈福 全年供奉 音乐 鞭炮 扫墓 分享 */
.sa-tools { display: grid; grid-template-columns: repeat(6, 1fr); height: 58px; align-items: center; padding: 0 4px; margin: 0;
  background: linear-gradient(#232c31, #1b2226); border-top: 1px solid #39464c; border-bottom: 1px solid #2c363b; }
.sa-tools button { all: unset; box-sizing: border-box; display: flex; flex-direction: column; align-items: center; gap: 3px; cursor: pointer; padding: 6px 0; min-height: 48px; justify-content: center; color: #e3dccb; -webkit-tap-highlight-color: transparent; }
.sa-tools button svg { width: 22px; height: 22px; stroke: #d6b678; fill: none; stroke-width: 1.4; stroke-linecap: round; stroke-linejoin: round; }
.sa-tools button span { font-size: 11px; line-height: 14px; letter-spacing: .5px; white-space: nowrap; }
.sa-tools button[aria-pressed="true"] svg { stroke: #ffc070; }
/* Support stays outside the offering rail, tool grid and nine-item navigation. */
.sa-visit .v03-intro > .support-entry { min-width: 64px; min-height: 44px; margin-top: 8px; }
.sa-visit .v03-intro > .support-entry[hidden] { display: none; }
@media (min-width: 701px) { .sa-tools { max-width: 720px; margin: 0 auto; border: 0; background: transparent; } }

/* ---------------------------------------------------------------- reading area & bottom nav (nine items, business order) */
.sa-visit > .card, .sa-visit > .tab-panel, .sa-visit > .notice { margin: 0; border-radius: 0; background: var(--sa-paper); color: var(--sa-ink); border: 0; border-bottom: 1px solid #e3ded5; padding: 18px 20px; box-shadow: none; }
.sa-visit > .card h2, .sa-visit > .tab-panel h2 { font-family: "Memorial Serif", serif; font-weight: 500; color: #2b3438; font-size: 17px; letter-spacing: 2px; }
.sa-visit .entitlement, .sa-visit .audio-note { font-size: 12px; color: #5d6a6e; line-height: 1.8; }
.sa-visit > .notice { font-size: 12px; color: #7a8487; background: #ece8e1; }
body.sa-page #visit-panel.public-surface { background: var(--sa-paper); }
.sa-visit .visit-bottom-nav { position: sticky; bottom: 0; z-index: 30; height: 58px; background: rgba(27, 34, 38, .97); border-top: 1px solid #39464c; box-shadow: 0 -4px 14px rgba(0, 0, 0, .25); -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px); }
.sa-visit .visit-content-tabs { display: flex; height: 58px; align-items: stretch; overflow-x: auto; scrollbar-width: none; padding: 0 6px;
  -webkit-mask-image: linear-gradient(90deg, #000 calc(100% - 34px), transparent); mask-image: linear-gradient(90deg, #000 calc(100% - 34px), transparent); }
.sa-visit .visit-content-tabs::-webkit-scrollbar { display: none; }
.sa-visit .visit-content-tabs > :is(button, a) { all: unset; flex: 0 0 auto; display: flex; align-items: center; padding: 0 12px; font-size: 13.5px; color: #a7b0b0; white-space: nowrap; position: relative; cursor: pointer; min-height: 44px; }
.sa-visit .visit-content-tabs > button[aria-selected="true"] { color: #f2e6c8; font-weight: 600; }
.sa-visit .visit-content-tabs > button[aria-selected="true"]::after { content: ""; position: absolute; left: 50%; bottom: 10px; width: 20px; height: 2px; margin-left: -10px; background: #d6b678; border-radius: 1px; }
@media (min-width: 701px) { .sa-visit .visit-content-tabs { justify-content: center; -webkit-mask-image: none; mask-image: none; } }

/* ---------------------------------------------------------------- dialogs */
body.sa-page dialog { background: var(--sa-paper); color: var(--sa-ink); border: 1px solid #cfc6b6; border-radius: 14px; box-shadow: 0 18px 40px rgba(10, 14, 18, .4); }
body.sa-page dialog::backdrop { background: rgba(14, 18, 22, .55); }
.sa-offer-preview { display: flex; gap: 12px; align-items: center; margin: 4px 0 12px; }
.sa-offer-preview img, .sa-sweep-grid img { background: radial-gradient(90% 85% at 50% 32%, #4b5a5f, #262f33); box-shadow: 0 0 0 1px rgba(214, 186, 130, .5) inset; }
.sa-offer-preview img { width: 64px; height: 64px; border-radius: 12px; }
.sa-sweep-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; margin: 6px 0 12px; }
.sa-sweep-grid figure { margin: 0; text-align: center; font-size: 12px; color: #2f3a3e; font-family: "Memorial Serif", serif; }
.sa-sweep-grid img { width: 100%; aspect-ratio: 1; border-radius: 10px; margin-bottom: 4px; }
.sa-sweep-grid figcaption small { display: block; font-size: 10px; color: #7a8487; }
.sa-sweep-total { display: flex; justify-content: space-between; font-size: 13px; color: #3a4448; border-top: 1px solid #e0d9cd; padding-top: 8px; margin: 2px 0 10px; }
.sa-note { font-size: 11.5px !important; color: #6b7679 !important; background: #ebe7df; border-radius: 8px; padding: 8px 10px; }
body.sa-page #toast { z-index: 60; bottom: calc(58px + 58px + 16px + env(safe-area-inset-bottom, 0px)); max-width: min(320px, calc(100vw - 40px)); box-sizing: border-box;
  padding: 11px 18px; text-align: center; line-height: 1.5; white-space: normal; background: rgba(27, 34, 38, .95); color: #f1e6cc; border-radius: 18px; font-size: 13px; }
.sa-sanctuary.firecracker-effect .sa-frame { animation: sa-shake .2s linear 6; }
@keyframes sa-shake { 50% { translate: .6px 0; } }
@media (prefers-reduced-motion: reduce) {
  .sa-flame, .sa-candle-light, .sa-lamp-light, .sa-ember { animation: none !important; }
}

/* ---------------------------------------------------------------- isolation from the shared (01/02/05) layers
   The stage keeps .shrine-stage / .ritual-effects / .memorial-photo-* for the shared smoke protection and the entitlement
   refresh; their legacy geometry is neutralised here with higher specificity, only inside .sa-visit. */
html body .visit.sa-visit { max-width: none; margin: 0; padding: 0; }
html body .sa-visit .sa-stage.shrine-stage { aspect-ratio: auto; min-height: 0; max-width: none; border: 0; border-radius: 0; box-shadow: none; margin: 0; padding: 0; isolation: isolate; color: inherit; }
html body .sa-visit .sa-stage .ritual-effects { position: absolute; inset: 0; z-index: 7; pointer-events: none; }
html body .sa-visit .sa-stage .ritual-effects .ritual-scene.sa-offerings { position: absolute; inset: 0; top: 0; left: 0; right: auto; width: 390px; height: 740px; }
html body .sa-visit .sa-stage .sa-identity .memorial-photo-frame { position: relative; left: auto; top: auto; transform: none; margin: 0; width: 88px; height: 117.33px; padding: 2.6px; border: 0; border-radius: 0;
  background: linear-gradient(160deg, #e9d2a0, #a8813f 45%, #dcbb7a 70%, #8a6430); box-shadow: 0 0 0 .6px rgba(20, 12, 4, .8), 0 3px 8px rgba(0, 0, 0, .55); }
html body .sa-visit .sa-stage .sa-identity .memorial-photo-frame::after { inset: 2.6px; border: 0; box-shadow: 0 0 0 .5px rgba(40, 24, 8, .7) inset, 0 0 8px rgba(0, 0, 0, .28) inset; }
html body .sa-visit .sa-stage .sa-identity .memorial-photo-frame .sa-photo { border: 0; outline: 0; aspect-ratio: auto; background: #383630; object-fit: cover; }
html body .sa-visit .sa-stage .sa-identity .memorial-photo-inscription { position: static; left: auto; top: auto; transform: none; width: 100%; min-height: 0; height: auto; max-height: none; padding: 0; gap: 0; background: none; border: 0; box-shadow: none; border-radius: 0; overflow: visible; color: inherit; }
html body .sa-visit .sa-stage .sa-identity .memorial-photo-inscription::before { content: none; }
html body .sa-visit .sa-stage .sa-identity .sa-inscription h1 { font-family: "Memorial Serif", serif; font-weight: 500; font-size: 17px; line-height: 21px; letter-spacing: 5px; padding-left: 5px; margin: 0; overflow-wrap: normal; color: var(--sa-name, #ecd6a4); }
html body .sa-visit .sa-stage .sa-identity .sa-dates { display: flex; flex-direction: column; flex-wrap: nowrap; gap: 0; margin: 3px 0 0; font: 400 10.5px/13px "Memorial Serif", serif; letter-spacing: .8px; color: var(--sa-dates, #d2bd93); }

html body .sa-visit .sa-tools { position: static; inset: auto; }
html body .sa-visit .sa-tools button { min-height: 48px; background: none; border: 0; box-shadow: none; font-size: inherit; padding: 6px 0; }
html body .sa-visit .sa-rail button { position: static; max-width: none; height: auto; background: none; border: 0; box-shadow: none; }
html body .sa-visit .visit-bottom-nav { left: auto; right: auto; width: auto; }

html body .sa-visit .sa-stage .sa-identity .sa-portrait-row { flex-direction: row; align-items: center; justify-content: center; gap: 4px; width: auto; }

/* ================================================================ per theme */
/* 03 月洞清晖 — moonlit granite */
.sa-t03 { --sa-name: #efe1bd; --sa-dates: #cfc3a6; --sa-fixed: #d9c9a2; --rail-top: 66px; --sweep-top: 548px; --sa-stick: 44px; --sa-bouquet: brightness(.74) saturate(.8) hue-rotate(-6deg); }
.sa-t03 .sa-grade { mix-blend-mode: soft-light; background:
  radial-gradient(260px 220px at 250px 96px, rgba(190, 210, 255, .22), transparent 70%),
  linear-gradient(transparent 70%, rgba(20, 30, 60, .25)); }
.sa-t03.sa-stage::before { background-color: #121828; }

/* 04 竹影书堂 — walnut study hall in the bamboo grove */
.sa-t04 { --sa-name: #f0dcae; --sa-dates: #dcc69a; --sa-fixed: #e2cc9c; --rail-top: 66px; --sweep-top: 548px; --sa-stick: 44px; --sa-bouquet: brightness(.98) saturate(.95) sepia(.06); }
.sa-t04 .sa-photo-frame, html body .sa-visit .sa-t04 .sa-identity .memorial-photo-frame { width: 86px; height: 114.67px; }
.sa-t04 .sa-plaque { left: 143px; top: 74px; width: 104px; height: 46px; }
.sa-t04 .sa-plaque p { gap: 10px; font-size: 30px; padding-top: 2px; }
.sa-t04 .sa-couplet { top: 92px; width: 34px; height: 228px; }
.sa-t04 .sa-couplet p { gap: 13px; font-size: 27px; }
.sa-t04 .sa-couplet-left { left: 67px; } .sa-t04 .sa-couplet-right { left: 301px; }
.sa-t04 .sa-couplet span { background-image: none; color: #2a1e14; filter: drop-shadow(0 .5px 0 rgba(255, 246, 225, .5)); opacity: .9; }
.sa-t04.sa-desk .sa-couplet { top: 120px; height: 236px; } .sa-t04.sa-desk .sa-couplet-left { left: -44px; } .sa-t04.sa-desk .sa-couplet-right { left: 388px; }
.sa-t04 .sa-grade { mix-blend-mode: soft-light; background: radial-gradient(240px 200px at 195px 60px, rgba(255, 226, 160, .3), transparent 70%), linear-gradient(transparent 76%, rgba(60, 40, 20, .2)); }

/* 06 松山怀远 — hewn rock stele on the pine terrace, clear mountain daylight */
.sa-t06 { --sa-name: #f2e2bc; --sa-dates: #ddd0b2; --sa-fixed: #e2d3ae; --rail-top: 66px; --sweep-top: 548px; --sa-stick: 44px; --sa-engrave: #2c3133; --sa-bouquet: brightness(1.02) saturate(.96); }
.sa-t06 .sa-plaque { left: 140px; top: 172px; width: 96px; height: 26px; }
.sa-t06 .sa-plaque p { gap: 4px; font-size: 19px; }
.sa-t06 .sa-grade { mix-blend-mode: soft-light; background: radial-gradient(300px 260px at 40px 120px, rgba(255, 238, 200, .32), transparent 70%), linear-gradient(90deg, transparent 60%, rgba(30, 50, 70, .14)); }

/* 07 金堂长明 — black-wood hall, fine dark-gold lines, warm palace lanterns; larger portrait */
.sa-t07 { --sa-name: #f1dfb2; --sa-dates: #d8c59c; --sa-fixed: #dcc89a; --rail-top: 236px; --sweep-top: 552px; --sa-stick: 44px; --sa-bouquet: brightness(.86) saturate(.92) sepia(.12);
  --sa-letter: linear-gradient(176deg, #f4e1b0 0%, #d9b46e 34%, #a87a3e 62%, #e4c48a 80%, #94672f 100%); }
.sa-t07 .sa-photo-frame, html body .sa-visit .sa-t07 .sa-identity .memorial-photo-frame { width: 104px; height: 138.67px; }
.sa-t07 .sa-identity { padding-top: 10px; }
.sa-t07 .sa-plaque { left: 108px; top: 88px; width: 174px; height: 46px; }
.sa-t07 .sa-plaque p { gap: 12px; font-size: 26px; padding-left: 4px; }
.sa-t07 .sa-couplet { top: 182px; width: 26px; height: 186px; }
.sa-t07 .sa-couplet p { gap: 6px; font-size: 19px; }
.sa-t07 .sa-couplet-left { left: 69px; } .sa-t07 .sa-couplet-right { left: 295px; }
.sa-t07.sa-desk .sa-plaque { top: 68px; } .sa-t07.sa-desk .sa-couplet { top: 172px; height: 206px; }
.sa-t07.sa-desk .sa-couplet-left { left: 22px; } .sa-t07.sa-desk .sa-couplet-right { left: 339px; }
.sa-t07 .sa-grade { mix-blend-mode: soft-light; background: radial-gradient(160px 160px at 12px 140px, rgba(255, 190, 110, .3), transparent 70%), radial-gradient(160px 160px at 378px 140px, rgba(255, 190, 110, .3), transparent 70%); }

/* 08 云水归心 — light stone memorial on the lake: dark engraved lettering on the pale polished panel */
.sa-t08 { --sa-name: #27333b; --sa-dates: #33414a; --sa-fixed: #35434c; --rail-top: 66px; --sweep-top: 548px; --sa-stick: 44px; --sa-engrave: #47545c; --sa-bouquet: brightness(1.03) saturate(.95); }
.sa-t08 .sa-inscription h1, html body .sa-visit .sa-t08 .sa-identity .sa-inscription h1, .sa-t08 .sa-dates, .sa-t08 .sa-fixed-col { text-shadow: 0 .8px 0 rgba(255, 255, 255, .55), 0 -.4px 0 rgba(0, 0, 0, .25); }
html body .sa-visit .sa-t08 .sa-identity .sa-inscription h1 { font-weight: 600; }
html body .sa-visit .sa-t08 .sa-identity .memorial-photo-frame { background: linear-gradient(160deg, #f4f6f7, #a9b2b8 45%, #e7ebee 70%, #8e989f); box-shadow: 0 0 0 .6px rgba(40, 50, 58, .5), 0 3px 8px rgba(30, 40, 50, .35); }
.sa-t08 .sa-plaque { left: 147px; top: 164px; width: 96px; height: 28px; }
.sa-t08 .sa-plaque p { gap: 5px; font-size: 20px; }
/* dates sit directly above the incense tips in the six scene templates: a soft dark halo keeps every digit legible
   when filmed smoke rises behind it (light-stone 08 overrides this with its engraved treatment below) */
html body .sa-visit .sa-stage .sa-identity .sa-dates { text-shadow: 0 1px 1px rgba(0, 0, 0, .7), 0 0 3px rgba(0, 0, 0, .75), 0 0 6px rgba(0, 0, 0, .45); }
/* dates: darker engraved ink with a light lower lip so they read clearly on the pale polished inset (size/position unchanged) */
.sa-t08 { --sa-dates: #1d2830; }
html body .sa-visit .sa-t08 .sa-identity .sa-dates { font-weight: 600; text-shadow: 0 .9px 0 rgba(255, 255, 255, .8), 0 -.5px 0 rgba(0, 0, 0, .32), 0 0 2px rgba(255, 255, 255, .5); }
.sa-t08 .sa-dates i { opacity: .7; }
/* 影青 censer: glaze, rolled rim and the ash bed are baked into sa/08/censer.webp (tools/opus-remaining/r08_censer.py,
   same alpha/size as before), so the old filter + blend overlays are gone. The incense ash is only the small disturbed
   patch where the three sticks stand, inside the baked ash bed. */
.sa-t08 .sa-ash { left: 10px; width: 20px; height: 3.6px; bottom: -.1px; border-radius: 50% 50% 45% 45%;
  background: radial-gradient(50% 62% at 50% 36%, rgba(190, 184, 174, .95), rgba(150, 143, 134, .8) 58%, rgba(140, 134, 126, 0)); }
.sa-t08 .sa-near::after { content: ""; position: absolute; left: 124px; top: 280px; width: 142px; height: 132px; pointer-events: none;
  background: radial-gradient(62px 58px at 71px 138px, rgba(64, 82, 98, .26), rgba(64, 82, 98, .09) 62%, transparent),
    linear-gradient(180deg, transparent 58%, rgba(64, 82, 98, .08) 82%, rgba(64, 82, 98, .14));
  -webkit-mask: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent); mask: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent); }
.sa-t08 .sa-smoke canvas { filter: blur(.45px); }
.sa-t08 .sa-grade { mix-blend-mode: soft-light; background: linear-gradient(180deg, rgba(220, 235, 255, .18), transparent 40%), radial-gradient(260px 200px at 340px 130px, rgba(255, 250, 235, .25), transparent 70%); }

/* 09 庭院春晖 — warm sandstone stele under a tiled cap in the spring courtyard */
.sa-t09 { --sa-name: #f3e3bd; --sa-dates: #e2d2b0; --sa-fixed: #e6d6b2; --rail-top: 66px; --sweep-top: 548px; --sa-stick: 44px; --sa-bouquet: brightness(1.02) saturate(1.0) sepia(.04); }
.sa-t09 .sa-grade { mix-blend-mode: soft-light; background: radial-gradient(320px 260px at 330px 80px, rgba(255, 236, 196, .34), transparent 70%), linear-gradient(transparent 78%, rgba(80, 60, 30, .14)); }
