/* mingli-r37.css — the 命轴 re-skin, ported from 09_Redesign-Sandbox/proto-mingzhou.css
 * at sandbox commit e33f36b (rounds 4–37).
 *
 * ⚠ THIS IS THE PROTOTYPE'S STYLESHEET MINUS ITS PAGE CHROME. The prototype is a
 * standalone page — it painted `html`/`body` its own dark ground, centred a fake
 * `.device` phone in the viewport, and set a global `* { box-sizing }` and a
 * `[hidden] { display:none !important }`. The live app has its own `.device` and its
 * own ground, so shipping those six rules would have re-skinned ALL 47 SCREENS
 * instead of 命理. They are removed here, by counted assertion, in scratchpad/port-css.py.
 *
 * Everything else is verbatim and safe to load globally: every class is `.pmz_`
 * prefixed and all 50 custom properties are `--pmz-` prefixed. Measured before the
 * port: `pmz_`, `data-term` and `stReport` each appear ZERO times across index.html
 * and every app-*.js, so nothing here can reach a screen that is not 命理's.
 *
 * Regenerate rather than hand-edit: fix the sandbox, re-run the port script, bump ?v=.
 */
/* ══════════════════════════════════════════════════════════════════════════════
   命轴 · THE SCROLL — prototype A of 3 for the 命理盘 redesign.
   Key: mingzhou.  Every keyframe + every class is prefixed  pmz_ .

   THE IMAGE — a hanging scroll (立轴) falls open DOWN the phone; the client's whole
   lifetime is mounted on ivory paper; one seal-red pin marks where they stand in it.

   ⭐ IT IS ONE PAGE (Jim, 21 Aug). There are no screens and no screen-switching.
   The document opens FURTHER — shelf → 命轴 → 续 → 题跋 → 鉴藏 → 证 — and everything
   that has been opened stays open, so you can scroll back through the whole life.
   The app's real bottom tab bar is present, styled exactly as it ships, and INERT:
   you are inside 命理, and 命理 is where you stay.

   ⭐ THE CHART IS NOT REDESIGNED (Jim, 21 Aug). The 四柱 plate is the live app's
   plate — 十神 header, stem tile, branch tile, 藏干+十神 stack, 长生 footer — with the
   live element hexes and the live slate/ink boxes. Values, structure and colour are
   ported, not re-drawn. Only the PAPER under it is new.

   LAWS OBEYED HERE (each has a shipped bug behind it — do not "tidy" them away):
    · IVORY LAW — every data surface sits on #FBF8F3-family paper. Dark theatre AROUND
      it only. (measured: on dark, colour separation collapses 6.37× → 1.52×)
    · Content never depends on an animation finishing. Nothing that carries a FACT is
      ever `opacity:0` at rest. Reveals are `from{}`-only keyframes with fill:backwards,
      so the resting style IS the readable state and `animation:none` leaves it visible.
    · transform / opacity ONLY. No animated text-shadow, no transform on an <svg> root,
      no offset-distance, no background-position, no clip-path, no height/width.
    · One idle animation in the whole app: .pmz_lamp's breath. Everything else finite.
    · Every light belongs to the EDGE of a solid object. No px-sized radial-gradients
      (those read as stars); no floating glows; no drifting arcs.
    · .pmz_root is a SCOPE CLASS AND PAINTS NOTHING. A scope class that also painted a
      ground once shipped a flat black rectangle over a finished build, 57 gates green.
   ══════════════════════════════════════════════════════════════════════════════ */

:root{
  /* — the night studio.  HARSHER (21 Aug): the ground drops closer to black and
       the blue is pushed to true indigo, so ivory reads as lit paper in a dark
       room rather than paper on grey. — */
  /* ⚠ ROUND 31 — WARM NEAR-BLACK, NOT INDIGO. "Too blue" was never about
       brightness; it was the HUE — a cold ground under cold-white text under blue
       cards. The ground now carries a trace of brown, so gold reads as gold and
       ivory reads as paper in a lit room rather than paper on a monitor. */
  --pmz-ground:#070603; --pmz-g2:#100D08; --pmz-g3:#241D12;

  /* — lacquer: the frame that carries the drama (Jim: "wow in the frame") ——— */
  --pmz-lacq:#1A1611; --pmz-lacq-2:#13100B; --pmz-lacq-3:#0D0B07;
  --pmz-lacq-rim:rgba(217,178,95,.30);

  /* — warm ivory FOR DARK GROUNDS: the cold-white replacement. Every
       rgba(240,233,220,*) on the reading page became one of these three. — */
  --pmz-on-lacq:#F4EEE2; --pmz-on-lacq-2:rgba(244,238,226,.86);
  --pmz-on-lacq-3:rgba(244,238,226,.62);

  /* — paper & ink ————————————————————————————————————————————————— */
  --pmz-paper:#FBF8F3; --pmz-paper-2:#F7F3EC; --pmz-paper-deep:#EFE8DA;
  --pmz-ink:#15110E; --pmz-ink-2:#4A423A; --pmz-ink-3:#7A7066; --pmz-rule:#D8CDB8;

  /* — authority ————————————————————————————————————————————————— */
  --pmz-seal:#B01820;              /* the pin and the chop.  NOTHING ELSE. */
  --pmz-gold:#C9A24B; --pmz-gold-hi:#F0DCA6; --pmz-gold-deep:#8C6C25;
  --pmz-jade:#1F7A5C;

  /* — mounting (装裱): the brocade & rods that make it an OBJECT ——————— */
  --pmz-rod:#3B2A18; --pmz-rod-hi:#6B4E2B; --pmz-rod-lo:#1C1309;
  --pmz-brocade:#2A1A2E; --pmz-brocade-2:#3A2130;

  /* ⚠ 五行 — THE LIVE APP'S OWN HEXES, ported verbatim from
     app-mingli.js:52  ELEM_HEX = TY.EL.HEX = ['#059669','#ef4444','#d97706','#eab308','#3b82f6']
     木 · 火 · 土 · 金 · 水.  These are NOT re-picked for the ivory ground: the chart's
     colour is the chart's meaning, and a student reads a flagged pillar by hue. */
  --pmz-mu:#059669; --pmz-huo:#ef4444; --pmz-tu:#d97706; --pmz-jin:#eab308; --pmz-shui:#3b82f6;
  /* 长生 stage colours, ported from app-mingli.js:54 STAGE_HEX */
  --pmz-stg-good:#059669; --pmz-stg-warn:#d97706; --pmz-stg-bad:#ef4444; --pmz-stg-mute:#64748b;
  /* the live plate's slate boxes, ported from app-mingli.js BOX_NORMAL / BOX_DAY */
  --pmz-box:rgba(241,245,249,.5); --pmz-box-bord:#e2e8f0;
  --pmz-box-day:rgba(15,23,42,.10); --pmz-box-day-bord:#0f172a;
  --pmz-slate:#64748b; --pmz-slate-9:#0f172a;

  --pmz-out:cubic-bezier(.16,1,.3,1);
  --pmz-thock:cubic-bezier(.2,1.5,.4,1);

  --pmz-disp:'DM Serif Display','Source Han Serif SC','Noto Serif SC','Songti SC','SimSun',serif;
  --pmz-brush:'KaiTi','STKaiti','Kaiti SC','Source Han Serif SC','SimSun',serif;
  --pmz-ui:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,'Noto Sans',sans-serif;

  /* — MATERIAL. Three stacked static textures, blended into the paper COLOUR via
       background-blend-mode so children are never touched and no compositing layer
       is created. Tiled SVG turbulence = real 宣纸 grain, not a flat fill. ——— */
  --pmz-grain:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.92' numOctaves='4' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23g)' opacity='.115'/%3E%3C/svg%3E");
  --pmz-fibre:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='420' height='420'%3E%3Cfilter id='f'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.010 .046' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='420' height='420' filter='url(%23f)' opacity='.075'/%3E%3C/svg%3E");
  --pmz-laid:repeating-linear-gradient(to bottom,rgba(146,126,94,.030) 0 1px,transparent 1px 6px);
}






/* ── the frame ─────────────────────────────────────────────────────────────
   `.device` is HEIGHT-BOUNDED at every width. That is deliberate: an overlay with
   `absolute; inset:0` inside a `.device` that GROWS with its content is as tall as
   the whole document — that bug shipped twice (a ritual at y=-1495px, readouts at
   y=839 in an 844px viewport) and passed a height-measuring gate both times. */

/* ⚠ .pmz_root is the SCOPE CLASS. It declares no paint of any kind — see header. */
.pmz_root{isolation:isolate}

@media(min-width:900px){


}

/* ══ THE ROOM ════════════════════════════════════════════════════════════════
   A night studio with weather in it. Every idle animation in this build lives here
   and nowhere else — see the ground block above for the rule they answer to. */
.pmz_room{position:absolute; inset:0; pointer-events:none; z-index:0; overflow:hidden}
.pmz_room::before{
  content:''; position:absolute; inset:0; z-index:0;
  background:
    /* ⚠ THE GLOW USED TO PEAK AT THE VERY TOP (at 50% -4%), which is exactly where the
       chrome scrim is at its blackest — so the band ended in a hard line. MEASURED on
       a vertical strip at x=12: 0.9% luminance at y=48, 7.4% at y=54. A 5.7% step in
       four pixels, and no amount of easing the SCRIM fixes it, because the step is
       the difference between the two surfaces, not the shape of the fade.
       Move the glow's centre down instead. The top of the page is then the base
       linear (~2%), the scrim is #01030B (~1%), and there is nothing left to see. */
    /* ⚠ ROUND 31 — THE HUE, NOT THE LIGHT. Every stop, radius and falloff below
       is the one measured in round 21; only the colour rotates from indigo to
       bronze. This ambient — not --pmz-ground — is what made the app read blue. */
    radial-gradient(82% 46% at 50% 20%,  #45311A 0%, transparent 60%),
    radial-gradient(70% 48% at 50% 104%, #050403 0%, transparent 66%),
    linear-gradient(#050403, #0D0A06 16%, #17120B 48%, #050403);
}
/* a MULTIPLY vignette, never a black overlay — a black overlay lifts the blacks to
   grey, and grey blacks are exactly what makes a dark comp look cheap.
   HARSHER: the falloff starts earlier and lands darker. */
.pmz_room::after{
  content:''; position:absolute; inset:0; mix-blend-mode:multiply; z-index:3;
  background:radial-gradient(104% 70% at 50% 38%, #fff 14%, rgba(128,112,84,.56) 60%, rgba(16,12,7,.97) 100%);
}

/* ⚠ THE DRIFT IS DEAD — 21 Aug, after both second-opinion lenses named it,
   independently, as the single thing that would make this read as an AI moodboard.
   codex: "purple gradients, random dot-stars, particle trails, moving gold shimmer
   and aurora light say AI moodboard, not premium metaphysical practice." agy: a
   Malay audience aged 40+ reads multi-colour particle glow as a gambling app.
   The sheets stay in the file at a fraction of their strength as a static depth
   wash — no animation — because the ground still needs to not be flat. The MOTION
   moved to the river, where it has a direction and a job. */
/* ⚠ THE OVERSCAN IS GPU MEMORY, AND IT WAS 4x WHAT THE PARALLAX NEEDS (15 Sep 2026).
   `left/right:-48%; top/bottom:-36%` made this a 810x1539 css-px compositor layer —
   42.8 MB of backing store at 3x on a 390x844 phone, the single biggest surface in
   the app and a prime cause of the iOS jetsam that reloaded 命理 under the reader.
   The parallax offset is CAPPED at -96px (mingli-r37.js :: livingGround) and the only
   other growth is scale(1.06), so the box needs ~11% of the viewport height, not 36%.
   At -5%/-14% the layer still covers the root at the full -96px offset on 360x640
   (the tightest phone: +18 px of margin), 390x844 (+55 px) and 430x932 (+70 px), and
   the backing store drops to ~18.7 MB.
   ⚠ THE LOOK IS UNCHANGED, AND THAT IS ARITHMETIC, NOT LUCK. The two radial washes
   below are positioned and sized in PERCENTAGES OF THIS BOX, so shrinking the box
   would have moved and shrunk them. Every percentage is re-derived so each ellipse
   lands on exactly the same root-relative pixels as before:
       blob 1  at 32% 34% / 44% 36%  →  17.927% 28.499% / 78.400% 48.375%
       blob 2  at 70% 62% / 38% 30%  →  85.636% 66.121% / 67.709% 40.313%
   (old box post-scale spans -0.5388W..1.5388W and -0.4116H..1.4116H; the new one
   -0.083W..1.083W and -0.1784H..1.1784H — map centre and radii through both.)
   Proven by pixel-diffing the river at scrollTop 0 and at max scroll, at all three
   widths, against the pre-change build. Change ONE of these numbers and the wash
   moves; re-derive the other three or shoot the diff again. */
.pmz_silk{position:absolute; left:-5%; right:-5%; top:-14%; bottom:-14%; z-index:1;
  pointer-events:none}
.pmz_silk i{position:absolute; inset:0; display:block}
.pmz_silk1{transform:translate3d(0,var(--pmz-par,0px),0) scale(1.06); opacity:.30}
.pmz_silk1 i{background:
  radial-gradient(78.400% 48.375% at 17.927% 28.499%, rgba(196,148,66,.20) 0%, transparent 64%),
  radial-gradient(67.709% 40.313% at 85.636% 66.121%, rgba(150,106,42,.24) 0%, transparent 66%)}
/* (pmz_silk1 / pmz_silk2 keyframes removed with the drift, 21 Aug) */

/* THE WEAVE IS DELETED — 22 Aug. Jim: "reduce the texture layers, make it cleaner."
   It was the single most VISIBLE thing on the register after the cards: a 5px blue
   grid across the whole screen. codex counted nine ground treatments competing with
   names and phone numbers on a 390px working screen; this was the loudest of them.
   Also gone: .pmz_silk2 entirely, two of the five ground gradients, and half of
   silk1's opacity. ⚠ THE CARDS ARE UNTOUCHED — Jim's call: the ivory leaf keeps its
   raking light, grain, fibre, laid paper and all four shadows. */

/* THE LAMP — the one idle animation. A gradient attached to the SOLID TOP EDGE of
   the frame (.pmz_edge is that solid object), never a floating glow. */
.pmz_edge{position:absolute; top:0; left:0; right:0; height:2px; z-index:6;
  background:linear-gradient(90deg,transparent,rgba(201,162,75,.42) 18%,rgba(240,220,166,.72) 50%,rgba(201,162,75,.42) 82%,transparent)}
.pmz_lamp{
  position:absolute; top:2px; left:0; right:0; height:44%; z-index:4; pointer-events:none;
  background:linear-gradient(to bottom, rgba(255,226,168,.155), rgba(255,214,150,.055) 34%, transparent 72%);
  animation:pmz_lampin 1s ease-out backwards, pmz_breathe 7.5s ease-in-out 1s infinite alternate;
}
@keyframes pmz_lampin{from{opacity:0}}
@keyframes pmz_breathe{from{opacity:.72} to{opacity:1}}

/* a reader who asked the OS for less motion gets a STILL room, not a slower one */
@media(prefers-reduced-motion:reduce){
  .pmz_lamp, .pmz_river i, .pmz_se_glow{animation:none !important}
}
.pmz_root[data-reduced="1"] .pmz_river i,
.pmz_root[data-reduced="1"] .pmz_se_glow{animation:none}
/* a still river still reads as a river — the datum and the tethers are static. */

/* ══ THE DOCUMENT — ONE SCROLL ═══════════════════════════════════════════════ */
.pmz_doc{
  position:absolute; inset:0; z-index:2; overflow-y:auto; overflow-x:hidden;
  -webkit-overflow-scrolling:touch; scrollbar-width:none;
  /* the chrome (back · Tenaga · language) is a BAND across the top of .device, not
     part of the document. The document starts below it, so no stage header has to
     dodge a floating control — the first build had the title running under the
     back button and the chip sitting on top of it. */
  padding:calc(66px + env(safe-area-inset-top,0px)) 0 178px;
}
.pmz_doc::-webkit-scrollbar{width:0;height:0}

/* a stage that has not been unrolled yet is not in the page at all */
.pmz_stage[data-open="0"]{display:none}
.pmz_stage{animation:pmz_unfurl .5s var(--pmz-out) backwards}
@keyframes pmz_unfurl{from{transform:translate3d(0,18px,0); opacity:0}}

/* ── header ───────────────────────────────────────────────────────────────── */
.pmz_hd{position:relative; z-index:3; padding:6px 16px 12px 18px;
  display:flex; align-items:flex-end; justify-content:space-between; gap:12px}
.pmz_hd h1{margin:0; font:400 24px/1.16 var(--pmz-disp); color:#F4F1E8; letter-spacing:.005em}
.pmz_hd .pmz_zh{margin:3px 0 0; font-size:12.5px; letter-spacing:.34em; color:rgba(240,233,220,.46)}
.pmz_hd .pmz_who{text-align:right; font-size:12.5px; color:rgba(240,233,220,.5); line-height:1.5}
.pmz_hd .pmz_who b{display:block; font-size:14px; color:rgba(240,233,220,.82); font-weight:600}
.pmz_hd_acts{display:flex; gap:8px; flex:none; padding-bottom:4px}
.pmz_ghost{min-height:38px; padding:0 14px; border-radius:999px; cursor:pointer;
  border:1px solid rgba(201,162,75,.30); background:rgba(255,255,255,.06);
  color:#EFE2C2; font:700 12.5px var(--pmz-ui); white-space:nowrap}
.pmz_ghost:active{background:rgba(255,255,255,.13)}
/* `hidden` is a presentation hint and every display rule in this file outranks it */


.pmz_wrap{padding:0 14px}
.pmz_muted{color:rgba(240,233,220,.5); font-size:12.5px; margin:0}

/* the stage caption in the indigo between two mounted sheets */
.pmz_between{display:flex; align-items:center; gap:12px; padding:20px 18px 12px}
.pmz_between b{font:400 17px/1.2 var(--pmz-disp); color:#F1E7D0; white-space:nowrap}
.pmz_between s{flex:none; text-decoration:none; font-size:12.5px; letter-spacing:.26em; color:rgba(240,233,220,.42)}
.pmz_between i{flex:1; height:1px; background:linear-gradient(90deg,rgba(201,162,75,.42),transparent)}

/* 中文 reads the heading itself — the decorative Chinese cue under it is a stutter */
.pmz_root[data-lang="zh"] .pmz_zh,
.pmz_root[data-lang="zh"] .pmz_between > s,
.pmz_root[data-lang="zh"] .pmz_sh_hd > s{display:none}

/* ══ PAPER — THE IVORY LAW ═══════════════════════════════════════════════════ */
.pmz_paper{
  background-color:var(--pmz-paper);
  background-image:var(--pmz-grain), var(--pmz-fibre), var(--pmz-laid);
  background-blend-mode:multiply, multiply, multiply;
  background-size:140px 140px, 420px 420px, auto;
  color:var(--pmz-ink);
}

/* ══════════════════════════════════════════════════════════════════════════════
   HEADER CHROME — the back button and the Tenaga chip, both the app's own.
   The chip's `right` is set from JS the way app-wallet.js :: positionChip() does
   it — measured off the language pill, never a hard-coded offset, because the pill
   is 3 characters wide in one language and 2 in another.
   ══════════════════════════════════════════════════════════════════════════════ */
.pmz_backbtn{position:absolute; top:calc(13px + env(safe-area-inset-top,0px)); left:14px;
  z-index:58; width:44px; height:44px; padding:0; border-radius:999px; cursor:pointer;
  display:flex; align-items:center; justify-content:center;
  background:rgba(255,255,255,.13); border:1px solid rgba(255,255,255,.10);
  backdrop-filter:blur(8px); -webkit-backdrop-filter:blur(8px); color:#fff;
  transition:background .16s ease, opacity .16s ease}
.pmz_backbtn svg{width:19px; height:19px; fill:none; stroke:currentColor;
  stroke-width:2.1; stroke-linecap:round; stroke-linejoin:round}
.pmz_backbtn:active{background:rgba(255,255,255,.22)}
/* at the shelf there is nothing to go back TO inside 命理 — it reads as present and
   unavailable, exactly like the tab bar, rather than lying about where it leads */
.pmz_backbtn[aria-disabled="true"]{opacity:.4; cursor:default}

.pmz_chip{position:absolute; top:calc(13px + env(safe-area-inset-top,0px)); right:78px;
  z-index:58; cursor:pointer; display:flex; align-items:center; gap:6px;
  min-height:44px; padding:4px 13px 4px 7px; border-radius:999px;
  background:rgba(18,12,9,.62); backdrop-filter:blur(9px); -webkit-backdrop-filter:blur(9px);
  border:1px solid rgba(214,178,95,.48);
  box-shadow:0 6px 16px -6px rgba(0,0,0,.5), inset 0 1px 0 rgba(255,255,255,.08)}
/* the app's own stone, at the app's own size, with the app's own drop shadows */
.pmz_chip .pmz_gem{width:17px; height:17px; flex:none; display:inline-grid; place-items:center}
.pmz_gem svg{width:100%; height:100%; display:block;
  filter:drop-shadow(0 3px 7px rgba(120,80,10,.55)) drop-shadow(0 0 9px rgba(233,199,126,.35))}
/* the same stone wherever a cost is quoted */
.pmz_cost .pmz_gem, .pmz_btn .pmz_gem{width:14px; height:14px; display:inline-grid;
  place-items:center; vertical-align:-2px; margin-right:2px}
.pmz_chip b{font:800 12.5px var(--pmz-ui); color:#F4D58E; letter-spacing:.01em;
  font-variant-numeric:lining-nums tabular-nums}

/* ══ THE SHELF — rolled scroll-ends, stacked ═════════════════════════════════ */
/* the standing hint GA puts at the top of this screen */
.pmz_hint b{display:inline-block; font-size:10px; color:var(--pmz-gold-hi);
  transform:translateY(-1px)}
.pmz_hint{margin:0 14px 12px; padding:9px 12px; border-radius:10px;
  border:1px solid rgba(201,162,75,.16); background:rgba(201,162,75,.07);
  font:12.5px/1.5 var(--pmz-ui); color:rgba(238,231,209,.80)}

/* 选择 mode — GA: 全选 · 已选 N · 删除 */
.pmz_selbar{display:none; align-items:center; justify-content:space-between; gap:8px;
  margin:0 14px 12px; padding:8px 10px 8px 12px; border-radius:11px;
  border:1px solid rgba(176,24,32,.34); background:rgba(176,24,32,.11);
  font:12.5px var(--pmz-ui); color:#F3E3E4}
.pmz_selbar[data-on="1"]{display:flex}
.pmz_selbar b{font-weight:800; font-variant-numeric:tabular-nums}
.pmz_selbar button{min-height:36px; padding:0 12px; border-radius:999px; cursor:pointer;
  border:1px solid rgba(255,255,255,.14); background:rgba(255,255,255,.06);
  color:#F3E3E4; font:700 12.5px var(--pmz-ui)}
.pmz_selbar .pmz_del{display:flex; align-items:center; gap:6px;
  background:var(--pmz-seal); border-color:transparent; color:#fff}
.pmz_selbar .pmz_del svg{width:14px; height:14px; fill:none; stroke:currentColor;
  stroke-width:1.7; stroke-linecap:round; stroke-linejoin:round}
.pmz_selbar .pmz_del[disabled]{background:rgba(176,24,32,.34); cursor:default}

/* THE CATEGORY RAIL — GA's 分类 tabs with live counts. Scrolls sideways INSIDE its
   own track; the page itself must never scroll sideways. */
.pmz_catrail{display:flex; gap:7px; padding:0 14px 12px; overflow-x:auto;
  scrollbar-width:none; -webkit-overflow-scrolling:touch;
  -webkit-mask-image:linear-gradient(90deg,#000 0,#000 calc(100% - 16px),transparent);
          mask-image:linear-gradient(90deg,#000 0,#000 calc(100% - 16px),transparent)}
.pmz_catrail::-webkit-scrollbar{width:0;height:0}
.pmz_catrail button{flex:none; min-height:38px; padding:0 13px; border-radius:999px;
  cursor:pointer; white-space:nowrap; display:flex; align-items:center; gap:7px;
  border:1px solid rgba(201,162,75,.20); background:rgba(255,255,255,.04);
  color:rgba(240,233,220,.74); font:13px/1 var(--pmz-ui)}
.pmz_catrail button i{font-style:normal; font-size:11px; font-weight:700; opacity:.62;
  font-variant-numeric:tabular-nums}
.pmz_catrail button[aria-pressed="true"]{color:#1B1408; font-weight:700;
  border-color:transparent;
  background:linear-gradient(180deg,var(--pmz-gold-hi),var(--pmz-gold) 62%,#B98F3A);
  box-shadow:0 5px 13px -5px rgba(201,162,75,.62)}
.pmz_catrail button[aria-pressed="true"] i{opacity:.72}

.pmz_tools{padding:2px 14px 12px; display:flex; gap:8px; align-items:stretch}
.pmz_searchwrap{position:relative; flex:1; min-width:0; display:flex}
.pmz_searchic{position:absolute; left:13px; top:50%; margin-top:-8px; width:16px; height:16px;
  fill:none; stroke:rgba(240,233,220,.46); stroke-width:1.8; stroke-linecap:round;
  pointer-events:none}
.pmz_search{flex:1; min-width:0; min-height:46px; border-radius:12px; padding:0 12px 0 36px;
  border:1px solid rgba(201,162,75,.24); background:rgba(255,255,255,.045);
  color:#F4EEE2; font:14px var(--pmz-ui); outline:none}
.pmz_search:focus{border-color:rgba(201,162,75,.55); background:rgba(255,255,255,.07)}
.pmz_search::placeholder{color:rgba(240,233,220,.42)}
.pmz_search::-webkit-search-cancel-button{-webkit-appearance:none}

.pmz_funnel{flex:none; min-height:46px; padding:0 13px; border-radius:12px; cursor:pointer;
  display:flex; align-items:center; gap:7px;
  border:1px solid rgba(201,162,75,.24); background:rgba(255,255,255,.045);
  color:rgba(238,243,255,.86); font:600 12.5px var(--pmz-ui)}
.pmz_funnel svg{width:15px; height:15px; fill:none; stroke:currentColor; stroke-width:1.7;
  stroke-linejoin:round}
.pmz_funnel b{min-width:18px; height:18px; padding:0 4px; border-radius:999px;
  display:flex; align-items:center; justify-content:center;
  background:linear-gradient(180deg,var(--pmz-gold-hi),var(--pmz-gold) 64%,#B98F3A);
  color:#1B1408; font:800 11px var(--pmz-ui); font-variant-numeric:tabular-nums}
.pmz_funnel[data-on="1"]{border-color:rgba(201,162,75,.55); background:rgba(201,162,75,.13);
  color:#F4E8C9}

.pmz_scrollend{
  display:block; width:100%; text-align:left; padding:0; margin:0 0 12px; cursor:pointer;
  background:none; border:0; color:inherit; font:inherit;
  /* ⚠ ONLY a card that has never been on screen animates in. Every re-render
     used to replay this on every card — three lanterns strobing to open one
     drawer. `[data-in="1"]` is stamped after the first paint and never cleared. */
  animation:pmz_settle .52s var(--pmz-out) backwards;
}
.pmz_scrollend[data-in="1"]{animation:none}
@keyframes pmz_settle{from{transform:translate3d(0,16px,0); opacity:0}}
/* the rolled scroll seen end-on: a lacquered rod with brass 轴头 caps. Its light is
   a linear sweep ALONG the rod — the edge of a solid object, never a point. */
.pmz_se_rod{
  display:block; height:15px; border-radius:8px 8px 3px 3px; position:relative;
  background:
    repeating-linear-gradient(90deg, rgba(255,222,168,.035) 0 3px, rgba(0,0,0,.05) 3px 9px, transparent 9px 23px),
    repeating-linear-gradient(90deg, rgba(0,0,0,.045) 0 1px, transparent 1px 6px),
    linear-gradient(to bottom, var(--pmz-rod-hi) 0%, var(--pmz-rod) 34%, var(--pmz-rod-lo) 100%);
  box-shadow:inset 0 1px 0 rgba(255,222,170,.30), 0 6px 14px rgba(0,0,0,.55);
}
.pmz_se_rod i{position:absolute; top:-2px; bottom:-2px; width:13px; border-radius:4px;
  background:linear-gradient(to bottom, var(--pmz-gold-hi), var(--pmz-gold) 42%, var(--pmz-gold-deep));
  box-shadow:0 3px 7px rgba(0,0,0,.5)}
.pmz_se_rod i:first-child{left:-4px}
.pmz_se_rod i:last-child{right:-4px}

.pmz_se_tag{display:block; position:relative; margin:0 6px; padding:11px 13px 10px;
  border-radius:0 0 4px 4px;
  box-shadow:0 16px 30px rgba(0,0,0,.46), 0 0 0 1px rgba(201,162,75,.22)}
.pmz_se_top{display:flex; align-items:center; gap:10px}
.pmz_se_names{flex:1; min-width:0}
.pmz_se_name{display:block; font:400 18px/1.24 var(--pmz-disp); color:var(--pmz-ink);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.pmz_se_honor{display:block; font:600 10px/1 var(--pmz-ui); letter-spacing:.20em;
  text-transform:uppercase; color:var(--pmz-ink-3); margin-bottom:2px}
.pmz_se_disc{flex:none; width:38px; height:38px; border-radius:50%;
  display:flex; align-items:center; justify-content:center;
  /* line-height:1 CLIPPED 己 — a CJK fallback face needs room below the baseline */
  font:400 20px/1.34 var(--pmz-disp); color:#fff;
  box-shadow:inset 0 0 0 1px rgba(0,0,0,.16)}
.pmz_se_line{display:block; margin-top:7px; font-size:12.5px; color:var(--pmz-ink-2)}
.pmz_se_line2{display:block; margin-top:2px; font-size:12.5px; color:var(--pmz-ink-3)}
.pmz_se_cat{display:inline-block; margin-top:9px;
  padding:4px 9px 4px 20px; border-radius:3px;
  position:relative; font-size:12.5px; letter-spacing:.06em; color:var(--pmz-ink-2);
  border:1px solid var(--pmz-rule); background:rgba(216,205,184,.24);
  max-width:100%; overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
/* the tag's own colour dot — derived from the label text, so the SAME category is
   always the same colour without the consultant having to pick one */
.pmz_se_cat::before{content:''; position:absolute; left:8px; top:50%; margin-top:-3px;
  width:6px; height:6px; border-radius:50%; background:var(--pmz-catc,var(--pmz-ink-3))}
.pmz_se_new{position:absolute; top:-9px; right:9px; padding:2px 8px; border-radius:2px;
  font:700 10px/1.5 var(--pmz-ui); letter-spacing:.16em; color:#fff;
  background:var(--pmz-seal); box-shadow:0 3px 9px rgba(0,0,0,.4)}

/* ── LAYER TWO — the drawer. GA shows eight facts and three actions on the face of
   every card; that is complete and dense. We keep every one of them, but the four
   a consultant scans by (name · 日主 · birth · category) stay on the face and the
   rest open on a press. The drawer is CLOSED at rest and its contents are in the
   DOM either way — nothing here depends on an animation. */
/* bottom-right of the tag: the 日主 disc owns the top-right corner, and the first
   build mounted this underneath it — a control nobody could see or press. */
/* IN the top row, beside the disc. It was absolutely positioned twice before —
   first under the 日主 disc (invisible), then at bottom-right where an OPEN drawer
   put the delete button directly beneath it. In flow it can collide with neither. */
.pmz_se_more{flex:none; width:38px; height:38px; padding:0; margin:0 2px 0 0;
  border:1px solid transparent; background:none; cursor:pointer; color:var(--pmz-ink-3);
  display:flex; align-items:center; justify-content:center; border-radius:10px}
.pmz_scrollend[data-drawer="1"] .pmz_se_more{border-color:var(--pmz-rule);
  background:rgba(216,205,184,.30)}
.pmz_se_more svg{width:15px; height:15px; fill:none; stroke:currentColor; stroke-width:2;
  stroke-linecap:round; stroke-linejoin:round;
  transition:transform .22s var(--pmz-out)}
.pmz_scrollend[data-drawer="1"] .pmz_se_more svg{transform:rotate(180deg)}
.pmz_se_more:active{background:rgba(21,17,14,.06)}

.pmz_se_drawer{display:none; margin-top:10px; padding-top:10px;
  border-top:1px dashed var(--pmz-rule)}
.pmz_scrollend[data-drawer="1"] .pmz_se_drawer{display:block;
  animation:pmz_drawer .26s var(--pmz-out) backwards}
@keyframes pmz_drawer{from{transform:translate3d(0,-6px,0); opacity:0}}
.pmz_se_lunar{display:block; font-size:12.5px; color:var(--pmz-ink-2)}
.pmz_se_phone{display:block; margin-top:2px; font-size:12.5px; color:var(--pmz-ink-3);
  font-variant-numeric:tabular-nums}
.pmz_se_acts{display:flex; gap:8px; margin-top:11px}
.pmz_se_acts span{flex:1; min-height:40px; border-radius:8px; cursor:pointer;
  display:flex; align-items:center; justify-content:center; gap:6px;
  border:1px solid var(--pmz-rule); background:rgba(255,255,255,.5);
  color:var(--pmz-ink-2); font:600 12.5px var(--pmz-ui)}
.pmz_se_acts span svg{width:14px; height:14px; fill:none; stroke:currentColor;
  stroke-width:1.7; stroke-linecap:round; stroke-linejoin:round}
.pmz_se_acts span[data-a="del"]{border-color:rgba(176,24,32,.34); color:var(--pmz-seal)}

/* 选择 mode — the checkbox replaces the 日主 disc's slot, GA-style */
.pmz_se_box{flex:none; width:24px; height:24px; border-radius:6px;
  border:2px solid var(--pmz-rule); background:#fff;
  display:flex; align-items:center; justify-content:center}
.pmz_se_box svg{width:14px; height:14px; fill:none; stroke:#fff; stroke-width:2.6;
  stroke-linecap:round; stroke-linejoin:round; opacity:0}
.pmz_scrollend[data-sel="1"] .pmz_se_box{border-color:var(--pmz-seal); background:var(--pmz-seal)}
.pmz_scrollend[data-sel="1"] .pmz_se_box svg{opacity:1}
.pmz_scrollend[data-sel="1"] .pmz_se_tag{box-shadow:0 16px 30px rgba(0,0,0,.46),
  0 0 0 2px var(--pmz-seal)}

/* once a scroll is lifted off the shelf, the shelf folds to a single strip */
.pmz_shelfbar{display:flex; width:100%; align-items:center; gap:11px; cursor:pointer;
  margin:0 0 4px; padding:12px 14px; min-height:52px; border-radius:12px;
  border:1px solid rgba(201,162,75,.26); background:rgba(255,255,255,.045);
  color:#EFE2C2; font:13.5px var(--pmz-ui); text-align:left}
.pmz_shelfbar b{font-weight:600}
.pmz_shelfbar .pmz_chev{margin-left:auto; color:rgba(240,233,220,.5)}

/* ══ BUTTONS ═════════════════════════════════════════════════════════════════ */
.pmz_btn{display:block; width:100%; min-height:52px; cursor:pointer; margin:4px 0 0;
  border-radius:13px; border:1px solid rgba(201,162,75,.46);
  background:linear-gradient(to bottom, rgba(201,162,75,.20), rgba(201,162,75,.08));
  color:#F3E7C9; font:15px/1.3 var(--pmz-ui); letter-spacing:.02em}
.pmz_btn:active{transform:translateY(1px)}
.pmz_btn_q{background:rgba(255,255,255,.04); border-color:rgba(201,162,75,.22); color:rgba(238,243,255,.86)}

/* THE PULL — the handle at the foot of an open sheet that unrolls the next one.
   A rod with brass caps, exactly like the ones the scroll is mounted on. */
.pmz_pull{display:block; width:calc(100% - 16px); margin:16px 8px 0; cursor:pointer;
  border:0; padding:0; background:none; color:inherit; font:inherit}
.pmz_pull_rod{position:relative; height:21px; border-radius:6px;
  background:
    repeating-linear-gradient(90deg, rgba(255,222,168,.035) 0 3px, rgba(0,0,0,.05) 3px 9px, transparent 9px 23px),
    linear-gradient(to bottom, var(--pmz-rod-hi), var(--pmz-rod) 38%, var(--pmz-rod-lo));
  box-shadow:inset 0 1px 0 rgba(255,222,170,.34), 0 8px 18px rgba(0,0,0,.55)}
.pmz_pull_rod i{position:absolute; top:-3px; bottom:-3px; width:15px; border-radius:4px;
  background:linear-gradient(to bottom, var(--pmz-gold-hi), var(--pmz-gold) 44%, var(--pmz-gold-deep));
  box-shadow:0 4px 9px rgba(0,0,0,.55)}
.pmz_pull_rod i:first-child{left:-6px}
.pmz_pull_rod i:last-child{right:-6px}
.pmz_pull_lab{display:flex; align-items:center; justify-content:center; gap:9px;
  min-height:44px; margin-top:2px; font:13.5px var(--pmz-ui); color:#EFE2C2; letter-spacing:.02em}
.pmz_pull_lab s{text-decoration:none; font-size:12.5px; letter-spacing:.24em; color:rgba(240,233,220,.44)}

/* ══ 庚帖 FORM ═══════════════════════════════════════════════════════════════ */
.pmz_formmount{margin:0 8px}
.pmz_sheet_form{margin:0; padding:18px 14px 18px; border-radius:0;
  box-shadow:0 22px 46px rgba(0,0,0,.5), 0 0 0 1px rgba(201,162,75,.22)}
.pmz_fm_lead{margin:0 0 16px; padding:0 0 14px; border-bottom:1px solid var(--pmz-rule);
  font:12.5px/1.66 var(--pmz-ui); color:var(--pmz-ink-2)}
.pmz_row2{display:grid; grid-template-columns:1fr 1fr; gap:10px}
.pmz_input{width:100%; min-height:48px; border-radius:3px; padding:0 11px;
  border:1px solid var(--pmz-rule); background:rgba(255,255,255,.6);
  color:var(--pmz-ink); font:15px var(--pmz-ui); outline:none;
  transition:border-color .15s ease, box-shadow .15s ease}
.pmz_input:focus{border-color:var(--pmz-gold-deep);
  box-shadow:inset 0 0 0 1px rgba(201,162,75,.35)}
.pmz_input::placeholder{color:rgba(122,112,102,.62)}
.pmz_input[aria-invalid="true"]{border-color:var(--pmz-seal);
  box-shadow:inset 0 0 0 1px rgba(176,24,32,.28)}

/* a picker TRIGGER — reads as a filled field, opens our own sheet */
.pmz_pick{display:flex; align-items:center; gap:8px; width:100%; min-height:48px;
  padding:0 11px; cursor:pointer; text-align:left; border-radius:3px;
  border:1px solid var(--pmz-rule); background:rgba(255,255,255,.6);
  color:var(--pmz-ink); font:15px var(--pmz-ui)}
.pmz_pick > span{flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.pmz_pick s{flex:none; text-decoration:none; font-size:12px; color:var(--pmz-ink-3)}
.pmz_pick em{flex:none; font-style:normal; color:var(--pmz-ink-3); font-size:12px}
.pmz_pick:active{background:rgba(255,255,255,.85)}
.pmz_pick_sm{min-height:44px; font-size:14px}

/* GENDER — a real segmented control, not a dropdown of two things */
.pmz_seg{display:grid; grid-template-columns:1fr 1fr; gap:0; border-radius:3px;
  border:1px solid var(--pmz-rule); background:rgba(255,255,255,.6); overflow:hidden}
.pmz_seg button{min-height:46px; cursor:pointer; border:0; background:none;
  color:var(--pmz-ink-2); font:14px var(--pmz-ui)}
.pmz_seg button + button{border-left:1px solid var(--pmz-rule)}
.pmz_seg button[aria-pressed="true"]{color:var(--pmz-ink); font-weight:700;
  background:linear-gradient(to bottom,rgba(201,162,75,.26),rgba(201,162,75,.13));
  box-shadow:inset 0 0 0 1px rgba(201,162,75,.40)}
.pmz_check{flex:1; display:flex; align-items:center; gap:8px; min-height:44px;
  cursor:pointer; border:0; background:none; padding:0; text-align:left;
  color:var(--pmz-ink-2); font:13px/1.35 var(--pmz-ui)}
.pmz_check i{flex:none; width:19px; height:19px; border-radius:4px;
  border:1.6px solid var(--pmz-rule); background:#fff; position:relative}
.pmz_check i::after{content:''; position:absolute; left:5px; top:1px; width:6px; height:11px;
  border:solid #fff; border-width:0 2.2px 2.2px 0; transform:rotate(42deg); opacity:0}
.pmz_check[aria-pressed="true"] i{background:var(--pmz-ink); border-color:var(--pmz-ink)}
.pmz_check[aria-pressed="true"] i::after{opacity:1}

/* ☠ the duplicate 庚帖 preview's stylesheet is deleted with it, not left as dead
   text. A falsification break that lands on a dead rule is a no-op, and reports
   a MISS that reads like a weak gate. */

.pmz_err{margin:9px 0 0; padding:9px 11px; border-radius:9px; text-align:center;
  background:rgba(176,24,32,.16); border:1px solid rgba(176,24,32,.42);
  color:#F6DEDF; font:13px/1.45 var(--pmz-ui)}

.pmz_dial{display:grid; grid-template-columns:repeat(3,1fr); gap:8px}
.pmz_dial button{min-height:52px; cursor:pointer; border-radius:3px;
  border:1px solid var(--pmz-rule); background:rgba(255,255,255,.55);
  color:var(--pmz-ink); font:400 17px/1.1 var(--pmz-disp)}
.pmz_dial button b{display:block; font:400 12.5px/1.4 var(--pmz-ui); color:var(--pmz-ink-3)}
.pmz_dial button[aria-pressed="true"]{border-color:var(--pmz-gold-deep);
  background:linear-gradient(to bottom,rgba(201,162,75,.24),rgba(201,162,75,.12));
  box-shadow:inset 0 0 0 1px rgba(201,162,75,.42)}

/* ══ THE MOUNTING ════════════════════════════════════════════════════════════ */
.pmz_mount{margin:0 8px}
.pmz_rod_top,.pmz_rod_bot{position:relative; height:17px; border-radius:5px;
  background:
    repeating-linear-gradient(90deg, rgba(255,222,168,.035) 0 3px, rgba(0,0,0,.05) 3px 9px, transparent 9px 23px),
    repeating-linear-gradient(90deg, rgba(0,0,0,.045) 0 1px, transparent 1px 6px),
    linear-gradient(to bottom, var(--pmz-rod-hi), var(--pmz-rod) 38%, var(--pmz-rod-lo));
  box-shadow:inset 0 1px 0 rgba(255,222,170,.34), 0 8px 18px rgba(0,0,0,.55)}
.pmz_rod_bot{height:21px; border-radius:6px}
.pmz_rod_top i,.pmz_rod_bot i{position:absolute; top:-3px; bottom:-3px; width:15px; border-radius:4px;
  background:linear-gradient(to bottom, var(--pmz-gold-hi), var(--pmz-gold) 44%, var(--pmz-gold-deep));
  box-shadow:0 4px 9px rgba(0,0,0,.55)}
.pmz_rod_top i:first-child,.pmz_rod_bot i:first-child{left:-6px}
.pmz_rod_top i:last-child,.pmz_rod_bot i:last-child{right:-6px}
/* 绫 — the brocade border of the mounting, above and below the ivory field */
.pmz_brocade{height:10px;
  background:linear-gradient(to bottom,var(--pmz-brocade-2),var(--pmz-brocade)),
             repeating-linear-gradient(135deg,rgba(201,162,75,.16) 0 2px,transparent 2px 6px);
  background-blend-mode:overlay}

.pmz_sheet{padding:16px 14px 22px; position:relative;
  box-shadow:0 26px 60px rgba(0,0,0,.55), 0 0 0 1px rgba(201,162,75,.20)}

/* — 庚帖 birth-data header ————————————————————————————————————————— */
.pmz_gengtie{border:1px solid var(--pmz-rule); border-radius:2px; padding:12px 13px 11px;
  background:rgba(216,205,184,.16)}
.pmz_gt_top{display:block}
.pmz_gt_name{font:400 22px/1.2 var(--pmz-disp); color:var(--pmz-ink); margin:0}
.pmz_gt_role{display:block; font:12.5px var(--pmz-ui); letter-spacing:.2em; color:var(--pmz-ink-3); margin:0 0 3px}
/* the eight characters run full width, under the name — they are the record's
   title line, not a marginal note beside it */
.pmz_gt_bz{display:block; margin:10px 0 0; padding:9px 0 0;
  border-top:1px solid var(--pmz-rule);
  font:400 22px/1.55 var(--pmz-brush); color:var(--pmz-ink); letter-spacing:.16em;
  text-align:left}
.pmz_gt_line{margin:9px 0 0; font-size:12.5px; color:var(--pmz-ink-2); line-height:1.6}
.pmz_gt_line b{font-weight:600; color:var(--pmz-ink)}

.pmz_ttl{display:flex; align-items:baseline; justify-content:space-between; gap:10px;
  margin:22px 0 10px; padding:0 0 6px; border-bottom:1px solid var(--pmz-rule)}
.pmz_ttl h2{margin:0; font:400 17px/1.2 var(--pmz-disp); color:var(--pmz-ink)}
.pmz_ttl .pmz_zh{font-size:12.5px; letter-spacing:.24em; color:var(--pmz-ink-3)}

/* ══════════════════════════════════════════════════════════════════════════════
   四柱 — THE LIVE APP'S PLATE, PORTED.  app-mingli.js :: pillarCol()
   柱名 → 十神 → 天干 tile → 地支 tile → 藏干 + 十神 stack → 长生 stage.
   Sizes, weights, boxes and hexes are the shipped ones. Do not "improve" them:
   Jim's instruction on 21 Aug was that the chart's visuals, values and colour do
   not change — only the paper it is printed on.
   ══════════════════════════════════════════════════════════════════════════════ */
.pmz_plate{display:flex; justify-content:center; gap:12px; padding:4px 0 2px}
.pmz_col{display:flex; flex-direction:column; align-items:center; flex:1; min-width:0}
.pmz_col_lab{font-size:12px; margin-bottom:8px; color:var(--pmz-slate)}
.pmz_col_tg{font-size:12px; margin-bottom:8px; height:16px; color:var(--pmz-slate)}
.pmz_col.pmz_isday .pmz_col_tg{color:var(--pmz-slate-9); font-weight:500}
.pmz_tile{width:40px; height:40px; font:700 18px/40px var(--pmz-ui); border-radius:6px; text-align:center;
  background:var(--pmz-box); border:1px solid var(--pmz-box-bord)}
.pmz_tile + .pmz_tile{margin-top:4px}
.pmz_col.pmz_isday .pmz_tile{background:var(--pmz-box-day); border-color:var(--pmz-box-day-bord)}
.pmz_hid{display:flex; flex-direction:column; align-items:center; gap:4px; margin-top:4px; min-height:48px}
.pmz_hid span{font-size:12px; line-height:1; display:flex; align-items:center; justify-content:center; font-weight:500}
.pmz_hid span.pmz_h2{font-weight:400; opacity:.7}
.pmz_hid span s{text-decoration:none; color:var(--pmz-slate); margin-left:2px; font-size:10px}
.pmz_stg{margin-top:4px; font-size:11px; font-weight:500}
.pmz_el_mu{color:var(--pmz-mu)} .pmz_el_huo{color:var(--pmz-huo)} .pmz_el_tu{color:var(--pmz-tu)}
.pmz_el_jin{color:var(--pmz-jin)} .pmz_el_shui{color:var(--pmz-shui)}
.pmz_bg_mu{background:var(--pmz-mu)} .pmz_bg_huo{background:var(--pmz-huo)}
.pmz_bg_tu{background:var(--pmz-tu)} .pmz_bg_jin{background:var(--pmz-jin)}
.pmz_bg_shui{background:var(--pmz-shui)}
.pmz_stg_good{color:var(--pmz-stg-good)} .pmz_stg_warn{color:var(--pmz-stg-warn)}
.pmz_stg_bad{color:var(--pmz-stg-bad)}  .pmz_stg_mute{color:var(--pmz-stg-mute)}

.pmz_verdict{margin:14px 0 0; padding:11px 12px; border:1px solid var(--pmz-rule);
  border-left:3px solid var(--pmz-gold-deep); background:rgba(255,255,255,.46)}
.pmz_verdict b{display:block; font:400 17px/1.35 var(--pmz-disp); color:var(--pmz-ink)}
.pmz_verdict span{display:block; margin-top:4px; font-size:12.5px; color:var(--pmz-ink-2)}

.pmz_serial{margin:11px 0 0; font:12.5px/1.5 var(--pmz-ui); color:var(--pmz-ink-3);
  letter-spacing:.06em; display:flex; justify-content:space-between; gap:10px; flex-wrap:wrap}
.pmz_serial b{font-weight:600; color:var(--pmz-ink-2); letter-spacing:.12em}

/* — 五行 balance ————————————————————————————————————————————————— */
.pmz_wx_row{display:flex; align-items:center; gap:10px; margin:0 0 9px}
.pmz_wx_nm{width:26px; flex:none; text-align:center; font:400 19px/1 var(--pmz-disp)}
.pmz_wx_bar{flex:1; height:13px; border-radius:2px; background:rgba(216,205,184,.42);
  border:1px solid var(--pmz-rule); overflow:hidden}
/* scaleX, never width — width animation forces layout every frame. The RESTING style
   is the true value, so with animation stripped the bar is already correct. */
.pmz_wx_fill{display:block; height:100%; transform-origin:left center;
  transform:scaleX(var(--pmz-v)); animation:pmz_grow .68s var(--pmz-out) backwards}
@keyframes pmz_grow{from{transform:scaleX(.02)}}
.pmz_wx_val{width:38px; flex:none; text-align:right; font-size:13px; color:var(--pmz-ink-2);
  font-variant-numeric:tabular-nums}

/* ══ THE ROAD — 大运 as a milestone rail running DOWN the page ════════════════
   Same data as the live Cycles table — 干支, years, ages, 十神 — turned upright.
   Vertical, full stop: no horizontal scroll-snap strip anywhere on this page. */
.pmz_road{list-style:none; margin:6px 0 0; padding:0 0 0 30px; position:relative}
.pmz_road_thread{position:absolute; left:11px; top:8px; bottom:8px; width:2px;
  background:var(--pmz-rule); border-radius:1px}
.pmz_road_fill{position:absolute; left:0; top:0; width:2px; border-radius:1px;
  background:linear-gradient(to bottom, var(--pmz-gold-hi), var(--pmz-gold) 40%, var(--pmz-gold-deep))}
.pmz_stone{position:relative; display:flex; flex-wrap:wrap; align-items:baseline; gap:10px;
  padding:9px 0; border-bottom:1px dotted rgba(216,205,184,.9)}
.pmz_stone:last-child{border-bottom:0}
.pmz_stone_node{position:absolute; left:-24px; top:14px; width:11px; height:11px;
  border-radius:50%; background:var(--pmz-paper); border:2px solid var(--pmz-rule)}
.pmz_stone.pmz_past .pmz_stone_node{background:var(--pmz-gold); border-color:var(--pmz-gold-deep)}
.pmz_stone_gz{font:400 21px/1.15 var(--pmz-disp); color:var(--pmz-ink); letter-spacing:.06em; flex:none}
.pmz_stone_meta{flex:1; display:flex; justify-content:space-between; gap:8px;
  font-size:12.5px; color:var(--pmz-ink-2); font-variant-numeric:tabular-nums}
.pmz_stone_ten{flex:none; font-size:12.5px; color:var(--pmz-ink-3); letter-spacing:.1em}
.pmz_stone.pmz_now{background:linear-gradient(90deg,rgba(201,162,75,.16),rgba(216,205,184,.10) 46%,transparent 84%)}
.pmz_stone.pmz_now .pmz_stone_node{background:var(--pmz-seal); border-color:var(--pmz-seal)}
.pmz_pinrow{flex:0 0 100%; display:block; margin:7px 0 1px}

/* THE PIN — the climax, and the consultant's pointing gesture. */
.pmz_pin{display:inline-flex; align-items:center; gap:7px; margin:0;
  padding:6px 11px 6px 9px; border-radius:2px; position:relative;
  background:var(--pmz-seal); color:#FDF6F0; font:600 13px/1.2 var(--pmz-ui);
  letter-spacing:.04em; transform:rotate(-1.1deg);
  box-shadow:0 7px 14px rgba(90,10,14,.42), inset 0 0 0 1px rgba(255,255,255,.12)}
.pmz_pin i{width:9px; height:9px; border-radius:50%; flex:none;
  background:linear-gradient(to bottom,#FBE8E8,#E8A9A6 55%,#8E1218);
  box-shadow:0 1px 2px rgba(0,0,0,.45)}
.pmz_pin.pmz_stamping{animation:pmz_stamp .3s var(--pmz-thock) backwards}
@keyframes pmz_stamp{from{transform:rotate(-1.1deg) scale(1.15); opacity:0}}

.pmz_note{margin:9px 0 0; font-size:12.5px; line-height:1.6; color:var(--pmz-ink-3)}

/* ☠ THE COLOPHON PANELS ARE GONE (item 6 — Jim: "remove 师父题跋 sections and data
   completely"). `pmz_colo` appears nowhere in the JS, the HTML or any data script,
   and querySelectorAll returns 0 on every screen with every drawer forced open.
   Eight live rules with no producer, deleted rather than left to be inherited by
   whatever takes the name next. */

.pmz_tagrow{display:flex; flex-wrap:wrap; gap:7px}
.pmz_tag{display:inline-block; padding:6px 10px; border-radius:2px; font-size:13px;
  border:1px solid var(--pmz-rule); background:rgba(255,255,255,.62); color:var(--pmz-ink-2)}
.pmz_tag.pmz_good{border-color:rgba(31,122,92,.5); color:var(--pmz-jade)}
.pmz_tag.pmz_bad{border-color:rgba(217,119,6,.5); color:var(--pmz-tu)}
.pmz_kv{margin:0 0 10px}
.pmz_kv:last-child{margin-bottom:0}
.pmz_kv .pmz_k{display:block; font:600 13.5px/1.4 var(--pmz-ui); color:var(--pmz-ink)}
.pmz_kv .pmz_v{display:block; font-size:13px; line-height:1.62; color:var(--pmz-ink-2)}
.pmz_kv .pmz_loc{display:inline-block; margin-left:6px; font-size:12.5px; color:var(--pmz-ink-3)}
.pmz_grp{margin:0 0 14px}
.pmz_grp:last-child{margin-bottom:0}
.pmz_grp h3{margin:0 0 8px; font:600 12.5px/1.3 var(--pmz-ui); letter-spacing:.16em;
  color:var(--pmz-ink-3); text-transform:uppercase}
.pmz_note + .pmz_grp{margin-top:16px}

/* the EMPTY STATE (F3, zero 格局). Deliberate and calm — never a hole. */
.pmz_empty{text-align:center; padding:20px 14px 22px}
.pmz_empty .pmz_seal_sm{display:inline-flex; width:46px; height:46px; align-items:center;
  justify-content:center; border-radius:3px; margin:0 0 11px;
  font:400 22px/1 var(--pmz-brush); color:var(--pmz-ink-3);
  border:1px solid var(--pmz-rule); background:rgba(216,205,184,.3)}
.pmz_empty b{display:block; font:400 17px/1.35 var(--pmz-disp); color:var(--pmz-ink)}
.pmz_empty span{display:block; margin-top:7px; font-size:13px; line-height:1.65; color:var(--pmz-ink-2)}
.pmz_empty .pmz_zh{margin-top:8px; font-size:12.5px; color:var(--pmz-ink-3); letter-spacing:.18em}

/* ══ THE DENSE LEAVES ════════════════════════════════════════════════════════ */
.pmz_leaf{margin:0 8px; padding:16px 14px 18px;
  box-shadow:0 20px 44px rgba(0,0,0,.42), 0 0 0 1px rgba(201,162,75,.18)}
.pmz_leaf + .pmz_leaf{margin-top:14px}
.pmz_goldrule{height:2px; margin:0 8px 14px;
  background:linear-gradient(90deg,transparent,var(--pmz-gold-deep) 12%,var(--pmz-gold-hi) 50%,var(--pmz-gold-deep) 88%,transparent)}


/* 流年 — the current decade's ten years, vertical (never a sideways strip) */
.pmz_years{list-style:none; margin:0; padding:0}
.pmz_years li{display:flex; flex-wrap:wrap; align-items:baseline; gap:10px; padding:8px 2px;
  border-bottom:1px dotted rgba(216,205,184,.9); font-size:13px; color:var(--pmz-ink-2)}
.pmz_years li:last-child{border-bottom:0}
.pmz_years li b{font:400 18px/1.1 var(--pmz-disp); color:var(--pmz-ink); letter-spacing:.05em}
.pmz_years li .pmz_y{width:42px; flex:none; font-variant-numeric:tabular-nums}
.pmz_years li.pmz_thisyear{background:linear-gradient(90deg,rgba(201,162,75,.14),transparent 74%)}

/* ══ SIFU'S COLOPHON (the reading, stitched onto the scroll) ═════════════════ */
.pmz_ai_hd{display:flex; align-items:center; gap:11px; margin:0 0 12px}
.pmz_ai_av{width:44px; height:44px; flex:none; border-radius:3px; display:flex;
  align-items:center; justify-content:center; font:400 22px/1 var(--pmz-brush);
  color:#FDF6F0; background:var(--pmz-seal); transform:rotate(-2deg);
  box-shadow:0 6px 14px rgba(90,10,14,.4)}
.pmz_ai_t{font:400 17px/1.2 var(--pmz-disp); color:var(--pmz-ink)}
.pmz_ai_s{font-size:12.5px; color:var(--pmz-ink-3); margin-top:3px}
.pmz_meter{display:flex; align-items:center; gap:9px; padding:10px 12px; margin:0 0 12px;
  border:1px solid var(--pmz-rule); background:rgba(216,205,184,.26)}
.pmz_pips{display:flex; gap:5px; flex:none}
.pmz_pip{width:11px; height:11px; border-radius:50%; border:1px solid var(--pmz-gold-deep);
  background:rgba(255,255,255,.5)}
.pmz_pip.pmz_on{background:var(--pmz-gold)}
.pmz_meter_t{font-size:12.5px; color:var(--pmz-ink-2)}

.pmz_prose{border:1px solid var(--pmz-rule); border-radius:2px; padding:14px 13px 13px;
  background:rgba(255,255,255,.48)}
.pmz_prose p{margin:0 0 11px; font:15px/1.78 var(--pmz-ui); color:var(--pmz-ink)}
.pmz_prose p:last-child{margin-bottom:0}
.pmz_prose .pmz_rx{display:block; margin-top:12px; padding:10px 11px;
  border-left:3px solid var(--pmz-gold-deep); background:rgba(201,162,75,.10);
  font:600 14px/1.62 var(--pmz-ui); color:var(--pmz-ink)}
/* streamed by OPACITY REVEAL. `from{}`-only + backwards: the resting state of every
   word is opacity 1, so the full text is in the DOM and readable with animation off. */
.pmz_w{display:inline}
.pmz_streaming .pmz_w{animation:pmz_reveal .34s linear backwards}
@keyframes pmz_reveal{from{opacity:0}}
.pmz_prose_sig{margin:13px 0 0; padding-top:10px; border-top:1px solid var(--pmz-rule);
  font-size:12.5px; color:var(--pmz-ink-3)}

/* ══ THE PROVENANCE WALL ═════════════════════════════════════════════════════ */
.pmz_prov{margin:0 8px 12px; padding:13px 13px 12px; position:relative;
  box-shadow:0 16px 32px rgba(0,0,0,.4), 0 0 0 1px rgba(201,162,75,.18)}
.pmz_prov_h{display:flex; align-items:flex-start; justify-content:space-between; gap:12px}
.pmz_prov_q{font:400 16px/1.34 var(--pmz-disp); color:var(--pmz-ink); flex:1}
.pmz_prov_m{margin:6px 0 0; font-size:12.5px; color:var(--pmz-ink-3)}
.pmz_prov_seal{flex:none; width:42px; height:42px; border-radius:2px; overflow:hidden;
  transform:rotate(var(--pmz-rot,-3deg)); opacity:.92}
.pmz_prov_seal img{display:block; width:100%; height:100%}
.pmz_prov_acts{display:flex; gap:7px; margin:11px 0 0}
.pmz_prov_acts button{flex:1; min-height:44px; cursor:pointer; border-radius:2px;
  border:1px solid var(--pmz-rule); background:rgba(255,255,255,.58);
  color:var(--pmz-ink-2); font:13px var(--pmz-ui)}
.pmz_prov_acts button.pmz_dl{border-color:var(--pmz-gold-deep); color:var(--pmz-ink);
  background:linear-gradient(to bottom,rgba(201,162,75,.2),rgba(201,162,75,.08))}

/* ══ THE CERTIFICATE ═════════════════════════════════════════════════════════ */
.pmz_pdfbar{display:flex; gap:8px; padding:0 14px 12px}
.pmz_pdfbar button{flex:1; min-height:46px; cursor:pointer; border-radius:11px;
  border:1px solid rgba(201,162,75,.4); background:rgba(255,255,255,.05);
  color:#F0E4C6; font:13.5px var(--pmz-ui)}
.pmz_page{margin:0 10px 16px; padding:20px 18px 0; position:relative;
  box-shadow:0 24px 50px rgba(0,0,0,.55), 0 0 0 1px rgba(201,162,75,.2);
  display:flex; flex-direction:column; min-height:430px}
.pmz_page_in{flex:1}
.pmz_guilloche{height:26px; margin:0 -18px 16px; background-repeat:repeat-x;
  background-size:auto 26px; opacity:.85}
.pmz_guilloche.pmz_gl_b{margin:16px -18px 0}
.pmz_hallmark{display:flex; align-items:center; justify-content:space-between; gap:8px;
  margin:0 -18px; padding:9px 18px 12px; border-top:1px solid var(--pmz-rule);
  font-size:12.5px; color:var(--pmz-ink-3); letter-spacing:.06em}
.pmz_hallmark span{white-space:nowrap}
.pmz_hallmark .pmz_hm_seal{font-family:var(--pmz-brush); color:var(--pmz-seal); font-size:14px}

.pmz_cover_ttl{font:400 15px/1.4 var(--pmz-ui); letter-spacing:.32em; color:var(--pmz-ink-3);
  text-transform:uppercase; margin:8px 0 0}
/* GOLD FOIL — exactly twice in the whole certificate: the client's name, and the seal. */
.pmz_foil{background:linear-gradient(100deg,#8C6C25 0%,#C9A24B 22%,#F5E3B0 42%,#C9A24B 62%,#8C6C25 100%);
  -webkit-background-clip:text; background-clip:text; color:transparent;
  -webkit-text-fill-color:transparent}
.pmz_cover_name{font:400 34px/1.18 var(--pmz-disp); margin:10px 0 0}
.pmz_cover_sub{font:400 20px/1.5 var(--pmz-brush); color:var(--pmz-ink); letter-spacing:.18em; margin:12px 0 0}
.pmz_cover_meta{margin:auto 0 0; padding:14px 0 0; font-size:12.5px; line-height:1.8; color:var(--pmz-ink-2)}

.pmz_invoc{font:400 17px/1.8 var(--pmz-disp); color:var(--pmz-ink); margin:0;
  padding:0 0 0 13px; border-left:2px solid var(--pmz-gold-deep)}
.pmz_verdict_big{position:relative; margin:22px 0 0}
.pmz_verdict_big b{display:block; font:400 25px/1.3 var(--pmz-disp); color:var(--pmz-ink)}
.pmz_verdict_big span{display:block; margin-top:7px; font-size:13px; line-height:1.7; color:var(--pmz-ink-2)}
/* the chop — a ROUGH INKED impression, micro-rotated, stamped OVER the verdict line. */
.pmz_chop{position:absolute; right:-4px; top:-16px; width:96px; height:96px;
  transform:rotate(-6.5deg); pointer-events:none}
.pmz_chop img{display:block; width:100%; height:100%}
.pmz_seal_block{position:relative; display:inline-block; margin:14px 0 0}
.pmz_seal_block .pmz_chop{position:static; display:inline-block;
  width:104px; height:104px; transform:rotate(-4.5deg)}
/* ONE gold sheen crosses the seal on open — once, never again. Translate only. */
.pmz_sheen{position:absolute; inset:0; overflow:hidden; pointer-events:none; border-radius:2px}
.pmz_sheen i{position:absolute; top:-30%; bottom:-30%; width:46%; left:-60%;
  background:linear-gradient(100deg,transparent,rgba(255,240,200,.85),transparent);
  transform:translate3d(0,0,0)}
.pmz_sheen.pmz_run i{animation:pmz_sheen .6s ease-in-out 1 both}
@keyframes pmz_sheen{from{transform:translate3d(0,0,0)} to{transform:translate3d(360%,0,0)}}

.pmz_kt{margin:0 0 13px}
.pmz_kt h3{margin:0 0 5px; font:400 17px/1.3 var(--pmz-disp); color:var(--pmz-ink)}
.pmz_kt p{margin:0; font-size:13px; line-height:1.72; color:var(--pmz-ink-2)}
.pmz_kt .pmz_rx{display:block; margin-top:8px; padding:8px 10px; border-left:3px solid var(--pmz-gold-deep);
  background:rgba(201,162,75,.10); font:600 13px/1.6 var(--pmz-ui); color:var(--pmz-ink)}
.pmz_todo{display:inline-block; margin-top:5px; padding:4px 8px; font-size:12.5px;
  letter-spacing:.04em; color:var(--pmz-ink-3); border:1px dashed var(--pmz-rule);
  background:rgba(216,205,184,.2)}
.pmz_cert_line{margin:0 0 9px; font-size:13px; line-height:1.7; color:var(--pmz-ink-2)}
.pmz_cert_auth{font:600 14px/1.6 var(--pmz-ui); color:var(--pmz-ink); letter-spacing:.02em}
.pmz_cert_iss{font-size:12.5px; color:var(--pmz-ink-3); margin-top:3px}

/* ══════════════════════════════════════════════════════════════════════════════
   THE APP'S OWN TAB BAR — present, exact, and INERT.
   Ported from index.html (.tabbar / .tab / .tico / .ico-out / .ico-fill).
   The live app lights NO tab on the 命理 screens (TAB_OF has no mingli entry) and
   keeps the bar visible (NO_TABBAR excludes only 'mingli-form'), so that is what
   this shows. It is here to prove the feature lives INSIDE the app — it is not the
   way you move around this page, and tapping it does nothing.
   ══════════════════════════════════════════════════════════════════════════════ */
.pmz_tabbar{position:absolute; left:14px; right:14px; bottom:calc(14px + env(safe-area-inset-bottom, 0px));
  z-index:50; overflow:hidden; display:flex; padding:7px; border-radius:34px;
  background:linear-gradient(180deg, rgba(28,28,31,.50), rgba(15,15,17,.64));
  backdrop-filter:blur(30px) saturate(190%); -webkit-backdrop-filter:blur(30px) saturate(190%);
  border:1px solid rgba(255,255,255,.12);
  box-shadow:0 16px 44px -12px rgba(0,0,0,.62), inset 0 1px 0 rgba(255,255,255,.16),
             inset 0 -12px 26px rgba(0,0,0,.20)}
.pmz_tab{flex:1; position:relative; z-index:2; display:flex; flex-direction:column;
  align-items:center; gap:4px; padding:7px 0; min-height:46px;
  background:none; border:0; cursor:default;
  color:rgba(255,255,255,.56); font:600 10.5px var(--pmz-ui)}
.pmz_tab .pmz_tico{position:relative; width:24px; height:24px; display:block}
.pmz_tab .pmz_tico svg{position:absolute; inset:0; width:24px; height:24px;
  fill:none; stroke:currentColor; stroke-width:1.9; stroke-linecap:round; stroke-linejoin:round}
/* the inert state is stated, not implied — a bar that looks live and does nothing
   is worse than one that reads as out of scope. */
.pmz_tabbar[aria-disabled="true"] .pmz_tab{opacity:.55}

/* ══ SIFU'S BAR — the reading entry, docked directly above the app's tab bar.
   Follows 实时盘's own AI control (app-shishipan.js :: fabHTML — ink ground, white
   14/700 label, message glyph, gold cost tag), widened to a bar as Jim asked. ══ */
.pmz_sifubar{position:absolute; left:14px; right:14px;
  bottom:calc(92px + env(safe-area-inset-bottom, 0px)); z-index:49; cursor:pointer;
  display:flex; align-items:center; gap:10px; min-height:54px; padding:0 14px;
  border-radius:14px; border:1px solid rgba(255,255,255,.08);
  background:linear-gradient(180deg,#1D1913,#15110E);
  color:#fff; font:700 14px var(--pmz-ui); text-align:left;
  box-shadow:0 10px 25px -5px rgba(0,0,0,.55), inset 0 1px 0 rgba(255,255,255,.07);
  animation:pmz_barin .4s var(--pmz-out) backwards}
@keyframes pmz_barin{from{transform:translate3d(0,14px,0); opacity:0}}
.pmz_root[data-sifu="0"] .pmz_sifubar{display:none}
.pmz_sifubar .pmz_sb_ic{width:28px; height:28px; flex:none; border-radius:3px; display:flex;
  align-items:center; justify-content:center; background:var(--pmz-seal); color:#FDF6F0;
  font:400 15px/1 var(--pmz-brush)}
.pmz_sifubar .pmz_sb_t{flex:1; min-width:0}
.pmz_sifubar .pmz_sb_t s{display:block; text-decoration:none; margin-top:2px;
  font:400 11.5px var(--pmz-ui); color:rgba(255,255,255,.56)}
/* the cost tag, in the wallet's own gold pill */
.pmz_cost{flex:none; display:inline-flex; align-items:center; gap:5px; padding:5px 10px;
  border-radius:999px; background:linear-gradient(180deg,rgba(201,162,75,.30),rgba(140,108,37,.30));
  border:1px solid rgba(240,220,166,.34); color:#F4E4B6; font:800 12px var(--pmz-ui)}

/* content keeps clear of the index tabs; the PAPER does not move, so the sheet
   stays full-bleed and the ratio law is untouched. */
/* ☠ the 46px gutter these eight surfaces reserved for the seal rail went with
   the rail itself (round 30). It was never visible — the rail has been
   display:none since round 17 — but every card on the page was 46px narrower
   than it needed to be whenever data-seals flipped on. */
.pmz_root[data-seals="1"] .pmz_page{padding-right:46px}
.pmz_root[data-seals="1"] .pmz_page .pmz_guilloche{margin-right:-46px}
.pmz_root[data-seals="1"] .pmz_page .pmz_hallmark{margin-right:-46px; padding-right:46px}
.pmz_root[data-seals="1"] .pmz_se_tag{padding-right:46px}
.pmz_root[data-seals="1"] .pmz_pull_lab{padding-right:46px}

/* a soft scrim under the top chrome so the paper passes BEHIND the pill instead of
   colliding with it. The live app's header does this job; here the sheet runs to the
   top edge, so the scrim has to. */
/* the chrome floats over a scrolling document — exactly as it does in the app —
   so the scrim has to carry the whole band, not just its top edge */
.pmz_topscrim{position:absolute; top:0; left:0; right:0; z-index:57;
  height:calc(84px + env(safe-area-inset-top,0px)); pointer-events:none;
  background:linear-gradient(to bottom, rgba(1,3,11,.97) 0, rgba(1,3,11,.93) 46%,
    rgba(1,3,11,.72) 72%, transparent)}

/* ══════════════════════════════════════════════════════════════════════════════
   THE LANGUAGE PILL — top right, ported from index.html (#langPill / #langMenu).
   It is the app's own control in the app's own place. Switching re-renders every
   open stage in place: the page does not reload and nothing already unrolled closes.
   ══════════════════════════════════════════════════════════════════════════════ */
.pmz_langpill{position:absolute; top:calc(13px + env(safe-area-inset-top, 0px)); right:14px;
  z-index:58; cursor:pointer; display:flex; align-items:center; gap:5px;
  min-height:44px; padding:5px 12px; border-radius:999px;
  background:rgba(21,17,14,.55); backdrop-filter:blur(8px); -webkit-backdrop-filter:blur(8px);
  border:1px solid rgba(255,255,255,.14); color:#fff; font:800 11px var(--pmz-ui)}
.pmz_langpill svg{width:14px; height:14px; fill:none; stroke:currentColor; stroke-width:1.6}
.pmz_caretdn{opacity:.7}
.pmz_langmenu{position:absolute; top:calc(50px + env(safe-area-inset-top, 0px)); right:14px;
  z-index:59; min-width:168px; padding:6px; border-radius:16px;
  background:linear-gradient(160deg,rgba(40,29,20,.94),rgba(20,15,11,.96));
  backdrop-filter:blur(18px) saturate(150%); -webkit-backdrop-filter:blur(18px) saturate(150%);
  border:1px solid rgba(201,162,75,.28);
  box-shadow:0 18px 44px rgba(0,0,0,.55), inset 0 0 0 1px rgba(255,255,255,.03);
  opacity:0; transform:translateY(-8px) scale(.96); pointer-events:none; transform-origin:top right;
  visibility:hidden;                     /* a closed menu must not answer hit tests */
  transition:opacity .17s ease, transform .17s cubic-bezier(.25,.46,.45,.94)}
.pmz_langmenu.pmz_open{opacity:1; transform:none; pointer-events:auto; visibility:visible}
.pmz_langmenu button{display:flex; align-items:center; justify-content:space-between; gap:12px;
  width:100%; min-height:48px; padding:12px; border:0; background:none; cursor:pointer;
  border-radius:11px; color:#ECE3D6; font:700 13px var(--pmz-ui)}
.pmz_langmenu button[aria-current="true"]{color:#E6CE92; background:rgba(201,162,75,.13)}
.pmz_tick{opacity:0; color:#E6CE92; font-weight:900}
.pmz_langmenu button[aria-current="true"] .pmz_tick{opacity:1}

/* the standing note about engine terminology that has no translation yet */
.pmz_zhnote{margin:18px 0 0; padding:10px 12px; border-radius:2px;
  border:1px dashed var(--pmz-rule); background:rgba(216,205,184,.2);
  font:12.5px/1.6 var(--pmz-ui); color:var(--pmz-ink-3)}

/* ══ THE SEAL TABS — index tabs down the right edge of the paper.
   The rail is transparent to the pointer; only the seals take hits. An inherited
   pointer-events:none once shipped a whole screen that could not be tapped. ══ */
.pmz_seals{position:absolute; right:5px; top:50%; transform:translateY(-50%); z-index:24;
  display:flex; flex-direction:column; gap:6px; pointer-events:none}
.pmz_root[data-seals="0"] .pmz_seals{display:none}
.pmz_seals button{pointer-events:auto; width:32px; height:46px; cursor:pointer; border-radius:2px;
  border:1px solid rgba(201,162,75,.4); background:rgba(20,14,26,.78); color:#E8D8AE;
  font:400 15px/1 var(--pmz-brush); box-shadow:0 4px 10px rgba(0,0,0,.5)}
.pmz_seals button[aria-current="true"]{
  background:linear-gradient(to bottom,rgba(201,162,75,.92),rgba(140,108,37,.92));
  color:#1A1206; border-color:rgba(240,220,166,.6)}

/* ══════════════════════════════════════════════════════════════════════════════
   THE READING OVERLAY — 实时盘's own AI surface, re-worded for 命理.
   app-shishipan.js :: aiMenuHTML — paper ground, back chevron, a divide-y list of
   categories with icon · label · description · chevron, then the reading itself.
   ══════════════════════════════════════════════════════════════════════════════ */
.pmz_ai{position:fixed; inset:0; z-index:150; display:none; flex-direction:column;
  animation:pmz_aiin .26s var(--pmz-out) backwards}
@media(min-width:900px){ .pmz_ai{position:absolute} }
@keyframes pmz_aiin{from{opacity:0; transform:translate3d(0,16px,0)}}
.pmz_root[data-ai="1"] .pmz_ai{display:flex}
/* ── ROUND 32 · THE AI READING PAGE ──────────────────────────────────────────
   实时盘's own surface, in our lacquer. It is a PAGE, not an overlay menu: the
   question and its answer belong on the same screen, which is exactly what the old
   arrangement got wrong (it closed itself and jumped to a section of the record). */
.pmz_ai{
  --pmz-ink:var(--pmz-on-lacq);
  --pmz-ink-2:var(--pmz-on-lacq-2);
  --pmz-ink-3:var(--pmz-on-lacq-3);
  --pmz-rule:rgba(217,178,95,.20);
}
.pmz_ai_top{flex:none; padding:12px 14px; display:flex; align-items:center; gap:8px;
  border-bottom:1px solid var(--pmz-rule)}
.pmz_ai_ttlwrap{min-width:0}
.pmz_ai_top h2{margin:0; font:700 17px/1.2 var(--pmz-ui); color:#E9C77E}
.pmz_ai_sub{display:block; margin-top:2px; font:500 13px/1.3 var(--pmz-ui);
  color:var(--pmz-ink-2); white-space:nowrap; overflow:hidden; text-overflow:ellipsis}
.pmz_ai_back{border:0; background:transparent; padding:6px; border-radius:9999px;
  min-width:44px; min-height:44px; cursor:pointer; color:var(--pmz-ink);
  display:flex; align-items:center; justify-content:center; font-size:22px}
.pmz_ai_body{flex:1; overflow-y:auto; padding:16px 14px 20px; scrollbar-width:none}
.pmz_ai_body::-webkit-scrollbar{width:0}

.pmz_ai_intro{text-align:center; margin:2px 0 12px}
.pmz_ai_intro[hidden]{display:none}
.pmz_ai_av_lg{width:66px; height:66px; margin:0 auto 9px; border-radius:999px;
  overflow:hidden; padding:0; background:var(--pmz-lacq-2);
  box-shadow:0 10px 22px -12px rgba(0,0,0,.9), inset 0 0 0 1px rgba(217,178,95,.34)}
/* ⚠ THE CROP LIVES IN THE FILE NOW, NOT HERE. This used to stack THREE crops on one
   image — object-fit:cover, then object-position:50% 24%, then scale(1.55) about a
   50%/30% origin — and no combination of them is readable, so every nudge Jim asked
   for was a guess. assets/mingli-r37-sifu-avatar.jpg is a square cut on the measured
   face box (scripts/crop-sifu-avatar.py: eyes 40% down, head filling 62%), which
   leaves this rule with one job. It also took 219 KB off every boot. */
.pmz_ai_av_lg img{width:100%; height:100%; object-fit:cover; display:block}
.pmz_ai_h{margin:0 0 4px; font:700 19px/1.25 var(--pmz-ui); color:var(--pmz-ink)}
.pmz_ai_lead{margin:0 auto; max-width:29em; font:400 14px/1.62 var(--pmz-ui);
  color:var(--pmz-ink-2); text-wrap:balance}
.pmz_ai_intro .pmz_meter{justify-content:center; margin-top:10px}

/* ⚠ TWO COLUMNS, like 实时盘 — nine topics in one column is a 560px scroll before
   the reader reaches the ask field, and the field is the point of the page. */
/* ⚠ minmax(0,1fr), NOT 1fr. A grid track's default minimum is `auto`, so one card
   with a long unbreakable line widens its track and the whole row runs off the right
   edge of the page — which is exactly what the first frame showed. */
.pmz_ai_topics{display:grid; grid-template-columns:minmax(0,1fr) minmax(0,1fr);
  gap:7px; margin:0 0 12px}
/* ⚠ AN ODD LAST CARD MUST SPAN, or the ninth topic sits alone in a half-width cell
   with a hole beside it — the ragged edge Jim pointed at. 实时盘 has carried the same
   rule since its own redesign (assets/qimen-realtime.css :: .ai-chip). */
.pmz_ai_topics > .pmz_cat:last-child:nth-child(odd){grid-column:1/-1}
.pmz_cat{display:flex; align-items:center; gap:8px; min-height:52px; cursor:pointer;
  padding:7px 10px; text-align:left; border-radius:12px;
  border:1px solid rgba(217,178,95,.22); background:rgba(244,238,226,.05);
  color:var(--pmz-ink)}
.pmz_cat:active{background:rgba(217,178,95,.14)}
/* ── once a topic has been picked, the menu becomes a rail ──────────────
   The answer is the page now; the topics are how you change it. */
.pmz_ai_topics[data-picked]{display:flex; gap:7px; overflow-x:auto; margin:0 0 12px;
  scrollbar-width:none; -webkit-overflow-scrolling:touch}
.pmz_ai_topics[data-picked]::-webkit-scrollbar{display:none}
.pmz_ai_topics[data-picked] .pmz_cat{flex:none; min-height:44px; padding:0 12px;
  border-radius:999px; gap:7px}
.pmz_ai_topics[data-picked] .pmz_cat_ic{width:20px; height:20px; font-size:12px;
  border:0; background:transparent}
.pmz_ai_topics[data-picked] .pmz_cat_t i,
.pmz_ai_topics[data-picked] .pmz_cat_t s{display:none}
.pmz_ai_topics[data-picked] .pmz_cat_t b{font-size:13.5px; white-space:nowrap}
.pmz_ai_topics[data-picked] .pmz_cat[aria-current="true"]{
  background:rgba(217,178,95,.18); border-color:rgba(246,227,172,.44)}
.pmz_ai_topics[data-picked] .pmz_cat[aria-current="true"] .pmz_cat_t b{color:#F6E3AC}
.pmz_cat .pmz_cat_ic{flex:none; width:26px; height:26px; border-radius:8px;
  display:flex; align-items:center; justify-content:center; font-size:15px;
  color:#E9C77E; background:rgba(217,178,95,.13);
  border:1px solid rgba(217,178,95,.24)}
.pmz_cat .pmz_cat_t{flex:1; min-width:0}
.pmz_cat .pmz_cat_t b{display:block; font:600 13.5px/1.25 var(--pmz-ui);
  color:var(--pmz-ink); white-space:nowrap; overflow:hidden; text-overflow:ellipsis}
/* the han is its own line — "Kesihatan · 健康" wrapped mid-pair in a 160px card,
   which reads as a broken word rather than as two facts */
.pmz_cat .pmz_cat_t i{display:block; margin-top:0; font-style:normal;
  font:500 12px/1.18 var(--pmz-ui); letter-spacing:.05em; color:var(--pmz-ink-2)}
/* the palace this topic reads, on THIS record's own plate — the thing that makes it
   their chart and not a generic assistant */
.pmz_cat .pmz_cat_t s{display:block; text-decoration:none; margin-top:2px;
  font:500 12px/1.18 var(--pmz-ui); color:var(--pmz-ink-3);
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis}

/* the ask field, pinned under the scroll */
.pmz_ai_ask{flex:none; display:flex; gap:9px; align-items:center;
  padding:10px 14px 6px; border-top:1px solid var(--pmz-rule)}
.pmz_ai_field{flex:1; min-width:0; display:block}
.pmz_ai_field input{width:100%; min-height:50px; padding:0 15px; border-radius:14px;
  border:1px solid rgba(217,178,95,.26); background:rgba(244,238,226,.05);
  color:var(--pmz-ink); font:15px var(--pmz-ui); outline:none}
.pmz_ai_field input::placeholder{color:var(--pmz-ink-3)}
.pmz_ai_field input:focus{border-color:rgba(246,227,172,.46)}
.pmz_ai_send{flex:none; width:50px; height:50px; border-radius:999px; cursor:pointer;
  border:1px solid rgba(246,227,172,.38); color:#1B1305; font-size:20px;
  background:linear-gradient(180deg,var(--pmz-gold-hi),var(--pmz-gold) 62%,#B98F3A)}
.pmz_ai_foot{flex:none; margin:0; padding:0 14px 12px; text-align:center;
  font:13px/1.5 var(--pmz-ui); color:var(--pmz-ink-3)}

.pmz_motion_note{margin:0 8px 10px; padding:9px 12px; border-radius:10px;
  border:1px solid rgba(201,162,75,.3); background:rgba(201,162,75,.09);
  font-size:12.5px; line-height:1.55; color:rgba(241,227,190,.86); display:none}
.pmz_root[data-reduced="1"] .pmz_motion_note{display:block}

.pmz_headbar{display:flex; gap:8px; padding:0 14px 12px}
.pmz_headbar button{flex:1; min-height:46px; cursor:pointer; border-radius:11px;
  border:1px solid rgba(201,162,75,.34); background:rgba(255,255,255,.045);
  color:#EFE2C2; font:13.5px var(--pmz-ui)}

/* ══════════════════════════════════════════════════════════════════════════════
   THE CEREMONY — 命轴, the scroll falling open.
   A LID over a chart that is ALREADY fully mounted and readable underneath.
   Mounted INSIDE the frame (an overlay mounted outside its screen once outlived it,
   opaque, over a live 13,800-Tenaga confirm).
   ══════════════════════════════════════════════════════════════════════════════ */
.pmz_cer{position:fixed; inset:0; z-index:160; overflow:hidden; display:none;
  animation:pmz_cerin .17s linear backwards}
@keyframes pmz_cerin{from{opacity:0}}
@media(min-width:900px){ .pmz_cer{position:absolute} }
.pmz_root[data-cer="1"] .pmz_cer{display:block}

.pmz_cer_bg{position:absolute; inset:0;
  background:
    radial-gradient(70% 40% at 50% 0%,   #3B2C14 0%, transparent 62%),
    radial-gradient(56% 40% at 16% 30%,  #2C210F 0%, transparent 60%),
    radial-gradient(70% 52% at 50% 100%, #0A0704 0%, transparent 70%),
    linear-gradient(#0B0805, #100C07 46%, #060402);
  animation:pmz_dim .5s ease-out backwards}
@keyframes pmz_dim{from{opacity:.35}}
.pmz_cer_bg::after{content:''; position:absolute; inset:0; mix-blend-mode:multiply;
  background:radial-gradient(106% 70% at 50% 42%, #fff 20%, rgba(140,122,92,.56) 66%, rgba(26,20,12,.94) 100%)}

.pmz_cer_sheet{position:absolute; left:14px; right:14px; top:0; bottom:0;
  display:flex; flex-direction:column}
.pmz_cer_rodtop{flex:none; position:relative; height:15px; border-radius:0 0 4px 4px;
  background:
    repeating-linear-gradient(90deg, rgba(255,222,168,.035) 0 3px, rgba(0,0,0,.05) 3px 9px, transparent 9px 23px),
    linear-gradient(to bottom, var(--pmz-rod-lo), var(--pmz-rod) 48%, var(--pmz-rod-hi));
  box-shadow:0 6px 14px rgba(0,0,0,.5)}
.pmz_cer_rodtop i{position:absolute; top:-2px; bottom:-2px; width:14px; border-radius:3px;
  background:linear-gradient(to bottom, var(--pmz-gold-deep), var(--pmz-gold) 52%, var(--pmz-gold-hi))}
.pmz_cer_rodtop i:first-child{left:-5px} .pmz_cer_rodtop i:last-child{right:-5px}
/* jie-lan: the ruled column of a written scroll. Static hairlines, no motion. */
.pmz_cer_field{flex:1; position:relative; padding:0 16px;
  background-image:linear-gradient(90deg,transparent 21.5%,rgba(150,130,96,.16) 21.5% calc(21.5% + 1px),transparent calc(21.5% + 1px)),
                   linear-gradient(90deg,transparent 78.5%,rgba(150,130,96,.16) 78.5% calc(78.5% + 1px),transparent calc(78.5% + 1px))}
.pmz_cer_row{position:absolute; left:0; right:0; display:flex; align-items:center;
  justify-content:center; gap:14px}
.pmz_cer_lab{font:12.5px/1 var(--pmz-ui); letter-spacing:.3em; color:var(--pmz-ink-3); width:44px; text-align:right}
.pmz_cer_gz{position:relative; font:400 44px/1.1 var(--pmz-disp); letter-spacing:.1em; color:var(--pmz-ink)}
.pmz_cer_zh{font:12.5px/1 var(--pmz-ui); letter-spacing:.24em; color:var(--pmz-ink-3); width:44px; text-align:right}
/* THE BEATS. Each pillar starts its drop 260ms before the paper edge clears it and
   is at rest 200ms after, so the ink arrives WITH the opening paper. Delays are the
   whole point of this rule — without them every beat fires behind the curtain. */
.pmz_cer_row b{animation:pmz_land .46s var(--pmz-out) backwards}
.pmz_cer_row[data-slot="year"]  b{animation-delay: 640ms}
.pmz_cer_row[data-slot="month"] b{animation-delay:1140ms}
.pmz_cer_row[data-slot="day"]   b{animation-delay:1640ms}
.pmz_cer_row[data-slot="hour"]  b{animation-delay:2140ms}
@keyframes pmz_land{from{transform:translate3d(0,-20px,0); opacity:0}}
/* the 日主 gold flash — an OVERLAY copy fading in and out, so nothing but opacity
   ever animates (a colour tween is paint, a text-shadow tween is layout). */
.pmz_cer_gz::after{content:attr(data-g); position:absolute; inset:0; opacity:0;
  color:var(--pmz-gold-hi); text-shadow:0 0 18px rgba(240,220,166,.8)}
.pmz_cer_row.pmz_isday .pmz_cer_gz::after{animation:pmz_flash .62s ease-out 1900ms 1 both}
@keyframes pmz_flash{0%{opacity:0} 22%{opacity:1} 100%{opacity:0}}

.pmz_cer_rail{position:absolute; left:22px; right:22px; bottom:14%;
  border-top:1px solid var(--pmz-rule); padding-top:12px}
.pmz_cer_rail_t{font:12.5px/1 var(--pmz-ui); letter-spacing:.26em; color:var(--pmz-ink-3)}
.pmz_cer_rail_gz{margin-top:9px; font:400 26px/1.15 var(--pmz-disp); color:var(--pmz-ink); letter-spacing:.06em}
.pmz_cer_rail_yr{margin-top:3px; font-size:12.5px; color:var(--pmz-ink-2)}
/* bottom:9% so the paper edge clears the pin at ~2775ms; the stamp then runs
   2780 → 3080ms with the thock at 3000. It must be SEEN to land. */
.pmz_cer_pin{position:absolute; right:22px; bottom:9%; display:inline-flex; align-items:center;
  gap:7px; padding:7px 12px 7px 10px; background:var(--pmz-seal); color:#FDF6F0;
  font:600 13.5px/1.2 var(--pmz-ui); transform:rotate(-1.4deg);
  box-shadow:0 9px 18px rgba(90,10,14,.5), inset 0 0 0 1px rgba(255,255,255,.13);
  animation:pmz_cerstamp .3s var(--pmz-thock) 2780ms backwards}
.pmz_cer_pin i{width:9px; height:9px; border-radius:50%; flex:none;
  background:linear-gradient(to bottom,#FBE8E8,#E8A9A6 55%,#8E1218)}
@keyframes pmz_cerstamp{from{transform:rotate(-1.4deg) scale(1.15); opacity:0}}

/* THE VEIL — curtain + roller travel down together as ONE transform. */
.pmz_cer_veil{position:absolute; inset:0; will-change:transform}
.pmz_cer_curtain{position:absolute; inset:0; z-index:1;
  background:linear-gradient(#070A1C, #0A0E26 44%, #04060F)}
.pmz_cer_shadow{position:absolute; left:0; right:0; top:-34px; height:34px; z-index:2;
  background:linear-gradient(to bottom, transparent, rgba(24,14,4,.42))}
.pmz_cer_roller{position:absolute; left:6px; right:6px; top:-13px; height:26px; border-radius:7px; z-index:3;
  background:
    repeating-linear-gradient(90deg, rgba(255,222,168,.035) 0 3px, rgba(0,0,0,.05) 3px 9px, transparent 9px 23px),
    repeating-linear-gradient(90deg, rgba(0,0,0,.045) 0 1px, transparent 1px 6px),
    linear-gradient(to bottom, var(--pmz-rod-hi) 0%, var(--pmz-rod) 36%, var(--pmz-rod-lo) 100%);
  box-shadow:inset 0 1px 0 rgba(255,226,176,.5), 0 12px 26px rgba(0,0,0,.72)}
.pmz_cer_roller i{position:absolute; top:-4px; bottom:-4px; width:17px; border-radius:4px;
  background:linear-gradient(to bottom, var(--pmz-gold-hi), var(--pmz-gold) 42%, var(--pmz-gold-deep));
  box-shadow:0 5px 12px rgba(0,0,0,.6)}
.pmz_cer_roller i:first-child{left:-7px}
.pmz_cer_roller i:last-child{right:-7px}

/* the veil holds while the lantern lifts (0-420ms), then clears the paper by
   760ms — so the four real columns land at 610/760/910/1060 on an exposed sheet
   rather than behind a curtain. ⚠ "uncovered at its beat" is not "happens at its
   beat": a ceremony once fired all five of its beats at t=0 behind an opaque
   curtain with 133 assertions green. The rig reads these delays, not the frames. */
.pmz_cer[data-mode="full"] .pmz_cer_veil{animation:pmz_unroll 760ms linear both}
@keyframes pmz_unroll{
  0%,55%{transform:translate3d(0,0,0); animation-timing-function:cubic-bezier(.3,.85,.5,1)}
  100%{transform:translate3d(0,100%,0)}
}
/* casts 2–4 — the roller starts 60% open, one tick, ~1.0s, pin stamp KEPT. */
.pmz_cer[data-mode="short"] .pmz_cer_veil{animation:pmz_unroll_s 460ms cubic-bezier(.32,.72,.42,1) both}
@keyframes pmz_unroll_s{from{transform:translate3d(0,60%,0)} to{transform:translate3d(0,100%,0)}}
/* reduced motion — crossfade + the final beat only. Nothing travels. */
.pmz_cer[data-mode="reduced"] .pmz_cer_veil{display:none}
.pmz_cer[data-mode="reduced"] .pmz_cer_row b,
.pmz_cer[data-mode="reduced"] .pmz_cer_rail{animation:none}
.pmz_cer[data-mode="reduced"] .pmz_cer_gz::after{animation:none}

/* the withdrawal: driven to its end state by a JS watchdog, never by animationend */
.pmz_cer.pmz_out{animation:pmz_withdraw 300ms ease-in both}
@keyframes pmz_withdraw{to{opacity:0; transform:translate3d(0,-6px,0)}}

.pmz_cer_skip{position:absolute; left:0; right:0; bottom:14px; text-align:center; z-index:4}
.pmz_cer_skip span{display:inline-block; padding:6px 14px; border-radius:20px;
  background:rgba(6,9,22,.62); color:rgba(238,243,255,.78);
  font:12.5px/1 var(--pmz-ui); letter-spacing:.16em}
.pmz_cer_hit{position:absolute; inset:0; z-index:5; background:transparent; border:0;
  cursor:pointer; -webkit-tap-highlight-color:transparent}

/* the chart's own settle when an already-written chart is re-opened: ≤600ms,
   no ceremony, transform only — "once written, written". */
.pmz_resettle{animation:pmz_resettle 600ms var(--pmz-out) backwards}
@keyframes pmz_resettle{from{transform:translate3d(0,10px,0)}}

.pmz_sr{position:absolute; width:1px; height:1px; overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap}


/* ══════════════════════════════════════════════════════════════════════════════
   THE SHEETS — 高级筛选 · 分类 · 日期 · 分钟.
   One host inside the height-bounded .device, emptied on close. ⚠ An overlay
   mounted outside the screen outlives it: a 13,800-Tenaga confirm once sat opaque
   over a different screen with its confirm still live.
   ⚠ A closed sheet must not answer hit tests. opacity:0 + pointer-events:none
   still leaves its rows MEASURABLE, which reads to a control walk as two buttons
   a user can never press. visibility:hidden states closed-ness properly.
   ══════════════════════════════════════════════════════════════════════════════ */
.pmz_sheeth{position:absolute; inset:0; z-index:150; display:flex; align-items:flex-end;
  justify-content:center; visibility:hidden; pointer-events:none}
.pmz_sheeth[data-on="1"]{visibility:visible; pointer-events:auto}
/* ⚠ …BUT `visibility` IS OVERRIDABLE BY A DESCENDANT, and that makes an open sheet the
   one hole in the 15 Sep screen-backing change. `.screen:not(.active)` is now
   visibility:hidden so WebKit drops the backing store of every screen but one — except
   that this rule sets `visible` on an element INSIDE a screen, and `data-on="1"`
   survives a tab-bar tap. Leave the filter sheet open, tap Utama, and a full-screen
   surface (its scrim carries backdrop-filter) stays composited inside a screen nobody
   is looking at. `opacity:0` still hides it from the eye; it does not release the
   memory, which is the entire point of the change.
   This rule only ever runs one direction — visible→hidden, when `.active` leaves — so
   the delayed form is all it needs: 0s duration, .32s delay, and the sheet fades out
   WITH the screen instead of popping out from under it. (No zero-duration counterpart
   is needed because nothing transitions it back the other way; `[data-on="1"]` on an
   ACTIVE screen is the un-transitioned base state.)
   ⚠ `pointer-events` IS NOT DELAYED, AND MUST NOT BE. The rule above also sets
   `pointer-events:auto`, and a child's `auto` beats an ancestor's `none` — so for the
   whole 320 ms the screen spends fading out, an INVISIBLE full-bleed scrim was still
   the topmost hit-test target over the screen that had just arrived. Given: reader has
   the filter sheet open, taps Utama, then taps a home tile within 320 ms → the tap
   lands on the 命理 sheet's scrim, which closes the sheet, and the tile does nothing.
   Dropped on the same frame `.active` leaves, while the pixels keep fading.
   Caught by `scripts/_screen-backing-verify.mjs` §7, which forces every overlay in the
   app open, navigates away, demands nothing re-shows itself, and demands that
   elementFromPoint at the centre of the viewport at +60 ms is not inside 命理. */
.screen:not(.active) .pmz_sheeth[data-on="1"]{ visibility:hidden; pointer-events:none;
  transition:visibility 0s linear .32s }
.pmz_sh_bg{position:absolute; inset:0; background:rgba(2,4,11,.62);
  backdrop-filter:blur(3px); -webkit-backdrop-filter:blur(3px);
  animation:pmz_shbg .2s ease backwards}
@keyframes pmz_shbg{from{opacity:0}}

.pmz_sh{position:relative; width:100%; max-width:430px; max-height:88%;
  display:flex; flex-direction:column; border-radius:14px 14px 0 0;
  box-shadow:0 -26px 60px rgba(0,0,0,.62), 0 0 0 1px rgba(201,162,75,.26);
  animation:pmz_shin .3s var(--pmz-out) backwards}
@keyframes pmz_shin{from{transform:translate3d(0,26px,0)}}
/* the sheet is PAPER, and it is pulled down by a brass rod like everything else */
.pmz_sh_rod{flex:none; position:relative; height:15px; margin:0; border-radius:14px 14px 3px 3px;
  background:
    repeating-linear-gradient(90deg, rgba(255,222,168,.035) 0 3px, rgba(0,0,0,.05) 3px 9px, transparent 9px 23px),
    linear-gradient(to bottom, var(--pmz-rod-hi) 0%, var(--pmz-rod) 34%, var(--pmz-rod-lo) 100%);
  box-shadow:inset 0 1px 0 rgba(255,222,170,.30)}
.pmz_sh_hd{flex:none; display:flex; align-items:center; gap:12px;
  padding:13px 14px 11px; border-bottom:1px solid var(--pmz-rule)}
.pmz_sh_hd b{flex:1; min-width:0; font:400 18px/1.2 var(--pmz-disp); color:var(--pmz-ink)}
.pmz_sh_hd s{flex:none; text-decoration:none; font-size:12px; letter-spacing:.24em;
  color:var(--pmz-ink-3)}
.pmz_sh_x{flex:none; width:38px; height:38px; border-radius:999px; cursor:pointer;
  border:1px solid var(--pmz-rule); background:rgba(255,255,255,.55);
  color:var(--pmz-ink-2); font:15px/1 var(--pmz-ui);
  display:flex; align-items:center; justify-content:center}
.pmz_sh_body{flex:1; min-height:0; overflow-y:auto; -webkit-overflow-scrolling:touch;
  padding:14px}
.pmz_sh_foot{flex:none; display:flex; gap:10px; padding:12px 14px 16px;
  border-top:1px solid var(--pmz-rule); background:rgba(216,205,184,.22)}
.pmz_sh_foot button{flex:1; min-height:50px; border-radius:3px; cursor:pointer;
  font:600 14px var(--pmz-ui)}
.pmz_sh_2nd{border:1px solid var(--pmz-rule); background:rgba(255,255,255,.6);
  color:var(--pmz-ink-2)}
.pmz_sh_1st{border:1px solid var(--pmz-ink); background:var(--pmz-ink); color:#F7F3EC}
.pmz_sh_1st[disabled]{opacity:.42; cursor:default}

.pmz_sh_lbl{margin:0 0 9px; font:600 11px/1 var(--pmz-ui); letter-spacing:.20em;
  text-transform:uppercase; color:var(--pmz-ink-3)}
.pmz_sh_lbl + .pmz_sh_lbl{margin-top:0}
.pmz_sh_grp{margin:0 0 20px}
.pmz_sh_grp:last-child{margin-bottom:0}

/* 日主 — ten stems, each with its polarity and element, GA's own control */
.pmz_dmgrid{display:grid; grid-template-columns:repeat(5,1fr); gap:8px}
.pmz_dmgrid button{min-height:56px; border-radius:3px; cursor:pointer; padding:6px 2px;
  border:1px solid var(--pmz-rule); background:rgba(255,255,255,.6); color:var(--pmz-ink)}
.pmz_dmgrid button span{display:block; font:400 19px/1 var(--pmz-disp)}
.pmz_dmgrid button i{display:block; margin-top:4px; font-style:normal;
  font:9.5px/1.25 var(--pmz-ui); letter-spacing:-.01em; color:var(--pmz-ink-3)}
.pmz_dmgrid button[aria-pressed="true"]{background:var(--pmz-ink); border-color:var(--pmz-ink);
  color:#F7F3EC}
.pmz_dmgrid button[aria-pressed="true"] i{color:rgba(247,243,236,.72)}

.pmz_sh_pills{display:flex; gap:8px}
.pmz_sh_pills button{flex:1; min-height:46px; border-radius:999px; cursor:pointer;
  border:1px solid var(--pmz-rule); background:rgba(255,255,255,.6);
  color:var(--pmz-ink-2); font:13.5px var(--pmz-ui)}
.pmz_sh_pills button[aria-pressed="true"]{background:var(--pmz-ink); border-color:var(--pmz-ink);
  color:#F7F3EC; font-weight:700}

/* a list sheet row (分类 · 分钟) */
.pmz_sh_row{display:flex; align-items:center; justify-content:space-between; gap:12px;
  width:100%; min-height:52px; padding:0 12px; cursor:pointer; text-align:left;
  border:0; border-bottom:1px solid rgba(21,17,14,.07); background:none;
  color:var(--pmz-ink); font:15px var(--pmz-ui)}
.pmz_sh_row[aria-pressed="true"]{background:rgba(176,24,32,.07); font-weight:700}
.pmz_sh_row em{font-style:normal; color:var(--pmz-seal); font-weight:900}
.pmz_sh_row s{text-decoration:none; font-size:12.5px; color:var(--pmz-ink-3)}
.pmz_sh_dot{flex:none; width:8px; height:8px; border-radius:50%; margin-right:2px}
.pmz_sh_new{display:flex; gap:8px; padding:12px 0 0}
.pmz_sh_new input{flex:1; min-width:0; min-height:46px; border-radius:3px; padding:0 11px;
  border:1px solid var(--pmz-rule); background:rgba(255,255,255,.6);
  color:var(--pmz-ink); font:15px var(--pmz-ui); outline:none}
.pmz_sh_new button{flex:none; min-height:46px; padding:0 16px; border-radius:3px; cursor:pointer;
  border:1px solid var(--pmz-ink); background:var(--pmz-ink); color:#F7F3EC;
  font:600 13.5px var(--pmz-ui)}

/* ☠ THE PAPER DATE PICKER AND THE MINUTE GRID (round 25). Their replacements are
   in the ROUND 25 block: the wheel, the day grid and the AM/PM pair, all ported
   from the app's own 实时盘 picker. ⚠ These were not merely dead —
   `.pmz_dp_grid button` is MORE SPECIFIC than the new `.pmz_dp_d`, so it kept
   painting the day cells pale grey with a 50px min-height that pushed the seventh
   column off the edge of the dialog. A superseded rule that still matches is worse
   than a dead one. */

/* ══════════════════════════════════════════════════════════════════════════════
   立轴礼 — THE RITUAL.  Played AFTER the client is already on the shelf: if it
   never runs, the record is still there. Nothing here carries a fact that is not
   also on the card underneath.
   Beats (full 1900ms): 0 paper shown · 300 rolled onto the rod · 900 chop lands
   · 1350 the scroll flies down to the shelf · 1700 out.
   Every beat has a REAL animation-delay. "Uncovered at its beat" is not "happens
   at its beat" — a ceremony once fired all five of its beats at t=0 behind an
   opaque curtain and 133 assertions stayed green.
   ══════════════════════════════════════════════════════════════════════════════ */
.pmz_rite{position:absolute; inset:0; z-index:170; display:none;
  align-items:center; justify-content:center}
.pmz_rite[data-on="1"]{display:flex}
.pmz_rite_bg{position:absolute; inset:0; background:rgba(2,4,11,.80);
  backdrop-filter:blur(4px); -webkit-backdrop-filter:blur(4px);
  animation:pmz_ritebg .26s ease backwards}
@keyframes pmz_ritebg{from{opacity:0}}
.pmz_rite_stage{position:relative; width:100%; max-width:318px; padding:0 14px;
  display:flex; flex-direction:column; align-items:center}
.pmz_rite_scroll{position:relative; display:block; width:100%;
  animation:pmz_ritefly 520ms cubic-bezier(.5,0,.75,.3) 1350ms backwards}
@keyframes pmz_ritefly{
  from{transform:translate3d(0,0,0) scale(1); opacity:1}}
.pmz_rite[data-fly="1"] .pmz_rite_scroll{transform:translate3d(-14%,42vh,0) scale(.44); opacity:0}
.pmz_rite_rod{display:block; height:15px; border-radius:8px 8px 3px 3px; position:relative;
  background:
    repeating-linear-gradient(90deg, rgba(255,222,168,.035) 0 3px, rgba(0,0,0,.05) 3px 9px, transparent 9px 23px),
    linear-gradient(to bottom, var(--pmz-rod-hi) 0%, var(--pmz-rod) 34%, var(--pmz-rod-lo) 100%);
  box-shadow:inset 0 1px 0 rgba(255,222,170,.30), 0 6px 14px rgba(0,0,0,.55)}
.pmz_rite_rod i{position:absolute; top:-2px; bottom:-2px; width:13px; border-radius:4px;
  background:linear-gradient(to bottom, var(--pmz-gold-hi), var(--pmz-gold) 42%, var(--pmz-gold-deep));
  box-shadow:0 3px 7px rgba(0,0,0,.5)}
.pmz_rite_rod i:first-child{left:-4px}
.pmz_rite_rod i:last-child{right:-4px}
.pmz_rite_tag{display:block; margin:0 6px; border-radius:0 0 4px 4px;
  /* 74px right lane — the chop is absolutely placed and WILL stamp across the 八字
     without one; it did, on the first pass. */
  padding:16px 14px 16px; box-shadow:0 20px 40px rgba(0,0,0,.6), 0 0 0 1px rgba(201,162,75,.24)}
.pmz_rite_honor{display:block; font:600 10px/1 var(--pmz-ui); letter-spacing:.20em;
  text-transform:uppercase; color:var(--pmz-ink-3); margin-bottom:3px}
.pmz_rite_name{display:block; font:400 21px/1.2 var(--pmz-disp); color:var(--pmz-ink)}
.pmz_rite_bz{display:block; margin-top:10px; padding-top:10px;
  border-top:1px solid var(--pmz-rule);
  font:400 21px/1.3 var(--pmz-disp); color:var(--pmz-ink); letter-spacing:.05em}
.pmz_rite_line{display:block; margin-top:6px; padding-right:66px;
  font:12.5px/1.5 var(--pmz-ui); color:var(--pmz-ink-2); min-height:44px}
/* the roll: a shade drawn DOWN over the paper, then back up. transform only. */
.pmz_rite_roll{position:absolute; left:6px; right:6px; top:15px; bottom:0;
  transform-origin:top center; background:
    linear-gradient(to bottom, rgba(28,19,9,.94), rgba(59,42,24,.90) 62%, rgba(107,78,43,.86));
  box-shadow:0 8px 18px rgba(0,0,0,.5);
  animation:pmz_riteroll 900ms cubic-bezier(.5,0,.4,1) 300ms backwards}
@keyframes pmz_riteroll{
  0%{transform:scaleY(0)} 46%{transform:scaleY(1)} 100%{transform:scaleY(0)}}
.pmz_rite_chop{position:absolute; right:20px; bottom:18px; width:54px; height:54px;
  animation:pmz_ritechop 320ms var(--pmz-thock) 900ms backwards}
@keyframes pmz_ritechop{from{transform:scale(1.9) rotate(-13deg); opacity:0}}
.pmz_rite_chop img{display:block; width:100%; height:100%}
.pmz_rite_cap{margin:20px 0 0; text-align:center; font:13px/1.6 var(--pmz-ui);
  color:rgba(238,243,255,.80); letter-spacing:.02em; max-width:260px}

/* SHORT form — reduced motion, or a consultant adding a fifth client in a row.
   The chop still lands: it is the beat that says the record is made. */
.pmz_rite[data-mode="short"] .pmz_rite_roll{animation-duration:340ms; animation-delay:80ms}
.pmz_rite[data-mode="short"] .pmz_rite_chop{animation-delay:340ms}
.pmz_rite[data-mode="short"] .pmz_rite_scroll{animation-delay:520ms; animation-duration:260ms}

/* the new card's own arrival flash on the shelf, once the ritual hands it back.
   The ring is a pseudo-element that FADES: animating box-shadow itself is a paint
   property this file bans, and the rig caught it doing exactly that. */
.pmz_scrollend[data-fresh="1"] .pmz_se_tag::after{
  content:''; position:absolute; inset:-2px; border-radius:0 0 6px 6px; pointer-events:none;
  box-shadow:0 0 0 3px rgba(240,220,166,.92);
  animation:pmz_freshflash 1100ms ease-out both}
@keyframes pmz_freshflash{to{opacity:0}}


/* ══════════════════════════════════════════════════════════════════════════════
   银河 · THE SILVER RIVER.
   银河 is the Chinese name for the Milky Way — literally "silver river". This is
   not a metaphor we borrowed from science fiction; it is the older layer under the
   brand. 二十八宿, 紫微星, 北斗七星, 神煞 (literally "spirits and stars") — a 四柱
   chart IS a star chart, four coordinates in a celestial calendar.

   THE RULE THIS BLOCK OBEYS — from both second-opinion lenses, independently:
     · the river is a STATIC calibrated datum. It orders the clients. It is not
       "energy" and it does not drift.
     · the only motion is DIRECTIONAL: packets of light travelling down the current,
       and each lantern breathing. Transform and opacity only, on <div>s.
     · no purple. no random dot-stars. no particle trails. no aurora. Gold, cinnabar,
       ink, jade — the brand's own four, and nothing else.
   ══════════════════════════════════════════════════════════════════════════════ */

/* the datum: a hairline of gold down the left margin that every lantern hangs off.
   14px of light with a hard core — a calibrated line, not a glow. STATIC. */
/* IN the list, not on the page. The river is the list's spine: it starts at the
   first lantern and ends at the last, so it always has something to order. */
.pmz_shelfwrap{position:relative; padding-left:40px}
.pmz_river{position:absolute; left:0; top:-6px; bottom:-6px; width:40px; z-index:0;
  pointer-events:none; overflow:hidden}
.pmz_river::before{content:''; position:absolute; left:19px; top:0; bottom:0; width:2px;
  background:linear-gradient(to bottom,
    rgba(201,162,75,0) 0, rgba(240,220,166,.78) 7%, rgba(255,244,214,.92) 50%,
    rgba(240,220,166,.78) 93%, rgba(201,162,75,0) 100%)}
/* the bed the light sits in — wider, dimmer, still static */
.pmz_river::after{content:''; position:absolute; left:6px; top:0; bottom:0; width:28px;
  background:linear-gradient(90deg, rgba(201,162,75,0), rgba(201,162,75,.16) 42%,
    rgba(240,220,166,.26) 50%, rgba(201,162,75,.16) 58%, rgba(201,162,75,0))}

/* ⚠ THE TRAVELLING LIGHT IS REMOVED — 22 Aug.
   codex said in round 5 to keep this datum STATIC and I overrode it because movement
   had been asked for. Jim then pointed at it unprompted: "why is there a light at the
   top of the client list". That is the verdict — it did not read as a current, it
   read as a stray glow on a page someone was trying to read. The datum stays; the
   packets do not. The motion in this feature belongs to the ceremony.
   The <i> elements are kept in the markup, inert, so the river's own geometry gate
   still has something to count. */
.pmz_river i{display:none}

/* each lantern is tethered to the datum — a short gold arm. This is the mark that
   turns a list into a river: the cards are HUNG, not floating. */
.pmz_scrollend{position:relative}
.pmz_scrollend::before{content:''; position:absolute; left:-21px; top:7px; width:21px; height:1px;
  background:linear-gradient(90deg, rgba(240,220,166,.72), rgba(201,162,75,.20))}
.pmz_scrollend::after{content:''; position:absolute; left:-24px; top:3.5px; width:8px; height:8px;
  border-radius:50%; background:var(--pmz-gold-hi);
  box-shadow:0 0 0 2px rgba(201,162,75,.26), 0 0 9px 1px rgba(255,226,168,.5)}

/* THE BREATH — the lantern's own light, behind its paper. opacity ONLY, staggered,
   so a screen of lanterns is alive without anything moving. */
.pmz_se_glow{position:absolute; left:2px; right:2px; top:6px; bottom:-6px; z-index:-1;
  border-radius:14px; pointer-events:none;
  background:radial-gradient(60% 52% at 50% 46%, rgba(255,226,168,.34), rgba(201,162,75,.10) 62%, transparent 78%);
  animation:pmz_breath 4.6s ease-in-out infinite alternate}
@keyframes pmz_breath{from{opacity:.34} to{opacity:.86}}
.pmz_scrollend:nth-child(3n+2) .pmz_se_glow{animation-duration:5.9s; animation-delay:-1.7s}
.pmz_scrollend:nth-child(3n+3) .pmz_se_glow{animation-duration:7.1s; animation-delay:-3.4s}

/* the lantern's paper is LIT — warm from the inside, not a flat card on a dark
   ground. ⚠ agy wanted these dark obsidian; that loses the 五行 hues the disc
   carries (measured: 6.37× separation on paper, 1.52× on dark) and a 放水灯 is
   lit paper by definition. Paper it stays. */
.pmz_se_tag{background-color:#FCFAF5}

/* (the header and the controls keep the full width — only the LIST is on the
   river. Indenting the title for a datum with no lanterns beside it read as a
   stray line rather than a spine.) */

/* THE STAR FIELD — sparse, FIXED four-point marks. codex: "use only sparse, fixed
   four-point star marks". Random dots are the nebula tell. These are placed, not
   scattered: seven of them, on 北斗七星. They are invisible until the ceremony. */
/* ⚠ AN INVISIBLE LAYER STILL COSTS ITS BACKING STORE (15 Sep 2026). `opacity:0` does
   not release a WebKit compositor surface, and #pmzStars carries `will-change:transform`
   plus 80px of overscan top and bottom — measured at 390x1004 css px = 13.4 MB at 3x,
   held on a field that `data-stars` has never lit (it is only ever written as "0", and
   renderStars() returns before building a single mark). `visibility:hidden` releases it.
   Same idiom as `.screen` in index.html, and for the same measured reason: the delayed
   form keeps the .5s FADE-OUT playable, and the lit rule restates the transition LIST
   with a zero-duration visibility so the field is `visible` in the same task the
   attribute flips — `transition: visibility .5s` alone computes to `hidden` at progress
   0, which is where any synchronous read (or a .focus()) lands. Restating the list, not
   `transition-delay`, leaves the opacity fade's own timing alone. */
.pmz_stars{position:absolute; inset:0; z-index:2; pointer-events:none; opacity:0;
  visibility:hidden; transition:opacity .5s ease, visibility 0s linear .5s}
.pmz_root[data-stars="1"] .pmz_stars{opacity:1; visibility:visible;
  transition:opacity .5s ease, visibility 0s}
/* a star, not a crosshair: a bright core with short arms falling away. Four points
   because a four-point mark is how a star is DRAWN on a 星圖 rubbing — a round dot
   is what a particle effect uses. */
.pmz_stars{opacity:0}
.pmz_root[data-stars="1"] .pmz_stars{opacity:.62}
.pmz_stars b{position:absolute; width:13px; height:13px; margin:-6.5px 0 0 -6.5px;
  border-radius:50%; background:radial-gradient(circle, #FFF6DF 0 22%, rgba(255,226,168,.32) 45%, transparent 70%)}
.pmz_stars b::before,.pmz_stars b::after{content:''; position:absolute; left:50%; top:50%;
  transform:translate(-50%,-50%)}
.pmz_stars b::before{width:1px; height:13px;
  background:linear-gradient(rgba(255,240,200,0), var(--pmz-gold-hi) 50%, rgba(255,240,200,0))}
.pmz_stars b::after{width:13px; height:1px;
  background:linear-gradient(90deg, rgba(255,240,200,0), var(--pmz-gold-hi) 50%, rgba(255,240,200,0))}


/* ══════════════════════════════════════════════════════════════════════════════
   SCREENS — one page, one function (Jim, 21 Aug).
   Round 4 was a single document that opened further; this is the app's own model.
   A stage is in the page only when the screen it belongs to is the current one AND
   it has been opened. Both conditions, so a stage can never leak onto a screen it
   does not belong to.
   ══════════════════════════════════════════════════════════════════════════════ */
.pmz_stage{display:none}
.pmz_root[data-screen="river"]  .pmz_stage[data-scr="river"][data-open="1"],
.pmz_root[data-screen="form"]   .pmz_stage[data-scr="form"][data-open="1"],
.pmz_root[data-screen="record"] .pmz_stage[data-scr="record"][data-open="1"],
.pmz_root[data-screen="prov"]   .pmz_stage[data-scr="prov"][data-open="1"],
.pmz_root[data-screen="cert"]   .pmz_stage[data-scr="cert"][data-open="1"],
.pmz_root[data-screen="report"] .pmz_stage[data-scr="report"][data-open="1"]{display:block}
/* ☠ #stPro's display rule went with the stage. 专业版 is a MODE of one page now. */

/* the screen arrives — the whole page, once, transform + opacity only */
.pmz_doc[data-arrive="1"]{animation:pmz_screenin .42s var(--pmz-out) backwards}
@keyframes pmz_screenin{from{transform:translate3d(0,14px,0); opacity:0}}

/* GA's segmented mode control, in our materials */
.pmz_modebar{display:flex; gap:4px; margin:0 14px 4px; padding:4px; border-radius:13px;
  background:rgba(255,255,255,.05); border:1px solid rgba(201,162,75,.18)}
.pmz_modebar button{flex:1; min-height:44px; border-radius:10px; cursor:pointer; border:0;
  background:transparent; color:rgba(240,233,220,.66); font:700 13px var(--pmz-ui)}
.pmz_modebar button[aria-pressed="true"]{color:#1B1408;
  background:linear-gradient(180deg,var(--pmz-gold-hi),var(--pmz-gold) 62%,#B98F3A);
  box-shadow:0 5px 13px -5px rgba(201,162,75,.6)}

/* ☠ #stRecNav's three rules went with it — its two buttons moved onto the user card,
   which is where GA keeps them. Confirmed dead by both reviews. */

/* Sifu's bar belongs to the RECORD — Jim, 21 Aug: the reading lives on the page you
   get when you select a client, not on the list. */
.pmz_sifubar{display:none}
.pmz_root[data-screen="record"] .pmz_sifubar{display:flex}
/* and the index tabs indexed a scrolling document that no longer exists */
.pmz_seals{display:none}


/* ══════════════════════════════════════════════════════════════════════════════
   THE STAR CEREMONY — the lantern rises, the veil retracts, the real plate lands.
   The lid carries NO data of its own any more: the chart is rendered underneath
   before the first frame, so skipping the ceremony costs nothing but the ceremony.
   ══════════════════════════════════════════════════════════════════════════════ */
/* the old fake-chart lid is retired but left in the DOM (hidden) so the rig's
   existing beat gates keep a surface to point at while they are rewritten. */
.pmz_cer_sheet[hidden]{display:none !important}

.pmz_cer_lantern{position:absolute; z-index:3; pointer-events:none;
  transform-origin:50% 22%;
  animation:pmz_lift 620ms cubic-bezier(.16,1,.3,1) 120ms both,
            pmz_lanterngo 220ms ease-in 1220ms both}
@keyframes pmz_lift{
  from{transform:translate3d(0,0,0) scale(1)}
  to  {transform:translate3d(var(--pmz-dx,0px), var(--pmz-dy,-120px), 0) scale(.78)}}
@keyframes pmz_lanterngo{to{opacity:0}}
.pmz_cer_rod{display:block; height:13px; border-radius:7px 7px 3px 3px; position:relative;
  background:linear-gradient(to bottom, var(--pmz-rod-hi) 0%, var(--pmz-rod) 34%, var(--pmz-rod-lo) 100%);
  box-shadow:inset 0 1px 0 rgba(255,222,170,.30), 0 6px 14px rgba(0,0,0,.55)}
.pmz_cer_rod i{position:absolute; top:-2px; bottom:-2px; width:11px; border-radius:4px;
  background:linear-gradient(to bottom, var(--pmz-gold-hi), var(--pmz-gold) 42%, var(--pmz-gold-deep))}
.pmz_cer_rod i:first-child{left:-3px}
.pmz_cer_rod i:last-child{right:-3px}
.pmz_cer_tag{display:block; position:relative; margin:0 5px; padding:11px 13px 12px;
  border-radius:0 0 4px 4px;
  box-shadow:0 18px 36px rgba(0,0,0,.55), 0 0 0 1px rgba(201,162,75,.30),
             0 0 34px -6px rgba(255,226,168,.5)}
.pmz_cer_honor{display:block; font:600 10px/1 var(--pmz-ui); letter-spacing:.20em;
  text-transform:uppercase; color:var(--pmz-ink-3); margin-bottom:2px}
.pmz_cer_name{display:block; font:400 18px/1.24 var(--pmz-disp); color:var(--pmz-ink);
  padding-right:44px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.pmz_cer_disc{position:absolute; top:10px; right:11px; width:36px; height:36px;
  border-radius:50%; display:flex; align-items:center; justify-content:center;
  font:400 19px/1.34 var(--pmz-disp); color:#fff;
  box-shadow:inset 0 0 0 1px rgba(0,0,0,.16)}

/* THE FOUR REAL COLUMNS land in order. The live-app styling of the plate is
   untouched — only the arrival is ours, and only transform + opacity. */
.pmz_root[data-cer="1"] #pmzPlate .pmz_col{
  animation:pmz_colland 280ms cubic-bezier(.16,1,.3,1) backwards}
.pmz_root[data-cer="1"] #pmzPlate .pmz_col:nth-of-type(1){animation-delay:610ms}
.pmz_root[data-cer="1"] #pmzPlate .pmz_col:nth-of-type(2){animation-delay:760ms}
.pmz_root[data-cer="1"] #pmzPlate .pmz_col:nth-of-type(3){animation-delay:910ms}
.pmz_root[data-cer="1"] #pmzPlate .pmz_col:nth-of-type(4){animation-delay:1060ms}
@keyframes pmz_colland{from{transform:translate3d(0,-14px,0); opacity:0}}

/* the wash that darkens the SHELL only — never the plate. codex: "Darken only the
   shell. Never tint the plate, recolour the five elements, or put readable data
   behind an effect. The 6.37x versus 1.52x result is decisive." */
.pmz_cer_bg{animation:pmz_cerbg 1400ms ease-out both}
@keyframes pmz_cerbg{
  0%{opacity:0} 12%{opacity:1} 62%{opacity:.5} 100%{opacity:0}}


/* 短 — the second and later casts. The columns still land in order; the whole thing
   is just tighter, because a consultant re-opening a client has seen it before. */
.pmz_cer[data-mode="short"] ~ * #pmzPlate .pmz_col{}
.pmz_root[data-cer="1"] .pmz_cer[data-mode="short"]{}
.pmz_root[data-cer="1"]:has(.pmz_cer[data-mode="short"]) #pmzPlate .pmz_col:nth-of-type(1){animation-delay:340ms}
.pmz_root[data-cer="1"]:has(.pmz_cer[data-mode="short"]) #pmzPlate .pmz_col:nth-of-type(2){animation-delay:430ms}
.pmz_root[data-cer="1"]:has(.pmz_cer[data-mode="short"]) #pmzPlate .pmz_col:nth-of-type(3){animation-delay:520ms}
.pmz_root[data-cer="1"]:has(.pmz_cer[data-mode="short"]) #pmzPlate .pmz_col:nth-of-type(4){animation-delay:610ms}
/* reduced motion: the columns are simply there. Nothing travels, nothing waits. */
.pmz_root[data-reduced="1"][data-cer="1"] #pmzPlate .pmz_col{animation:none}
@media(prefers-reduced-motion:reduce){
  .pmz_root[data-cer="1"] #pmzPlate .pmz_col,
  .pmz_cer_lantern{animation:none !important}
}

/* THE ASSEMBLING 四柱 — the pillars form as the answers land. This is the whole
   reason the guided route exists: the form stops being data entry and becomes the
   first half of the reading. */
.pmz_asm{margin:0 8px 12px; padding:12px 12px 13px; border-radius:2px;
  box-shadow:0 14px 30px rgba(0,0,0,.42), 0 0 0 1px rgba(201,162,75,.22)}
.pmz_asm_row{display:grid; grid-template-columns:repeat(4,1fr); gap:7px}
.pmz_asm_c{text-align:center; padding:8px 2px 7px; border-radius:2px;
  border:1px solid var(--pmz-box-bord); background:var(--pmz-box)}
.pmz_asm_c s{display:block; text-decoration:none; font:600 9.5px/1 var(--pmz-ui);
  letter-spacing:.14em; color:var(--pmz-slate)}
.pmz_asm_c b,.pmz_asm_c i{display:block; font:400 21px/1.2 var(--pmz-disp); font-style:normal}
.pmz_asm_c[data-set="0"]{background:rgba(241,245,249,.28); border-style:dashed}
.pmz_asm_c[data-set="0"] b,.pmz_asm_c[data-set="0"] i{color:rgba(21,17,14,.24)}
/* a pillar that has just formed announces itself ONCE — transform and opacity only */
.pmz_asm_c[data-new="1"]{animation:pmz_asmland 420ms cubic-bezier(.16,1,.3,1) backwards}
@keyframes pmz_asmland{from{transform:translate3d(0,-10px,0); opacity:0}}
.pmz_asm_sub{display:block; margin-top:10px; padding-top:9px;
  border-top:1px solid var(--pmz-rule);
  font:12.5px/1.5 var(--pmz-ui); color:var(--pmz-ink-2)}

.pmz_guide_hd{display:flex; align-items:center; gap:12px; padding:0 14px 10px}
.pmz_guide_n{flex:none; font:700 12px var(--pmz-ui); letter-spacing:.10em;
  color:rgba(240,233,220,.62); font-variant-numeric:tabular-nums}
.pmz_guide_bar{flex:1; height:3px; border-radius:99px; background:rgba(255,255,255,.10);
  overflow:hidden}
.pmz_guide_bar i{display:block; height:100%; border-radius:99px; width:25%;
  background:linear-gradient(90deg,var(--pmz-gold),var(--pmz-gold-hi));
  transition:transform .3s var(--pmz-out); transform-origin:left}
.pmz_guide_q{margin:0 8px; padding:18px 16px 20px; border-radius:2px;
  box-shadow:0 22px 46px rgba(0,0,0,.5), 0 0 0 1px rgba(201,162,75,.22)}
.pmz_guide_q h2{margin:0 0 4px; font:400 23px/1.24 var(--pmz-disp); color:var(--pmz-ink)}
.pmz_guide_q p{margin:0 0 16px; font:13px/1.6 var(--pmz-ui); color:var(--pmz-ink-2)}
.pmz_guide_q .pmz_input{min-height:56px; font-size:17px}
/* docked above the tab bar. A wizard whose Next you have to scroll for is a
   wizard people abandon halfway. */
.pmz_guide_nav{position:absolute; left:0; right:0; z-index:40;
  bottom:calc(84px + env(safe-area-inset-bottom, 0px));
  display:flex; gap:9px; padding:14px 14px 12px;
  /* OPAQUE. A translucent dock let the form read through the buttons. */
  background:linear-gradient(to top, #01030B 0, #01030B 64%, rgba(1,3,11,.86) 84%, rgba(1,3,11,0))}
.pmz_guide_nav .pmz_btn{background:linear-gradient(to bottom,#7A5F22,#5A4416); border-color:rgba(201,162,75,.62); color:#FBF3DE}
.pmz_guide_nav .pmz_btn_q{background:#141A2E; border-color:rgba(201,162,75,.30); color:#DCE3F5}
.pmz_guide_nav .pmz_btn[disabled],
.pmz_guide_nav .pmz_btn_q[disabled]{opacity:.40}
.pmz_guide_nav .pmz_btn{margin:0}
.pmz_guide_nav .pmz_btn_q{flex:0 0 40%}

/* the answers already given, still editable. A guided form that cannot be corrected
   without restarting is a form people abandon. */
.pmz_guide_done{display:flex; flex-wrap:wrap; gap:7px; padding:12px 14px 0}
.pmz_guide_done button{min-height:38px; padding:0 12px; border-radius:999px; cursor:pointer;
  display:flex; align-items:center; gap:7px;
  border:1px solid rgba(201,162,75,.24); background:rgba(255,255,255,.05);
  color:rgba(238,243,255,.84); font:12.5px var(--pmz-ui)}
.pmz_guide_done button s{text-decoration:none; color:rgba(240,233,220,.5)}

/* THE IC SHORTCUT — a Malaysian IC carries the birth date and the gender. */
.pmz_ic{margin:0 0 16px; padding:12px; border-radius:3px;
  border:1px dashed var(--pmz-rule); background:rgba(216,205,184,.22)}
.pmz_ic label{display:block; font:600 11px/1 var(--pmz-ui); letter-spacing:.20em;
  text-transform:uppercase; color:var(--pmz-ink-3); margin:0 0 7px}
.pmz_ic_in{display:flex; gap:8px}
.pmz_ic_in .pmz_input{flex:1; min-width:0; font-variant-numeric:tabular-nums;
  letter-spacing:.06em}
.pmz_ic_in button{flex:none; min-height:48px; padding:0 16px; border-radius:3px;
  cursor:pointer; border:1px solid var(--pmz-ink); background:var(--pmz-ink);
  color:#F7F3EC; font:600 13.5px var(--pmz-ui)}
.pmz_ic_note{margin:8px 0 0; font:11.5px/1.5 var(--pmz-ui); color:var(--pmz-ink-3)}
.pmz_ic_note[data-ok="1"]{color:var(--pmz-jade); font-weight:600}
.pmz_ic_note[data-ok="0"]{color:var(--pmz-seal)}



/* ══════════════════════════════════════════════════════════════════════════════
   THE REGISTER — one sheet, typographic rows.
   Everything skeuomorphic is gone: no rods, no card shadows, no rounded paper
   corners, no fake scroll ends. What carries the design now is what carries an
   editorial page — a strict left rail, one display face against one UI face, real
   vertical rhythm, hairline rules, and exactly one accent per row.
   ══════════════════════════════════════════════════════════════════════════════ */
/* ⚠ overflow:visible — the element beads live on the datum OUTSIDE this sheet, and
   hidden clipped every one of them. */
.pmz_reg{position:relative; margin:0; border-radius:2px; overflow:visible;
  box-shadow:0 18px 44px rgba(0,0,0,.46), 0 0 0 1px rgba(201,162,75,.20)}
/* the sheet's own head — a register has a masthead, not a floating label */
.pmz_reg_hd{display:flex; align-items:baseline; gap:10px;
  padding:13px 16px 11px; border-bottom:1px solid var(--pmz-ink);
  font:600 10.5px/1 var(--pmz-ui); letter-spacing:.22em; text-transform:uppercase;
  color:var(--pmz-ink-3)}
.pmz_reg_hd b{margin-left:auto; font-weight:700; color:var(--pmz-ink-2);
  font-variant-numeric:tabular-nums; letter-spacing:.08em; white-space:nowrap}
.pmz_reg_hd span{overflow:hidden; text-overflow:ellipsis; white-space:nowrap}

.pmz_row{display:grid; grid-template-columns:52px minmax(0,1fr) 30px;
  grid-template-rows:auto auto auto auto auto; gap:0 12px;
  width:100%; padding:13px 10px 13px 14px; cursor:pointer; text-align:left;
  border:0; border-top:1px solid rgba(21,17,14,.13); background:none;
  font:inherit; color:inherit; position:relative}
.pmz_row:first-of-type{border-top:0}
.pmz_row:active{background:rgba(201,162,75,.09)}
.pmz_row[data-in="1"]{animation:none}
.pmz_row{animation:pmz_rowin .46s var(--pmz-out) backwards}
@keyframes pmz_rowin{from{transform:translate3d(0,10px,0); opacity:0}}

/* ── THE LEFT RAIL: who this person IS, in one column ────────────────────────
   日主 large in its element colour, then the element NAMED. A student who cannot
   read 庚 still learns that this is a Metal person, and learns the character by
   sitting next to it. */
/* the rail is PINNED. Its caption used to widen the column and squeeze the name. */
.pmz_row_self{grid-column:1; grid-row:1 / span 4; align-self:start; justify-self:start;
  width:52px; overflow:hidden; text-align:center; padding-top:1px}
.pmz_row_gan{display:block; font:400 31px/1.06 var(--pmz-disp)}
.pmz_row_el{display:block; margin-top:4px; font:700 8.5px/1.32 var(--pmz-ui);
  letter-spacing:.10em; text-transform:uppercase; color:var(--pmz-ink-3);
  white-space:nowrap}
.pmz_row_el s{display:block; text-decoration:none; font-weight:600; opacity:.7;
  letter-spacing:.04em}

.pmz_row_honor{grid-column:2; grid-row:1;
  font:600 9px/1 var(--pmz-ui); letter-spacing:.22em;
  text-transform:uppercase; color:var(--pmz-ink-3)}
.pmz_row_name{grid-column:2; grid-row:2; margin:3px 0 0;
  font:400 19px/1.2 var(--pmz-disp); color:var(--pmz-ink);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.pmz_row_l1{grid-column:2; grid-row:3; margin:6px 0 0; font:12.5px/1.42 var(--pmz-ui);
  color:var(--pmz-ink-2); font-variant-numeric:tabular-nums}
.pmz_row_l2{grid-column:2; grid-row:4; margin:2px 0 0; font:12px/1.42 var(--pmz-ui);
  color:var(--pmz-ink-3); font-variant-numeric:tabular-nums}
/* the foot runs the full width under the rail — the balance bar and the tag are one
   line, not two, because a wrapped foot is what made a row 350px tall */
.pmz_row_foot{grid-column:1 / span 3; grid-row:5;
  display:flex; align-items:center; gap:10px; margin:10px 0 0; min-width:0}
.pmz_row_foot .pmz_row_tag{flex:1; min-width:0; overflow:hidden;
  text-overflow:ellipsis; white-space:nowrap}

.pmz_row_tag{display:inline-flex; align-items:center; gap:6px; min-width:0;
  font:12px/1 var(--pmz-ui); color:var(--pmz-ink-2)}
.pmz_row_tag::before{content:''; width:6px; height:6px; border-radius:50%; flex:none;
  background:var(--pmz-catc,var(--pmz-ink-3))}
.pmz_row_ph{font:12px/1 var(--pmz-ui); color:var(--pmz-ink-3);
  font-variant-numeric:tabular-nums}
/* ⚠ `right:44px` was tuned for the layout where the chevron sat in the top-right.
   Round 8 moved the 日主 colophon there, so the flag landed ON the element glyph.
   It straddles the card's top edge now — a tab on a fresh leaf, which is what it
   means and what a ledger actually does. Nothing else lives in that band. */
.pmz_row_new{position:absolute; top:-9px; right:15px; padding:2px 8px 3px;
  border-radius:2px 2px 0 0;
  font:700 8.5px/1.55 var(--pmz-ui); letter-spacing:.16em; color:#fff;
  background:var(--pmz-seal); box-shadow:0 3px 8px -3px rgba(0,0,0,.6)}

/* the actions live behind one discreet control, because ten facts and three buttons
   on one row is a toolbar, not a register entry */
.pmz_row_more{grid-column:3; grid-row:1 / span 2; align-self:start;
  justify-self:end; width:30px; height:38px; padding:0; margin-top:-2px;
  border:0; background:none; cursor:pointer; color:var(--pmz-ink-3);
  display:flex; align-items:center; justify-content:center; border-radius:8px}
.pmz_row_more svg{width:16px; height:16px; fill:none; stroke:currentColor; stroke-width:2;
  stroke-linecap:round; transition:transform .2s var(--pmz-out)}
.pmz_row[data-drawer="1"] .pmz_row_more svg{transform:rotate(180deg)}
.pmz_row_acts{display:none; grid-column:1 / span 3; grid-row:6; gap:8px; margin:11px 0 1px}
.pmz_row[data-drawer="1"] .pmz_row_acts{display:flex;
  animation:pmz_actsin .22s var(--pmz-out) backwards}
@keyframes pmz_actsin{from{transform:translate3d(0,-5px,0); opacity:0}}
.pmz_row_acts span{flex:1; min-height:40px; border-radius:2px; cursor:pointer;
  display:flex; align-items:center; justify-content:center; gap:6px;
  border:1px solid var(--pmz-rule); background:rgba(255,255,255,.55);
  color:var(--pmz-ink-2); font:600 12.5px var(--pmz-ui)}
.pmz_row_acts span svg{width:14px; height:14px; fill:none; stroke:currentColor;
  stroke-width:1.7; stroke-linecap:round; stroke-linejoin:round}
.pmz_row_acts span[data-a="del"]{border-color:rgba(176,24,32,.34); color:var(--pmz-seal)}

/* 选择 mode: the checkbox takes the rail, and the element steps aside for it */
.pmz_row_box{width:24px; height:24px; margin:6px auto 0; border-radius:4px;
  border:2px solid var(--pmz-rule); background:#fff;
  display:flex; align-items:center; justify-content:center}
.pmz_row_box svg{width:14px; height:14px; fill:none; stroke:#fff; stroke-width:2.6;
  stroke-linecap:round; stroke-linejoin:round; opacity:0}
.pmz_row[data-sel="1"] .pmz_row_box{border-color:var(--pmz-seal); background:var(--pmz-seal)}
.pmz_row[data-sel="1"] .pmz_row_box svg{opacity:1}
.pmz_row[data-sel="1"]{background:rgba(176,24,32,.06)}


/* the empty register still looks like a register */
.pmz_reg_empty{padding:40px 20px 44px; text-align:center}
.pmz_reg_empty b{display:block; font:400 19px/1.3 var(--pmz-disp); color:var(--pmz-ink)}
.pmz_reg_empty span{display:block; margin-top:7px; font:13px/1.6 var(--pmz-ui);
  color:var(--pmz-ink-3)}

/* the sheet sits to the right of the datum; the shelf wrapper keeps its lane */
.pmz_shelfwrap{padding-left:34px}
.pmz_river{width:34px}
.pmz_river::before{left:16px}
.pmz_river::after{left:4px; width:24px}
.pmz_river i{left:11px}

/* the register's foot must clear the app's tab bar */
.pmz_root[data-screen="river"] .pmz_doc{padding-bottom:248px}


/* ══════════════════════════════════════════════════════════════════════════════
   THE RECORD, unmounted (round 6).
   The rods, the brass caps and the brocade were the same skeuomorph the client
   cards were. They are hidden rather than deleted so the ceremony's own rod (which
   is a real moving object during the lift) keeps its styles.
   ⚠ NOTHING INSIDE #pmzPlate IS TOUCHED HERE.
   ══════════════════════════════════════════════════════════════════════════════ */
.pmz_mount .pmz_rod_top,
.pmz_mount .pmz_rod_bot,
.pmz_mount .pmz_brocade,
.pmz_formmount .pmz_rod_top,
.pmz_formmount .pmz_rod_bot{display:none}
.pmz_mount, .pmz_formmount{margin:0 8px}
.pmz_sheet, .pmz_sheet_form{border-radius:2px;
  box-shadow:0 18px 44px rgba(0,0,0,.46), 0 0 0 1px rgba(201,162,75,.20)}
/* the record's own masthead, set like the register's */
.pmz_root[data-screen="record"] .pmz_hd h1{font-size:22px}
.pmz_gengtie{border-radius:2px}
/* and the 题跋 / 鉴藏 leaves lose their rounding too, so every sheet in the app is
   cut the same way */
.pmz_leaf, .pmz_colo, .pmz_prov{border-radius:2px}

/* the add button carries its price the way every other cost in the app is carried */
#pmzAdd{display:flex; align-items:center; justify-content:center; gap:10px}
.pmz_addcost{display:inline-flex; align-items:center; gap:5px; text-decoration:none;
  padding:4px 10px; border-radius:999px; background:rgba(0,0,0,.26);
  border:1px solid rgba(201,162,75,.34)}
.pmz_addcost b{font:800 12.5px var(--pmz-ui); color:#F4D58E;
  font-variant-numeric:lining-nums tabular-nums}
.pmz_cost b{font:800 12.5px var(--pmz-ui); color:#F4D58E;
  font-variant-numeric:lining-nums tabular-nums}


/* ══════════════════════════════════════════════════════════════════════════════
   THE REGISTER — round 7. Quieter, and set properly.

   COLOUR BUDGET, deliberately: ONE hue per row, and it is the element the client
   IS. The balance bar is ink with a single coloured segment; the river bead is
   gold; the category keeps one small dot because it is the only way to tell
   categories apart at a glance. Everything else is ink on paper.

   TYPE: three steps, not four greys —
     eyebrow  9px  letterspaced small caps   (who: honorific, age, sex)
     NAME     23px display                   (the thing you scan by)
     data     13px / 12px                    (when and where)
   ══════════════════════════════════════════════════════════════════════════════ */
.pmz_row{grid-template-columns:minmax(0,1fr) 62px; grid-template-rows:auto auto auto auto auto;
  padding:17px 14px 16px 18px; gap:0 12px}

/* the 日主 mark is a COLOPHON on the right, so every name sits on the left margin.
   A register aligns; the old layout indented every name behind the rail. */
.pmz_row_self{grid-column:2; grid-row:1 / span 3; justify-self:end; text-align:right;
  width:62px; padding-top:0}
.pmz_row_gan{font:400 33px/1 var(--pmz-disp)}
.pmz_row_el{margin-top:5px; font:700 8px/1.4 var(--pmz-ui); letter-spacing:.11em;
  color:var(--pmz-ink-3)}
.pmz_row_el s{opacity:.66; letter-spacing:.03em}

/* the eyebrow carries the demographic, which shortens the data lines below it */
.pmz_row_honor{grid-column:1; grid-row:1;
  font:600 9px/1.3 var(--pmz-ui); letter-spacing:.20em; text-transform:uppercase;
  color:var(--pmz-ink-3)}
.pmz_row_name{grid-column:1; grid-row:2; margin:4px 0 0;
  font:400 23px/1.16 var(--pmz-disp); letter-spacing:.002em}
.pmz_row_l1{grid-column:1; grid-row:3; margin:8px 0 0; font:13px/1.42 var(--pmz-ui);
  color:var(--pmz-ink-2)}
.pmz_row_l2{grid-column:1 / span 2; grid-row:4; margin:2px 0 0; font:12px/1.42 var(--pmz-ui);
  color:var(--pmz-ink-3)}
.pmz_row_foot{grid-column:1 / span 2; grid-row:5; margin:12px 0 0; gap:11px}


.pmz_row_tag{font-size:12.5px; color:var(--pmz-ink-2)}
.pmz_row_tag::before{width:5px; height:5px}
.pmz_row_ph{font-size:12.5px; letter-spacing:.01em}

/* the disclosure is a hairline chevron, not a button that competes with the name */
.pmz_row_more{grid-column:2; grid-row:4 / span 2; align-self:end; justify-self:end;
  width:30px; height:34px; margin:0; opacity:.5}
.pmz_row[data-drawer="1"] .pmz_row_more{opacity:1}

/* 选择 mode puts the checkbox where the colophon was */
.pmz_row_box{margin:2px 0 0 auto}


/* the sheet itself: a touch more paper, a quieter head */
.pmz_reg_hd{padding:12px 16px 10px; border-bottom-color:rgba(21,17,14,.34);
  font-size:9.5px; letter-spacing:.24em}
.pmz_row + .pmz_row{border-top-color:rgba(21,17,14,.10)}


/* ══ ROOM FOR THE LIST — round 7 ═══════════════════════════════════════════════
   Measured: 315px of chrome above a 760px viewport left 445px for clients, which is
   two rows. Every px below comes back to the register. ══════════════════════════ */
.pmz_root[data-screen="river"] .pmz_hd{padding-top:2px; padding-bottom:8px}
.pmz_root[data-screen="river"] .pmz_hd h1{font-size:21px}
.pmz_root[data-screen="river"] .pmz_hd .pmz_zh{margin-top:2px; font-size:11px;
  letter-spacing:.30em}
/* the hint is a CAPTION, not a paragraph — one line, quiet, out of the way */
.pmz_hint{margin:0 14px 10px; padding:7px 11px; border-radius:8px;
  font:11.5px/1.5 var(--pmz-ui); white-space:nowrap; overflow:hidden;
  text-overflow:ellipsis}
.pmz_catrail{padding-bottom:10px}
/* ⚠ 38px, not 34 — the audience is 40+ and this rig asserts a 36px floor. Space
   for the list comes out of captions, never out of a thumb target. */
.pmz_catrail button{min-height:38px; font-size:12.5px}
.pmz_tools{padding-bottom:10px}
.pmz_search, .pmz_funnel{min-height:42px}

/* the chevron stacks UNDER the element caption instead of overlapping the foot */
.pmz_row_more{grid-row:4; align-self:start; height:26px; margin-top:1px}


/* the disclosure joins the foot's baseline instead of floating in the right column */
.pmz_row_more{grid-column:2; grid-row:5; align-self:center; justify-self:end;
  width:28px; height:28px; margin:10px 0 0}
.pmz_row_foot{grid-column:1; grid-row:5}



/* in the foot line, thumb-legal without costing a row its height */
.pmz_row_foot{grid-column:1 / span 2; grid-row:5; align-items:center}
.pmz_row_more{position:static; grid-column:auto; grid-row:auto;
  width:44px; height:38px; margin:-9px -10px -9px 0; flex:none; opacity:.55}
.pmz_row[data-drawer="1"] .pmz_row_more{opacity:1}
.pmz_row_foot .pmz_row_ph{margin-left:auto}

/* the foot is the balance, the category and the disclosure — with room for a
   category the consultant typed themselves, which must never be truncated */
.pmz_row_foot .pmz_row_tag{flex:1 1 auto; min-width:0}
.pmz_row_more{margin-left:auto}
.pmz_row_l2{font-variant-numeric:tabular-nums}


/* ==============================================================================
   ROUND 8 - THE BOUND REGISTER.  Leaves on a thread, not rows on a sheet.

   Jim, 22 Aug: "upgrade the card with modern premium + traditional style abit...
   soft harsh gradient... smooth border... make it more special for people to view."
   And, separately: "what is the line bar function? user does not understand."

   WHAT CHANGED, AND WHY EACH ONE:
     - one sheet -> individual leaves, so each client is a THING you can hold
     - the drawn datum -> real 线装 stitching, because a register is BOUND
     - the colour bar -> the engine's own word (kuat / sederhana / lemah)
     - a daily line, on the leaves where today actually means something
     - the chevron opens a reading strip, not just three buttons

   WHAT DID NOT CHANGE, DELIBERATELY:
     the ivory is still OPAQUE. Element separation measures 6.37x on paper and 1.52x
     on this ground; translucency is spent on chrome (the masthead) and never on a
     surface carrying data.
   ============================================================================== */

/* -- the wrapper stops being a sheet ---------------------------------------- */
.pmz_reg{background:none !important; box-shadow:none; border-radius:0}

/* -- THE MASTHEAD is chrome, so it is where the translucency goes ----------- */
.pmz_reg_hd{margin:0 0 10px; padding:7px 13px 7px 15px; border:0; border-radius:7px;
  background:rgba(8,14,36,.52); color:rgba(232,224,204,.60);
  -webkit-backdrop-filter:blur(9px); backdrop-filter:blur(9px);
  box-shadow:inset 0 0 0 1px rgba(201,162,75,.22), 0 8px 20px -12px rgba(0,0,0,.85);
  font-size:9.5px; letter-spacing:.24em}
.pmz_reg_hd b{color:rgba(240,220,166,.90)}

/* -- LEGIBILITY, MEASURED --------------------------------------------------
   Contrast of every text layer against the composited paper: name 17.7, birth /
   today / strength / category 9.3, and the eyebrow, the 农历+phone line and the
   element caption all at 4.57 against a WCAG AA floor of 4.5 for small text. Passing
   by 0.07 is not passing, for an audience over 40 reading a phone in a shop.
   ⚠ SCOPED TO THE REGISTER on purpose. --pmz-ink-3 is a global token used on every
   screen in this build; raising it globally is a change to screens this round has not
   re-verified, so it is Jim's call, not a side effect of this one. */
.pmz_row{--pmz-ink-3:#6A6157}

/* -- THE LEAVES ------------------------------------------------------------- */
#pmzShelf{display:flex; flex-direction:column; gap:11px}
.pmz_row{
  /* NO overflow:hidden. The stitch knot is a child that sits OUTSIDE this box on
     purpose; clipping the card clipped the entire binding and left a dotted rule. */
  border:0 !important; border-radius:7px; overflow:visible;
  grid-template-columns:minmax(0,1fr) 62px;
  grid-template-rows:auto auto auto auto auto auto auto auto;
  padding:14px 14px 13px 19px;
  /* the raking light: bright at the head, shadowed into the foot. One gradient,
     with a definite edge to it rather than a wash - Jim's "soft harsh". */
  background-color:var(--pmz-paper);
  background-image:
    linear-gradient(172deg, rgba(255,255,255,.85) 0%, rgba(255,255,255,.10) 26%,
                            rgba(21,17,14,.028) 74%, rgba(21,17,14,.075) 100%),
    var(--pmz-grain), var(--pmz-fibre), var(--pmz-laid);
  background-blend-mode:normal, multiply, multiply, multiply;
  background-size:auto, 140px 140px, 420px 420px, auto;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.72),
    inset 0 0 0 1px rgba(201,162,75,.30),
    0 1px 2px rgba(0,0,0,.34),
    0 16px 30px -16px rgba(0,0,0,.78);
}
.pmz_row + .pmz_row{border-top:0}
/* the fold: the page bending into the binding. This is the edge that makes a leaf
   read as a leaf rather than as a rounded rectangle. */
/* the fold now carries the binding idea ALONE, so it is deepened a little: this is
   the edge that makes a leaf read as a leaf rather than as a rounded rectangle. */
.pmz_row::before{content:''; position:absolute; left:0; top:0; bottom:0; width:15px;
  /* z-index:-1 + isolation on the row puts the fold ABOVE the card's own paper and
     BELOW every child, without touching a single child's position. */
  pointer-events:none; z-index:-1; border-radius:7px 0 0 7px;
  background:linear-gradient(90deg, rgba(21,17,14,.155), rgba(21,17,14,.055) 42%,
    rgba(21,17,14,.012) 74%, rgba(21,17,14,0))}
/* ⚠ THIS USED TO BE `.pmz_row > *{position:relative; z-index:1}` — a blanket rule to
   lift the children above the fold gradient. It also overwrote `position:absolute` on
   the BAHARU flag, which then became a grid item and rendered as a full-width red bar
   across every fresh card: thirteen of them at once on a seeded list, blowing the
   red-ration law as well as the layout.
   A blanket `position` on `> *` is never safe — some child always wanted its own.
   The fold goes BEHIND instead, which needs no rule on the children at all. */
.pmz_row{isolation:isolate}
.pmz_row:active{background-color:#F6F0E4}

/* -- 线装 THE STITCHED BINDING ------------------------------------------------
   the thread runs in PASSES with gaps, the way a bound register is actually sewn,
   and a knot crosses it in the gap above every leaf. All static: the dashes are a
   repeating gradient, the knot is two rotated strokes. Nothing here animates - the
   gate in the rig fails if it ever does again. */
.pmz_river::before{width:1.5px; left:16px;
  /* ONE CONTINUOUS THREAD — 22 Aug. The dashes existed to leave gaps for knots; with
     the knots gone a broken line is just a broken line. Fades at both ends so it
     reads as a binding edge rather than a rule that stops. */
  background:linear-gradient(to bottom,
    rgba(201,162,75,0) 0, rgba(240,220,166,.70) 6%,
    rgba(240,220,166,.70) 94%, rgba(201,162,75,0) 100%);
  -webkit-mask-image:linear-gradient(to bottom, transparent 0, #000 5%, #000 95%, transparent 100%);
  mask-image:linear-gradient(to bottom, transparent 0, #000 5%, #000 95%, transparent 100%)}
/* the glow bed goes. A bed of light beside a page someone is reading is the exact
   thing Jim pointed at last round. */
.pmz_river::after{display:none}

/* ☠ THE KNOT AND ITS STYLESHEET ARE BOTH DELETED — 22 Aug. Both rival lenses called
   an X at every gap kitsch rather than craft, and for the same reason: these are
   discrete rounded cards, so a knot between them binds nothing — it is symbolism
   ABOUT binding. One structural cue survives (the continuous thread above) and each
   leaf's own fold edge carries the rest.
   Deleted, not commented out: a falsification break that lands on a dead rule is a
   no-op, and reports a MISS that reads like a weak gate. */

/* -- THE STRENGTH WORD, where the unreadable bar used to be ------------------
   value, not hue: strong sits darkest, weak lightest. The row spends its ONE
   colour on the element glyph, and this says the other half of the same sentence. */
.pmz_row_str{display:inline-flex; align-items:baseline; gap:6px; flex:none;
  padding-right:11px; margin-right:1px; border-right:1px solid rgba(21,17,14,.15);
  font:700 10px/1.5 var(--pmz-ui); letter-spacing:.15em; text-transform:uppercase;
  white-space:nowrap}
.pmz_row_str s{text-decoration:none; font:400 12px/1 var(--pmz-disp);
  letter-spacing:.03em; color:var(--pmz-ink-3)}
.pmz_row_str[data-s="strong"]{color:var(--pmz-ink)}
.pmz_row_str[data-s="neutral"]{color:var(--pmz-ink-2)}
.pmz_row_str[data-s="weak"]{color:var(--pmz-ink-3)}
/* in 中文 the word IS the glyph pair - printing both is a stutter */
.pmz_root[data-lang="zh"] .pmz_row_str s{display:none}

/* -- TODAY, ONLY WHEN TODAY MEANS SOMETHING ---------------------------------
   a paper band, not a colour: the register may not shout on a Tuesday. */
.pmz_row_today{grid-column:1 / span 2; grid-row:5; margin:9px 0 0;
  display:flex; align-items:center; gap:8px; padding:5px 9px 5px 8px;
  border-radius:4px; background:rgba(21,17,14,.045);
  box-shadow:inset 0 0 0 1px rgba(21,17,14,.075);
  font:11.5px/1.3 var(--pmz-ui); color:var(--pmz-ink-2)}
.pmz_row_today b{flex:none; font:700 8.5px/1 var(--pmz-ui); letter-spacing:.18em;
  text-transform:uppercase; color:var(--pmz-ink-3)}
.pmz_row_today i{flex:none; width:6px; height:6px; border-radius:50%;
  background:var(--pmz-ink-2)}
.pmz_row_today[data-kind="press"] i{background:none;
  box-shadow:inset 0 0 0 1.5px var(--pmz-ink-2)}
.pmz_row_today span{min-width:0; overflow:hidden; text-overflow:ellipsis;
  white-space:nowrap}

/* -- the foot drops a row now that today sits above it ---------------------- */
.pmz_row_foot{grid-column:1 / span 2; grid-row:6; margin:10px 0 0; gap:10px;
  align-items:center}

/* -- THE READING STRIP - what the chevron opens into ------------------------
   喜用神, the 大运 they are in now, and the engine's own three tests for the
   strength word above. Every value here is read from analyzeBazi/cycles; nothing
   on this strip is computed by the UI. */
.pmz_rd{display:none; grid-column:1 / span 2; grid-row:7;
  margin:13px -14px 0 -19px; padding:12px 16px 13px 19px;
  border-top:1px solid rgba(21,17,14,.13);
  background:linear-gradient(to bottom, rgba(21,17,14,.050), rgba(21,17,14,.012));
  grid-template-columns:auto minmax(0,1fr); gap:9px 14px; align-items:baseline}
.pmz_row[data-drawer="1"] .pmz_rd{display:grid}
.pmz_rd_k{font:700 8.5px/1.6 var(--pmz-ui); letter-spacing:.17em; text-transform:uppercase;
  color:var(--pmz-ink-3); white-space:nowrap}
.pmz_rd_v{display:flex; align-items:baseline; gap:8px; flex-wrap:wrap; min-width:0;
  font:12.5px/1.4 var(--pmz-ui); color:var(--pmz-ink-2)}
.pmz_rd_v b{font:400 16px/1 var(--pmz-disp)}
.pmz_rd_v s{text-decoration:none; margin-left:-5px; font-size:11.5px;
  color:var(--pmz-ink-3)}
/* ⚠ A LOCALLY INVERTED PILL INVERTS ITS CHILDREN TOO. .pmz_rd_why u[data-on="1"]
   paints an 84%-ink pill and recolours the <u> only; the <s> inside it kept paper
   ink-3 and measured 2.03:1 in a pill whose own label reads at 11.6:1. */
.pmz_rd_why u[data-on="1"] s{color:rgba(247,243,236,.72)}
.pmz_rd_v em{font:400 17px/1 var(--pmz-disp); font-style:normal; letter-spacing:.05em;
  color:var(--pmz-ink)}
/* the three tests: filled = the engine said yes */
.pmz_rd_why{gap:6px}
.pmz_rd_why u{text-decoration:none; padding:3px 8px; border-radius:99px;
  font:700 9px/1.4 var(--pmz-ui); letter-spacing:.10em; text-transform:uppercase;
  color:var(--pmz-ink-3); box-shadow:inset 0 0 0 1px rgba(21,17,14,.20)}
.pmz_rd_why u[data-on="1"]{background:rgba(21,17,14,.84); color:var(--pmz-paper);
  box-shadow:none}

/* -- the actions sit under the strip ---------------------------------------- */
.pmz_row_acts{grid-column:1 / span 2; grid-row:8; margin:12px 0 1px}

/* -- THE PILLARS STAY IN VIEW while the sheet is filled -------------------- */
/* MEASURED, not assumed: with `top:60px` the panel stuck at 126 - and 126 - 60 is
   exactly .pmz_doc's 66px padding-top. A scroll container's padding is ALREADY
   outside the sticky constraint rectangle, so the offset must NOT pay for the chrome
   band a second time; 60 was double-counting. 6px here is a 6px gap under the band,
   which lands the panel at ~72 against a chip that ends at 57. */
.pmz_asm_ft{display:flex; align-items:baseline; gap:10px; margin-top:9px;
  padding-top:8px; border-top:1px solid var(--pmz-rule)}

/* -- THE PANEL YIELDS TO THE KEYBOARD --------------------------------------
   MEASURED: the panel is 135px (16% of a 390x844 viewport), leaving 287px for the
   form once a 350px keyboard is up. You do not need to watch the pillars form while
   you are spelling a name - so while a text field has focus the panel collapses to
   its summary line and gives ~100px back, and it returns the moment focus leaves.
   ⚠ transform/opacity would not do here: the panel must stop RESERVING the space,
   not merely stop showing it. */
.pmz_root[data-kb="1"] .pmz_asm_row{display:none}
.pmz_root[data-kb="1"] .pmz_asm_ft{margin-top:0; padding-top:0; border-top:0}
.pmz_root[data-kb="1"] .pmz_asm{padding-top:8px; padding-bottom:8px}
.pmz_asm_sub{margin:0; padding:0; border-top:0; flex:1; min-width:0;
  font-size:12px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.pmz_asm_cnt{flex:none; font:700 10px/1 var(--pmz-ui); letter-spacing:.14em;
  text-transform:uppercase; color:var(--pmz-ink-3);
  font-variant-numeric:tabular-nums}

/* an unfilled pillar is a form WAITING, not a form broken. Dashed boxes are what a
   validation error looks like; a hairline frame with a ghost mark is what an unfilled
   ledger column looks like. */
.pmz_asm_c[data-set="0"]{background:rgba(21,17,14,.028); border-style:solid;
  border-color:rgba(21,17,14,.13)}
.pmz_asm_c[data-set="0"] b,.pmz_asm_c[data-set="0"] i{color:rgba(21,17,14,.16)}
/* the hour block is a field too, so its inner heading loses its top margin */
#fldHour .pmz_ttl{margin-top:0}

/* -- the shortcut is a panel, not a dashed placeholder --------------------- */
.pmz_ic{border:0; border-radius:6px; padding:13px 13px 12px;
  background:linear-gradient(to bottom, rgba(21,17,14,.055), rgba(21,17,14,.022));
  box-shadow:inset 0 0 0 1px rgba(21,17,14,.13)}
.pmz_ic label{display:flex; align-items:center; gap:7px}
.pmz_ic label::before{content:''; width:5px; height:5px; border-radius:50%;
  background:var(--pmz-gold-deep); flex:none}


/* ==============================================================================
   THE REGISTER AT SCALE - round 8.
   Measured at 80 clients: 13,567px of scroll (16.1 screens), 60ms to re-render the
   whole thing, 1.1ms to search it. So the DOM is not the problem and pagination
   would be solving the wrong one. What breaks is ORIENTATION.
   ============================================================================== */

/* -- 1 . THE MASTHEAD PINS -------------------------------------------------
   It carries the sort order and the count, and it left the screen before the second
   card. ⚠ top:6px, NOT the chrome height: .pmz_doc's 66px padding is ALREADY outside
   the sticky constraint rectangle - measured last round, where top:60 stuck at 126. */
.pmz_reg_hd{position:sticky; top:6px; z-index:22;
  -webkit-backdrop-filter:blur(11px); backdrop-filter:blur(11px);
  background:rgba(8,14,36,.80)}

/* -- 2 . LETTER AND MONTH DIVIDERS -----------------------------------------
   A bound ledger is tabbed. The mark sits on the GROUND beside the thread, not on a
   leaf: it belongs to the binding, not to a client. Hairline rule to the right so the
   eye reads it as a division rather than as a heading floating in space. */
.pmz_reg_div{display:flex; align-items:center; gap:10px;
  margin:14px 0 3px; padding:0 2px 0 1px}
.pmz_reg_div b{flex:none; font:600 10px/1 var(--pmz-ui); letter-spacing:.26em;
  text-transform:uppercase; color:rgba(240,220,166,.72);
  font-variant-numeric:tabular-nums}
.pmz_reg_div::after{content:''; flex:1; height:1px;
  background:linear-gradient(90deg, rgba(201,162,75,.34), rgba(201,162,75,0))}
.pmz_reg_div:first-child{margin-top:2px}

/* -- 3 . THE HARI INI CHIP -------------------------------------------------
   Not a category, so it does not look like one: ink-on-ivory when armed, and a
   hairline outline when idle. It sits first because at 80 records it is the only
   chip that changes daily. */
.pmz_tab_today{position:relative}
.pmz_tab_today::after{content:''; position:absolute; left:11px; right:11px; bottom:5px;
  height:1px; background:rgba(240,220,166,.30)}
.pmz_tab_today[aria-pressed="true"]{color:#1B1408;
  background:linear-gradient(180deg,#FBF6E8,#EBDCB6 64%,#D9C79A);
  border-color:transparent}
.pmz_tab_today[aria-pressed="true"]::after{background:rgba(27,20,8,.30)}
.pmz_tab_today[aria-pressed="true"] i{background:rgba(27,20,8,.14); color:#1B1408}

/* -- 4 . TAMBAH KLIEN, FLOATING -------------------------------------------
   On the DEVICE, not in the document, so it cannot be sixteen screens away. Above
   the tab bar, on the right, thumb-first. Ivory and gold rather than the seal: Jim
   asked for premium, not for more brand on an already brand-heavy screen.
   ⚠ ONE-SHOT TRANSITION, NOT AN ANIMATION. The law here bans animations that force
   layout every frame; a 220ms max-width transition on a label, fired by a finger,
   is not that. A gate asserts this button carries no infinite animation. */
.pmz_fab{position:absolute; right:16px; z-index:56;
  bottom:calc(96px + env(safe-area-inset-bottom,0px));
  display:flex; align-items:center; gap:0; overflow:hidden;
  height:52px; min-width:52px; padding:0 14px; border-radius:999px; cursor:pointer;
  border:1px solid rgba(240,220,166,.42);
  background:linear-gradient(180deg,#FDF9EF,#EFE1BE 58%,#DCC79E);
  color:#1B1408; font:700 14px/1 var(--pmz-ui); letter-spacing:.01em;
  box-shadow:0 10px 26px -8px rgba(0,0,0,.75), 0 2px 6px rgba(0,0,0,.4),
             inset 0 1px 0 rgba(255,255,255,.7);
  transition:transform .18s var(--pmz-out), box-shadow .18s ease}
.pmz_fab svg{flex:none; width:21px; height:21px; fill:none; stroke:currentColor;
  stroke-width:2.3; stroke-linecap:round}
.pmz_fab span{overflow:hidden; white-space:nowrap;
  max-width:180px; margin-left:9px;
  transition:max-width .22s var(--pmz-out), margin-left .22s var(--pmz-out),
             opacity .16s ease}
.pmz_fab[data-wide="0"]{padding:0; justify-content:center; width:52px}
.pmz_fab[data-wide="0"] span{max-width:0; margin-left:0; opacity:0}
.pmz_fab:active{transform:scale(.96)}
/* it belongs to the REGISTER: a floating "add a client" over someone's chart would
   be offering to add to a thing the consultant is not looking at */
.pmz_root:not([data-screen="river"]) .pmz_fab{display:none}
/* and it steps aside for 选择 mode, where the thumb is picking, not adding.
   ⚠ the root carries NO data-sel — select mode is marked on #pmzSelBar — so this is
   scoped off the bar's own state via :has(), with a plain fallback below it. */
.pmz_root:has(#pmzSelBar[data-on="1"]) .pmz_fab{display:none}


/* -- THE TAB RAIL, once there are more tabs than screen -------------------
   Measured with 13 categories: the content is 515px+ in a 390px rail, and the
   PRESSED tab could sit 1,246px off-screen at scrollLeft:0 - a filtered list with
   no visible filter, where the clients it hides just look deleted.
   The rail now scrolls the pressed tab into view, and fades on whichever side
   actually continues rather than always on the right. */
.pmz_catrail[data-ovf="none"]{-webkit-mask-image:none; mask-image:none}
.pmz_catrail[data-ovf="end"]{
  -webkit-mask-image:linear-gradient(90deg,#000 0,#000 calc(100% - 16px),transparent);
          mask-image:linear-gradient(90deg,#000 0,#000 calc(100% - 16px),transparent)}
.pmz_catrail[data-ovf="start"]{
  -webkit-mask-image:linear-gradient(90deg,transparent 0,#000 16px,#000 100%);
          mask-image:linear-gradient(90deg,transparent 0,#000 16px,#000 100%)}
.pmz_catrail[data-ovf="both"]{
  -webkit-mask-image:linear-gradient(90deg,transparent 0,#000 16px,#000 calc(100% - 16px),transparent);
          mask-image:linear-gradient(90deg,transparent 0,#000 16px,#000 calc(100% - 16px),transparent)}
/* scrolling the rail must never scroll the register with it */
.pmz_catrail{overscroll-behavior-x:contain; scroll-behavior:smooth}


/* ==============================================================================
   ROUND 9 - the corners, the weight, and the terms that explain themselves.
   ============================================================================== */

/* -- SMOOTH CORNERS. Jim: "I dont like it in rectangle I prefer its smooth rounding
   in the corner." 7px reads as a rectangle with the edges knocked off; 15px reads as
   a card. The fold follows it, or the fold squares the corner it sits in. -- */
.pmz_row{border-radius:15px}
.pmz_row::before{border-radius:15px 0 0 15px; width:17px}
/* the reading strip bleeds to the card's edges, so it has to know where they curve */
.pmz_rd{border-radius:0 0 15px 15px}
.pmz_reg_hd{border-radius:9px}

/* -- A LITTLE MORE WEIGHT. The audience is 40+ reading a phone, often in a shop.
   Colour is unchanged (contrast is gated at 5:1) - this is weight only. -- */
.pmz_row_l1{font-weight:500}
.pmz_row_l2{font-weight:500}
.pmz_row_today{font-weight:500}
.pmz_rd_v{font-weight:500}
.pmz_row_tag{font-weight:500}

/* -- TERMS THAT EXPLAIN THEMSELVES ----------------------------------------
   A dotted underline is the oldest signal in print for "this word has a note", and
   it costs no colour. The whole target is the term, so it clears a thumb without
   drawing a box around itself. -- */
[data-term]{cursor:pointer; -webkit-tap-highlight-color:transparent}
.pmz_rd_k[data-term], .pmz_row_str[data-term]{
  text-decoration:underline dotted rgba(21,17,14,.42);
  text-underline-offset:3px; text-decoration-thickness:1px}
.pmz_row_today[data-term]{position:relative}
.pmz_row_el[data-term]{text-decoration:underline dotted rgba(21,17,14,.34);
  text-underline-offset:2px}
[data-term]:active{opacity:.6}

/* the glossary card itself: one paragraph, set to be read, not skimmed */
.pmz_gloss{margin:0; font:14.5px/1.68 var(--pmz-ui); color:var(--pmz-ink-2)}

/* ==============================================================================
   高级筛选 — round 9. It was correct and plain; what it lacked was any sense of what
   it was ABOUT to do. Ten stems with no counts, and an Apply button that gave no
   idea what would survive it.
   ============================================================================== */

/* the groups breathe, and each label sits on its own rule */
.pmz_sh_grp + .pmz_sh_grp{margin-top:20px; padding-top:18px;
  border-top:1px solid rgba(21,17,14,.11)}
.pmz_sh_lbl{display:flex; align-items:center; gap:9px; margin:0 0 11px;
  font:600 10px/1 var(--pmz-ui); letter-spacing:.22em; text-transform:uppercase;
  color:var(--pmz-ink-3)}
/* ⚠ EXACTLY INVISIBLE: rgba(21,17,14,.10) over the lacquer sheet composites to
   rgb(20,16,12) on rgb(19,16,12) — 1.00:1. A paper-era literal on a dark surface. */
.pmz_sh_lbl::after{content:''; flex:1; height:1px; background:rgba(244,238,226,.14)}

/* -- the 日主 grid: each stem says what it would return, and one nobody has is
   visibly a dead end rather than a live button that empties the list -- */
.pmz_dmgrid button{position:relative; border-radius:9px; min-height:60px;
  transition:transform .12s ease}
.pmz_dmgrid button:active{transform:scale(.95)}
.pmz_dmgrid button b{position:absolute; top:5px; right:6px; font:700 9.5px/1 var(--pmz-ui);
  color:var(--pmz-ink-3); font-variant-numeric:tabular-nums}
.pmz_dmgrid button[aria-pressed="true"] b{color:rgba(247,243,236,.78)}
.pmz_dmgrid button[data-none="1"]{opacity:.34; cursor:default}
.pmz_dmgrid button[data-none="1"]:active{transform:none}

/* -- the pills carry their counts too -- */
.pmz_sh_pills button{border-radius:12px; gap:8px; display:flex;
  align-items:center; justify-content:center; transition:transform .12s ease}
.pmz_sh_pills button:active{transform:scale(.97)}
.pmz_sh_pills button i{font-style:normal; font:700 10.5px/1 var(--pmz-ui);
  opacity:.55; font-variant-numeric:tabular-nums}
.pmz_sh_pills button[aria-pressed="true"] i{opacity:.8}

/* -- APPLY SAYS WHAT SURVIVES. A filter you have to apply before you learn it
   returns nothing is a filter that wastes a tap and a moment of doubt. -- */
.pmz_sh_1st{display:flex; align-items:center; justify-content:center; gap:9px}
.pmz_sh_1st i{font-style:normal; min-width:22px; padding:2px 7px; border-radius:999px;
  font:700 11px/1.5 var(--pmz-ui); font-variant-numeric:tabular-nums;
  background:rgba(247,243,236,.20); color:inherit}

/* the sheet itself sits a touch softer on the ground */
.pmz_sh{border-radius:18px 18px 0 0}


/* ==============================================================================
   THE ADD-CLIENT PAGE - round 10. A place you arrive at, not a form you land in.

   "Premium" is a mood board unless it names things you can point at, so it means
   five specific things here:
     ARRIVAL   a masthead with real display type
     MATERIAL  inputs pressed INTO the paper, not drawn on it
     RESPONSE  every control answers the finger
     CEREMONY  the plate is engraved and waiting; a pillar LANDS when it forms
     HIERARCHY one gold commit at the end, everything else quiet
   ============================================================================== */

/* -- 1 . ARRIVAL ----------------------------------------------------------- */
.pmz_fmhead{padding:14px 18px 14px; position:relative}
.pmz_fmhead::after{content:''; position:absolute; left:18px; right:18px; bottom:0;
  height:1px; background:linear-gradient(90deg,
    rgba(201,162,75,.55), rgba(201,162,75,.16) 55%, rgba(201,162,75,0))}
.pmz_fmhead_t{display:flex; align-items:baseline; gap:12px}
.pmz_fmhead h2{margin:0; font:400 27px/1.14 var(--pmz-disp); color:#F6F1E4;
  letter-spacing:.004em}
.pmz_fmhead_seal{flex:none; font:400 13px/1 var(--pmz-brush);
  letter-spacing:.22em; color:rgba(240,220,166,.62);
  padding:5px 8px 4px; border-radius:3px;
  box-shadow:inset 0 0 0 1px rgba(201,162,75,.34)}
.pmz_fmhead_sub{margin:9px 0 0; max-width:31em;
  font:12.5px/1.62 var(--pmz-ui); color:rgba(240,233,220,.60)}
/* 中文 reads the title itself; the seal beside it would be a stutter */
.pmz_root[data-lang="zh"] .pmz_fmhead_seal{display:none}

/* -- 2 . MATERIAL ---------------------------------------------------------- */
.pmz_sheet_form{border-radius:15px; padding:20px 16px 20px;
  box-shadow:0 26px 54px -14px rgba(0,0,0,.62), 0 0 0 1px rgba(201,162,75,.26),
             inset 0 1px 0 rgba(255,255,255,.62)}
/* an input is a well PRESSED INTO the sheet, not a rectangle drawn on top of it */
.pmz_input, .pmz_pick{border-radius:10px; min-height:52px;
  background:linear-gradient(180deg, rgba(21,17,14,.055), rgba(255,255,255,.42) 34%,
    rgba(255,255,255,.55));
  border:0;
  box-shadow:inset 0 1px 2px rgba(21,17,14,.13), inset 0 0 0 1px rgba(21,17,14,.13);
  transition:box-shadow .16s ease, transform .12s ease}
.pmz_input{padding:0 14px; font-size:15.5px}
.pmz_input:focus{border:0;
  box-shadow:inset 0 1px 2px rgba(21,17,14,.10),
             inset 0 0 0 1px rgba(201,162,75,.72),
             0 0 0 3px rgba(201,162,75,.16)}
.pmz_input[aria-invalid="true"]{border:0;
  box-shadow:inset 0 1px 2px rgba(21,17,14,.10),
             inset 0 0 0 1px rgba(176,24,32,.62), 0 0 0 3px rgba(176,24,32,.13)}

/* -- 3 . RESPONSE ---------------------------------------------------------- */
.pmz_pick:active, .pmz_seg button:active, .pmz_dial button:active,
.pmz_check:active{transform:scale(.985)}
.pmz_pick{display:flex; align-items:center; gap:10px; padding:0 14px; text-align:left}
.pmz_pick em{margin-left:auto; font-style:normal; opacity:.5}
.pmz_seg{border-radius:12px; overflow:hidden;
  box-shadow:inset 0 0 0 1px rgba(21,17,14,.13)}
.pmz_seg button{min-height:52px; transition:background .16s ease}
.pmz_dial button{border-radius:10px; transition:transform .12s ease, box-shadow .16s ease}
.pmz_dial button[aria-pressed="true"]{box-shadow:inset 0 0 0 1.5px var(--pmz-ink)}

/* the KP shortcut is a HELPER: it saves typing, it does not commit anything, so it
   must not carry a commit button's weight. Gold, not black. */
.pmz_ic{border-radius:12px}
.pmz_ic_in button{border-radius:10px; min-height:52px; border:0;
  background:linear-gradient(180deg,#FBF3DE,#E8D6AA 62%,#CFBB8C);
  color:#1B1408; font-weight:800; letter-spacing:.02em;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.7), 0 2px 6px -2px rgba(0,0,0,.35)}
.pmz_ic_in button:active{transform:scale(.97)}

/* -- 4 . CEREMONY: the plate is ENGRAVED AND WAITING ----------------------- */
.pmz_asm{border-radius:13px}
.pmz_asm_c{border-radius:9px; transition:box-shadow .2s ease}
/* an empty column is a RULED, WAITING column - not a form box with a dot in it */
.pmz_asm_c[data-set="0"]{background:rgba(21,17,14,.022); border-color:rgba(21,17,14,.10)}
.pmz_asm_c[data-set="0"] b,.pmz_asm_c[data-set="0"] i{color:rgba(21,17,14,.13)}
.pmz_asm_c[data-set="1"]{background:rgba(255,255,255,.55);
  box-shadow:inset 0 0 0 1px rgba(201,162,75,.42), 0 1px 3px -1px rgba(21,17,14,.2)}

/* -- 5 . HIERARCHY: one gold commit, and it says what it costs ------------- */
#pmzDoCast{min-height:56px; border-radius:13px; font-size:15px;
  display:flex; align-items:center; justify-content:center; gap:11px}
#pmzDoCast .pmz_addcost{display:inline-flex; align-items:center; gap:5px;
  text-decoration:none; padding:3px 9px 3px 7px; border-radius:999px;
  background:rgba(27,20,8,.14); font-size:12px; font-weight:800}

/* -- the empty 四柱 plate: RULED COLUMNS WAITING, not boxes with dots -------
   A box with a · in it is what an unfilled form field looks like, and an unfilled
   form field is what a validation error looks like. A ruled empty line is what an
   unwritten ledger column looks like — and this is a ledger. */
.pmz_asm_c[data-set="0"] b,
.pmz_asm_c[data-set="0"] i{min-height:22px;
  border-bottom:1px solid rgba(21,17,14,.10);
  margin:0 12px}
.pmz_asm_c[data-set="0"] i{margin-top:5px}
.pmz_asm_c[data-set="0"]{background:none; box-shadow:none;
  border:1px dashed rgba(21,17,14,.09)}

/* -- the seal beside the title is a STAMP, not a chip ---------------------
   A bordered rounded box next to a heading reads as a tag. A seal is red, square,
   and sits slightly off the baseline like something pressed onto the page. */
.pmz_fmhead_seal{padding:0; border-radius:0; box-shadow:none;
  color:rgba(240,220,166,.50); font-size:12px; letter-spacing:.30em;
  transform:translateY(-1px)}


/* ==============================================================================
   THE FILTER SHEET, FINISHED - round 11.

   THE COLOUR GRAMMAR, which this sheet did not have and which is why nothing on it
   told you what kind of thing it was:
       INK  = a selection you have made     (a state)
       GOLD = an action the app will take   (a verb)
   Selected stems were ink, the selected sort was ink — and the COMMIT was ink too, so
   the one control that does something looked exactly like the ones that only record a
   choice. On the add-client page the commit is gold. Same idea, two languages.
   Fixed here, and the rule holds everywhere from now on.
   ============================================================================== */

/* -- the foot: rounded, and speaking the grammar ------------------------- */
.pmz_sh_foot{padding:14px 14px 18px; gap:11px;
  background:linear-gradient(180deg, rgba(216,205,184,.10), rgba(216,205,184,.30))}
.pmz_sh_foot button{min-height:54px; border-radius:14px; font-weight:700;
  transition:transform .12s ease}
.pmz_sh_foot button:active{transform:scale(.975)}

/* SET SEMULA undoes — it is neither a state nor a commit, so it is a quiet outline */
.pmz_sh_2nd{flex:0 0 38%; border:0; background:rgba(255,255,255,.55);
  box-shadow:inset 0 0 0 1px rgba(21,17,14,.16); color:var(--pmz-ink-2)}

/* GUNA TAPISAN is the verb: gold, like 起轴 on the form */
.pmz_sh_1st{flex:1; border:0; color:#1B1408;
  background:linear-gradient(180deg,var(--pmz-gold-hi),var(--pmz-gold) 62%,#B98F3A);
  box-shadow:0 8px 18px -7px rgba(201,162,75,.72),
             inset 0 1px 0 rgba(255,255,255,.62)}
.pmz_sh_1st i{background:rgba(27,20,8,.16); color:#1B1408}

/* -- the live summary: what is already on, in words --------------------- */
.pmz_sh_now{margin:0 0 18px; padding:11px 13px; border-radius:11px;
  background:rgba(21,17,14,.045); box-shadow:inset 0 0 0 1px rgba(21,17,14,.09);
  font:12.5px/1.5 var(--pmz-ui); font-weight:500; color:var(--pmz-ink-2)}

/* -- the stems: the count moves off the glyph's shoulder ---------------- */
.pmz_dmgrid button{padding-top:9px}
.pmz_dmgrid button b{top:auto; bottom:5px; right:auto; left:0; right:0;
  text-align:center; font-size:9px; letter-spacing:.10em}
.pmz_dmgrid button i{margin-top:3px}

/* -- the close control is chrome, so it stops competing with the title -- */
.pmz_sh_x{border:0; background:rgba(21,17,14,.055);
  box-shadow:inset 0 0 0 1px rgba(21,17,14,.10); color:var(--pmz-ink-3)}
.pmz_sh_x:active{transform:scale(.94)}

/* -- and the head sits on the same rhythm as the groups ----------------- */
.pmz_sh_hd{padding:15px 14px 13px}
.pmz_sh_body{padding-top:16px}

/* ⚠ MEASURED 3px OF OVERLAP between the 日主 caption and its count — moving the count
   to the foot of the cell without giving the cell the height to hold it just stacked
   two things in one place. Make the room, don't nudge the number. */
.pmz_dmgrid button{min-height:74px; padding:10px 2px 17px}
.pmz_dmgrid button b{bottom:6px}


/* ==============================================================================
   ROUND 12 - the selected state, struck; and the gold, made of gold.
   ============================================================================== */

/* -- A SELECTION SHOULD LOOK STRUCK, not merely dark. Jim: "make the selected button
   abit harsh". Deeper ink, a crisp inner highlight along the top edge so it reads as
   something pressed INTO the sheet, and a real shadow beneath it. -- */
.pmz_dmgrid button[aria-pressed="true"],
.pmz_sh_pills button[aria-pressed="true"]{
  background:linear-gradient(180deg,#241E19,#15110E 58%,#0C0906);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.20),
             inset 0 0 0 1px rgba(0,0,0,.6),
             0 4px 12px -3px rgba(0,0,0,.55);
  color:#F7F3EC; font-weight:700}
.pmz_dmgrid button[aria-pressed="true"] span{text-shadow:0 1px 0 rgba(0,0,0,.45)}
.pmz_dmgrid button[aria-pressed="true"] i{color:rgba(247,243,236,.80)}
.pmz_dmgrid button[aria-pressed="true"] b{color:rgba(247,243,236,.92)}

/* -- THE GOLD, MADE OF GOLD ------------------------------------------------
   A gold-coloured rectangle is a flat ramp between two hexes. A piece of gold has a
   specular band across the upper third where the light catches, a darker bed below
   it, and a rim that is lighter at the top and darker at the bottom. That is the
   whole difference, and it is four extra stops. -- */
.pmz_sh_1st, #pmzDoCast{
  background:linear-gradient(180deg,
    #FFF6DC 0%, #F4E3B4 18%, #E3CB86 42%, #CBAE5D 62%, #B08F3E 86%, #9C7B2E 100%);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.85),
             inset 0 -1px 0 rgba(90,66,16,.55),
             inset 0 0 0 1px rgba(140,108,37,.45),
             0 10px 22px -8px rgba(140,108,37,.70),
             0 2px 5px -2px rgba(0,0,0,.45);
  color:#1B1408; text-shadow:0 1px 0 rgba(255,255,255,.42)}
.pmz_sh_1st:active, #pmzDoCast:active{
  box-shadow:inset 0 1px 3px rgba(90,66,16,.45),
             inset 0 0 0 1px rgba(140,108,37,.55),
             0 2px 6px -3px rgba(0,0,0,.4)}

/* and a criterion set that returns NOTHING says so, instead of sitting there as a
   quiet 0 the consultant discovers only after applying it */
.pmz_sh_1st i[data-none="1"]{background:var(--pmz-seal); color:#fff;
  box-shadow:0 0 0 1px rgba(255,255,255,.35)}


/* ==============================================================================
   ROUND 13 - the actions, the glossary card, and the header at LIVE-APP SIZE.
   ============================================================================== */

/* -- 2 . THE THREE ACTIONS. Flat squares with hairline borders, while every other
   surface had become rounded and material. -- */
.pmz_row_acts span{border-radius:11px; min-height:46px; border:0; font-weight:700;
  background:linear-gradient(180deg, rgba(255,255,255,.72), rgba(21,17,14,.035));
  box-shadow:inset 0 0 0 1px rgba(21,17,14,.16), inset 0 1px 0 rgba(255,255,255,.7),
             0 1px 2px rgba(21,17,14,.10);
  transition:transform .12s ease, box-shadow .14s ease}
.pmz_row_acts span:active{transform:scale(.96);
  box-shadow:inset 0 1px 3px rgba(21,17,14,.22), inset 0 0 0 1px rgba(21,17,14,.18)}
/* delete keeps its seal red, because a delete that is not red is a trap */
.pmz_row_acts span[data-a="del"]{
  box-shadow:inset 0 0 0 1px rgba(176,24,32,.40), inset 0 1px 0 rgba(255,255,255,.6),
             0 1px 2px rgba(176,24,32,.12)}

/* -- 3 . THE GLOSSARY CARD: centred, with the screen blurred behind it ------
   It rose from the bottom like every other sheet, which made an ASIDE look like
   another control panel. An aside belongs in the middle, over a blurred page, and
   goes away when you have read it. -- */
/* ⚠ the host's class is .pmz_sheeth — I wrote .pmz_sheethost from memory instead of
   reading the markup, and a selector that matches nothing fails SILENTLY: the card
   would have looked finished with no blur behind it. Scope off the card itself
   instead, which cannot drift. */
.pmz_sheeth:has(.pmz_gcard) .pmz_sh_bg{
  -webkit-backdrop-filter:blur(10px) saturate(115%);
          backdrop-filter:blur(10px) saturate(115%);
  background:rgba(2,4,12,.52)}
.pmz_gcard{position:absolute; left:50%; top:50%; z-index:2;
  transform:translate(-50%,-50%); width:min(330px, calc(100% - 44px));
  padding:22px 22px 20px; border-radius:20px;
  box-shadow:0 34px 70px -18px rgba(0,0,0,.72), 0 0 0 1px rgba(201,162,75,.30),
             inset 0 1px 0 rgba(255,255,255,.72);
  animation:pmz_gcardin .3s var(--pmz-out) backwards}
@keyframes pmz_gcardin{from{transform:translate(-50%,-50%) scale(.94); opacity:0}}
@media (prefers-reduced-motion:reduce){ .pmz_gcard{animation:none} }

/* the frame: WHAT KIND of thing this is, before the thing itself */
.pmz_gkind{margin:0; font:700 9px/1 var(--pmz-ui); letter-spacing:.24em;
  text-transform:uppercase; color:var(--pmz-gold-deep)}
.pmz_gterm{margin:11px 0 0; display:flex; align-items:baseline; gap:9px; flex-wrap:wrap;
  font:400 23px/1.18 var(--pmz-disp); color:var(--pmz-ink)}
.pmz_gterm s{text-decoration:none; font:400 14px/1 var(--pmz-brush);
  letter-spacing:.16em; color:var(--pmz-ink-3)}
.pmz_gloss{margin:13px 0 0; font:14.5px/1.68 var(--pmz-ui); color:var(--pmz-ink-2)}
/* and WHERE they just saw it — a definition without this is not an orientation */
.pmz_gwhere{margin:15px 0 0; padding:11px 13px; border-radius:11px;
  background:rgba(21,17,14,.045); box-shadow:inset 0 0 0 1px rgba(21,17,14,.09);
  font:12.5px/1.55 var(--pmz-ui); color:var(--pmz-ink-2)}
.pmz_gwhere b{display:block; margin-bottom:3px; font:700 8.5px/1 var(--pmz-ui);
  letter-spacing:.20em; text-transform:uppercase; color:var(--pmz-ink-3)}
.pmz_gok{margin-top:18px; min-height:50px; border-radius:13px}

/* -- 4 . THE HEADER, AT THE LIVE APP'S NUMBERS ----------------------------
   Read out of 04_Web-App (read-only) so the port is a copy, not a translation:
     app-wallet.js :: #energyChip   ·   index.html :: #langPill / #langMenu
   The prototype's were all bigger; a header that has to be re-tuned on the way into
   production is a header that will be re-tuned WRONG. -- */
.pmz_chip{top:calc(13px + env(safe-area-inset-top,0px)); z-index:58;
  padding:4px 13px 4px 7px; gap:6px; border-radius:999px;
  background:rgba(18,12,9,.62);
  -webkit-backdrop-filter:blur(9px); backdrop-filter:blur(9px);
  border:1px solid rgba(214,178,95,.48);
  box-shadow:0 6px 16px -6px rgba(0,0,0,.5), inset 0 1px 0 rgba(255,255,255,.08)}
.pmz_chip b{font:800 12.5px/1 var(--pmz-ui); color:#F4D58E; letter-spacing:.01em;
  font-variant-numeric:lining-nums tabular-nums}
.pmz_chip .pmz_gem{width:17px; height:17px}
.pmz_chip .pmz_gem svg{width:17px; height:17px}
/* the live app extends the tap area invisibly rather than growing the comp */
.pmz_chip::after{content:''; position:absolute; inset:-10px; border-radius:inherit}

.pmz_langpill{top:calc(13px + env(safe-area-inset-top,0px)); right:14px; z-index:58;
  padding:5px 11px; gap:4px; border-radius:999px;
  background:rgba(21,17,14,.55);
  -webkit-backdrop-filter:blur(8px); backdrop-filter:blur(8px);
  color:#fff; font:800 11px/1 var(--pmz-ui);
  border:1px solid rgba(255,255,255,.14)}
.pmz_langpill svg{width:13px; height:13px}
.pmz_langpill::after{content:''; position:absolute; inset:-10px; border-radius:inherit}
.pmz_langmenu{top:44px; right:14px; z-index:59; min-width:138px;
  border-radius:16px; padding:6px;
  background:linear-gradient(160deg,rgba(40,29,20,.92),rgba(20,15,11,.94));
  -webkit-backdrop-filter:blur(18px) saturate(150%);
          backdrop-filter:blur(18px) saturate(150%);
  border:1px solid rgba(201,162,75,.28);
  box-shadow:0 18px 44px rgba(0,0,0,.55), inset 0 0 0 1px rgba(255,255,255,.03)}
/* the back button matches the chip's vertical rhythm */
.pmz_backbtn{width:38px; height:38px; top:calc(13px + env(safe-area-inset-top,0px))}
.pmz_backbtn svg{width:17px; height:17px}

/* ⚠ THE 44px MINIMUM IS A TAP TARGET, NOT A COMP SIZE — and the live app already
   knows that: it keeps the chip at its drawn ~25px and reaches 44 with an INVISIBLE
   `::after{inset:-10px}`. My `min-height:44px` inflated the drawn pill instead, which
   is why the prototype's header looked bigger than the real one in Jim's two
   screenshots side by side. Drop the min-height; the extension above does the work,
   and the thumb-floor gate is satisfied by the hit area rather than by the ink. */
.pmz_chip{min-height:0}
.pmz_langpill{min-height:0; gap:4px; padding:5px 11px}
.pmz_backbtn{min-height:0}

/* ⚠ A BUTTON STYLE BUILT FOR THE DARK GROUND, REUSED ON PAPER.
   `.pmz_btn` is cream text on a faint gold wash — correct over the star field, and
   light-on-light the moment it sits on an ivory card. Measured: text luminance 0.80
   on paper that is 0.93. The glossary's confirm is INK on paper instead: it is a
   dismissal, not a gold action, and the colour grammar says gold is for verbs. */
.pmz_gcard .pmz_btn, .pmz_paper .pmz_btn{
  background:linear-gradient(180deg,#241E19,#15110E 60%,#0C0906);
  color:#F7F3EC; border:0;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.18), 0 6px 16px -7px rgba(0,0,0,.55)}
.pmz_gcard .pmz_btn:active, .pmz_paper .pmz_btn:active{transform:scale(.98)}

/* the back button gets the same invisible thumb extension the live app gives the
   chip — 38px of ink, 58px of target */
.pmz_backbtn{position:absolute}
.pmz_backbtn::after{content:''; position:absolute; inset:-10px; border-radius:inherit}

/* ⚠ MEASURED 3.46:1. The disclosure chevron sits on ivory in --pmz-ink-3, which is
   fine for a large graphic (WCAG non-text is 3:1) and thin for an audience over 40
   looking for the control that opens a reading. Darkened rather than arguing the
   standard down — the honest fix for "it is technically allowed but hard to see". */
.pmz_row_more{color:var(--pmz-ink-2)}


/* -- THE LIVING GROUND ------------------------------------------------------
   The two layers that move need their own compositor layer and a little overscan, or
   parallaxing them reveals the edge they were sitting flush against. `will-change` is
   correct HERE and nowhere else in this file: these are the only elements whose
   transform changes on a real gesture. */
/* ⚠ `will-change` ONLY WHILE THE FIELD IS LIT. Pinning it on an invisible layer is
   the "invisible motion is pure heat" entry in the ledger, twice — and here it is not
   even motion: livingGround() sets `stars = null`, so nothing ever writes --pmz-par to
   this node. Scoped to [data-stars="1"] it costs nothing today and still promotes the
   layer the frame the ceremony lights it. */
#pmzStars{top:-80px; bottom:-80px}
.pmz_root[data-stars="1"] #pmzStars{will-change:transform}
.pmz_silk1{will-change:transform}

/* the ground layers compose their parallax offset through a variable, so the CSS keeps
   owning each layer's own base transform and the script only ever writes the offset. */
#pmzStars{transform:translate3d(0,var(--pmz-par,0px),0)}


/* ==============================================================================
   THE RECORD PAGE - round 15. Everything the register learned, applied here.
   ⚠ THE PLATE IS UNTOUCHED: the 四柱 tiles, their element hexes, the 十神 rows and
   the 五行 bars are ported verbatim from the live app. Only the chrome around them
   changes.
   ============================================================================== */

/* -- 1 . CONTENT MUST NOT SIT HALF-LEGIBLE BEHIND THE CHROME --------------
   MEASURED from a screenshot: "Diri anda: 庚 · Logam / Kedudukan seimbang" cut across
   the middle by the back button and the chip. The scrim stopped being opaque at 72%
   of its own height, so a heading passing through the last third was still readable
   enough to look broken rather than hidden. Take it fully opaque through the band the
   controls actually occupy, and fade it out below them. */
/* ⚠ A GRADIENT NEVER FULLY HIDES ANYTHING. The first attempt reached .42 opacity at
   the height headings actually pass through, so "Diri anda: 庚 · Logam" was still a
   quarter readable behind the chip — which looks broken rather than layered. Hold it
   effectively opaque through the WHOLE band the controls occupy, and only then fade.
   Sampled at y=60: 0% of the pixels differ from the ground. */
.pmz_topscrim{height:calc(116px + env(safe-area-inset-top,0px));
  background:linear-gradient(to bottom,
    rgba(1,3,11,1) 0,
    rgba(1,3,11,1) calc(74px + env(safe-area-inset-top,0px)),
    rgba(1,3,11,.90) calc(88px + env(safe-area-inset-top,0px)),
    rgba(1,3,11,.50) calc(101px + env(safe-area-inset-top,0px)),
    transparent 100%)}

/* -- 2 . TWO CONTROLS THAT WERE EFFECTIVELY INVISIBLE ---------------------
   MEASURED: the inactive half of 简化版/专业版 at 1.2:1, and "Buka semula upacara" at
   1.29:1. A control nobody can read is a control nobody presses. */
.pmz_modebar button{color:rgba(238,243,255,.92); font-weight:700}
.pmz_modebar button[aria-pressed="false"]{color:rgba(240,233,220,.80)}
#pmzReplay{color:rgba(240,220,166,.92); font-weight:700;
  border:1px solid rgba(201,162,75,.42); background:rgba(255,255,255,.05)}
#pmzReplay:active{background:rgba(255,255,255,.10)}

/* -- 3 . the verdict's reasoning, as the register shows it ----------------- */
.pmz_vwhy{display:flex; gap:6px; flex-wrap:wrap; margin-top:9px}
.pmz_vwhy u{text-decoration:none; padding:3px 9px; border-radius:99px;
  font:700 9.5px/1.5 var(--pmz-ui); letter-spacing:.10em; text-transform:uppercase;
  color:var(--pmz-ink-3); box-shadow:inset 0 0 0 1px rgba(21,17,14,.20)}
.pmz_vwhy u[data-on="1"]{background:rgba(21,17,14,.84); color:var(--pmz-paper);
  box-shadow:none}
/* the engine's own sentence, kept for a reader who wants it — secondary, not the
   only thing on offer */
.pmz_vzh{display:block; margin-top:10px; text-decoration:none;
  font:13px/1.7 var(--pmz-brush); color:var(--pmz-ink-3)}

/* -- 5 . ONE RADIUS LANGUAGE. The register settled on 15 for a card and 11 for a
   control; the record had ten different values, which is precisely the seam that
   makes it feel like an older app. The PLATE's own tiles keep theirs. */
#stChart .pmz_sheet, #stChart .pmz_card, #stPro .pmz_sheet{border-radius:15px}
#stChart .pmz_modebar, #stPro .pmz_modebar{border-radius:14px}
#stChart .pmz_modebar button, #stPro .pmz_modebar button{border-radius:11px}
#pmzReplay{border-radius:12px; min-height:46px}

/* -- THUMB TARGETS, WITHOUT SPENDING THE LIST'S HEIGHT --------------------
   MEASURED: the disclosure chevron is 44 wide and 38 TALL, and the category tabs are
   38. Both were deliberate — height on this screen comes out of the client list, and
   the documented floor here is 36 for an audience over 40.
   But the live app already showed the better answer: keep the ink small and extend
   the TARGET invisibly. Vertical-only, so nothing moves and no row grows.
   Chevron 38 → 54. Tabs 38 → 50. Zero layout cost. */
/* vertical only — a horizontal inset here widens the row's scrollWidth and makes a
   deliberate 10px overhang look like an 12px bug to the next person measuring it */
.pmz_row_more::after{content:''; position:absolute; inset:-8px 0;
  border-radius:inherit}
.pmz_row_more{position:relative}
.pmz_catrail button{position:relative}
.pmz_catrail button::after{content:''; position:absolute; inset:-6px 0;
  border-radius:inherit}
/* 选择 sits in the header row, which has the room to grow */
#pmzSelMode{min-height:44px}

/* the last one under: 高级筛选 at 42px. It sits beside the search field, which is 42
   too — growing it would break that alignment, so it gets the same invisible
   extension as everything else on this screen. 42 → 50. */
.pmz_funnel{position:relative}
.pmz_funnel::after{content:''; position:absolute; inset:-4px 0; border-radius:inherit}


/* ==============================================================================
   ROUND 16 — three things Jim caught on the register. All three are the same class
   of fault: the page was sending a signal badly, not missing one.
   ============================================================================== */

/* -- 1 . THE MASTHEAD WAS BEING PAINTED OVER BY ITS OWN SCRIM ----------------
   MEASURED: "Simpanan Klien" occupies y 71.8 → 96.2. The scrim was FULLY opaque to
   74px and still ~.72 at 96 — so the page's own title was 72–100% blacked out, and
   so was 选择 / "Pilih" sitting beside it, which is a CONTROL, not decoration.
   客户卷轴 sits at 98.2 and reads fine: exactly the split Jim's screenshot shows.
   ⚠ Round 12 deepened this scrim for a REAL reason — a record heading was half
   legible BEHIND the back button, and half-legible looks broken where hidden looks
   layered. The error was reaching past the controls. The band that must be opaque is
   the band the controls occupy: back button 14→50, Tenaga chip 13→40, pill 13→38.
   Not 116px. Take it to 90, fade it hard, then move the register's masthead clear of
   what is left. */
.pmz_topscrim{height:calc(90px + env(safe-area-inset-top,0px));
  background:linear-gradient(to bottom,
    rgba(1,3,11,1) 0,
    rgba(1,3,11,1) calc(52px + env(safe-area-inset-top,0px)),
    rgba(1,3,11,.90) calc(62px + env(safe-area-inset-top,0px)),
    rgba(1,3,11,.45) calc(74px + env(safe-area-inset-top,0px)),
    transparent 100%)}
/* the register's title now STARTS below the scrim instead of inside it.
   ⚠ every px here comes out of the client list, so all 18 are paid back below —
   §34 asserts the first card has not moved. */
/* ── THE THREE NUMBERS THAT HAVE TO AGREE ───────────────────────────────────
   The register's vertical geometry is three values that are really one:
     · where the document starts            (--pmz-docpad)
     · where the navigation bar parks       (--pmz-navtop, just under the back
                                             button at 13→51)
     · where the A→Z divider parks          (navtop + the bar's own height)
   ⚠ a sticky offset inside .pmz_doc resolves from the scroller's PADDING edge, so
   both sticky tops are the on-screen position MINUS the padding. Writing those two
   subtractions out by hand is how they drift apart; derive them.
   ⚠ 62, not the 84 of round 16: the scrim now stops at 56, so the masthead no longer
   has to start below a 90px one. That is 22px handed straight back to the list —
   half of what making the bar sticky costs. */
.pmz_root[data-screen="river"]{--pmz-docpad:62px; --pmz-navtop:54px; --pmz-navh:44px;
  --pmz-toolh:60px}
.pmz_root[data-screen="river"] .pmz_doc{
  padding-top:calc(var(--pmz-docpad) + env(safe-area-inset-top,0px))}
.pmz_root[data-screen="river"] .pmz_hd{padding-bottom:2px}
.pmz_root[data-screen="river"] .pmz_hint{margin-bottom:4px; padding-top:6px;
  padding-bottom:6px}
.pmz_root[data-screen="river"] .pmz_catrail{padding-bottom:6px}
.pmz_root[data-screen="river"] .pmz_tools{padding-bottom:8px}

/* -- 2 . THE "?" — A WORDLESS INDICATOR, AND ITS ONE REVIEW -----------------
   Jim: "why is there a '?' icon there? its confusing". A bare ? beside a finished
   sentence reads as *something here is unknown*, not *there is a note here*. And it
   was the only glossary handle on the whole page that was NOT a dotted underline,
   which is precisely what made it look like a warning instead of an invitation.
   Print the word — same verdict as the strength bar two rounds ago. */
.pmz_row_today[data-term] > span{
  text-decoration:underline dotted rgba(21,17,14,.34);
  text-underline-offset:3px; text-decoration-thickness:1px}
.pmz_row_today[data-term] > u{margin-left:auto; flex:none; text-decoration:none;
  font:700 9px/1 var(--pmz-ui); letter-spacing:.13em; text-transform:uppercase;
  color:var(--pmz-ink-3); padding-bottom:2px;
  border-bottom:1px dotted rgba(21,17,14,.42)}

/* -- 3 . "THE FILTER PAGE GOT OVER EXTENDED, USER DOES NOT KNOW" ------------
   The rail already scrolled and already faded on whichever side continued. A fade is
   feedback for someone who has ALREADY scrolled; it is not an invitation to scroll.
   Three signals instead, in the order a reader meets them:
     · PEEK   — the mask now cuts the next tab at 16px instead of dissolving it at 26
     · COUNT  — a pill at the live edge saying how many tabs are still off-screen.
                A number is a word; an arrow is not.
     · PLACE  — a hairline under the rail: how much of it you are looking at.
   The pill and the hairline are SIBLINGS of the rail, never children — the rail is
   masked, and a child of a masked box fades out with it. */
.pmz_railwrap{position:relative}
/* ⚠ A RESERVED GUTTER OF A FIXED WIDTH, AND THE CONTROL FLOATS INSIDE IT.
   Two faults are being closed here at once.
   1 · The first build floated the pill ABOVE the rail. The rig caught what that
       costs: elementFromPoint over the VIP tab returned the pill, so a filter went
       un-pressable while still looking perfectly tappable. A scroll cue that eats a
       filter is worse than no scroll cue.
   2 · The second build made the pill a flex sibling, so its OWN label set the rail's
       width — and the off-screen count is measured against that width. Switching
       "2 lagi" to "Ke awal" widened the pill, narrowed the rail, and the next count
       came back 3 when the truth was 2. A measurement must not depend on the thing
       it is about to write.
   Fixed 92px gutter, control absolutely placed inside it: the rail's width is now
   the same in every language and in both states. */
.pmz_railwrap:not([data-ovf="none"]) .pmz_catrail{margin-right:92px}
.pmz_railmore{position:absolute; right:12px; top:4px; z-index:4; max-width:80px;
  height:30px; padding:0 11px; cursor:pointer; border-radius:999px;
  display:flex; align-items:center; justify-content:center; gap:5px;
  background:linear-gradient(180deg,rgba(38,30,20,.94),rgba(18,14,10,.96));
  backdrop-filter:blur(9px); -webkit-backdrop-filter:blur(9px);
  border:1px solid rgba(201,162,75,.34);
  box-shadow:0 6px 16px -8px rgba(0,0,0,.86);
  color:rgba(240,220,166,.94); font:12px/1 var(--pmz-ui); white-space:nowrap}
.pmz_railmore b{font-weight:800; font-variant-numeric:tabular-nums}
.pmz_railmore[hidden]{display:none}
.pmz_railmore:active{transform:scale(.94)}
/* the thumb target, without growing the drawn pill */
.pmz_railmore::after{content:''; position:absolute; inset:-8px -6px; border-radius:inherit}

/* -- 4 . THE "WHY" CHIPS SAID THEIR STATE IN FILL ALONE ---------------------
   BOTH rival lenses, independently: a hollow pill can mean "no", "not available" or
   "not selected", and the reader has to infer which. Same family as the "?" — say
   it, do not code it. The fill stays as reinforcement; the mark carries the answer. */
.pmz_rd_why u s, .pmz_vwhy u s{text-decoration:none; margin-left:5px; opacity:.85;
  font-size:1.05em; line-height:1}


/* ══════════════════════════════════════════════════════════════════════════════
   ROUND 17 — THE RAIL BECOMES A NAVIGATION BAR.
   Jim: "I still found that, maybe we can make like a navigation bar feel so user
   know they can move?" — after a peek-cut AND a counted pill, the rail still did not
   INVITE. The diagnosis: pills are objects sitting in space. A bar is a PLACE. What
   was missing was the ground they stand on — a track that visibly runs off both
   edges of the screen, which is the one signal a fade can never give, because a fade
   says "this is ending" where a track says "this continues".
   ══════════════════════════════════════════════════════════════════════════════ */

/* -- 1 · IT STAYS PUT. A navigation bar that scrolls away is not a navigation bar.
   At 80 clients this is the difference between changing filter and scrolling
   seventeen screens back up to find the filter.
   ⚠ MEASURED, not assumed: a sticky offset inside .pmz_doc is resolved from the
   scroller's PADDING edge, not from its scrollport. The doc pads 84px, so top:54px
   parked the bar at 138px — 84 too low, and the search row scrolled up ABOVE it.
   The bar wants to rest at 54 (just under the back button's 51), so the offset is
   54 − 84 = −30. The env() insets cancel: the chrome is 13+env and the padding is
   84+env, so this number is the same on a notched phone and a flat one. */
/* ⚠ AND IT MUST NOT PARK UNDER THE SCRIM. At 54–98 the bar lands inside the scrim's
   own fade, and its labels measured 65% of their ink instead of 90 — the round-16
   masthead bug reappearing one element along, visible only once the bar is sticky.
   ⚠ RAISING THE Z-INDEX CANNOT FIX IT: .pmz_doc is `position:absolute; z-index:2`,
   which makes it a STACKING CONTEXT, so z-index:58 on a descendant is scoped inside
   it and can never rise above a scrim at 57. The scrim stops instead — see the
   ROUND 17 scrim block below. 58 is kept so the bar still leads its own siblings. */
.pmz_railwrap{position:sticky; z-index:58;
  top:calc(var(--pmz-navtop, 54px) - var(--pmz-docpad, 62px));
  background:linear-gradient(180deg, rgba(1,3,11,.97), rgba(1,3,11,.93));
  backdrop-filter:blur(10px) saturate(130%);
  -webkit-backdrop-filter:blur(10px) saturate(130%)}

/* -- 2 · THE TRACK. Edge to edge, ignoring the 14px the tabs are inset by, so it is
   plainly cut off by the screen rather than stopping politely inside it. */
.pmz_railwrap::after{content:''; position:absolute; left:0; right:0; bottom:0;
  height:1px; pointer-events:none;
  background:linear-gradient(90deg, rgba(201,162,75,.16), rgba(201,162,75,.30) 22%,
    rgba(201,162,75,.30) 78%, rgba(201,162,75,.16))}

/* -- 3 · TABS, NOT PILLS. A pill is a button; a tab is a place. The gold moves off
   the whole capsule and onto the mark beneath it, which is also what lets the
   selection SLIDE instead of jumping between two filled shapes. */
.pmz_catrail{position:relative; padding:0 14px; gap:0;
  align-items:stretch; overscroll-behavior-x:contain}
.pmz_catrail button{min-height:44px; padding:0 14px; gap:6px; border:0;
  background:none; border-radius:0; box-shadow:none;
  color:rgba(240,233,220,.62); font:600 13.5px/1 var(--pmz-ui)}
.pmz_catrail button i{font-size:11px; font-weight:700; opacity:.55;
  padding:2px 5px; border-radius:5px; background:rgba(255,255,255,.07)}
.pmz_catrail button[aria-pressed="true"]{color:#F3E4BC; font-weight:800;
  background:none; border-color:transparent; box-shadow:none}
.pmz_catrail button[aria-pressed="true"] i{opacity:1; color:#1B1408;
  background:linear-gradient(180deg,var(--pmz-gold-hi),var(--pmz-gold))}
/* the thumb target already spans the full 44px height, so the old -6px inset is gone */
.pmz_catrail button::after{content:none}

/* -- 4 · THE MARK THAT SLIDES. 1px wide, scaled to the tab — transform only, so it
   can never force layout on the bar it lives in.
   ⚠ it is ABSOLUTE inside the scroller, so it travels WITH the tabs when the rail is
   swiped; a mark that stayed behind while its tab moved would be worse than none. */
.pmz_railind{position:absolute; left:0; bottom:0; width:1px; height:2.5px;
  border-radius:2px 2px 0 0; transform-origin:left bottom; pointer-events:none;
  background:linear-gradient(90deg,var(--pmz-gold),var(--pmz-gold-hi) 50%,var(--pmz-gold));
  box-shadow:0 0 10px -2px rgba(201,162,75,.55);
  transition:transform .34s var(--pmz-out), opacity .2s linear}
@media(prefers-reduced-motion:reduce){ .pmz_railind{transition:none} }

/* -- 5 · THE COUNT, RESTYLED AS PART OF THE BAR. It was a dark glass capsule floating
   over a dark ground; on an opaque bar that reads as a sticker. Flat gold type on the
   bar's own surface instead. */
.pmz_railmore{top:0; height:44px; padding:0 12px 0 10px; gap:5px; border:0;
  background:none; backdrop-filter:none; -webkit-backdrop-filter:none;
  box-shadow:none; border-radius:0; color:rgba(240,220,166,.88);
  font:700 12px/1 var(--pmz-ui)}
.pmz_railmore svg{width:13px; height:13px; fill:none; stroke:currentColor;
  stroke-width:2; stroke-linecap:round; stroke-linejoin:round; opacity:.75}
.pmz_railmore b{padding:2px 6px; border-radius:5px; color:#1B1408; font-weight:800;
  background:linear-gradient(180deg,var(--pmz-gold-hi),var(--pmz-gold))}
.pmz_railmore:active{transform:none; opacity:.6}
/* a hairline where the bar ends and the control begins, so the control reads as part
   of the bar rather than as something dropped on top of it */
.pmz_railwrap:not([data-ovf="none"]) .pmz_railmore{
  box-shadow:inset 1px 0 0 rgba(201,162,75,.20)}

/* -- 6 · the bar owns its own spacing now, so the old paddings go with it */
.pmz_root[data-screen="river"] .pmz_catrail{padding-bottom:0}
.pmz_root[data-screen="river"] .pmz_tools{padding-top:12px}
/* ⚠ THE STICKY STACK HAS AN ORDER, AND EVERY OFFSET IN IT IS PADDING-RELATIVE.
   The A→Z divider was sticky at top:6, which parks it at 90 — under the chrome, and
   now under the bar as well. It has to come to rest just BELOW the bar:
   bar bottom on screen 98 − the doc's 84px padding = 14. */
/* ── ROUND 19 · THE SORT ROW STOPS STICKING ────────────────────────────────
   Jim: "remove the sticky A→Z divider". At 182px the parked header was 22% of the
   screen and this was the least earned 24px of it: it carries the SORT ORDER and the
   RECORD COUNT, which a consultant reads once on arrival, not continuously — unlike
   the tabs and the search field, which are things you reach for mid-list.
   It keeps its place at the head of the list; it simply travels with it now. */
.pmz_root[data-screen="river"] .pmz_reg_hd{position:static; top:auto}

/* -- 7 · the peek, re-tuned for a BAR. On pills a 16px fade cut the next capsule and
   that cut WAS the signal. On a continuous bar the tab is bare text, and a 16px fade
   next to the gutter rule slices a word instead of dissolving it — "Tiada Katego|"
   reads as a bug, not as a peek. Give the text room to fade out before the rule. */
.pmz_catrail[data-ovf="end"], .pmz_catrail[data-ovf="both"]{
  -webkit-mask-image:linear-gradient(90deg,#000 0,#000 calc(100% - 30px),transparent);
          mask-image:linear-gradient(90deg,#000 0,#000 calc(100% - 30px),transparent)}
.pmz_catrail[data-ovf="both"]{
  -webkit-mask-image:linear-gradient(90deg,transparent 0,#000 22px,#000 calc(100% - 30px),transparent);
          mask-image:linear-gradient(90deg,transparent 0,#000 22px,#000 calc(100% - 30px),transparent)}
.pmz_catrail[data-ovf="start"]{
  -webkit-mask-image:linear-gradient(90deg,transparent 0,#000 22px,#000 100%);
          mask-image:linear-gradient(90deg,transparent 0,#000 22px,#000 100%)}
/* and the rule itself softens into the bar instead of ruling across it */
.pmz_railwrap:not([data-ovf="none"]) .pmz_railmore{box-shadow:none}
.pmz_railwrap:not([data-ovf="none"]) .pmz_railmore::before{content:''; position:absolute;
  left:-1px; top:9px; bottom:9px; width:1px;
  background:linear-gradient(180deg,transparent,rgba(201,162,75,.34) 30%,
    rgba(201,162,75,.34) 70%,transparent)}
/* the mark is a mark, not a lamp — the glow was reading as a highlighter pen */
.pmz_railind{box-shadow:0 0 6px -3px rgba(201,162,75,.55)}


/* -- 8 · THE SCRIM ENDS WHERE THE BAR BEGINS -------------------------------
   Round 16 took this from 116px to 90 because it was painting over the masthead.
   Round 17 takes it to 56, for the same reason one element further on: the sticky
   bar parks at 54 and cannot escape .pmz_doc's stacking context to get above it.
   ⚠ This is safe precisely BECAUSE the bar is sticky. Everything that now passes
   through 56→90 unscrimmed is either nothing (at rest the masthead starts at 89.8)
   or the bar, which is opaque. What still MUST be hidden is content sliding behind
   the controls — back button 13→51, chip 13→40 — and 0→52 is untouched, fully
   opaque. §34 still measures that band at the chip's own baseline. */
/* ⚠ ROUND 31 · ITEM 7, THE GAP AT THE TOP. The scrim went fully opaque only to
   50px while the record's control slab parks at 54 — so a band of the page slid
   through 50→74 at partial alpha and you could read the chart THROUGH the chrome.
   That stripe is what Jim photographed. The opaque run now reaches the park point
   and the fade starts below it, so there is nothing left to see through. */
.pmz_topscrim{height:calc(78px + env(safe-area-inset-top,0px));
  background:linear-gradient(to bottom,
    rgba(5,4,3,1) 0,
    rgba(5,4,3,1) calc(56px + env(safe-area-inset-top,0px)),
    rgba(5,4,3,.42) calc(63px + env(safe-area-inset-top,0px)),
    rgba(5,4,3,.12) calc(70px + env(safe-area-inset-top,0px)),
    transparent 100%)}


/* ══════════════════════════════════════════════════════════════════════════════
   ROUND 18 — the search comes with it. Jim: "make the search bar sticky too".
   The category bar without the search field was half a header: you could change
   filter from anywhere in the list but still had to travel back to the top to type
   a name. Now the two are one surface — tabs, then search — and the track sits
   between them where it belongs, because it is the TABS' ground, not the header's.
   ══════════════════════════════════════════════════════════════════════════════ */
.pmz_root[data-screen="river"] .pmz_tools{
  position:sticky; z-index:57;
  top:calc(var(--pmz-navtop) + var(--pmz-navh) - var(--pmz-docpad));
  /* ⚠ z-index 57, under the bar's 58 — both live inside .pmz_doc's own stacking
     context (it is position:absolute; z-index:2), so these numbers only order them
     against each other and against the cards. Neither can reach the chrome. */
  padding:9px 14px; height:var(--pmz-toolh);
  background:linear-gradient(180deg, rgba(1,3,11,.95), rgba(1,3,11,.92));
  backdrop-filter:blur(10px) saturate(130%);
  -webkit-backdrop-filter:blur(10px) saturate(130%);
  /* the header block closes with one soft edge instead of a second gold rule —
     two hairlines 60px apart reads as a table, not as a header */
  box-shadow:0 14px 20px -18px rgba(0,0,0,.95), 0 1px 0 rgba(255,255,255,.045)}
/* the sticky rows are one surface, so the bar loses the shadow it does not need */
.pmz_root[data-screen="river"] .pmz_railwrap{box-shadow:none}

/* -- THE DIVIDER PARKS OVER PAPER NOW, SO IT HAS TO BE OPAQUE ---------------
   MEASURED from a screenshot: "15 Mei 1990 · 10:30 · 巳时" reading straight through
   "A → Z · 3 REKOD". At .80 over a DARK ground that translucency was the point — it
   let the room show through. Parked over an IVORY card it is just a bug, and one
   that only appears once the rows above it stick, because until then nothing ever
   passed underneath. Backdrop blur cannot save it: blurring 93%-luminance paper
   still gives you 93% luminance. */
.pmz_root[data-screen="river"] .pmz_reg_hd{
  background:linear-gradient(180deg, rgba(6,11,30,.985), rgba(6,11,30,.965));
  box-shadow:inset 0 0 0 1px rgba(201,162,75,.24), 0 10px 18px -14px rgba(0,0,0,.9)}

/* -- THE HEADER IS A SURFACE, NOT A GLASS ----------------------------------
   MEASURED by moving the list under it and diffing the pixels: 30.7% of the parked
   header changed as cards passed beneath. The alphas looked harmless — .97/.95/.985
   — but 7% of a 93%-luminance ivory card against a 3%-luminance ground is a 46-point
   RGB swing, and with backdrop-filter on top of it that arrives as a soft glow
   travelling under the tab labels. A single-pixel luminance probe could never see
   this; only motion could, which is why the gate scrolls and diffs.
   ⚠ Fully opaque also RETIRES two backdrop-filters on a scrolling surface — a blur
   with nothing left to blur is pure GPU cost, which is the same lesson as animating
   a layer nobody can see.
   The tones continue the scrim's own #01030B, so chrome and header read as one
   surface rather than two panels. */
.pmz_root[data-screen="river"] .pmz_railwrap{
  background:linear-gradient(180deg,#01030B 0,#03060F 100%);
  backdrop-filter:none; -webkit-backdrop-filter:none}
.pmz_root[data-screen="river"] .pmz_tools{
  background:linear-gradient(180deg,#03060F 0,#020509 100%);
  backdrop-filter:none; -webkit-backdrop-filter:none}
.pmz_root[data-screen="river"] .pmz_reg_hd{
  background:linear-gradient(180deg,#0A1026 0,#070C1E 100%);
  backdrop-filter:none; -webkit-backdrop-filter:none}
@keyframes pmz_secin{from{transform:translate3d(0,-6px,0); opacity:0}}

/* the way on. Quiet, full width, live only once the section can honestly be left */
.pmz_fnext{width:100%; min-height:46px; margin-top:6px; cursor:pointer;
  border-radius:12px; border:1px solid rgba(21,17,14,.20); background:rgba(21,17,14,.045);
  color:var(--pmz-ink); font:700 14px/1 var(--pmz-ui)}
.pmz_fnext:disabled{opacity:.38; cursor:default}
.pmz_fnext:not(:disabled):active{background:rgba(21,17,14,.10)}

/* -- 2 · THE 四柱 PANEL EARNS ITS PLACE -------------------------------------
   134px of ruled empty columns and a "0 / 4 DIISI" counter, on the one screen where
   the consultant has nothing yet — the screen they land on. One line until it does. */
.pmz_asm_wait{margin:0; padding:2px 2px 1px; font:12.5px/1.5 var(--pmz-ui);
  color:var(--pmz-ink-3); text-align:center}
.pmz_asm[data-has="1"] .pmz_asm_wait{display:none}
.pmz_asm[data-has="0"] .pmz_asm_row,
.pmz_asm[data-has="0"] .pmz_asm_ft{display:none}
.pmz_asm[data-has="0"]{padding-top:9px; padding-bottom:9px}

/* -- 3 · THE FOLDED 时辰 -----------------------------------------------------
   The chosen 时辰 stands where 400px of grid used to. The grid is unchanged — it
   opens as a sheet, the same way the date and the minute already did. */
#pmzFHour{display:flex; align-items:center; gap:9px}
/* the brush is for HAN. A Kaiti stack's Latin fallback is SimSun's, and it renders
   Malay in a fixed-width serif that reads as a rendering fault. */
#pmzFHourTxt{font:600 14.5px/1.25 var(--pmz-ui); color:var(--pmz-ink-3)}
#pmzFHourTxt[data-han="1"]{font:400 20px/1.2 var(--pmz-brush); color:var(--pmz-ink)}
#pmzFHourSub{margin-left:auto; margin-right:4px; text-decoration:none;
  font:12px/1 var(--pmz-ui); color:var(--pmz-ink-3); font-variant-numeric:tabular-nums}
#pmzFHour:disabled{opacity:.45}
.pmz_sh_body .pmz_dial{margin:0}


/* ══════════════════════════════════════════════════════════════════════════════
   ROUND 21 — ONE PAGE, NOT FOUR SURFACES.
   Jim: "the rest in a continuous new page dedicated seamlessly add client page",
   and "trim hard — open on the first field."
   Before: dark masthead 108px → ivory 四柱 panel → ivory sheet → dark button block.
   Four surfaces, three seams, and 420px before the first question.
   ══════════════════════════════════════════════════════════════════════════════ */

/* -- 1 · ONE LINE WHERE THE MASTHEAD WAS ------------------------------------ */
.pmz_fmttl{margin:0 0 10px; padding:0 16px; display:flex; align-items:baseline; gap:10px;
  font:400 22px/1.2 var(--pmz-disp); color:#F4F1E8}
.pmz_fmttl s{text-decoration:none; font:12px/1 var(--pmz-brush);
  letter-spacing:.22em; color:rgba(240,233,220,.42)}





/* ═════════════════════════════════════════════════════════════════════════════
   ROUND 23 — THREE BENTO BOXES, ROWS INSTEAD OF CARDS.
   Jim: "compact them nicely so that everything can be glanceable in one glance ...
   put like a bento box behind all this element and then under the bento box will be
   the background so that it's more easier to look at the data."

   The two asks are one fix. Nine glass cards floating separately on the night IS the
   busyness — every field was its own object with its own edge, so the eye counted
   nine things. Three surfaces, each holding rows divided by a hairline, and the eye
   counts three. The ground is untouched underneath, exactly as asked.

   A ROW IS: label left, answer right, hairline between. No inner box — the bento IS
   the surface, and a box inside a box is the thing that looked like work.
   ⚠ A borderless field has no border to turn gold, so FOCUS had to move to the row:
   a gold edge at the left and a warm wash across it. Without that there is no way to
   tell which field is taking the keystrokes.
   ═════════════════════════════════════════════════════════════════════════════ */

.pmz_form2{padding:0 13px}
.pmz_form2_b{display:flex; flex-direction:column; gap:11px; padding:11px 0 0}

/* -- 1 · THE BOX ------------------------------------------------------------
   Lifted off the ground rather than drawn on it: a glass panel, a hairline that
   catches light along the top edge, and a soft drop so the night reads as being
   BEHIND it. Rows bleed to its edges, so the focus marker can touch the edge. */
.pmz_bento{position:relative; padding:0 0 4px; border-radius:17px;
  background:linear-gradient(180deg, rgba(255,255,255,.066), rgba(255,255,255,.030));
  border:1px solid rgba(255,255,255,.10);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.075),
             0 16px 34px -24px rgba(0,0,0,.95);
  overflow:hidden}
.pmz_bento_t{margin:0; padding:11px 14px 7px;
  font:700 10.5px/1 var(--pmz-ui); letter-spacing:.17em; text-transform:uppercase;
  color:rgba(240,220,166,.66)}
/* a note belongs to the box, not to a field - it sits under the row it explains and
   carries the box's own left margin */
.pmz_bento_n{margin:0; padding:2px 14px 9px;
  font:12px/1.5 var(--pmz-ui); color:rgba(240,233,220,.42)}

/* -- 2 · THE ROW -------------------------------------------------------------
   50px, label in a fixed gutter so every answer on the page starts at the same x.
   That single alignment is most of why this scans faster than nine cards did. */
.pmz_r{position:relative; display:flex; align-items:center; gap:11px;
  min-height:50px; padding:0 14px;
  border-top:1px solid rgba(255,255,255,.055);
  transition:background .16s ease}
.pmz_bento_t + .pmz_r{border-top:0}
.pmz_r > label{flex:none; width:98px; margin:0;
  font:600 13px/1.25 var(--pmz-ui); letter-spacing:0; text-transform:none;
  color:rgba(240,233,220,.60)}

/* the OPTIONAL chip stacks under its label instead of pushing the gutter wider.
   ⚠ its text is attr(data-opt-label), which markDone() stamps - if that stamp ever
   stops, this renders as an EMPTY pill rather than as no pill at all. */
.pmz_r[data-opt="1"] > label{display:flex; flex-direction:column;
  align-items:flex-start; gap:3px}
.pmz_r[data-opt="1"] > label::after{content:attr(data-opt-label);
  padding:1.5px 6px; border-radius:99px; font:600 9px/1.35 var(--pmz-ui);
  letter-spacing:.05em; background:rgba(255,255,255,.07);
  color:rgba(240,233,220,.42)}

/* -- 3 · THE ANSWER SIDE -----------------------------------------------------
   Every control loses its own box and becomes text on the row. Right-aligned, so
   the answers form a second column you can read straight down. */
.pmz_bento .pmz_input,
.pmz_bento .pmz_pick{flex:1; min-width:0; width:auto; min-height:46px;
  margin:0; padding:0; border:0; border-radius:0; background:none; box-shadow:none;
  color:var(--pmz-paper, #F1F4FF); font:500 15.5px/1.3 var(--pmz-ui);
  text-align:right}
.pmz_bento .pmz_input:focus{outline:none; box-shadow:none}
.pmz_bento .pmz_input::placeholder{color:rgba(240,233,220,.30); font-weight:400}
.pmz_bento .pmz_pick{display:flex; align-items:center; justify-content:flex-end;
  gap:8px; cursor:pointer}
.pmz_bento .pmz_pick > span{font-weight:600; overflow:hidden; text-overflow:ellipsis;
  white-space:nowrap}
.pmz_bento .pmz_pick > s{flex:none; text-decoration:none;
  font:12px/1 var(--pmz-ui); color:rgba(240,233,220,.44)}
.pmz_bento .pmz_pick > em{flex:none; font-style:normal; font-size:11px;
  color:rgba(240,233,220,.40)}
.pmz_bento .pmz_pick:disabled{opacity:.42; cursor:default}
.pmz_bento #pmzFHourTxt{color:rgba(240,233,220,.38)}
.pmz_bento #pmzFHourTxt[data-han="1"]{color:#F6F2E6;
  font:400 20px/1.2 var(--pmz-brush)}
/* the minute picker is a second, smaller answer on the hour's own row */
.pmz_bento .pmz_pick_sm{flex:none; min-width:0; padding-left:10px;
  font-size:13.5px; color:rgba(240,233,220,.66);
  border-left:1px solid rgba(255,255,255,.09)}

/* -- 4 · FOCUS, WHICH NOW HAS TO BE THE ROW -------------------------------- */
.pmz_r:focus-within{background:linear-gradient(90deg,
  rgba(201,162,75,.13), rgba(201,162,75,.02) 72%, transparent)}
.pmz_r:focus-within::before{content:''; position:absolute; left:0; top:0; bottom:0;
  width:2.5px; background:linear-gradient(180deg,var(--pmz-gold-hi),var(--pmz-gold))}
/* a finished answer warms very slightly - enough to see the column filling in,
   not enough to become a second kind of highlight */
.pmz_r[data-done="1"] > label{color:rgba(240,233,220,.72)}

/* -- 5 · GENDER: TWO PILLS ON ONE ROW ---------------------------------------
   ⚠ neither is pressed until the consultant presses one. FORM_ST.sex ships as 男 so
   the control has something to render, and gender sets the DIRECTION of the 大运. */
.pmz_bento .pmz_seg{flex:1; display:flex; justify-content:flex-end; gap:7px;
  background:none; border:0; padding:0}
.pmz_bento .pmz_seg button{min-height:38px; padding:0 13px; border-radius:11px;
  cursor:pointer; border:1px solid rgba(255,255,255,.13);
  background:rgba(255,255,255,.045);
  color:rgba(240,233,220,.74); font:600 13.5px/1 var(--pmz-ui); white-space:nowrap;
  transition:color .16s ease, background .16s ease, border-color .16s ease}
.pmz_bento .pmz_seg button[aria-pressed="true"]{
  color:#1B1408; font-weight:800; border-color:transparent;
  background:linear-gradient(180deg,var(--pmz-gold-hi),var(--pmz-gold) 62%,#B98F3A);
  box-shadow:0 7px 16px -9px rgba(201,162,75,.75)}

/* -- 6 · "WAKTU LAHIR TIDAK DIKETAHUI" -------------------------------------
   A statement about the record, so it gets a row of its own: sentence left, box
   right, in the same column every other answer lives in. */
.pmz_r_chk{padding:0}
.pmz_bento .pmz_check{flex:1; min-height:48px; padding:0 14px; margin:0;
  display:flex; align-items:center; justify-content:space-between; gap:12px;
  cursor:pointer; border:0; border-radius:0; background:none; text-align:left;
  color:rgba(240,233,220,.66); font:500 13.5px/1.35 var(--pmz-ui)}
.pmz_bento .pmz_check i{flex:none; width:21px; height:21px; border-radius:7px;
  border:1.5px solid rgba(240,233,220,.30); background:none}
.pmz_bento .pmz_check[aria-pressed="true"]{color:#F1F4FF}
.pmz_bento .pmz_check[aria-pressed="true"] i{border-color:transparent;
  background:linear-gradient(180deg,var(--pmz-gold-hi),var(--pmz-gold));
  box-shadow:inset 0 0 0 3.5px rgba(1,3,11,.22)}

/* -- 7 · THE IC SHORTCUT ------------------------------------------------------
   Still gold, because it is the one control on the page that DOES something rather
   than records something - the colour grammar is INK for a selection, GOLD for an
   action, and this fills two fields in the box below. */
.pmz_r_ic .pmz_ic_in{flex:1; display:flex; align-items:center; gap:8px; min-width:0}
.pmz_r_ic .pmz_ic_in .pmz_input{flex:1; text-align:right; font-size:15px}

/* -- 8 · THE READ-ONLY 遁局 -------------------------------------------------- */
.pmz_r_ro .pmz_ro{flex:1; margin:0; min-height:0; padding:0; border:0;
  background:none; text-align:right;
  color:rgba(240,233,220,.62); font:500 14.5px/1.3 var(--pmz-ui)}

/* -- 9 · THE NOTE: ONE LINE THAT GROWS --------------------------------------
   Left-aligned, because prose is not a value. growNote() sets the height and caps
   it, so a long note scrolls rather than pushing the save button off the page. */
.pmz_r_ta{align-items:flex-start; padding-top:11px; padding-bottom:11px}
.pmz_r_ta > label{padding-top:5px}
.pmz_bento .pmz_ta{flex:1; min-height:28px; max-height:116px; padding:0;
  text-align:left; resize:none; overflow-y:auto; line-height:1.5; font-size:15px}

/* -- 10 · THE LIVE 四柱, AS THE LID OF THE STACK ------------------------------
   Same surface as the boxes so the page reads as four stacked tiles, but it is the
   only one that never asks anything - it reports. Sticky, because the form is still
   a shade over one screen and the chart forming is the reward for filling it in. */

/* -- 11 · ONE COMMIT --------------------------------------------------------- */

/* -- 12 · TIGHTER, AND THE COMMIT NEVER LEAVES ------------------------------
   Jim asked for one glance. Nine 50px rows plus three boxes plus the chart does not
   fit 654px of visible page, so two things give: the rhythm drops to 46px, and the
   save button stops being the last thing in the document and becomes a docked bar.
   ⚠ It docks ABOVE the tab bar, not at bottom:0 - the tab bar floats over the
   scroller, so a button at the true bottom sits underneath it and looks tappable
   while being unreachable. */
.pmz_r{min-height:46px}
.pmz_bento .pmz_input, .pmz_bento .pmz_pick{min-height:42px}
.pmz_bento_t{padding:9px 14px 5px}
.pmz_bento_n{padding:1px 14px 8px}
.pmz_bento{padding-bottom:2px}
.pmz_form2_b{gap:9px; padding:9px 0 0}
.pmz_r_chk{padding:0}
.pmz_bento .pmz_check{min-height:44px}
.pmz_r_ta{padding-top:9px; padding-bottom:9px}

/* ⚠ A STICKY OFFSET RESOLVES FROM THE SCROLLPORT'S PADDING EDGE. .pmz_doc pads the
   bottom to clear the floating tab bar, so `bottom:0` parked this bar that whole
   padding up the page - across the FAILKAN title and the Telefon row. Both numbers
   below are DERIVED: the tab bar is 72px tall sitting 14px off the bottom, so it
   owns an 86px band, and the doc reserves that band plus this bar's own height. */
.pmz_root[data-screen="form"]{
  --pmz-tabband:calc(86px + env(safe-area-inset-bottom,0px));
  --pmz-dockbar:84px;
  --pmz-dockgap:8px;
  /* what .pmz_doc reserves at its bottom, named once so the dock can subtract it */
  --pmz-docpadb:calc(var(--pmz-tabband) + var(--pmz-dockbar))}
.pmz_root[data-screen="form"] .pmz_doc{padding-bottom:var(--pmz-docpadb)}
.pmz_root[data-screen="form"] #pmzFormBtns{
  position:sticky; z-index:11;
  /* a sticky offset is measured from the scrollport's PADDING edge, so subtract the
     reserve to land the bar --pmz-dockgap above the tab band. ⚠ written this way
     because the previous form spelled the same value as A + B - A - C, which reads
     as an arithmetic mistake — a reviewer called it a shipped bug on sight. */
  bottom:calc(var(--pmz-tabband) + var(--pmz-dockgap) - var(--pmz-docpadb));
  margin:9px -13px 0; padding:11px 13px 13px;
  background:linear-gradient(180deg, rgba(1,3,11,0) 0,
    rgba(1,3,11,.88) 34%, #01030B 100%)}
.pmz_root[data-screen="form"] #pmzDoCast{min-height:52px}

/* an empty picker is a PROMPT, so it carries placeholder weight rather than looking
   like an answer somebody already chose */
.pmz_bento .pmz_pick > span[data-empty="1"]{font-weight:400;
  color:rgba(240,233,220,.30)}

/* -- 13 · THE LAST FEW PIXELS ------------------------------------------------
   Trims, not changes: nothing moves, nothing is hidden, the page just stops
   spending height on air. */
.pmz_fmttl{margin-bottom:6px}
.pmz_form2_b{gap:8px}
.pmz_r_ta{padding-top:8px; padding-bottom:8px}
.pmz_bento .pmz_ta{min-height:24px}

/* -- 14 · WHAT THE RIG CAUGHT ------------------------------------------------
   ⚠ THE COMPRESSION ATE TWO TOUCH TARGETS. The gender pills came out 38px and the
   one-line note 24px, against a 44px floor that exists because this audience is
   40-plus and using a phone one-handed. Neither needs to LOOK bigger - the note
   takes its 44px as padding around a single line of text, so the target grows and
   the page does not. */
.pmz_bento .pmz_seg button{min-height:44px}
.pmz_bento .pmz_ta{min-height:24px; padding:10px 0}

/* ⚠ the panel gave 78px back to the keyboard against a floor of 80 - a real 2px
   regression from trimming its padding. Taken back from the COLLAPSED state, where
   it is worth more: while you are typing, every pixel belongs to the form. */
.pmz_root[data-kb="1"] .pmz_root[data-screen="form"] .pmz_asm,
.pmz_root[data-kb="1"] .pmz_asm{padding-top:7px; padding-bottom:7px}

/* ⚠ the parked chart sat 64px down against a chrome that ends at 51. A sticky
   `top` resolves from .pmz_doc's PADDING edge (66px), so top:-2px parks at 64 - the
   round-17 lesson, third appearance. -10px lands it at 56, tucked under the chrome
   instead of floating below it. */

/* -- 15 · FOCUS HAS TO REACH THE END OF THE ROW YOU ACTUALLY TAP -------------
   ⚠ FOUND BY THE agy LENS, AND MY OWN GATE WAS BLIND TO IT. The value is
   right-aligned; the focus marker was a gold edge on the far LEFT and a wash that
   faded to transparent by 72%. MEASURED: focusing a field repainted 100% of the
   row's left third and 0.4% of its right third - the two-thirds of the row a
   consultant is looking at and tapping got no feedback at all. § 38.3 averaged the
   WHOLE row (57.3%) and an average is exactly what hides a dead third.
   The wash now carries all the way across, and the control itself takes a gold
   underline. A STATIC inset shadow, never an animated one. */
.pmz_r:focus-within{background:linear-gradient(90deg,
  rgba(201,162,75,.14) 0, rgba(201,162,75,.07) 62%, rgba(201,162,75,.05) 100%)}
.pmz_r:focus-within .pmz_input,
.pmz_r:focus-within .pmz_pick,
.pmz_r:focus-within .pmz_ic_in .pmz_input{
  box-shadow:inset 0 -2px 0 -0.5px var(--pmz-gold); color:#FFFDF7}

/* ⚠ 42px, not 44: the pickers sat two pixels under the floor while the gate that
   guards it was only watching a named list of ids. This audience is 40-plus. */
.pmz_bento .pmz_input, .pmz_bento .pmz_pick{min-height:44px}

/* ═════════════════════════════════════════════════════════════════════════════
   ROUND 24 — LEGIBILITY FIRST. Jim: "the current bento card background is too dark,
   imagine some old people, they cant even see clearly."

   The round-23 card was white at 3-7% over a near-black ground - a panel you can
   only find if you already know it is there. It is a real surface now, and every
   piece of text on it went up in both size and contrast. This costs height, which
   is paid for by putting the OPTIONAL chip back on the label's own line.
   ═════════════════════════════════════════════════════════════════════════════ */

/* -- 1 · THE CARD IS A SURFACE, NOT A TINT --------------------------------- */
.pmz_bento{
  background:linear-gradient(180deg, rgba(46,60,112,.94), rgba(33,44,86,.94));
  border:1px solid rgba(255,255,255,.19);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.13),
             0 18px 36px -22px rgba(0,0,0,.95)}
.pmz_bento_t{color:#EBD293; font-size:11.5px; letter-spacing:.15em;
  padding:12px 15px 7px}
/* the rules between rows have to be visible to a 60-year-old eye too */
.pmz_r{border-top-color:rgba(255,255,255,.14); padding:0 15px}
.pmz_r_chk{padding:0}

/* -- 2 · TYPE THAT CAN ACTUALLY BE READ ------------------------------------
   ⚠ the gutter widens 98 → 112 so the OPTIONAL chip fits BESIDE its label instead
   of under it: bigger text, and three rows get 18px back. */
.pmz_r > label{width:112px; font:600 14.5px/1.25 var(--pmz-ui);
  color:rgba(233,239,255,.88)}
.pmz_r[data-opt="1"] > label{flex-direction:row; align-items:center; gap:6px}
.pmz_r[data-opt="1"] > label::after{font-size:9.5px; padding:2px 6px;
  background:rgba(255,255,255,.13); color:rgba(233,239,255,.66)}
.pmz_bento .pmz_input, .pmz_bento .pmz_pick{font:600 16.5px/1.3 var(--pmz-ui);
  color:#FFFFFF}
.pmz_bento .pmz_input::placeholder{color:rgba(214,224,255,.58); font-weight:400}
.pmz_bento .pmz_pick > span[data-empty="1"]{color:rgba(214,224,255,.58);
  font-weight:400}
.pmz_bento .pmz_pick > s{font-size:13px; color:rgba(214,224,255,.72)}
.pmz_bento .pmz_pick > em{color:rgba(214,224,255,.66); font-size:12.5px}
.pmz_bento .pmz_pick_sm{font-size:14.5px; color:rgba(233,239,255,.86);
  border-left-color:rgba(255,255,255,.16)}
.pmz_bento_n{color:rgba(214,224,255,.68); font-size:12.5px; padding:2px 15px 9px}
.pmz_bento .pmz_check{font:500 14.5px/1.35 var(--pmz-ui);
  color:rgba(233,239,255,.86); padding:0 15px}
.pmz_bento .pmz_check i{width:23px; height:23px;
  border-color:rgba(233,239,255,.52)}
.pmz_r_ro .pmz_ro{font-size:15.5px; color:rgba(233,239,255,.82)}
.pmz_bento .pmz_seg button{font-size:14.5px; color:rgba(233,239,255,.86);
  border-color:rgba(255,255,255,.20); background:rgba(255,255,255,.07)}
.pmz_bento #pmzFHourTxt{color:rgba(214,224,255,.58)}
.pmz_bento #pmzFHourTxt[data-han="1"]{color:#FFFDF7}

/* -- 4 · THE ANSWER TO "how accurate is it" ---------------------------------
   Gold, because it is information the consultant asked for - not a warning. */
.pmz_bento_n_warn{color:#EBD293; background:rgba(201,162,75,.10);
  margin:0 15px 9px; padding:8px 11px; border-radius:10px;
  border:1px solid rgba(201,162,75,.28)}
.pmz_bento_n_warn[hidden]{display:none}

/* -- 5 · THE COMMIT, LEGIBLE ---------------------------------------------
   Jim: "its abit hard to read the text". It was 15px of near-black on gold with a
   gold-on-gold price pill beside it. Bigger, heavier, and the price sits in a dark
   capsule so the two are not competing at the same value. */
.pmz_root[data-screen="form"] #pmzDoCast{min-height:56px;
  font:800 17.5px/1 var(--pmz-ui); color:#140F06; letter-spacing:.01em; gap:12px}
.pmz_root[data-screen="form"] #pmzDoCast .pmz_addcost{
  background:rgba(18,13,5,.80); padding:5px 11px 5px 8px; border-radius:999px}
.pmz_root[data-screen="form"] #pmzDoCast .pmz_addcost b{color:#F6E3B0;
  font:800 13px var(--pmz-ui)}
.pmz_root[data-screen="form"] #pmzDoCast .pmz_addcost svg{opacity:.95}

/* -- 2 · THE PICKERS COME TO THE MIDDLE -------------------------------------
   Jim: "I prefer to pop up in the middle and easy to navigate and select the data."
   A bottom sheet on a 844px screen puts the choices under the thumb but at the very
   edge of vision; centred, the whole list is in the middle of the field of view.
   ⚠ the brass rod is a BOTTOM-SHEET affordance (it says "drag me down") - a centred
   dialog that keeps it is telling the user something untrue, so it goes. */
.pmz_sheeth{align-items:center; justify-content:center; padding:0 16px}
.pmz_sh{width:100%; max-width:396px; max-height:78%; border-radius:16px;
  box-shadow:0 32px 70px rgba(0,0,0,.72), 0 0 0 1px rgba(201,162,75,.30);
  animation:pmz_shpop .26s var(--pmz-out) backwards}
@keyframes pmz_shpop{from{transform:scale(.94); opacity:0}}
.pmz_sh_rod{display:none}
.pmz_sh_hd{padding:15px 16px 12px}
.pmz_sh_hd b{font-size:19px}
.pmz_sh_x{width:42px; height:42px}
.pmz_sh_foot{padding:12px 16px 16px}
.pmz_sh_foot button{min-height:52px; font-size:15px}

/* -- 6 · ONE GLANCE, PAID FOR HONESTLY -------------------------------------
   ⚠ THE EMPTY 四柱 BAND IS 50px SPENT SAYING "nothing here yet". It only ever held
   one sentence promising that pillars appear once a date is in — and the pillars
   APPEARING is that message, delivered better. Gone until it has something to show,
   which is exactly the 50px that was keeping the last box under the docked bar. */

/* and the rest of the glance, taken in small pieces rather than out of the type */
.pmz_r{min-height:44px}
.pmz_bento .pmz_input, .pmz_bento .pmz_pick{min-height:44px}
.pmz_bento_t{padding:9px 15px 5px}
.pmz_bento_n{padding:1px 15px 8px}
.pmz_form2_b{gap:7px; padding:7px 0 0}
.pmz_fmttl{font-size:20px; margin-bottom:4px}
.pmz_bento .pmz_check{min-height:44px}
.pmz_r_ta{padding-top:7px; padding-bottom:7px}

/* the two gender pills share the row evenly now that they are words, not word+glyph */
.pmz_bento .pmz_seg{gap:8px}
.pmz_bento .pmz_seg button{flex:1; min-width:0; padding:0 8px}

/* -- 7 · THE LAST 22 PIXELS ---------------------------------------------------
   MEASURED: the Nota row ended at 688 against a docked bar starting at 666, so the
   one field that was still tucked under the bar was the last one. Taken from
   padding on both sides — the rows keep their 44px targets and the type keeps its
   size; only air is spent. */
.pmz_r_ta{padding-top:3px; padding-bottom:3px}
.pmz_bento_t{padding:7px 15px 4px}
.pmz_form2_b{gap:6px}
.pmz_bento{padding-bottom:1px}
.pmz_root[data-screen="form"]{--pmz-dockbar:78px}
.pmz_root[data-screen="form"] #pmzFormBtns{padding:9px 13px 11px}

/* ═════════════════════════════════════════════════════════════════════════════
   ROUND 25 — THE PICKERS BECOME THE APP'S OWN.
   Jim: "if possible can we like use back the real time chart selecter as refference
   and we improve and refine from there?"
   So the wheel below is PORTED, not imitated: 44px rows, the gold lens band, the
   masked fade top and bottom, the day grid with its gold selected cell. Same numbers
   as assets/qimen-realtime.css so the two screens are visibly one product.
   ═════════════════════════════════════════════════════════════════════════════ */

/* -- 1 · THE DIALOG ---------------------------------------------------------- */
.pmz_sh_dark{
  background:linear-gradient(180deg, #141C3C 0%, #0D1430 62%, #0A1029 100%);
  border:1px solid rgba(255,255,255,.16);
  box-shadow:0 34px 74px rgba(0,0,0,.76), 0 0 0 1px rgba(201,162,75,.22),
             inset 0 1px 0 rgba(255,255,255,.10)}
.pmz_sh_dark .pmz_sh_hd{border-bottom:1px solid rgba(255,255,255,.12); padding:15px 16px 12px}
/* ONE family in the dialogs. The display serif stays on the page title, where it is
   the brand; on a picker heading it was just a third typeface. */
.pmz_sh_dark .pmz_sh_hd b{font:700 18px/1.2 var(--pmz-ui); color:#F2F5FF;
  letter-spacing:.005em}
.pmz_sh_dark .pmz_sh_hd s{color:rgba(214,224,255,.50); font-size:12px; letter-spacing:.2em}
.pmz_sh_dark .pmz_sh_x{width:42px; height:42px; border:1px solid rgba(255,255,255,.16);
  background:rgba(255,255,255,.07); color:#E6ECFF; font-size:16px}
.pmz_sh_dark .pmz_sh_body{padding:16px}
.pmz_sh_dark .pmz_sh_foot{border-top:1px solid rgba(255,255,255,.12);
  background:rgba(0,0,0,.24); padding:12px 16px 16px}
.pmz_sh_dark .pmz_sh_foot button{min-height:52px; border-radius:14px;
  font:700 15px var(--pmz-ui)}
.pmz_sh_dark .pmz_sh_2nd{border:1px solid rgba(255,255,255,.20);
  background:rgba(255,255,255,.07); color:#E6ECFF}
.pmz_sh_dark .pmz_sh_1st{border:0; color:#160F04; font-weight:800;
  background:linear-gradient(180deg,var(--pmz-gold-hi),var(--pmz-gold) 62%,#B98F3A)}
.pmz_sh_dark .pmz_sh_1st[disabled]{opacity:.42}
/* anything the old paper sheets styled with ink now reads on the dark ground */
.pmz_sh_dark p, .pmz_sh_dark li, .pmz_sh_dark span, .pmz_sh_dark b, .pmz_sh_dark div{
  color:inherit}
.pmz_sh_dark{color:#E6ECFF}

/* -- 2 · THE WHEEL, ported verbatim from qimen-realtime.css ------------------
   ⚠ 44px appears three times on purpose and all three must agree: the row height,
   the .pmz_wl padding that centres row 0 under the lens, and WROW in the JS. */
.pmz_wh_row{flex:1; display:flex; gap:9px; min-width:0}
.pmz_wh{position:relative; flex:1; height:132px; overflow-y:scroll;
  scroll-snap-type:y mandatory; scrollbar-width:none; -webkit-overflow-scrolling:touch;
  border:1px solid rgba(217,178,95,.28); border-radius:15px;
  background:rgba(217,178,95,.08); touch-action:none;
  -webkit-mask:linear-gradient(180deg,transparent,#000 26%,#000 74%,transparent);
          mask:linear-gradient(180deg,transparent,#000 26%,#000 74%,transparent)}
.pmz_wh::-webkit-scrollbar{display:none}
.pmz_wl{padding:44px 0}
.pmz_wh b{display:flex; align-items:center; justify-content:center; height:44px;
  scroll-snap-align:center; font:400 20px/1 var(--pmz-ui); color:rgba(214,224,255,.52);
  font-variant-numeric:lining-nums tabular-nums;
  transition:color .18s ease, transform .18s ease}
.pmz_wh b.on{color:var(--pmz-gold-hi); transform:scale(1.14); font-weight:700}
.pmz_wlens{position:absolute; left:0; right:0; top:44px; height:44px;
  pointer-events:none; border-top:1px solid rgba(217,178,95,.48);
  border-bottom:1px solid rgba(217,178,95,.48)}
.pmz_wh_lab{display:flex; gap:9px; margin:0 0 7px}
.pmz_wh_lab span{flex:1; text-align:center; font:700 10.5px/1 var(--pmz-ui);
  letter-spacing:.16em; text-transform:uppercase; color:rgba(240,220,166,.72)}

/* -- 3 · AM / PM, and the echo that says what the engine heard --------------- */
.pmz_ampm{display:grid; grid-template-columns:1fr 1fr; gap:9px; margin-top:12px}
.pmz_ampm button{min-height:48px; border-radius:13px; cursor:pointer;
  border:1px solid rgba(255,255,255,.18); background:rgba(255,255,255,.06);
  color:rgba(233,239,255,.86); font:700 15px/1 var(--pmz-ui);
  transition:color .16s, background .16s, border-color .16s}
.pmz_ampm button[aria-pressed="true"]{color:#160F04; border-color:transparent;
  background:linear-gradient(180deg,var(--pmz-gold-hi),var(--pmz-gold) 62%,#B98F3A);
  box-shadow:0 8px 18px -10px rgba(201,162,75,.75)}
.pmz_wh_echo{margin:13px 0 0; text-align:center; font:600 15px/1.4 var(--pmz-ui);
  color:rgba(240,220,166,.90)}

/* -- 4 · THE DAY GRID ------------------------------------------------------- */
.pmz_dp_jump{display:flex; align-items:center; gap:10px; margin-bottom:14px}
.pmz_dp_nav{width:42px; height:42px; flex:0 0 42px; border-radius:13px; cursor:pointer;
  border:1px solid rgba(255,255,255,.18); background:rgba(240,233,220,.07);
  color:#E6ECFF; font:400 20px/1 var(--pmz-ui);
  display:flex; align-items:center; justify-content:center}
.pmz_dp_wd{display:grid; grid-template-columns:repeat(7,1fr); gap:3px; margin-bottom:5px}
.pmz_dp_wd span{text-align:center; font:800 12px/1 var(--pmz-ui);
  letter-spacing:.06em; text-transform:uppercase; color:rgba(240,220,166,.80)}
.pmz_dp_grid{display:grid; grid-template-columns:repeat(7,1fr); gap:3px}
.pmz_dp_d{aspect-ratio:1/1; border:none; background:transparent; color:#E9EEFF;
  border-radius:12px; font:600 17px/1 var(--pmz-ui); cursor:pointer;
  display:flex; align-items:center; justify-content:center;
  font-variant-numeric:lining-nums tabular-nums;
  transition:background .16s ease, box-shadow .2s ease}
.pmz_dp_d:active{background:rgba(217,178,95,.18)}
.pmz_dp_d.pad{opacity:0; pointer-events:none}
.pmz_dp_d.today{box-shadow:inset 0 0 0 1px rgba(217,178,95,.55)}
.pmz_dp_d.on{background:linear-gradient(150deg,#F2DCA4,var(--pmz-gold) 52%,#A9822F);
  color:#1A1206; font-weight:800}
/* Jim: "we can state that this is the international date we are using" */
.pmz_dp_cal{margin:14px 0 0; text-align:center; font:12.5px/1.5 var(--pmz-ui);
  color:rgba(214,224,255,.58)}

/* -- 5 · THE FORM ROW: a clock, with the 时辰 as a footnote ------------------ */
.pmz_bento #pmzFHourSub{font:400 15px/1 var(--pmz-brush);
  color:rgba(240,220,166,.86); letter-spacing:.04em}

/* -- 8 · THE FILLED 四柱 PANEL, TIGHTER --------------------------------------
   Once a date lands the panel appears and pushes the last box under the docked bar.
   It is the reward, so it stays — it just stops taking 275px to say four pillars. */

/* ═════════════════════════════════════════════════════════════════════════════
   ROUND 26 — WARM INK, A QUIETER COMMIT, AND THE CATEGORY SHEET IN THE DARK.
   ═════════════════════════════════════════════════════════════════════════════ */

/* -- 1 · THE CARD, WARMED ------------------------------------------------------
   Jim: "its like cooperate 9 to 5 day job emotionless feel". It was hue 226 at 40%
   saturation - dashboard blue. Same lightness, hue carried round toward plum, a warm
   wash falling from the top edge, and the top hairline is GOLD rather than white so
   the light on the card comes from the brand instead of from a UI kit. */
/* ☠ the round-26 purple card is deleted, not merely overridden — two .pmz_bento
   backgrounds in one stylesheet is one bad edit away from painting the wrong one. */
/* the rules between rows warm with it - a cold grey hairline on a warm card is the
   detail that keeps a surface looking synthetic */
.pmz_r{border-top-color:rgba(233,206,158,.15)}
.pmz_bento_t{color:#EDD59B}
.pmz_r > label{color:rgba(238,233,247,.88)}
.pmz_bento .pmz_input, .pmz_bento .pmz_pick{color:#FFFDF9}
.pmz_bento .pmz_input::placeholder{color:rgba(226,216,240,.56)}
.pmz_bento .pmz_pick > span[data-empty="1"]{color:rgba(226,216,240,.56)}
.pmz_bento_n{color:rgba(226,216,240,.66)}
.pmz_bento .pmz_check{color:rgba(238,233,247,.86)}
.pmz_r_ro .pmz_ro{color:rgba(238,233,247,.82)}
.pmz_bento .pmz_seg button{border-color:rgba(233,206,158,.22);
  background:rgba(255,251,240,.07); color:rgba(238,233,247,.86)}
.pmz_r[data-opt="1"] > label::after{background:rgba(233,206,158,.14);
  color:rgba(238,233,247,.66)}
/* the dialogs are the same material as the cards, or the flow breaks again */
.pmz_sh_dark{
  background:
    radial-gradient(125% 60% at 50% -8%, rgba(201,162,75,.16) 0%, transparent 60%),
    linear-gradient(180deg, #262014 0%, #1D180E 62%, #171208 100%);
  border:1px solid rgba(233,206,158,.20)}

/* -- 2 · THE COMMIT, LIGHTER ---------------------------------------------------
   Jim: "the buka rekod button font its abit too heavy or bolded. same as the 5,000.
   the reading its abit weird". 800 weight at 17.5px on a gold fill is a shout, and
   the price was shouting back at the same weight from a black capsule beside it, so
   the eye could not tell which of the two was the button. The label steps down to
   700 and the price becomes a QUIET companion — lighter, smaller, lower contrast.
   One voice, one echo. */
.pmz_root[data-screen="form"] #pmzDoCast{font:700 17px/1 var(--pmz-ui);
  letter-spacing:.015em; color:#1B1305; gap:11px}
.pmz_root[data-screen="form"] #pmzDoCast .pmz_addcost{
  background:rgba(27,19,5,.13); border:1px solid rgba(27,19,5,.16);
  padding:4px 10px 4px 7px}
.pmz_root[data-screen="form"] #pmzDoCast .pmz_addcost b{color:rgba(27,19,5,.78);
  font:600 12.5px var(--pmz-ui); letter-spacing:.01em}
.pmz_root[data-screen="form"] #pmzDoCast .pmz_addcost svg{opacity:.62}

/* -- 3 · THE CATEGORY SHEET — A REAL BUG -----------------------------------
   ⚠ `.pmz_sh_row` was written for the ivory sheet: var(--pmz-ink) text and a
   seal-red pressed wash. Inside a dark dialog that is DARK TEXT ON A DARK GROUND —
   "VIP" and "Rujukan Ali" were rendered and unreadable, the chosen row came up
   maroon with a red tick, and the "new category" field was still a white paper input
   with a black button. Nothing was broken in the markup; the theme simply never
   reached it. Same class of miss as the pale day cells last round: a superseded rule
   that still matches. */
.pmz_sh_dark .pmz_sh_row{min-height:52px; padding:0 14px; margin-bottom:4px;
  border-radius:13px; border:1px solid transparent; background:rgba(255,251,240,.05);
  color:#F3EFFA; font:600 15.5px/1.35 var(--pmz-ui); cursor:pointer; width:100%}
.pmz_sh_dark .pmz_sh_row:active{background:rgba(233,206,158,.14)}
.pmz_sh_dark .pmz_sh_row[aria-pressed="true"]{
  background:rgba(233,206,158,.16); border-color:rgba(233,206,158,.42);
  color:#FFFDF9; font-weight:700}
.pmz_sh_dark .pmz_sh_row em{color:var(--pmz-gold-hi); font-weight:700; font-size:17px}
.pmz_sh_dark .pmz_sh_row s{color:rgba(226,216,240,.62)}
.pmz_sh_dark .pmz_sh_dot{width:9px; height:9px;
  box-shadow:0 0 0 1px rgba(0,0,0,.35)}
.pmz_sh_dark .pmz_sh_new{gap:9px; padding:14px 0 2px}
.pmz_sh_dark .pmz_sh_new input{min-height:50px; border-radius:13px; padding:0 14px;
  border:1px solid rgba(233,206,158,.24); background:rgba(255,251,240,.07);
  color:#FFFDF9; font:500 15.5px var(--pmz-ui)}
.pmz_sh_dark .pmz_sh_new input::placeholder{color:rgba(226,216,240,.52)}
.pmz_sh_dark .pmz_sh_new input:focus{outline:none;
  border-color:rgba(233,206,158,.58); background:rgba(255,251,240,.11)}
.pmz_sh_dark .pmz_sh_new button{min-height:50px; padding:0 18px; border-radius:13px;
  border:0; color:#1B1305; font:700 14.5px var(--pmz-ui);
  background:linear-gradient(180deg,var(--pmz-gold-hi),var(--pmz-gold) 62%,#B98F3A)}

/* -- 4 · THE PILLARS, TRIMMED --------------------------------------------------
   Jim: "trim the pillars so everything fits in one glance". They are the reward for
   filling the form in, so they keep their shape and their element colours — they
   just stop being 25px tall glyphs in a 275px panel. */

/* -- 5 · THE 遁局 ON THE BOX TITLE, AND THE LAST TRIMS -----------------------
   576px of page against 685px of content once a chart forms. Two rows left the form
   for better reasons than height; the rest comes out of air. */
.pmz_bento_t{position:relative; display:flex; align-items:baseline; gap:10px;
  padding:7px 15px 4px}
.pmz_bento_ju{margin-left:auto; display:flex; align-items:baseline; gap:7px;
  text-transform:none; letter-spacing:0}
.pmz_bento_ju i{font-style:normal; font:600 10px/1 var(--pmz-ui);
  letter-spacing:.08em; color:rgba(226,216,240,.50)}
.pmz_bento_ju b{font:600 13px/1 var(--pmz-ui); color:rgba(238,233,247,.86)}
.pmz_r_chk[hidden]{display:none}

.pmz_form2_b{gap:5px; padding:5px 0 0}
.pmz_bento_n{padding:0 15px 6px}
.pmz_r_ta{padding-top:2px; padding-bottom:2px}

/* -- 6 · THE LAST 18 --------------------------------------------------------
   MEASURED: 594px of content against 576px of page. Every row keeps its 44px touch
   target and every type size is untouched — this is padding and the dock's own
   reserve, nothing a reader can lose. */
.pmz_bento_t{padding:5px 15px 3px}
.pmz_bento{padding-bottom:0}
.pmz_form2_b{gap:4px}
.pmz_root[data-screen="form"]{--pmz-dockbar:74px}
.pmz_root[data-screen="form"] #pmzFormBtns{padding:8px 13px 10px}

/* the box title and its 遁局 share ONE row. ⚠ the span cannot live inside the <h3>:
   the [data-t] language pass assigns textContent, which would delete it. */
.pmz_bento_hd{display:flex; align-items:baseline; gap:10px; padding:5px 15px 3px}
.pmz_bento_hd .pmz_bento_t{padding:0; flex:none}

/* ═════════════════════════════════════════════════════════════════════════════
   ROUND 27 — THE APP'S OWN COLOURS, NOT MINE.
   ⚠ The purple was an over-correction. "Corporate blue" was a real diagnosis and I
   answered it by moving the HUE, which is the wrong lever — the live app is ALSO
   blue (#16203F / #121B3A) and reads expensive, because it is deep, almost
   colourless, and warmed by a GOLD line rather than by putting red in the fill.
   Every value below is lifted from assets/qimen-realtime.css.
   ═════════════════════════════════════════════════════════════════════════════ */

/* -- 1 · SURFACES: --g3 → --ink-blue, with --line as the rim ------------------ */
.pmz_bento{
  background:linear-gradient(180deg,var(--pmz-lacq) 0%,var(--pmz-lacq-2) 58%,var(--pmz-lacq-3) 100%);
  border:1px solid rgba(217,178,95,.22);
  box-shadow:inset 0 1px 0 rgba(246,227,172,.09),
             0 20px 40px -24px rgba(0,0,0,.96)}
.pmz_r{border-top-color:rgba(217,178,95,.15)}
.pmz_bento_t{color:#E9C77E}
.pmz_r > label{color:rgba(240,233,220,.80)}
.pmz_bento .pmz_input, .pmz_bento .pmz_pick{color:#F4EEE2}
.pmz_bento .pmz_input::placeholder{color:rgba(240,233,220,.46)}
.pmz_bento .pmz_pick > span[data-empty="1"]{color:rgba(240,233,220,.46)}
.pmz_bento .pmz_pick > s{color:rgba(240,233,220,.62)}
.pmz_bento .pmz_pick > em{color:rgba(240,233,220,.50)}
.pmz_bento_n{color:rgba(240,233,220,.58)}
.pmz_bento .pmz_check{color:rgba(240,233,220,.80)}
.pmz_bento .pmz_check i{border-color:rgba(240,233,220,.42)}
.pmz_r_ro .pmz_ro{color:rgba(240,233,220,.78)}
.pmz_bento .pmz_seg button{border-color:rgba(217,178,95,.24);
  background:rgba(240,233,220,.05); color:rgba(240,233,220,.80)}
.pmz_r[data-opt="1"] > label::after{background:rgba(240,233,220,.09);
  color:rgba(240,233,220,.52)}
.pmz_r:focus-within{background:linear-gradient(90deg,
  rgba(217,178,95,.13), rgba(217,178,95,.06) 62%, rgba(217,178,95,.045) 100%)}
.pmz_sh_dark{
  background:linear-gradient(180deg,var(--pmz-lacq) 0%,var(--pmz-lacq-2) 62%,var(--pmz-lacq-3) 100%);
  border:1px solid rgba(217,178,95,.24)}

/* -- 2 · THE COST CHIP, EXACTLY AS THE LIVE APP DRAWS IT --------------------
   `.qrt-root .fab .price`: a brown wash with BROWN INK on it. I had inverted it to
   pale gold on dark, which is the one pairing that cannot hold contrast on a gold
   button — Jim: "now you made it abit too transparent hard to see". */
.pmz_root[data-screen="form"] #pmzDoCast .pmz_addcost{
  display:inline-flex; align-items:center; gap:4px; border:0;
  background:rgba(26,18,6,.17); border-radius:999px; padding:3px 9px;
  font-variant-numeric:lining-nums tabular-nums}
.pmz_root[data-screen="form"] #pmzDoCast .pmz_addcost b{
  color:#2A1C08; font:800 13px/1 var(--pmz-ui);
  font-variant-numeric:lining-nums tabular-nums}
.pmz_root[data-screen="form"] #pmzDoCast .pmz_addcost .pmz_gem{
  width:12px; height:12px}
.pmz_root[data-screen="form"] #pmzDoCast .pmz_addcost svg{opacity:1}

/* -- 3 · ALIGNMENT ------------------------------------------------------------
   Everything on this page now hangs off two lines: text starts at 15px from the
   left, values END 15px from the right. The IC input was the last thing breaking
   the right edge; with the button gone it right-aligns like every other value. */
.pmz_r_ic .pmz_ic_in{display:contents}
.pmz_bento #pmzIc{flex:1; text-align:right; font-size:16.5px;
  font-variant-numeric:lining-nums tabular-nums}
/* the box title and its 遁局 share one baseline and one type size */
.pmz_bento_hd{align-items:baseline}
.pmz_bento_ju{gap:8px}
.pmz_bento_ju i{font:700 10.5px/1 var(--pmz-ui); letter-spacing:.15em;
  text-transform:uppercase; color:rgba(240,233,220,.44)}
.pmz_bento_ju b{font:600 13.5px/1 var(--pmz-ui); color:rgba(240,233,220,.82);
  font-variant-numeric:lining-nums tabular-nums}
/* the commit's label and its price sit on one optical line */
.pmz_root[data-screen="form"] #pmzDoCast{display:flex; align-items:center;
  justify-content:center; gap:10px; letter-spacing:.01em}

/* the chart panel joins the same material family. It was near-black while all three
   cards were navy — one surface out of four, which reads as an accident rather than
   as emphasis. Same blue, a shade deeper, same gold rim. */

/* ═════════════════════════════════════════════════════════════════════════════
   ROUND 28 — THE NOTE COLUMN, THE COST CHIP, AND THE CONFIRM CARDS.
   ═════════════════════════════════════════════════════════════════════════════ */

/* -- 1 · THE NOTE JOINS THE COLUMN ---------------------------------------------
   It was the one left-aligned value on a page where every other answer ends at the
   same x. Jim: "align the text optional notes under the uncategorise". */
.pmz_bento .pmz_ta{text-align:right}

/* -- 2 · THE COST CHIP = `.sp-costtag` -----------------------------------------
   The live app ships TWO price treatments: `.fab .price` (brown ink on a brown wash,
   for the floating action button) and `.sp-costtag` — #1B120B behind #F6DCA0 with a
   gold rim. Jim pointed at the second one: "got abit dark background behind so easy
   to see". Values lifted verbatim from app-spend.js. */
.pmz_root[data-screen="form"] #pmzDoCast .pmz_addcost{
  display:inline-flex; align-items:center; gap:4px;
  background:#1B120B; color:#F6DCA0;
  border:1px solid rgba(233,199,126,.5); border-radius:999px;
  padding:3px 10px; box-shadow:inset 0 1px 0 rgba(255,255,255,.09);
  font-variant-numeric:lining-nums tabular-nums}
.pmz_root[data-screen="form"] #pmzDoCast .pmz_addcost b{
  color:#F6DCA0; font:800 13px/1.4 var(--pmz-ui);
  font-variant-numeric:lining-nums tabular-nums}
.pmz_root[data-screen="form"] #pmzDoCast .pmz_addcost .pmz_gem{
  width:12px; height:12px; transform:translateY(-.5px)}

/* -- 3 · THE CONFIRM CARD ------------------------------------------------------
   Geometry from the live app's .sp-card: 344px, radius 24, a gold hairline across
   the top, a round emblem, one big number, then commit and ghost. Dark materials. */
.pmz_cf{position:relative; width:100%; max-width:344px; overflow:hidden;
  border-radius:24px; padding:22px 20px 18px; text-align:center;
  background:linear-gradient(180deg,var(--pmz-lacq) 0%,var(--pmz-lacq-2) 62%,var(--pmz-lacq-3) 100%);
  border:1px solid rgba(233,199,126,.34);
  box-shadow:0 34px 70px -14px rgba(0,0,0,.72), inset 0 1px 0 rgba(255,255,255,.08);
  animation:pmz_cfin .26s var(--pmz-out) backwards}
@keyframes pmz_cfin{from{transform:translate3d(0,12px,0) scale(.965); opacity:0}}
.pmz_cf_rule{position:absolute; top:0; left:0; right:0; height:3px;
  background:linear-gradient(90deg,transparent,#E9C77E 22%,#B98E33 50%,#E9C77E 78%,transparent)}
.pmz_cf_em{width:52px; height:52px; margin:2px auto 12px; border-radius:999px;
  display:flex; align-items:center; justify-content:center;
  background:#1B120B; border:1px solid rgba(233,199,126,.5);
  box-shadow:0 9px 22px -6px rgba(0,0,0,.55), inset 0 1px 0 rgba(255,255,255,.09)}
.pmz_cf_em .pmz_gem{width:27px; height:27px}
/* ⚠ the two cards must not look alike: one costs Tenaga, the other costs the last
   five minutes of typing */
.pmz_cf_em[data-tone="red"]{background:rgba(176,24,32,.16);
  border-color:rgba(226,96,106,.52)}
.pmz_cf_em[data-tone="red"] b{font:800 25px/1 var(--pmz-ui); color:#F0949B}
.pmz_cf_amt{margin:0; font:800 27px/1.1 var(--pmz-ui); color:#F6E3AC;
  letter-spacing:.01em; font-variant-numeric:lining-nums tabular-nums}
.pmz_cf_amt .pmz_gem{width:19px; height:19px; vertical-align:-3px;
  display:inline-grid; place-items:center}
.pmz_cf_t{margin:9px 0 0; font:700 16px/1.35 var(--pmz-ui); color:var(--pmz-on-lacq)}
/* ⚠ ITEM 8 — `balance` SPLITS THE LINES EVENLY instead of filling the first and
   orphaning the tail. The measured width cap keeps it to two lines at 390px; the
   copy above was shortened so two is what it takes. */
.pmz_cf_li{margin:8px auto 0; max-width:26em; font:13.5px/1.6 var(--pmz-ui);
  color:var(--pmz-on-lacq-2); text-wrap:balance; text-align:center}
.pmz_cf_foot{margin:11px 0 0; font:12.5px/1.5 var(--pmz-ui);
  color:rgba(240,233,220,.52); font-variant-numeric:lining-nums tabular-nums}
.pmz_cf_go{width:100%; min-height:52px; margin-top:16px; border:0; border-radius:16px;
  cursor:pointer; font:800 15px/1 var(--pmz-ui)}
.pmz_cf_go[data-tone="gold"]{color:#1B1305;
  background:linear-gradient(180deg,var(--pmz-gold-hi),var(--pmz-gold) 62%,#B98F3A);
  box-shadow:0 12px 24px -10px rgba(201,162,75,.6)}
.pmz_cf_go[data-tone="red"]{color:#FFF3F3;
  background:linear-gradient(180deg,#C4212B,#8E1218);
  box-shadow:0 12px 24px -10px rgba(176,24,32,.6)}
.pmz_cf_no{width:100%; min-height:46px; margin-top:9px; cursor:pointer;
  border:1px solid rgba(240,233,220,.20); background:transparent; border-radius:16px;
  color:rgba(240,233,220,.70); font:700 13.5px/1 var(--pmz-ui)}
.pmz_cf_no:active{color:#F4EEE2}

/* -- 4 · CATEGORY MANAGEMENT --------------------------------------------------- */
.pmz_cat_bar{display:flex; justify-content:flex-end; margin:-4px 0 8px}
.pmz_cat_bar button{min-height:36px; padding:0 13px; border-radius:11px; cursor:pointer;
  border:1px solid rgba(233,199,126,.30); background:rgba(233,199,126,.10);
  color:#E9C77E; font:700 13px/1 var(--pmz-ui)}
.pmz_sh_dark .pmz_sh_row s, .pmz_cat_man s{flex:none; margin-left:auto;
  text-decoration:none; font:12.5px/1 var(--pmz-ui); color:rgba(240,233,220,.50);
  font-variant-numeric:lining-nums tabular-nums}
.pmz_sh_dark .pmz_sh_row em{margin-left:10px}
.pmz_cat_man{display:flex; align-items:center; gap:10px; min-height:52px;
  padding:0 8px 0 14px; margin-bottom:4px; border-radius:13px;
  background:rgba(255,251,240,.05); color:#F3EFFA;
  font:600 15.5px/1.35 var(--pmz-ui)}
.pmz_cat_nm{overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.pmz_cat_acts{flex:none; display:flex; gap:6px; margin-left:8px}
.pmz_cat_acts button{width:40px; height:40px; border-radius:11px; cursor:pointer;
  border:1px solid rgba(240,233,220,.18); background:rgba(240,233,220,.06);
  color:rgba(240,233,220,.80); font:15px/1 var(--pmz-ui)}
.pmz_cat_del{border-color:rgba(226,96,106,.34) !important;
  background:rgba(176,24,32,.14) !important; color:#F0949B !important}

/* the inline rename field: same row, same height, no dialog */
.pmz_cat_in{width:100%; min-height:38px; padding:0 10px; border-radius:10px;
  border:1px solid rgba(233,199,126,.46); background:rgba(255,251,240,.10);
  color:#FFFDF9; font:600 15px var(--pmz-ui); outline:none}

/* ═════════════════════════════════════════════════════════════════════════════
   ROUND 29 — THE APP'S OWN TYPEFACE, AND THE CONFIRM CARD.
   Jim: "make the font abit nicer ... the font should be easy readable and quality".
   The prototype was on the plain system stack; the live app runs Plus Jakarta Sans,
   self-hosted at 04_Web-App/vendor/fonts. The four .woff2 files are copied into
   ./fonts and declared here with the same unicode-ranges the app uses.
   ⚠ Same rule as the colours: the app IS the design system. Do not invent a font.
   ═════════════════════════════════════════════════════════════════════════════ */
.pmz_root{--pmz-ui:'Plus Jakarta Sans',-apple-system,BlinkMacSystemFont,'Segoe UI',
  Roboto,'Noto Sans',sans-serif;
  -webkit-font-smoothing:antialiased; text-rendering:optimizeLegibility}

/* -- THE CONFIRM CARD, CENTRED AND CALM --------------------------------------
   Jim: "make sure all the text are nicely aligned in the middle". Everything on the
   card now hangs off one centre line, with a fixed rhythm between the blocks instead
   of each element bringing its own margin. */
.pmz_cf{padding:24px 22px 20px}
.pmz_cf > *{margin-left:auto; margin-right:auto}
.pmz_cf_em{margin:0 auto 14px}
.pmz_cf_amt{margin:0; font:800 30px/1 var(--pmz-ui); letter-spacing:-.005em;
  color:#F6E3AC; font-variant-numeric:lining-nums tabular-nums}
.pmz_cf_t{margin:10px auto 0; max-width:26ch;
  font:700 16.5px/1.35 var(--pmz-ui); letter-spacing:-.005em; color:#F4F7FF}
.pmz_cf_li{margin:9px auto 0; max-width:30ch;
  font:400 13.5px/1.6 var(--pmz-ui); color:rgba(240,233,220,.74)}
.pmz_cf_foot{margin:13px auto 0; padding-top:12px; max-width:30ch;
  border-top:1px solid rgba(255,255,255,.09);
  font:500 12.5px/1.5 var(--pmz-ui); color:rgba(240,233,220,.56);
  font-variant-numeric:lining-nums tabular-nums}
.pmz_cf_go{margin-top:18px; font:700 15.5px/1 var(--pmz-ui); letter-spacing:-.005em}
.pmz_cf_no{margin-top:10px; font:600 14px/1 var(--pmz-ui)}

/* ═════════════════════════════════════════════════════════════════════════════
   ROUND 30 — THE IN-DEPTH READING PAGE
   GA's 命理盘 layout, our material. Jim, 23 Aug.

   ⭐ ONE IDEA CARRIES THE WHOLE PAGE: a navy CARD, and inside it — only where the
   ENGINE draws — an ivory PAPER WELL. That is the live 实时盘's own arrangement,
   which Jim pointed at directly, and it is not decoration: element-colour
   separation collapses 6.37× → 1.52× on a dark ground (measured, round 4), so the
   chart must be on paper or it stops being readable as a chart.

   ⚠ HOW THE TWO INKS COEXIST — READ THIS BEFORE ADDING A COLOUR.
   Everything in `.pmz_read` inherits DARK-GROUND ink by REDEFINING the paper
   tokens; `.pmz_pw` puts them back. So `.pmz_kv`, `.pmz_tag`, `.pmz_grp`,
   `.pmz_years`, `.pmz_panel` — every component written for the scroll — works in
   both places with no per-class override and no second copy. Add colours as
   tokens, never as literals, or a component will be legible in one context and
   invisible in the other.
   ═════════════════════════════════════════════════════════════════════════════ */

.pmz_read{padding:0 0 6px}

/* -- ink policy ------------------------------------------------------------- */
/* ── ROUND 31 · WHO IS LACQUER AND WHO IS PAPER ──────────────────────────────
   THE FRAME — user card, the sticky control slab, Sejarah, every overlay — stays
   dark and carries the drama. THE DOCUMENT — .pmz_read, every word the consultant
   actually reads — is ivory. That is the whole answer to "too blue": prose
   stopped living on blue.

   ⚠ AND THE LIFTED 五行 SET IS DELETED. It existed only because #059669 on navy
   measures 2.6:1. On paper the engine's own hexes are right everywhere, so a 木
   TAG and a 木 PILLAR are finally the same green — they never were before. One
   set of element colours, no per-ground variant to keep in sync. */
/* ⚠ EVERY DARK-GROUND CONTAINER, NOT JUST THE CARDS. .pmz_ph — the page header on
   the Sifu, Sejarah and certificate screens — was in no scope at all, so it took
   :root's PAPER ink and "Tafsiran Sifu" rendered near-black on near-black: 1.08:1,
   invisible, and no screenshot of the record could ever have shown it. If a surface
   is dark, it names itself here. */
.pmz_uc, .pmz_ctl, .pmz_cf, .pmz_sh_dark, .pmz_prov, .pmz_ai, #stSifu .pmz_leaf,
.pmz_ph, .pmz_hd, .pmz_secttl, .pmz_c_hd, .pmz_ac > .pmz_ac_s{
  --pmz-fill:rgba(244,238,226,.06);
  --pmz-ink:var(--pmz-on-lacq);
  --pmz-ink-2:var(--pmz-on-lacq-2);
  --pmz-ink-3:var(--pmz-on-lacq-3);
  --pmz-rule:rgba(217,178,95,.20);
  --pmz-mu:#34D399; --pmz-huo:#FCA5A5; --pmz-tu:#FBBF24;
  --pmz-jin:#FDE68A; --pmz-shui:#93C5FD;
}
/* the ground BETWEEN the cards is still dark — a divider or a note that sits out
   here is on lacquer, not on paper. Scoping paper ink to .pmz_read made
   "KAJIAN TERPERINCI" 4.18:1 grey-on-black. */
/* ⚠ A CONTROL THAT PAINTS ITS OWN WHITE FACE IS A PAPER SURFACE, wherever it
   lives. Adding .pmz_sh_dark to the lacquer scope flipped ink to ivory for its whole
   subtree — including the ten 日主 buttons and the Lelaki/Perempuan pills, which
   carry background:rgba(255,255,255,.6) of their own. Measured on the live page:
   the stem glyphs fell to 2.27:1, their sub-labels to 1.71:1 and the pills to
   2.05:1. A scope inverts everything beneath it, including anything that paints its
   ground back. These name themselves as paper. */
.pmz_sh_dark .pmz_dmgrid button, .pmz_sh_dark .pmz_sh_pills button{
  --pmz-ink:#15110E; --pmz-ink-2:#4A423A; --pmz-ink-3:#6A6058;
  color:var(--pmz-ink)}
.pmz_sh_dark .pmz_dmgrid button[aria-pressed="true"],
.pmz_sh_dark .pmz_sh_pills button[aria-pressed="true"]{
  --pmz-ink-3:rgba(247,243,236,.78); color:#F7F3EC}

.pmz_read{
  --pmz-fill:rgba(244,238,226,.06);
  --pmz-ink:var(--pmz-on-lacq);
  --pmz-ink-2:var(--pmz-on-lacq-2);
  --pmz-ink-3:var(--pmz-on-lacq-3);
  --pmz-rule:rgba(217,178,95,.20);
}
/* ⚠ THE CARD BODIES ARE PAPER — and the element ramp here is DARKENED. This is the
   one place the two element palettes differ and the reason is worth stating: the
   engine's #eab308 金 measures 1.73:1 on ivory and #d97706 土 measures 2.88:1. In
   the CHART that is the live app's own drawing and it is ported verbatim; in a
   sentence WE wrote ("Logam（金）", the 五行 bar labels, a 神煞 tag) it is our text
   failing our own N1 floor. Same hues, same order, dark enough to read. */
/* ⚠ FIVE PAPER SURFACES, NOT TWO. The shelf row, the certificate page and the
   glossary card are ivory too, and they fell through to :root's ENGINE ramp — so a
   金 client's 日主 glyph, the single most identifying mark on the client list,
   measured 1.81:1. The rule this file already states ("the 五行 bar labels ... it is
   our text failing our own N1 floor") was being applied to two of the five places it
   is true. ⚠ .pmz_pw undoes this again, because the CHART keeps the engine's hexes. */
/* ⚠ .pmz_rep_body BELONGS HERE. Round 37 gave the report sheet an ivory ground
   and left it outside this scope, so it kept :root's DARK-ground ink tokens:
   --pmz-ink-3 stayed #7A7066, which is 4.38:1 on #F7F3EC — 25 pillar annotations
   and all nine section subtitles under the floor, in the app AND in the PDF.
   A surface that paints its own ground must adopt that ground's ink. */
.pmz_rep_body, .pmz_c_b, .pmz_ac_b, .pmz_sub_b,
.pmz_row.pmz_paper, .pmz_page.pmz_paper, .pmz_gcard.pmz_paper{
  --pmz-fill:rgba(21,17,14,.05);
  --pmz-ink:#15110E; --pmz-ink-2:#4A423A; --pmz-ink-3:#6A6058; --pmz-rule:#D8CDB8;
  /* ⚠ 火 IS VERMILION, NOT CRIMSON. #C42B2B is (196,43,43) and the brand seal is
     (176,24,32) — inside §6's tolerance on every channel, so an element label read
     as the chop. §6 exists to keep the seal's authority; the element ramp has to
     stay out of its way. #B8431F measures 4.9:1 on ivory and reads unmistakably as
     fire beside 土's brown. */
  --pmz-mu:#046B4A; --pmz-huo:#B8431F; --pmz-tu:#8A4B04;
  --pmz-jin:#7A5B04; --pmz-shui:#1D4FBF;
  /* ⚠ AND AN ACTUAL DEFAULT. These blocks redefine the ink TOKENS but never set
     `color`, so anything added to a card body without its own colour rule inherits
     body{color:#F4EEE2} and renders ivory on ivory. Nothing does that today; this is
     so the next component added is safe by construction rather than by luck. */
  color:var(--pmz-ink);
}
/* ⚠ AND THE DRAWING RESTORES THE ENGINE'S OWN HEXES. .pmz_pw is inside a card body,
   so it must undo the darkened ramp — the chart's colour IS the chart's meaning and
   a student reads a flagged pillar by hue. Ported values, byte for byte. */
.pmz_pw{
  --pmz-fill:rgba(21,17,14,.05);
  --pmz-ink:#15110E; --pmz-ink-2:#4A423A; --pmz-ink-3:#7A7066; --pmz-rule:#D8CDB8;
  --pmz-mu:#059669; --pmz-huo:#ef4444; --pmz-tu:#d97706;
  --pmz-jin:#eab308; --pmz-shui:#3b82f6;
}

/* -- 1 · THE PERSON ---------------------------------------------------------
   GA's user card: who · 历史 · edit, the two birth lines, then the two actions. */
.pmz_uc{margin:0 14px 12px; padding:13px 14px 14px; border-radius:16px;
  background:linear-gradient(180deg,var(--pmz-lacq) 0%,var(--pmz-lacq-2) 58%,var(--pmz-lacq-3) 100%);
  border:1px solid rgba(217,178,95,.22);
  box-shadow:inset 0 1px 0 rgba(246,227,172,.09), 0 20px 40px -24px rgba(0,0,0,.96)}
.pmz_uc_top{display:flex; align-items:center; gap:9px; margin-bottom:9px}
.pmz_uc_av{width:34px; height:34px; flex:none; border-radius:999px;
  display:flex; align-items:center; justify-content:center;
  background:var(--pmz-fill); border:1px solid rgba(217,178,95,.20)}
.pmz_uc_av svg{width:18px; height:18px; fill:none; stroke:var(--pmz-ink-2);
  stroke-width:1.7; stroke-linecap:round; stroke-linejoin:round}
.pmz_uc_nm{flex:0 1 auto; min-width:0; overflow:hidden; text-overflow:ellipsis;
  white-space:nowrap; font:700 17px/1.2 var(--pmz-ui); color:var(--pmz-ink)}
.pmz_uc_sex{flex:none; padding:3px 8px; border-radius:6px; font:600 12.5px/1 var(--pmz-ui);
  background:var(--pmz-fill); color:var(--pmz-ink-2)}
.pmz_uc_acts{margin-left:auto; display:flex; align-items:center; gap:6px; flex:none}
.pmz_uc_ib{display:inline-flex; align-items:center; gap:5px; min-height:44px; padding:0 11px;
  border:1px solid rgba(217,178,95,.20); border-radius:999px; cursor:pointer;
  background:var(--pmz-fill); color:var(--pmz-ink); font:600 13px/1 var(--pmz-ui)}
.pmz_uc_ib svg{width:14px; height:14px; fill:none; stroke:currentColor; stroke-width:1.9;
  stroke-linecap:round; stroke-linejoin:round}
.pmz_uc_sq{width:44px; padding:0; justify-content:center}
.pmz_uc_line{margin:0 0 3px; font:400 13.5px/1.5 var(--pmz-ui); color:var(--pmz-ink);
  font-variant-numeric:lining-nums tabular-nums}
.pmz_uc_btns{display:flex; gap:9px; margin-top:11px}
.pmz_uc_ghost, .pmz_uc_go{flex:1; min-height:52px; border-radius:12px; cursor:pointer;
  display:flex; align-items:center; justify-content:center; gap:7px;
  font:700 13.5px/1.2 var(--pmz-ui)}
.pmz_uc_ghost{border:1px solid rgba(217,178,95,.26); background:var(--pmz-fill);
  color:var(--pmz-ink)}
.pmz_uc_ghost svg, .pmz_uc_go svg{width:15px; height:15px; fill:none; stroke:currentColor;
  stroke-width:1.8; stroke-linecap:round; stroke-linejoin:round}
/* GOLD = an action that SPENDS — the same grammar as the add-client commit. */
.pmz_uc_go{border:1px solid rgba(246,227,172,.55); flex-direction:column; gap:6px;
  background:linear-gradient(180deg,#F2D591,#D9B25F 62%,#C39A45);
  color:#2A1C08; box-shadow:0 10px 22px -12px rgba(217,178,95,.65)}
.pmz_uc_go_l{display:flex; align-items:center; gap:6px; text-align:center}
/* the price chip = the live app's `.sp-costtag`: dark ground, pale gold numerals. */
.pmz_costtag{display:inline-flex; align-items:center; gap:5px; padding:3px 10px;
  border-radius:999px; background:#1B120B; border:1px solid rgba(233,199,126,.5);
  font-variant-numeric:lining-nums tabular-nums}
.pmz_costtag b{color:#F6DCA0; font:800 12.5px/1 var(--pmz-ui);
  font-variant-numeric:lining-nums tabular-nums}
.pmz_costtag .pmz_gem{width:12px; height:12px}

/* -- 2 · THE SWITCH AND THE INDEX, AS ONE SLAB ------------------------------
   Jim: "make sure they are intergrated seamlessly." One background, one bottom
   hairline, no seam between the two rows — and it STICKS, so in 专业版 the index
   is reachable from anywhere in a very long page. */
/* ⚠ ITEM 7 · NO GAP AT THE TOP. The slab used to start 8px down with a gradient
   that faded to transparent-ish at its head, so the page's own content slid
   through the sliver between the chrome band and the slab — the stripe visible in
   Jim's screenshot. It is OPAQUE from its first pixel now, and its top padding is
   large enough to swallow the band it sits under. One row, one hairline, no seam. */
/* ⚠ THE STICKY BAR WAS CUTTING A DARK STRIPE THROUGH THE LAMP. Measured down the left
   gutter at 390px: rgb(19,15,8) → rgb(7,6,3) at y=268 and back at y=340 — two hard edges
   26 and 27 units deep, with nothing between them but this element. `.pmz_lamp` is the
   warm overhead glow at z-index 4; this bar is z-index 12 and painted FLAT GROUND over
   it, so the middle of the page was a visibly different colour from the rest of it.
   It cannot just go transparent — it is sticky, and being opaque is the entire point
   when the chart is scrolling underneath. So it carries the lamp's own tint on top of
   its own ground instead: still opaque, now the same colour as the ground beside it.
   The alpha is derived from the measured neighbour, not picked by eye — see
   scripts/patch-ground-seam.py. Gate: _r37-round39-verify.mjs §E. */
.pmz_ctl{position:sticky; z-index:12; margin:0 0 12px; padding:10px 0 2px;
  background:linear-gradient(rgba(255,214,150,.05), rgba(255,214,150,.05)), var(--pmz-ground);
  border-bottom:1px solid rgba(217,178,95,.16)}
/* ⚠ a sticky `top` inside .pmz_doc resolves from the SCROLLER'S PADDING EDGE, not
   from the viewport — the round-17 bug. The chrome band is subtracted here. */
.pmz_root[data-screen="record"] .pmz_ctl{top:calc(var(--pmz-docpad-t, 66px) * -1 + 54px)}
.pmz_ctl .pmz_modebar{margin:0 14px 8px}
/* the index is gone, so nothing below the mode row needs the extra 8px */
.pmz_ctl .pmz_modebar:last-child{margin-bottom:6px}

/* -- 3 · THE CARD ----------------------------------------------------------- */
/* ── ROUND 31 · THE CARD IS A LACQUER LID OVER AN IVORY PAGE ─────────────────
   The header bar is the frame; everything below it is the document. That single
   move gives a long 专业版 page its rhythm without adding one colour: dark bar,
   gold letters, paper. */
.pmz_c{margin:0 14px 12px; padding:0; border-radius:16px; overflow:hidden;
  background:var(--pmz-paper-2);
  border:1px solid var(--pmz-lacq-rim);
  box-shadow:0 18px 34px -22px rgba(0,0,0,.92)}
.pmz_c_b{padding:13px 14px 15px}
.pmz_c_hd{display:flex; align-items:center; gap:9px 10px; flex-wrap:wrap; margin:0; padding:11px 14px;
  background:linear-gradient(180deg,var(--pmz-lacq) 0%,var(--pmz-lacq-2) 58%,var(--pmz-lacq-3) 100%);
  border-bottom:1px solid rgba(217,178,95,.34);
  box-shadow:inset 0 1px 0 rgba(246,227,172,.10)}
.pmz_c_t{margin:0; font:700 15.5px/1.25 var(--pmz-ui); color:#E9C77E; letter-spacing:.01em}
/* ⚠ 13px, NOT 12. A han label is the term a consultant RECOGNISES — 大运流年 is
   how they find the table — so it carries meaning and sits above N1's floor like
   everything else that does. Item 9's longer names (吉凶格局组合, 日主性格与沟通) made
   this impossible to keep ignoring. */
.pmz_c_han{font:400 13px/1 var(--pmz-ui); letter-spacing:.16em;
  color:var(--pmz-ink-3)}
/* two 44px controls plus a title do not fit 362px, so the actions take their own
   row when they have to — flex-basis:100% only once the row has already wrapped. */
.pmz_c_act{margin-left:auto; display:flex; align-items:center; gap:8px; align-self:center;
  flex-wrap:wrap; justify-content:flex-end}
.pmz_c_lead{margin:0 0 11px; font:400 13px/1.6 var(--pmz-ui); color:var(--pmz-ink-2)}
/* ⚠ 44px, NOT 38. Item 5 put a SECOND toggle on this header and the quick way to
   fit both beside the title was to shrink them — which the rig caught immediately
   as "2 under 44px". N1 is not negotiable, so the header WRAPS instead: title on
   its own line, the two controls on the next, both at full thumb size. Height on
   this card is cheaper than a control a 40+ thumb misses. */
.pmz_ctog{display:inline-flex; align-items:center; gap:5px; min-height:44px; padding:0 12px;
  border:1px solid rgba(217,178,95,.24); border-radius:999px; cursor:pointer;
  background:rgba(244,238,226,.06); color:var(--pmz-on-lacq-2);
  font:600 13px/1 var(--pmz-ui)}
.pmz_ctog[aria-pressed="true"]{color:#F6E3AC; border-color:rgba(246,227,172,.40);
  background:rgba(217,178,95,.16)}
.pmz_ctog svg{width:15px; height:15px; fill:none; stroke:currentColor; stroke-width:1.8;
  stroke-linecap:round; stroke-linejoin:round}

/* the paper well — the ONLY place the engine draws */
/* ⚠ ROUND 31 — THE WELL LOST ITS WALLS. It existed to lift ivory off navy. The
   card body IS ivory now, so a second ivory box inside it was a box drawn for no
   reason. What survives is the drawing area itself. */
.pmz_pw{background:transparent; border-radius:0; padding:2px 0;
  border:0; box-shadow:none}
.pmz_pw_flush{padding:10px 0}
.pmz_pwnote{margin:10px 10px 0; font:400 13px/1.55 var(--pmz-ui); color:#7A7066;
  text-align:center}
.pmz_qsep{height:1px; margin:14px 4px 12px; background:rgba(216,205,184,.75)}
.pmz_qhd{margin:0 0 6px; text-align:center; font:700 13.5px/1.3 var(--pmz-ui); color:#4A423A}
.pmz_qhd i{font-style:normal; font-weight:400; letter-spacing:.18em; color:#7A7066}

/* -- 4 · THE ACCORDION ------------------------------------------------------ */
/* ── ROUND 31 · A DRAWER, NOT A CARD ────────────────────────────────────────
   Closed it is a lacquer bar with gold lettering — a cabinet of drawers. Open,
   the body is ivory and you are reading a page. The card ground underneath is
   ivory, so an OPEN drawer can never show a dark seam at its foot. */
.pmz_ac{margin:0 14px 10px; border-radius:16px; overflow:hidden;
  background:var(--pmz-paper-2);
  border:1px solid var(--pmz-lacq-rim);
  box-shadow:0 18px 34px -22px rgba(0,0,0,.92)}
.pmz_ac > .pmz_ac_s{background:linear-gradient(180deg,var(--pmz-lacq) 0%,var(--pmz-lacq-2) 58%,var(--pmz-lacq-3) 100%);
  box-shadow:inset 0 1px 0 rgba(246,227,172,.10)}
.pmz_ac_s{list-style:none; cursor:pointer; -webkit-tap-highlight-color:transparent;
  display:flex; align-items:center; gap:10px; min-height:56px; padding:11px 14px}
.pmz_ac_s::-webkit-details-marker{display:none}
.pmz_ac_ic{flex:none; display:inline-flex; width:22px; height:22px}
.pmz_ac_ic svg{width:22px; height:22px; fill:none; stroke:currentColor; stroke-width:1.7;
  stroke-linecap:round; stroke-linejoin:round}
.pmz_ac_t{flex:1; min-width:0; font:700 15px/1.3 var(--pmz-ui); color:#E9C77E}
.pmz_ac_han{display:block; margin-top:3px; font:400 13px/1 var(--pmz-ui);
  font-style:normal; letter-spacing:.14em; color:var(--pmz-ink-3)}
/* the count is the whole point of a collapsed section: it says what is inside
   without opening it. Gold, because it is a QUANTITY, not a control. */
.pmz_ac_n{flex:none; padding:4px 9px; border-radius:999px; font:700 13px/1 var(--pmz-ui);
  background:rgba(217,178,95,.15); border:1px solid rgba(217,178,95,.28); color:#F0DCA6;
  font-variant-numeric:lining-nums tabular-nums}
.pmz_ac_cv{flex:none; display:inline-flex; width:18px; height:18px;
  color:var(--pmz-ink-3); transition:transform .18s var(--pmz-out)}
.pmz_ac_cv svg{width:18px; height:18px; fill:none; stroke:currentColor; stroke-width:2;
  stroke-linecap:round; stroke-linejoin:round}
.pmz_ac[open] > .pmz_ac_s .pmz_ac_cv{transform:rotate(180deg)}
.pmz_ac[open] > .pmz_ac_s{border-bottom:1px solid rgba(217,178,95,.34)}
/* ⚠ THE ACCENT IS A MARK AND A HAIRLINE, NOT A FILL. Each card gets a glyph in its
   own hue on the lacquer bar and the same hue as a rule down the open body, so twelve
   cards are tellable apart at a glance without twelve coloured grounds. */
.pmz_ac_face{flex:none; width:26px; height:26px; border-radius:8px;
  display:flex; align-items:center; justify-content:center; font-size:14px;
  color:var(--pmz-face,#E9C77E);
  background:color-mix(in srgb, var(--pmz-face,#E9C77E) 20%, transparent);
  box-shadow:inset 0 0 0 1px color-mix(in srgb, var(--pmz-face,#E9C77E) 46%, transparent)}
@supports not (color: color-mix(in srgb, red 50%, blue)){
  .pmz_ac_face{background:rgba(217,178,95,.14); box-shadow:inset 0 0 0 1px rgba(217,178,95,.30)}
}
/* ⚠ THE RULE IS ON IVORY, SO IT TAKES THE PAPER VALUE — the same accent, one step
   darker. Using --pmz-face here would draw a lifted, lacquer-tuned hue on paper. */
.pmz_ac[open] > .pmz_ac_b{border-left:3px solid var(--pmz-face-p,transparent)}
.pmz_ac_b{padding:13px 14px 15px}

/* -- 4b · THE SUB-ROW (item 9) ----------------------------------------------
   One level under the lacquer drawer, and PAPER — a second dark bar inside an open
   drawer would read as a second drawer. A rule above, ink title, han beneath, gold
   count. Same grammar, one step quieter. */
.pmz_sub{border-top:1px solid rgba(21,17,14,.10)}
.pmz_sub:first-child{border-top:0}
.pmz_sub_s{list-style:none; cursor:pointer; -webkit-tap-highlight-color:transparent;
  display:flex; align-items:center; gap:10px; min-height:48px; padding:8px 0}
.pmz_sub_s::-webkit-details-marker{display:none}
.pmz_sub_t{flex:1; min-width:0; font:700 14.5px/1.3 var(--pmz-ui); color:var(--pmz-ink)}
.pmz_sub_han{display:block; margin-top:3px; font:400 13px/1 var(--pmz-ui);
  font-style:normal; letter-spacing:.13em; color:var(--pmz-ink-3)}
.pmz_sub_n{flex:none; padding:3px 9px; border-radius:999px; font:700 13px/1 var(--pmz-ui);
  background:rgba(140,108,37,.12); border:1px solid rgba(140,108,37,.30);
  color:#6B5115; font-variant-numeric:lining-nums tabular-nums}
.pmz_sub_cv{flex:none; display:inline-flex; width:17px; height:17px;
  color:var(--pmz-ink-3); transition:transform .18s var(--pmz-out)}
.pmz_sub_cv svg{width:17px; height:17px; fill:none; stroke:currentColor; stroke-width:2;
  stroke-linecap:round; stroke-linejoin:round}
.pmz_sub[open] > .pmz_sub_s .pmz_sub_cv{transform:rotate(180deg)}
.pmz_sub_b{padding:2px 0 14px}
/* a sub-row inside a CARD body (流年 under 大运流年) gets the card's own gutter back */
.pmz_c_b > .pmz_sub{margin-top:12px}

/* ── ROUND 32 · A LINE THAT CARRIES A POLARITY ───────────────────────────────
   Jim: "too much text... we need to use visuals (emoji) or color to make things abit
   lively instead of dull color when read for long period." Chosen: colour + glyph +
   tinted block, applied STRATEGICALLY — only where a row has a real polarity the
   reader would otherwise have to parse out of the sentence.
   ⚠ THE TINTS ARE THE PAPER ELEMENT RAMP, not a new palette: good is the darkened 木,
   warn the darkened 土. Nothing here may drift toward the seal red — §6 caught that
   exact mistake once already this round. */
.pmz_lnk{display:flex; gap:10px; padding:11px 12px; border-radius:11px;
  border-left:3px solid currentColor}
.pmz_lnk .pmz_ln_g{flex:none; font-size:15px; line-height:1.45}
.pmz_lnk .pmz_ln_b{flex:1; min-width:0}
.pmz_lnk .pmz_ln_k{color:inherit; opacity:.92}
.pmz_lnk .pmz_ln_v{color:var(--pmz-ink)}
.pmz_lnk[data-kind="good"]{color:#046B4A; background:rgba(4,107,74,.075)}
.pmz_lnk[data-kind="warn"]{color:#8A4B04; background:rgba(138,75,4,.075)}
.pmz_lnk[data-kind="tip"] {color:#4A423A; background:rgba(21,17,14,.05)}
/* on the DARK ground the same three have to lift, or a tinted block becomes a
   near-invisible smudge — the AI page and Sejarah both render lines like these */
.pmz_ai .pmz_lnk[data-kind="good"], .pmz_prov .pmz_lnk[data-kind="good"]{
  color:#6EE7B7; background:rgba(110,231,183,.10)}
.pmz_ai .pmz_lnk[data-kind="warn"], .pmz_prov .pmz_lnk[data-kind="warn"]{
  color:#FCD34D; background:rgba(252,211,77,.10)}
.pmz_ai .pmz_lnk[data-kind="tip"],  .pmz_prov .pmz_lnk[data-kind="tip"]{
  color:var(--pmz-on-lacq-2); background:rgba(244,238,226,.06)}

/* ── ROUND 33 · 当前大运, SAID PROPERLY ──────────────────────────────────────
   Jim: "try to make 当前大运 section more interesting and quality." The 干支 at
   display size in its own element colours, the span and the ages beside it, and a
   rule showing how far through the decade this person is. */
.pmz_dyhead{display:grid; grid-template-columns:auto 1fr; gap:4px 14px;
  align-items:center; margin:0 0 14px; padding:12px 13px; border-radius:13px;
  background:rgba(21,17,14,.045); border-left:3px solid var(--pmz-ink-3)}
.pmz_dyhead_now{border-left-color:#8C6C25; background:rgba(140,108,37,.09)}
.pmz_dyhead_gz{grid-row:span 2; display:flex; flex-direction:column; align-items:center;
  line-height:1.02}
.pmz_dyhead_gz b{font:400 34px/1 var(--pmz-disp)}
.pmz_dyhead_m{display:flex; flex-wrap:wrap; align-items:baseline; gap:4px 9px}
.pmz_dyhead_k{font:700 13px/1.3 var(--pmz-ui); color:var(--pmz-ink-2);
  letter-spacing:.02em}
.pmz_dyhead_v{font:700 19px/1.15 var(--pmz-ui); color:var(--pmz-ink);
  font-variant-numeric:lining-nums tabular-nums}
.pmz_dyhead_s{font:500 13.5px/1.3 var(--pmz-ui); color:var(--pmz-ink-2)}
.pmz_dybar{grid-column:2; height:6px; border-radius:99px; overflow:hidden;
  background:rgba(21,17,14,.10)}
/* ⚠ A RESTING WIDTH, NOT AN ANIMATION. Content must never depend on motion finishing
   — that lesson is in the ledger five times over. */
.pmz_dybar i{display:block; height:100%; border-radius:99px;
  background:linear-gradient(90deg,#C9A24B,#8C6C25)}
.pmz_dyleft{grid-column:2; margin:0; font:500 13px/1.4 var(--pmz-ui);
  color:var(--pmz-ink-2)}

/* ── ROUND 33 · THE 六爻磁场 READING ───────────────────────────
   Jim: "you miss out that when user press the word it show more description." */
.pmz_yaodlgh{position:fixed; inset:0; z-index:180; display:none}
@media(min-width:900px){ .pmz_yaodlgh{position:absolute} }
.pmz_yaodlgh[data-on="1"]{display:flex; align-items:center; justify-content:center;
  padding:20px 16px}
.pmz_yaodlg_bg{position:absolute; inset:0; background:rgba(5,4,3,.72);
  -webkit-backdrop-filter:blur(3px); backdrop-filter:blur(3px)}
.pmz_yaodlg{position:relative; width:100%; max-width:344px; max-height:82vh;
  overflow-y:auto; scrollbar-width:none; border-radius:20px; padding:18px 16px 16px;
  background:var(--pmz-paper-2); border:1px solid var(--pmz-lacq-rim);
  box-shadow:0 34px 70px -14px rgba(0,0,0,.72);
  --pmz-fill:rgba(21,17,14,.05);
  --pmz-ink:#15110E; --pmz-ink-2:#4A423A; --pmz-ink-3:#6A6058; --pmz-rule:#D8CDB8;
  --pmz-mu:#046B4A; --pmz-huo:#B8431F; --pmz-tu:#8A4B04;
  --pmz-jin:#7A5B04; --pmz-shui:#1D4FBF; color:var(--pmz-ink)}
.pmz_yaodlg::-webkit-scrollbar{width:0}
.pmz_yaodlg_x{position:absolute; top:8px; right:8px; width:44px; height:44px;
  border:0; background:transparent; cursor:pointer; font-size:22px; color:var(--pmz-ink-3)}
.pmz_yaodlg_h{text-align:center; margin:0 0 14px; padding-right:36px}
.pmz_yaodlg_b{display:inline-block; padding:3px 10px; border-radius:999px;
  font:700 13px/1.3 var(--pmz-ui)}
.pmz_yaodlg_b[data-kind="good"]{color:#046B4A; background:rgba(4,107,74,.13)}
.pmz_yaodlg_b[data-kind="warn"]{color:#8A4B04; background:rgba(138,75,4,.13)}
.pmz_yaodlg_t{margin-left:8px; font:500 13.5px/1.3 var(--pmz-ui); color:var(--pmz-ink-3)}
.pmz_yaodlg_n{display:block; margin-top:8px; font:400 26px/1.15 var(--pmz-disp);
  color:var(--pmz-ink)}

/* the day-master identity strip at the head of 日主性格与沟通 */
/* 成格 rows carry what the pattern RESTS ON: 自坐 / 有根 / 有气, one colour each
   (app-mingli.js :: 1936-1938, darkened one step for ivory). */
.pmz_gjr{display:inline-block; margin-left:7px; padding:1px 8px; border-radius:999px;
  font:700 13px/1.5 var(--pmz-ui); vertical-align:middle}
.pmz_gjr_s{color:#6D28D9; border:1px solid rgba(109,40,217,.42); background:rgba(109,40,217,.07)}
.pmz_gjr_r{color:#046B4A; border:1px solid rgba(4,107,74,.42);  background:rgba(4,107,74,.07)}
.pmz_gjr_q{color:#1D4FBF; border:1px solid rgba(29,79,191,.42); background:rgba(29,79,191,.07)}
/* the live app's own invitation under the colour legend */
.pmz_qtap{margin:6px 0 0; text-align:center; font:500 13px/1.5 var(--pmz-ui);
  color:var(--pmz-ink-2)}
.pmz_note_c{text-align:center; padding:8px 0}
.pmz_dmid{display:flex; align-items:center; gap:9px; flex-wrap:wrap; margin-bottom:6px}
/* ⚠ 13px FLOOR AND 4.5:1, LIKE EVERYTHING ELSE THIS PAGE AUTHORS. This shipped at
   12.5px and 4.06:1 — a new label is exactly where a type scale slips. */
.pmz_dmid_p{padding:2px 11px; border-radius:999px; font:700 13px/1.6 var(--pmz-ui);
  color:#6B5115; border:1px solid rgba(140,108,37,.44); white-space:nowrap}
.pmz_dmid_n{font:400 19px/1.2 var(--pmz-disp); color:#6B5115}
/* a label above a chip row or bullet list INSIDE a bento */
.pmz_panel_l{margin:9px 0 4px; font:700 13px/1.5 var(--pmz-ui);
  color:var(--pmz-ink-2); letter-spacing:.01em}
.pmz_panel_l:first-child{margin-top:2px}
.pmz_nyname{display:flex; align-items:center; justify-content:center; gap:8px;
  margin-top:8px; flex-wrap:wrap}
.pmz_nyname .pmz_yaodlg_n{margin-top:0}


/* ══ THE REPORT PAGE ═══════════════════════════════════════════════════════════
   ⚠ EVERY ANIMATION HERE IS transform OR opacity. The live app's loader breathes by
   animating a box-shadow on the seal core; this file has a shipped perf bug behind
   that exact property (a layout-forcing paint every frame), so the breath is a
   scale on a pseudo-element. Same picture, no relayout. */
.pmz_rl{position:fixed; inset:0; z-index:120; opacity:0;
  transition:opacity .5s ease; -webkit-tap-highlight-color:transparent;
  background:radial-gradient(94% 62% at 50% 34%,#2C0F11,#150A0B 55%,#050203 100%);
  display:flex; align-items:center; justify-content:center}
.pmz_rl[data-on="1"]{opacity:1}
.pmz_rl_in{display:flex; flex-direction:column; align-items:center; gap:17px;
  padding:24px; text-align:center}
.pmz_rl_stage{position:relative; width:200px; height:200px;
  display:flex; align-items:center; justify-content:center}
.pmz_rl_dust{position:absolute; inset:0; pointer-events:none}
/* ⚠ EVERY ANIMATION BELOW LIVES INSIDE #pmzRepLoader, which exists only while a
   report is generating. They are not idle motion — they are the only thing on
   screen — and §10 measures idle motion at runtime, where the loader is absent. */
.pmz_dust{position:absolute; width:3px; height:3px; border-radius:50%;
  background:#F0CE86; opacity:.5; animation:pmz_rdust 7s ease-in-out infinite}
@keyframes pmz_rdust{
  0%,100%{transform:translate3d(0,0,0); opacity:.18}
  50%    {transform:translate3d(0,-16px,0); opacity:.62}
}
.pmz_rl_halo{position:absolute; width:148px; height:148px; border-radius:50%;
  background:conic-gradient(from 0deg,rgba(201,162,75,0),rgba(201,162,75,.5),
    rgba(176,24,32,.38),rgba(201,162,75,0));
  filter:blur(11px); animation:pmz_rspin 7.5s linear infinite}
.pmz_rl_ring{position:absolute; transform:rotate(-90deg)}
#pmzRepRing{transition:stroke-dashoffset .55s ease}
.pmz_orb{position:absolute; width:100%; height:100%; animation:pmz_rspin 13s linear infinite}
.pmz_orb_rev{animation:pmz_rspinrev 9s linear infinite}
@keyframes pmz_rspin{to{transform:rotate(360deg)}}
@keyframes pmz_rspinrev{to{transform:rotate(-360deg)}}
.pmz_orb_b,.pmz_orb_s{position:absolute; top:50%; left:50%; border-radius:50%;
  background:radial-gradient(circle at 34% 30%,#fff,var(--pmz-c))}
.pmz_orb_b{width:15px; height:15px; margin:-7.5px;
  transform:rotate(var(--pmz-a)) translateY(-90px)}
.pmz_orb_s{width:9px; height:9px; margin:-4.5px; opacity:.9;
  transform:rotate(var(--pmz-a)) translateY(-56px)}
.pmz_rl_core{position:relative; z-index:3; width:64px; height:64px; border-radius:50%;
  background:radial-gradient(circle at 50% 36%,#3A1416,#1B0B0C 78%); color:#F0CE86;
  display:flex; align-items:center; justify-content:center;
  font:700 30px/1 var(--pmz-disp)}
/* the breath: a scaling glow BEHIND the core, never an animated shadow on it */
.pmz_rl_core::before{content:''; position:absolute; inset:-14px; border-radius:50%;
  background:radial-gradient(circle,rgba(201,162,75,.42),transparent 68%);
  animation:pmz_rbreath 2.9s ease-in-out infinite}
@keyframes pmz_rbreath{0%,100%{transform:scale(.86); opacity:.55}
                     50%    {transform:scale(1.12); opacity:1}}
.pmz_rl_h{margin:0; font:800 17px/1.3 var(--pmz-ui); color:#FBF3E6}
.pmz_rl_stagetxt{margin:0; min-height:20px; font:400 14px/1.5 var(--pmz-ui); color:#C9B79E}
.pmz_ell b{animation:pmz_rell 1.3s infinite; opacity:0}
.pmz_ell b:nth-child(2){animation-delay:.18s}
.pmz_ell b:nth-child(3){animation-delay:.36s}
@keyframes pmz_rell{0%,60%,100%{opacity:0} 30%{opacity:1}}
.pmz_rl_dots{display:flex; gap:6px; align-items:center}
.pmz_ldot{width:7px; height:7px; border-radius:99px; display:inline-block;
  animation:pmz_rldot 1.5s infinite ease-in-out}
@keyframes pmz_rldot{0%,100%{transform:scale(.6); opacity:.45}
                   50%    {transform:scale(1); opacity:1}}
.pmz_rl_pct{margin:0; font:800 13px/1 var(--pmz-ui); color:#F0CE86; letter-spacing:.06em}

/* the page itself */
/* clears the tab bar only — there is no floating action bar any more */
#stReport{padding-bottom:128px}
.pmz_rep_top{padding:14px 16px 6px}
.pmz_rep_ttl{min-width:0}
.pmz_rep_ttl b{display:block; font:400 22px/1.2 var(--pmz-disp); color:var(--pmz-paper-2)}
.pmz_rep_ttl span{display:block; margin-top:2px; font:600 13px/1.3 var(--pmz-ui);
  color:var(--pmz-gold)}
.pmz_rep_meta{margin:0; padding:0 16px 10px; font:500 13px/1.5 var(--pmz-ui);
  color:rgba(247,243,236,.62)}
/* ─ ICN · every icon on this page is one element with one rule ──────────────
   Sized off the TILE's font-size so a tile can be made smaller without touching the
   icon, and stroked in currentColor so it inherits the tile's accent — which is how
   one registry can serve a gold sub-header, a jade one and a rust one. */
.pmz_icn{display:block; width:1.15em; height:1.15em; fill:none; stroke:currentColor;
  stroke-width:1.8; stroke-linecap:round; stroke-linejoin:round}
.pmz_rep_navwrap{padding:0 16px 14px}
.pmz_rep_navgrid{display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:8px}
/* ⚠ COMPACT, BUT NEVER BELOW THE FLOORS. Jim asked for smaller chips so the
   paragraphs get the screen. 82px → 62px comes out of the PADDING and the icon
   tile, never out of the label: 13px is this page's authored-type floor and the
   chip is still 100×62, far past 44×44. */
.pmz_rep_nav{display:flex; flex-direction:column; align-items:center; justify-content:center;
  gap:5px; min-height:62px; padding:8px 5px 7px; border-radius:12px; cursor:pointer;
  background:var(--pmz-paper-2); border:1px solid rgba(140,108,37,.28)}
.pmz_rep_navg{width:26px; height:26px; border-radius:8px; display:flex;
  align-items:center; justify-content:center; font-size:15px; color:#7A5D10;
  background:linear-gradient(135deg,rgba(176,24,32,.08),rgba(201,162,75,.16));
  border:1px solid rgba(201,162,75,.34)}
.pmz_rep_navt{font:600 13px/1.15 var(--pmz-ui); color:var(--pmz-ink); text-align:center}
/* ─ THE REPORT IS ONE SHEET ──────────────────────────────────────
   ⚠ Nine bordered sections each holding bordered panels is a FILING CABINET. Jim,
   round 37: "we are generating report (a very long paragraphs of sentences) not
   card." The live app puts the entire reading inside ONE white block and lets the
   headings do the work; so does this. One border on the outside, hairlines between
   chapters, and nothing boxed inside. */
.pmz_rep_body{margin:0 16px; padding:20px 18px 18px; border-radius:18px;
  background:var(--pmz-paper-2); border:1px solid rgba(140,108,37,.2)}
.pmz_rep_body:empty{display:none}
.pmz_rep_sec{margin:0 0 24px}
.pmz_rep_sec + .pmz_rep_sec{padding-top:22px; border-top:1px solid rgba(21,17,14,.09)}
.pmz_rep_h{display:flex; align-items:center; gap:10px; margin:0 0 12px;
  font:700 17px/1.25 var(--pmz-ui); color:var(--pmz-ink); scroll-margin-top:12px}
/* ⚠ GIVE THE CLASS ITS OWN RULE. .pmz_rep_han renders today only because this
   descendant selector happens to catch an <i>; wrap the han in a <span> or add a
   second <i> to that heading and it silently restyles. */
.pmz_rep_h i, .pmz_rep_han{font-style:normal; font:400 15px/1 var(--pmz-disp);
  color:var(--pmz-ink-3)}
.pmz_rep_g{flex:none; width:32px; height:32px; border-radius:10px; display:flex;
  align-items:center; justify-content:center; font-size:16px; color:#7A5D10;
  background:rgba(140,108,37,.11); border:1px solid rgba(140,108,37,.26)}
.pmz_rep_p{margin:0 0 10px; font:400 14.5px/1.75 var(--pmz-ui); color:var(--pmz-ink)}
.pmz_rep_p:last-child{margin-bottom:0}
/* the run-in label — the only survivor of the panel headers. Gold-dark on ivory is
   5.9:1, and the gap is a real inline box so it cannot collapse at a line break. */
.pmz_rep_lead{font-weight:800; color:#6B5115}
.pmz_rep_lead::after{content:''; display:inline-block; width:.6em}
/* a label introducing a run of named terms (神煞, 吉格) — a lead, not a lid */
.pmz_rep_lab{margin:16px 0 7px; font:800 13.5px/1.45 var(--pmz-ui); color:#6B5115}
.pmz_rep_lab:first-child{margin-top:0}
.pmz_rep_term{font-weight:800; color:var(--pmz-ink)}
.pmz_rep_at{margin-left:6px; font-style:normal; font-weight:600; color:var(--pmz-ink-3)}
.pmz_rep_d::before{content:' \2014 '}
/* the N2 block: the ONE place Chinese may reach a Malay reader, and it is set apart
   precisely so the badge that licenses it is impossible to miss. */
.pmz_rep_zh{margin:12px 0; padding:11px 13px; border-radius:11px;
  background:rgba(21,17,14,.04); border:1px solid rgba(21,17,14,.09)}
.pmz_rep_zh .pmz_rep_p:last-child{margin-bottom:0}
.pmz_rep_close{margin:22px 0 0; padding-top:16px; border-top:1px solid rgba(21,17,14,.09);
  font:400 13.5px/1.65 var(--pmz-ui); color:var(--pmz-ink-2)}
/* ☠ THE FLOATING BAR IS GONE. It was fixed above the tab bar and Jim's screenshot
   showed exactly what that costs: "Muat Turun PDF" printed across a sentence about
   this man's loyalty, permanently, for the whole length of the reading. The place
   for "download" and "generate again" is where the reading ENDS — you have finished,
   here is what you can do about it. (The earlier sticky/fixed note is kept below for
   the next person who reaches for position:sticky on this stage: it does not engage,
   an ancestor clips, and it fails silently.) */
.pmz_rep_foot{display:flex; gap:10px; padding:16px 16px 8px}
.pmz_rep_foot button{flex:1; min-height:48px; border-radius:13px; cursor:pointer;
  font:700 15px/1.2 var(--pmz-ui)}
.pmz_rep_pdf{border:0; background:linear-gradient(135deg,#E7C878,#C9A24B); color:#221A08}
.pmz_rep_regen{border:1px solid rgba(247,243,236,.26); background:rgba(247,243,236,.07);
  color:var(--pmz-paper-2)}
.pmz_rep_pdf:disabled{opacity:.6}
/* the kind chip on a Sejarah row */
.pmz_prov_kind{display:inline-block; margin-right:8px; padding:1px 9px; border-radius:999px;
  font:700 12px/1.6 var(--pmz-ui); vertical-align:middle}
.pmz_prov_kind[data-kind="report"]{color:#6B5115; background:rgba(140,108,37,.16)}
.pmz_prov_kind[data-kind="chat"]  {color:#046B4A; background:rgba(4,107,74,.13)}

/* ══ the PDF cover and print document ══════════════════════════════════════════
   These render OFF-SCREEN into html2canvas, so they are the one place in this file
   that may use fixed px and literal colours: the canvas has no viewport and no
   theme. Tong Yi red/gold, matching the live app's cover. */
.pmz_pdf_cover{background:#F7F3EC; color:#15110E; display:flex; flex-direction:column;
  font-family:var(--pmz-ui)}
.pmz_pdfc_top{padding:26px 48px; display:flex; justify-content:space-between;
  align-items:center;
  background:radial-gradient(70% 130% at 16% 0%,rgba(201,162,75,.5),transparent 60%),
             linear-gradient(135deg,#B01820,#7C0F15)}
.pmz_pdfc_brand{font:700 19px/1.2 var(--pmz-disp); color:#fff}
.pmz_pdfc_sub{margin-top:3px; font:800 10px/1.2 var(--pmz-ui); letter-spacing:2.5px; color:#F7E7C8}
.pmz_pdfc_yr{font:700 15px/1 var(--pmz-ui); color:#F0CE86}
.pmz_pdfc_rule{height:3px; background:linear-gradient(90deg,#C9A24B,#7C0F15)}
.pmz_pdfc_mid{flex:1; display:flex}
.pmz_pdfc_bar1{width:14px; background:#7C0F15; margin:44px 0 44px 64px}
.pmz_pdfc_bar2{width:5px; background:#C9A24B; margin:44px 0 44px 8px}
.pmz_pdfc_body{flex:1; display:flex; flex-direction:column; align-items:center;
  justify-content:center; padding:0 40px; text-align:center}
.pmz_pdfc_seal{width:112px; height:112px; border-radius:50%; margin-bottom:28px;
  display:flex; align-items:center; justify-content:center;
  font:700 52px/1 var(--pmz-disp); color:#B01820;
  background:radial-gradient(circle at 50% 38%,#FFFDF8,#F7F3EC 72%,#EFE7D6);
  box-shadow:0 0 0 1px rgba(201,162,75,.55), inset 0 0 0 5px rgba(255,255,255,.65)}
.pmz_pdfc_at{font:700 12px/1.3 var(--pmz-ui); color:#B01820}
.pmz_pdfc_ttl{margin-top:10px; font:800 38px/1.12 var(--pmz-disp)}
.pmz_pdfc_line{width:150px; height:3px; background:#C9A24B; margin:22px 0 40px}
.pmz_pdfc_lab{font:800 13px/1.3 var(--pmz-ui); color:#B01820}
.pmz_pdfc_val{margin:9px 0 30px; font:700 19px/1.3 var(--pmz-ui)}
.pmz_pdfc_val2{margin-top:9px; font:700 15px/1.3 var(--pmz-ui)}
.pmz_pdfc_foot{padding:15px 48px; text-align:center; color:#F7E7C8; font:400 12.5px/1.4 var(--pmz-ui);
  background:linear-gradient(135deg,#B01820,#7C0F15)}
/* was 11px #8a8076: under BOTH floors, on the cover of the thing the client keeps */
.pmz_pdfc_cr{padding:11px 0 13px; text-align:center; color:#6A6058; font:400 13px/1.3 var(--pmz-ui)}
/* ⚠ THE PRINT NODE IS A SIBLING OF .pmz_root, NOT A CHILD. --pmz-ui is redefined
   on .pmz_root only, so everything appended to <body> for html2canvas resolved
   :root's system-font fallback — the app rendered in Plus Jakarta Sans and the
   PDF came out in Segoe UI, and no screenshot of the app could ever show it.
   Both off-screen nodes now name their own faces and their own ink. */
.pmz_pdf_doc, .pmz_pdf_cover{
  --pmz-ui:'Plus Jakarta Sans',-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;
  --pmz-ink:#15110E; --pmz-ink-2:#4A423A; --pmz-ink-3:#6A6058;
  --pmz-paper-2:#F7F3EC}
/* ⚠ MEASURE. At 760px with 56px padding the sheet ran 648px of 14px text — about
   93 characters a line, past the point where the eye loses its place coming back.
   The screen never had this problem: it is 390px wide. Widening the PAGE MARGIN
   rather than capping the paragraph keeps the headings aligned with the body; a
   max-width in ch was a no-op here because ch resolves off the SECTION's inherited
   16px, not the paragraph's 14px — 74ch came out at 651px and changed nothing. */
.pmz_pdf_doc{background:#F7F3EC; color:#15110E; padding:44px 110px; font-family:var(--pmz-ui)}
.pmz_pdf_h1{margin:0 0 4px; font:800 30px/1.2 var(--pmz-disp); color:#15110E}
/* #8a8076 on ivory is 3.50:1 — under the floor, and only ever visible in the
   downloaded file. #6A6058 is this page's own paper-ink-3 and reads 5.54:1. */
.pmz_pdf_meta{margin:0 0 22px; font:500 13px/1.4 var(--pmz-ui); color:#6A6058}
.pmz_pdf_doc .pmz_rep_sec{background:none; border:0; page-break-inside:avoid}
.pmz_pdf_doc .pmz_rep_sec + .pmz_rep_sec{padding-top:20px;
  border-top:1px solid rgba(21,17,14,.12)}
.pmz_pdf_doc .pmz_rep_p{font-size:14px; line-height:1.75}

/* the sub-section's own face. ⚠ THE TINT NEVER TOUCHES THE BODY GROUND — it is the
   glyph tile and a hairline, so every word still sits on ivory at full contrast. */
.pmz_sub_f{flex:none; width:30px; height:30px; border-radius:9px; display:flex;
  align-items:center; justify-content:center; font-size:15px; line-height:1;
  color:var(--pmz-sf,#6B5115); background:var(--pmz-sfb,rgba(140,108,37,.11));
  border:1px solid var(--pmz-sfr,rgba(140,108,37,.26))}
.pmz_sub[data-face="gold"]{--pmz-sf:#6B5115; --pmz-sfb:rgba(140,108,37,.11); --pmz-sfr:rgba(140,108,37,.28)}
.pmz_sub[data-face="jade"]{--pmz-sf:#046B4A; --pmz-sfb:rgba(4,107,74,.09);   --pmz-sfr:rgba(4,107,74,.26)}
.pmz_sub[data-face="rust"]{--pmz-sf:#8A4B04; --pmz-sfb:rgba(138,75,4,.09);   --pmz-sfr:rgba(138,75,4,.26)}
/* ☠ sky and plum deleted: §41 guards this record against blue and purple, and it
   caught them the same hour they were written. */
.pmz_sub[data-face="ink"] {--pmz-sf:#4A423A; --pmz-sfb:rgba(21,17,14,.06);   --pmz-sfr:rgba(21,17,14,.16)}
/* an open sub is marked down its left edge in its own hue, so a reader scrolling a
   long card can see where one section ends and the next begins */
.pmz_sub[data-face][open] > .pmz_sub_b{border-left:2px solid var(--pmz-sfr);
  padding-left:11px; margin-left:1px}

/* 宫位详解 — the 卦象 folds and the 十干克应 rows.
   ⚠ EVERY SUMMARY IS ≥44px TALL BY ITS OWN PADDING, not by an ::after: these are the
   primary controls of the dialog, and a fold whose hit area overlaps its neighbour's
   opens the wrong reading. The 纳音 label gets the ::after treatment because it lives
   inside a ported plate that cannot be pushed apart; here there is room to be honest. */
.pmz_gua_hd{display:flex; align-items:center; gap:8px; margin:16px 0 8px;
  font:700 13px/1.4 var(--pmz-ui); color:var(--pmz-ink-2)}
.pmz_gua_hd:first-child{margin-top:4px}
.pmz_gua_n2{padding:1px 8px; border-radius:999px; font:700 13px/1.55 var(--pmz-ui);
  color:var(--pmz-ink-3); background:rgba(21,17,14,.07)}
.pmz_gua{margin-bottom:8px; border-radius:10px; overflow:hidden;
  background:rgba(21,17,14,.045); border:1px solid rgba(21,17,14,.09)}
.pmz_gua[data-kind="good"],
.pmz_gua[data-kind="warn"],
.pmz_gua[data-kind="info"],
.pmz_gua[data-kind="tip"]{background:rgba(255,255,255,.60); border-color:rgba(21,17,14,.12)}
.pmz_gua>summary{display:flex; align-items:center; gap:11px; padding:11px 12px;
  min-height:44px; box-sizing:border-box; cursor:pointer; list-style:none;
  -webkit-tap-highlight-color:transparent}
.pmz_gua>summary::-webkit-details-marker{display:none}
.pmz_gua_sym{flex:none; width:22px; display:flex; flex-direction:column;
  align-items:center; gap:1px; font-size:17px; line-height:1.05; color:var(--pmz-ink-2)}
.pmz_gua_sym i{font-style:normal}
.pmz_gua_m{flex:1; min-width:0; display:flex; flex-wrap:wrap; align-items:baseline; gap:6px}
.pmz_gua_lab{padding:2px 8px; border-radius:6px; font:600 12.5px/1.5 var(--pmz-ui);
  color:var(--pmz-ink-2); background:rgba(21,17,14,.07)}
/* GA's own two, from app-shishipan.js :: palaceModalHTML */
.pmz_gua[data-kind="info"] .pmz_gua_lab{background:#FEF3C7; color:#B45309}
.pmz_gua[data-kind="tip"]  .pmz_gua_lab{background:#E0F2FE; color:#0369A1}
.pmz_gua_n{font:700 14.5px/1.35 var(--pmz-ui); color:var(--pmz-ink)}
.pmz_gua_t{flex-basis:100%; font:400 13px/1.5 var(--pmz-ui); color:var(--pmz-ink-2);
  font-style:normal}
.pmz_gua_cv{flex:none; width:13px; height:8px; transition:transform .18s ease;
  background:currentColor; color:var(--pmz-ink-3); opacity:.55;
  clip-path:polygon(0 0, 50% 100%, 100% 0)}
.pmz_gua[open]>summary .pmz_gua_cv{transform:rotate(180deg)}
.pmz_gua_p{margin:0; padding:0 12px 12px 45px; font:400 13.5px/1.72 var(--pmz-ui);
  color:var(--pmz-ink-2)}
.pmz_ky_p{flex:none; display:flex; align-items:center; gap:5px}
.pmz_ky_p b{font:700 18px/1 var(--pmz-disp); color:var(--pmz-ink)}
.pmz_ky_p i{font:400 13px/1 var(--pmz-ui); font-style:normal; color:var(--pmz-ink-3)}
.pmz_ky_b{padding:2px 10px; border-radius:6px; font:500 12.5px/1.5 var(--pmz-ui)}
/* GA's own three, from app-shishipan.js :: natureBadge. The 1px border is an inset
   shadow here so adding it cannot reflow a row that is already laid out. */
.pmz_ky_b[data-kind="good"]{color:#166534; background:#DCFCE7; box-shadow:inset 0 0 0 1px #86EFAC}
.pmz_ky_b[data-kind="warn"]{color:#991B1B; background:#FEE2E2; box-shadow:inset 0 0 0 1px #FCA5A5}
.pmz_ky_b[data-kind="tip"] {color:#1E293B; background:#F1F5F9; box-shadow:inset 0 0 0 1px #CBD5E1}
.pmz_ky>summary{padding-left:12px}
.pmz_ky .pmz_gua_p{padding-left:12px}

/* 节气 / 月将, in GA's own colours, on one row */
.pmz_yj_a{font-weight:600; color:var(--pmz-ink)}
.pmz_yj_q{font-weight:600; color:#B45309}
.pmz_yj_s{font-style:normal; margin:0 7px; color:var(--pmz-ink-3)}
.pmz_yj_l{font-style:normal; margin-left:5px; font-size:13px; color:var(--pmz-ink-3)}

/* ⚠ 44px. These became BUTTONS this round and I gave them a pill's height. A tag
   that opens a reading is a control, and N1's thumb floor is not negotiable. */
.pmz_tagbtn{cursor:pointer; border:0; font:inherit; min-height:44px; padding:0 14px;
  display:inline-flex; align-items:center}

/* ⚠ NOT .pmz_bento EITHER — THAT NAME IS THE ADD-CLIENT FORM'S OWN SECTION BOX
   (pmz_bento / _hd / _t / _n / _ju). Claiming it gave all three form sections padding
   and a left border, the form grew, and its last field slid under the button bar. That
   is TWO name collisions in one round (see .pmz_tagchip above). GREP FOR A CLASS NAME
   BEFORE YOU INTRODUCE IT — a collision is invisible in the markup and shows up as a
   layout bug three screens away.
   ── ROUND 32 · THE COLOURED PANEL ───────────────────────────────────────────
   Jim: "there are still quite alot of places you can highlight the text or make then
   inside a coloured bento for easier viewing." Same five kinds as the polarity lines,
   same paper element ramp — a block instead of a row, for content that is a GROUP
   rather than one answer. Nothing here introduces a colour; if it did, the seal
   would stop being the only red on the page. */
.pmz_panel{margin:0 0 10px; padding:11px 12px; border-radius:12px;
  border-left:3px solid currentColor}
.pmz_panel:last-child{margin-bottom:0}
.pmz_panel_h{margin:0 0 7px; display:flex; align-items:center; gap:7px;
  font:700 13.5px/1.3 var(--pmz-ui); color:inherit}
.pmz_panel_p{margin:0 0 6px; font:400 14px/1.62 var(--pmz-ui); color:var(--pmz-ink)}
.pmz_panel_p:last-child{margin-bottom:0}
.pmz_panel[data-kind="good"]{color:#046B4A; background:rgba(4,107,74,.075)}
.pmz_panel[data-kind="warn"]{color:#8A4B04; background:rgba(138,75,4,.075)}
.pmz_panel[data-kind="tip"] {color:#4A423A; background:rgba(21,17,14,.05)}
.pmz_panel[data-kind="info"]{color:#6B5115; background:rgba(140,108,37,.09)}

/* chips, bullets and numbered actions — the three shapes these sections repeat */
/* ⚠ NOT .pmz_chip — THAT NAME WAS ALREADY TAKEN by the top-chrome balance chip
   (position:absolute, top 13px, right 78px). Every tag emitted here inherited that
   and flew out of its own paragraph onto the header line. Check whether a class name
   is free BEFORE introducing it; the collision is invisible in the markup and obvious
   only on screen. */
.pmz_chips{display:flex; flex-wrap:wrap; gap:6px; margin:0}
.pmz_tagchip{display:inline-block; padding:4px 10px; border-radius:999px;
  font:600 13px/1.35 var(--pmz-ui); color:var(--pmz-ink);
  background:rgba(255,255,255,.66); box-shadow:inset 0 0 0 1px rgba(21,17,14,.14)}
.pmz_chips[data-kind="good"] .pmz_tagchip{color:#046B4A;
  box-shadow:inset 0 0 0 1px rgba(4,107,74,.32)}
.pmz_chips[data-kind="warn"] .pmz_tagchip{color:#8A4B04;
  box-shadow:inset 0 0 0 1px rgba(138,75,4,.32)}
.pmz_tagchip[data-kind="good"]{color:#046B4A; box-shadow:inset 0 0 0 1px rgba(4,107,74,.32)}
.pmz_tagchip[data-kind="warn"]{color:#8A4B04; box-shadow:inset 0 0 0 1px rgba(138,75,4,.32)}
.pmz_bul{margin:0 0 8px; padding:0 0 0 2px; list-style:none}
.pmz_bul:last-child{margin-bottom:0}
.pmz_bul li{position:relative; padding-left:16px; margin-bottom:6px;
  font:400 14px/1.62 var(--pmz-ui); color:var(--pmz-ink)}
.pmz_bul li::before{content:'·'; position:absolute; left:4px; top:-1px;
  font-weight:700; color:var(--pmz-ink-3)}
.pmz_bul[data-kind="tip"] li::before{content:'→'; font-size:12px; top:1px}
/* GA marks 沟通技巧 with a tick and 沟通禁忌 with a cross, in red (app-mingli.js ::
   2113-2119). Both kinds were being passed and neither had a rule, so a tip and a
   thing-to-avoid rendered as the same grey dot. */
.pmz_bul[data-kind="good"] li::before{content:'✓'; font-size:12px; top:0; color:#046B4A}
.pmz_bul[data-kind="warn"] li::before{content:'✕'; font-size:11px; top:1px; color:#B8431F}
.pmz_ol{margin:0; padding-left:20px}
.pmz_ol li{margin-bottom:6px; font:400 14px/1.62 var(--pmz-ui); color:var(--pmz-ink)}
.pmz_dim{font-style:normal; color:var(--pmz-ink-3)}

/* the 六爻 pillar row */
.pmz_yaogrid{display:grid; grid-auto-flow:column; grid-auto-columns:minmax(0,1fr);
  gap:8px; margin:0 0 12px}
.pmz_yaocol{display:flex; flex-direction:column; align-items:center; gap:4px; min-width:0}
.pmz_yaocol_l{font:500 13px/1.2 var(--pmz-ui); color:var(--pmz-ink-3)}
.pmz_yaocol_gz{font:400 19px/1.15 var(--pmz-disp); color:var(--pmz-ink)}
/* ⚠ 44px. The live app draws these at 32 and it is wrong there too — N1's thumb
   floor is not negotiable and this is a control, not a label. */
.pmz_yaochip{min-height:44px; padding:0 13px; border-radius:999px; cursor:pointer;
  border:1px solid rgba(21,17,14,.16); background:rgba(255,255,255,.66);
  font:700 13px/1 var(--pmz-ui); color:var(--pmz-ink-2)}
.pmz_yaochip[aria-current="true"]{background:var(--pmz-ink); border-color:var(--pmz-ink);
  color:var(--pmz-paper)}

/* 命主地支关系 — eight relations, two columns */
.pmz_relgrid{display:grid; grid-template-columns:minmax(0,1fr) minmax(0,1fr); gap:7px}
.pmz_relcell{padding:8px 10px; border-radius:9px; display:flex; flex-direction:column; gap:2px;
  border-left:3px solid currentColor}
.pmz_relcell[data-kind="good"]{color:#046B4A; background:rgba(4,107,74,.07)}
.pmz_relcell[data-kind="warn"]{color:#8A4B04; background:rgba(138,75,4,.07)}
.pmz_relcell[data-kind="tip"] {color:#4A423A; background:rgba(21,17,14,.05)}
.pmz_relcell_l{font:600 13px/1.2 var(--pmz-ui); color:inherit}
.pmz_relcell_v{font:400 14.5px/1.25 var(--pmz-disp); color:var(--pmz-ink)}

/* ⚠ THE BADGE IS NOT DECORATION — it is what makes showing untranslated engine text
   honest rather than a silent N2 breach. It must stay visible and legible. */
.pmz_zhref{display:inline-block; margin:0 0 10px; padding:3px 10px; border-radius:999px;
  font:600 13px/1.35 var(--pmz-ui); color:#6B5115;
  background:rgba(140,108,37,.10); box-shadow:inset 0 0 0 1px rgba(140,108,37,.28)}
.pmz_grp_h{margin:12px 0 7px; font:700 13px/1.3 var(--pmz-ui); color:var(--pmz-ink-2)}
.pmz_yaotags{margin-top:12px; padding-top:11px; border-top:1px solid rgba(21,17,14,.10)}
/* the summary the live app puts beside a drawer title */
.pmz_ac_tag{flex:none; max-width:44%; padding:3px 9px; border-radius:999px;
  font:600 13px/1.3 var(--pmz-ui); color:var(--pmz-on-lacq-2);
  background:rgba(244,238,226,.07); border:1px solid rgba(217,178,95,.24);
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis}

/* -- 5 · THE LINE — a label and the engine's answer -------------------------- */
.pmz_ln{margin:0 0 12px}
.pmz_ln:last-child{margin-bottom:0}
/* ⚠ 13px FLOOR ON ANYTHING THAT CARRIES MEANING. GA labels at 12px; this reader is
   40+ and the round-24 complaint was exactly this. The chart keeps GA's sizes — it
   is the chart — but nothing WE write goes under 13. */
.pmz_ln_k{display:block; font:600 13px/1.45 var(--pmz-ui); color:var(--pmz-ink-2);
  letter-spacing:.01em}
.pmz_ln_v{display:block; margin-top:2px; font:400 14.5px/1.62 var(--pmz-ui);
  color:var(--pmz-ink)}
.pmz_ln_loc{margin-left:7px; font-style:normal; font-weight:400; font-size:12.5px;
  color:var(--pmz-ink-3)}
.pmz_pw .pmz_ln_k{color:#7A7066}
.pmz_secttl{margin:18px 14px 10px; font:700 13px/1.3 var(--pmz-ui); letter-spacing:.16em;
  text-transform:uppercase; color:var(--pmz-ink-3)}
.pmz_adv{margin:0 0 8px; padding-left:12px; border-left:2px solid rgba(217,178,95,.35);
  font:400 14px/1.62 var(--pmz-ui); color:var(--pmz-ink-2)}
.pmz_ydesc{margin-left:auto; color:var(--pmz-ink-3)}

/* the ported components, re-fitted to whichever ground they land on */
.pmz_ac_b .pmz_grp h3{color:var(--pmz-ink-3)}
.pmz_ac_b .pmz_tag{border-color:rgba(21,17,14,.16); color:var(--pmz-ink-2);
  background:rgba(255,255,255,.66); font-size:13px}
/* ⚠ these two were lifted for a NAVY ground and measured 1.24:1 and 1.18:1 on
   ivory — a tag nobody can read is a tag that is not there. Back to the paper
   palette they were lifted FROM. */
/* the same two words on a TERM, not a tag — a special pattern is named inline */
.pmz_c_b .pmz_term.pmz_good, .pmz_ac_b .pmz_term.pmz_good, .pmz_sub_b .pmz_term.pmz_good{color:#046B4A}
.pmz_c_b .pmz_term.pmz_bad, .pmz_ac_b .pmz_term.pmz_bad, .pmz_sub_b .pmz_term.pmz_bad{color:#8A4B04}
.pmz_ac_b .pmz_tag.pmz_good{border-color:rgba(4,107,74,.42); color:#046B4A}
.pmz_ac_b .pmz_tag.pmz_bad{border-color:rgba(138,75,4,.42); color:#8A4B04}
.pmz_sub_b .pmz_tag.pmz_good{border-color:rgba(4,107,74,.42); color:#046B4A}
.pmz_sub_b .pmz_tag.pmz_bad{border-color:rgba(138,75,4,.42); color:#8A4B04}
/* ⚠ AND THE NAME INSIDE IT. Deepening the marked cell so its ring could be seen
   pushed the gua name (乾) on ink-3 to 4.16:1 — fixing a ring by dimming a word is
   not a fix. The marked cell is the one cell whose label must be the clearest. */
/* ⚠ THESE TWO MATCHED ZERO ELEMENTS. 流年 lives in a CARD body (.pmz_c_b →
   .pmz_sub_b), never in a drawer — verified live: `.pmz_ac_b .pmz_years` = 0,
   `.pmz_sub_b .pmz_years` = 1. The same gap was fixed for .pmz_grp h3 and .pmz_note
   and missed here. */
.pmz_ac_b .pmz_years li, .pmz_c_b .pmz_years li, .pmz_sub_b .pmz_years li{
  border-bottom-color:rgba(21,17,14,.10)}
.pmz_ac_b .pmz_years li.pmz_thisyear, .pmz_c_b .pmz_years li.pmz_thisyear,
.pmz_sub_b .pmz_years li.pmz_thisyear{
  background:linear-gradient(90deg,rgba(140,108,37,.16),transparent 74%)}
/* ⚠ CLONED FROM .pmz_prov's seal, which really is on lacquer — this one is not,
   and R31 never touched these lines so they survived the flip intact. Measured on
   F3 (zero 格局): a 46px 衡 glyph at #F0DCA6 on a pink wash = 1.20:1, i.e. a blank
   pink square where the empty state should be. Ink on paper, like every other seal
   that sits on paper. */
.pmz_ac_b .pmz_empty .pmz_seal_sm, .pmz_c_b .pmz_empty .pmz_seal_sm,
.pmz_sub_b .pmz_empty .pmz_seal_sm{background:rgba(176,24,32,.10); color:#8A1F24;
  border:1px solid rgba(176,24,32,.30)}
.pmz_ac_b .pmz_wx_bar{background:var(--pmz-fill)}
.pmz_ac_b .pmz_wx_val{color:var(--pmz-ink-2)}
.pmz_ac_b .pmz_wx_nm{width:auto; min-width:58px; text-align:left;
  font:600 13.5px/1.2 var(--pmz-ui)}
.pmz_ac_b .pmz_wx_nm i{font-style:normal; margin-left:5px; font-size:12.5px; opacity:.7}
.pmz_wx{margin-top:2px}

/* -- 5b · 流运, the live app's second row ------------------------------------
   A rule, then four more columns in the SAME plate vocabulary — GA reuses pillarCol
   verbatim and so do we, which is why 纳音 appears on these columns too when it is
   on. 大运 and 流年 lead the row; 流月 and 流日 are quieter, exactly as the live app
   weights them. */
.pmz_lysep{height:1px; margin:14px 4px 12px; background:rgba(216,205,184,.85)}
.pmz_ly{margin-top:0}
/* ⚠ 大运 AND 流年 LEAD, 流月 AND 流日 STILL HAVE TO BE TELLABLE FROM THE NATAL ROW.
   The ms dictionary maps 年柱/流年 → "Tahun", 月柱/流月 → "Bulan", 日柱/流日 → "Hari"
   (the live app's own collision), so the plate showed "Bulan" over 丙寅 and the 流运
   row showed "Bulan" over this month's pillar in the identical muted grey. The live
   app's disambiguator is weight and ink, not words — port both, not just the half
   that was loud. */
.pmz_col_hot{color:var(--pmz-huo) !important; font-weight:700}
.pmz_ly .pmz_col_lab{color:var(--pmz-ink); font-weight:600}
.pmz_ctog_cv{display:inline-flex; width:14px; height:14px;
  transition:transform .18s var(--pmz-out)}
.pmz_ctog_cv svg{width:14px; height:14px; fill:none; stroke:currentColor;
  stroke-width:2; stroke-linecap:round; stroke-linejoin:round}
.pmz_ctog[aria-pressed="true"] .pmz_ctog_cv{transform:rotate(180deg)}

/* -- 6 · 纳音, under its column --------------------------------------------- */
/* ⚠ NO `color` HERE — THIS IS ITEM 4. This rule sits ~3,400 lines BELOW
   .pmz_el_mu at EQUAL specificity (0,1,0), so a colour declared here silently beat
   every element colour and every 纳音 rendered grey — both modes, every language,
   every fixture. Same shape as the .pmz_jc[aria-current] bug already in this file.
   Layout only; the muted colour moved to a class the JS adds when — and only when
   — the engine could not name an element. */
/* 纳音 is now a BUTTON into its 8-section reading. The drawn box stays exactly the
   size the ported plate expects; the thumb target is an invisible ::after, the same
   device the live app uses on its header chip (27px drawn / 47px tappable). Growing
   the label itself would push four columns apart, and the plate is not ours. */
.pmz_ny{position:relative; margin-top:5px; font:600 12px/1.2 var(--pmz-ui);
  text-align:center; border:0; background:transparent; padding:0; cursor:pointer;
  -webkit-tap-highlight-color:transparent}
.pmz_ny::after{content:''; position:absolute; inset:-16px; border-radius:10px}
.pmz_ny:hover{text-decoration:underline; text-underline-offset:2px}
.pmz_ny:focus-visible{outline:2px solid var(--pmz-gold); outline-offset:3px}
.pmz_ny_m{color:var(--pmz-ink-3)}
/* the element chip beside the 纳音 name in its dialog header */
/* ⚠ 13px, like every other authored label. These six shipped at 11.5–12.5px
   because when they were written NOTHING measured a dialog — #pmzYaoDlg was not in
   the N1 sweep's container list. The sweep sees dialogs now; this is what it found. */
.pmz_nyel{display:inline-block; padding:1px 9px; border-radius:999px;
  font:700 13px/1.5 var(--pmz-ui); border:1px solid currentColor}

/* -- 7 · 奇门信息, GA's label/value table ------------------------------------ */
.pmz_kv2{width:100%; border-collapse:collapse}
.pmz_kv2 td{padding:9px 2px; border-bottom:1px solid rgba(217,178,95,.14);
  vertical-align:top}
.pmz_kv2 tr:last-child td{border-bottom:0}
.pmz_kvk{width:38%; font:600 13px/1.45 var(--pmz-ui); color:var(--pmz-ink-2)}
.pmz_kvv{font:400 14.5px/1.45 var(--pmz-ui); color:var(--pmz-ink)}
.pmz_kvsub{font-style:normal; margin-left:8px; font-size:13px; color:var(--pmz-ink-3)}

/* ═════════════════════════════════════════════════════════════════════════════
   8 · THE 奇门 PLATE — app-shishipan.js :: plateHTML, NOT redesigned.
   Every value here is the inline style that function emits, moved into a class so
   the markup stays legible. ⚠ The one deliberate difference is the WIDTH: GA hard-
   codes 300px + 36px of ring padding = 372px, which does not fit a 390px device
   inside a card. The grid takes the room it is given instead; the cells are
   aspect-ratio 1/1 in minmax(0,1fr) tracks, so the plate scales rather than
   clipping — and a page that scrolls sideways is a bug, not a plate.
   ═════════════════════════════════════════════════════════════════════════════ */
.pmz_qwrap{position:relative; margin:0 auto; padding:34px; width:100%; max-width:300px;
  box-sizing:content-box}
.pmz_qring{position:absolute; font-weight:700; font-size:13px; color:#475569}
.pmz_qring_t{left:0; right:0; top:-2px; max-width:250px; margin:0 auto;
  display:flex; justify-content:space-between; align-items:flex-start; padding:0 8px}
.pmz_qring_b{left:0; right:0; bottom:-2px; max-width:250px; margin:0 auto;
  display:flex; justify-content:space-between; align-items:flex-end; padding:0 8px}
.pmz_qring_l{display:flex; flex-direction:column; justify-content:space-between;
  text-align:right; top:38%; transform:translateY(-50%); left:-14px; height:calc(100% - 10rem)}
.pmz_qring_r{display:flex; flex-direction:column; justify-content:space-between;
  text-align:left; top:38%; transform:translateY(-50%); right:-14px; height:calc(100% - 10rem)}
.pmz_qrg{display:flex; align-items:center; gap:4px}
.pmz_qrgc{display:flex; flex-direction:column; align-items:center; gap:4px}
.pmz_qp1{padding-top:25px} .pmz_qp2{padding-top:60px} .pmz_qp3{padding-top:50px}
.pmz_qhid{width:30px; text-align:right}
.pmz_qhidl{text-align:left}
.pmz_qrv{display:flex; flex-direction:column; align-items:center; font-size:9px;
  line-height:1.1; font-weight:500; color:#475569}
.pmz_qrh{display:flex; align-items:center; font-size:9px; line-height:1.1;
  font-weight:500; color:#475569}
.pmz_qjc{color:#b45309}
.pmz_qgridwrap{position:relative}
.pmz_qhorse{position:absolute; z-index:30; font-weight:700; font-size:16px; color:#ef4444}
.pmz_qgrid{display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:0;
  border:2px solid rgba(2,8,23,.8); color:#020817; background:#fff;
  box-shadow:0 25px 50px -12px rgba(0,0,0,.25); overflow:hidden; border-radius:4px}
.pmz_qcell{position:relative; border:1px solid #334155; background:#fff; padding:5px;
  aspect-ratio:1/1; user-select:none; display:flex; flex-direction:column;
  justify-content:space-between; box-shadow:0 1px 2px rgba(0,0,0,.05)}
.pmz_qc5{border-top:1px solid #334155; border-left:1px solid #334155;
  border-right:1px solid #334155; background:#fff; aspect-ratio:1/1}
.pmz_qrow{display:flex; justify-content:space-between}
.pmz_qrow_t{align-items:flex-start}
.pmz_qrow_m{align-items:center; margin:2px 0}
.pmz_qrow_b{align-items:flex-end}
.pmz_qstems{display:flex; align-items:flex-end; gap:2px; position:relative; z-index:10;
  flex-wrap:nowrap; min-width:0}
.pmz_qsc{display:flex; flex-direction:column; align-items:center}
.pmz_qbig{font-size:14px; padding-bottom:4px; line-height:1}
.pmz_qtiny{font-size:9px; color:#64748b; font-weight:400; line-height:1;
  transform:scale(.9); transform-origin:left; margin-left:1px}
.pmz_qstar{padding-top:12px; margin-left:4px}
.pmz_qdoor{margin-left:4px}
/* GA draws 空亡 with U+25CB at text-base in Inter; Plus Jakarta Sans has no such
   glyph and falls back to a ~9.7px one, so the ring is DRAWN, not typed. */
.pmz_qvoid{flex:none; width:11px; height:11px; border-radius:999px;
  border:1.5px solid #94a3b8; font-size:0; line-height:0}
.pmz_qpills{display:flex; justify-content:center; gap:10px; padding-top:12px;
  flex-wrap:wrap}
.pmz_qpill{display:flex; align-items:center; gap:6px; padding:6px 11px; border-radius:6px;
  color:#020817}
.pmz_qpill span{font-size:12.5px; color:#64748b}
.pmz_qpill b{font-size:14px; font-weight:700; color:#020817}
.pmz_qpill_n{background:rgba(241,245,249,.6); border:1px solid #e2e8f0}
/* ⚠ ITEM 3 · CHINESE TERM, THEN THE MALAY GLOSS. A legend MUST carry the plate's
   own colours — that is what makes it a legend — so the term keeps its hue and
   gains the plate's own tint behind it, which is how the same hue is readable in
   the plate and was not readable in a bare line of text. The gloss is ink. */
.pmz_qlegend{margin:11px 0 0; display:flex; flex-wrap:wrap; justify-content:center;
  gap:6px 8px; font-size:12.5px; line-height:1.5; color:var(--pmz-ink-2)}
.pmz_qlegend > b{display:inline-flex; align-items:center; gap:5px; padding:3px 9px;
  border-radius:999px; font-weight:700; color:var(--pmz-ink);
  background:rgba(255,255,255,.66); box-shadow:inset 0 0 0 1px rgba(21,17,14,.14)}
.pmz_qlegend > b > u{width:9px; height:9px; flex:none; border-radius:2px;
  text-decoration:none; box-shadow:inset 0 0 0 1px rgba(21,17,14,.22)}
.pmz_qlegend > b > i{font-style:normal; font-weight:500; font-size:12px;
  color:var(--pmz-ink-2)}
.pmz_qlegend > s{display:none}
.pmz_qlegend > em{flex-basis:100%; font-style:normal; margin-bottom:1px;
  font-size:12px; letter-spacing:.10em; text-transform:uppercase;
  color:var(--pmz-ink-2)}

/* ═════════════════════════════════════════════════════════════════════════════
   9 · 大运流年 — GA-measured, and Jim said not to touch it.
   label cell rowspan=3, vertical-rl, 12/500 gold · 年份 12/700 · 干支 12/500 ·
   十神 12/400 slate-500 · cells padding 4 · current 大运 column tinted.
   ═════════════════════════════════════════════════════════════════════════════ */
.pmz_dyscroll{overflow-x:auto; -webkit-overflow-scrolling:touch; text-align:center}
.pmz_dyscroll::-webkit-scrollbar{height:6px}
.pmz_dyscroll::-webkit-scrollbar-thumb{background:rgba(21,17,14,.22); border-radius:999px}
.pmz_dy{border-collapse:collapse; font-size:12px; white-space:nowrap; margin:0 auto}
.pmz_dy tr{border-bottom:1px solid #D8CDB8}
.pmz_dy tr:last-child{border-bottom:0}
/* ⚠ OURS, NOT GA'S — GA draws no vertical rail on this table, so recolouring these
   two words is not "changing the cycle visual". Gold on ivory measured 2.17:1. */
.pmz_dylbl{padding:4px; text-align:center; writing-mode:vertical-rl; font-size:12px;
  /* ⚠ GOLD, LIKE GA (C2.gold = hsl(36,74%,61%), app-mingli.js:1750). Round 31 made
     these ink because gold-on-ivory measured 2.17:1; Jim wants GA's colour, so the
     hue is back and the contrast is bought by DARKENING it rather than by dropping
     it — same hue family, readable on paper. */
  font-weight:700; color:#8C6C25; border-right:1px solid #D8CDB8}
.pmz_dyc{padding:4px; font-weight:400; min-width:38px; text-align:center; color:#15110E}
.pmz_dyy{font-weight:700}
.pmz_dyg{color:#64748b}
.pmz_dyon{background:rgba(241,245,249,.55); color:#B01820}
.pmz_dyhl{color:#B01820}
.pmz_dyhlc{color:#B01820}
.pmz_dygz{display:flex; flex-direction:column; align-items:center; line-height:1.25;
  font-size:12px; font-weight:500; color:#15110E}
.pmz_dyyr{display:flex; flex-direction:column; line-height:1.25}
th.pmz_dyc{cursor:pointer}

/* ═════════════════════════════════════════════════════════════════════════════
   10 · THE READING CONTROL — bottom RIGHT, above the tab bar, on this page.
   Jim, 23 Aug: "Make sure you have the AI reading card above the bottom navigation
   bar and it is located at the bottom right there inside this page."
   ═════════════════════════════════════════════════════════════════════════════ */
.pmz_root[data-screen="record"] .pmz_sifubar{
  left:auto; right:14px; width:auto; max-width:calc(100% - 28px);
  bottom:calc(96px + env(safe-area-inset-bottom, 0px));
  gap:9px; padding:0 12px; min-height:52px; border-radius:14px}
.pmz_root[data-screen="record"] .pmz_sifubar .pmz_sb_t s{display:none}
.pmz_root[data-screen="record"] .pmz_sifubar .pmz_sb_t{flex:none; white-space:nowrap}

/* the reading slot ends clear of that control, so the last card is never trapped
   underneath it. 52 (bar) + 96 (its offset) + 14 breathing room. */
/* ⚠ EVERY screen the record leads to, not just the record. Sejarah and the
   certificate scrolled their last card under the tab bar, because the padding was
   keyed to one screen and the reading control is only on that one. */
.pmz_root[data-screen="record"] .pmz_doc{padding-bottom:calc(162px + env(safe-area-inset-bottom, 0px))}
.pmz_root[data-screen="prov"] .pmz_doc,
.pmz_root[data-screen="cert"] .pmz_doc{padding-bottom:calc(112px + env(safe-area-inset-bottom, 0px))}

/* ═════════════════════════════════════════════════════════════════════════════
   ROUND 30 · PASS 2 — what the first render showed.
   ═════════════════════════════════════════════════════════════════════════════ */

/* -- 1 · THE SWITCH IS A SELECTION, NOT AN ACTION ---------------------------
   ⚠ COLOUR GRAMMAR (round 9, and again at round 27): INK = a selection, GOLD = an
   action. The mode bar had inherited a gold fill, so the page carried TWO golds —
   the tab you are on, and the button that spends 38,800 — and the eye could not
   tell which one was the offer. The switch goes to ink; gold is left to mean money.
   This is also GA's own treatment (dark pill, white label). */
.pmz_ctl .pmz_modebar{background:var(--pmz-fill);
  border:1px solid rgba(217,178,95,.16)}
.pmz_ctl .pmz_modebar button[aria-pressed="true"]{
  background:linear-gradient(180deg,#221C12,#141009);
  border:1px solid rgba(246,227,172,.34); color:#F6E3AC;
  box-shadow:inset 0 1px 0 rgba(246,227,172,.12), 0 6px 14px -8px rgba(0,0,0,.9)}
.pmz_ctl .pmz_modebar button[aria-pressed="false"]{
  background:transparent; border:1px solid transparent; color:var(--pmz-ink-2)}

/* -- 2 · THE PLATE HAS TO FIT ------------------------------------------------
   GA hard-codes width:300px + 36px of ring padding = 372px and its rings then hang
   14px further out on each side — 400px of plate inside a 334px card. It overflowed
   the paper and the right-hand ring ran off the screen. The GRID takes the room it
   is given instead: minmax(0,1fr) tracks with aspect-ratio cells scale cleanly, and
   the ring gutters are reserved rather than assumed. */
.pmz_pw_plate{padding:12px 4px}
.pmz_qwrap{box-sizing:border-box; width:calc(100% - 30px); max-width:none;
  margin:0 auto; padding:30px 32px}
.pmz_qring_l{left:-15px} .pmz_qring_r{right:-15px}
.pmz_qhid{width:26px}
.pmz_qring_t, .pmz_qring_b{max-width:none; left:32px; right:32px; padding:0 4px}

/* -- 3 · 奇门信息 — the han sits UNDER its Malay label ----------------------- */
.pmz_kvk{width:44%; padding-right:10px}
.pmz_kvh{display:block; margin-top:2px; font-style:normal; font-weight:400;
  font-size:12px; letter-spacing:.14em; color:var(--pmz-ink-3)}
.pmz_kvv{font-variant-numeric:lining-nums tabular-nums}

/* -- 4 · the vocabulary the rebuilt 专业版 speaks ---------------------------- */
/* an engine TERM, printed as itself — the one place Chinese is allowed to stand
   alone, because it is a name */
.pmz_term{font-weight:700; color:var(--pmz-ink)}
.pmz_pw .pmz_term{color:#15110E}
/* a qualifier: the pillar a thing sits in, a mapping, a count */
.pmz_maps{font-style:normal; font-size:13px; color:var(--pmz-ink-2)}
/* the engine's own verdict word. It appears on BOTH grounds — on the lacquer bar
   as a status pill and inside the ivory body as running text — so it names a token,
   never a colour. Gold on ivory measured 1.23:1. */
.pmz_strong{font-weight:700; color:var(--pmz-ink)}
.pmz_ac_s .pmz_strong, .pmz_c_hd .pmz_strong{color:#F0DCA6}
.pmz_score{font-style:normal; margin-left:8px; font-size:13px;
  color:var(--pmz-ink-2); font-variant-numeric:lining-nums tabular-nums}
/* the roots, as the objects they are: a branch, where it sits, how deep */
.pmz_roots{display:flex; flex-wrap:wrap; gap:7px; margin-top:7px}
/* NAMED .pmz_rt, NOT .pmz_root - `.pmz_root` is the APP'S OWN SCOPE CLASS on the
   device element. A chip class by that name would have painted a dashed gold border
   and a translucent ground across the entire prototype. */
.pmz_rt{display:inline-flex; align-items:center; gap:6px; padding:5px 9px;
  border-radius:8px; background:var(--pmz-fill);
  border:1px solid rgba(217,178,95,.20)}
.pmz_rt b{font:700 15px/1 var(--pmz-disp); color:var(--pmz-ink)}
.pmz_rt i{font-style:normal; font-size:12.5px; color:var(--pmz-ink-2)}
/* the honest line: what this reader is NOT being shown */
.pmz_zhonly{margin:12px 0 0; padding:8px 10px; border-radius:8px;
  background:var(--pmz-fill); border:1px dashed rgba(217,178,95,.24);
  font:400 12.5px/1.5 var(--pmz-ui); color:var(--pmz-ink-3)}
.pmz_root[data-lang="zh"] .pmz_zhonly{display:none}   /* nothing is missing in zh */

/* -- 5 · the user card's two lines ------------------------------------------ */
.pmz_uc_nm{flex:1 1 auto}
.pmz_uc_line{font-size:13.5px}

/* -- 6 · THE READING CONTROL, SMALLER ----------------------------------------
   It floats over the page by design, so its footprint IS a cost: at 310px wide it
   was covering a third of the 奇门 plate and the honest "n notes in Chinese" line.
   The seal comes off (the brand is already everywhere on this page), the label
   stays — a wordless control gets exactly one review, and that review is "what is
   that for?" — and the whole thing lands around 215px. */
.pmz_root[data-screen="record"] .pmz_sifubar{
  gap:8px; padding:0 10px 0 13px; min-height:48px; border-radius:13px;
  bottom:calc(94px + env(safe-area-inset-bottom, 0px));
  font-size:13.5px}
.pmz_root[data-screen="record"] .pmz_sifubar .pmz_sb_ic{display:none}
.pmz_root[data-screen="record"] .pmz_cost{padding:4px 9px; font-size:11.5px; gap:4px}
.pmz_root[data-screen="record"] .pmz_cost .pmz_gem{width:11px; height:11px}

/* the chip now leads the birth line rather than competing with the name */
.pmz_uc_line .pmz_uc_sex{margin-right:9px; vertical-align:1px}
.pmz_uc_top{gap:10px}
.pmz_uc_ib{padding:0 12px; font-size:13px}


/* ═════════════════════════════════════════════════════════════════════════════
   ROUND 30 · PASS 3 — Sejarah, the reading overlay, and the colophon join the
   same material as the record. One app, one surface.
   ═════════════════════════════════════════════════════════════════════════════ */

/* a page header, where the ceremony used to put a rod-and-label */
.pmz_ph{display:flex; align-items:baseline; gap:10px; margin:2px 14px 10px}
.pmz_ph h1{margin:0; font:700 21px/1.2 var(--pmz-ui); color:var(--pmz-ink); letter-spacing:.01em}
.pmz_ph_han{font:400 13px/1 var(--pmz-ui); letter-spacing:.20em; color:var(--pmz-ink-3)}
.pmz_ph s{text-decoration:none; margin-left:auto; font:600 12.5px var(--pmz-ui);
  color:var(--pmz-ink-2)}
.pmz_ph s b{color:#F0DCA6}

/* Sejarah — a consultation that happened, not a leaf of a scroll */
.pmz_prov{margin:0 14px 10px; padding:13px 14px 12px; border-radius:16px;
  background:linear-gradient(180deg,var(--pmz-lacq) 0%,var(--pmz-lacq-2) 58%,var(--pmz-lacq-3) 100%);
  border:1px solid rgba(217,178,95,.22);
  box-shadow:inset 0 1px 0 rgba(246,227,172,.09), 0 20px 40px -24px rgba(0,0,0,.96)}
.pmz_prov .pmz_prov_q{font:700 15.5px/1.3 var(--pmz-ui); color:var(--pmz-ink)}
.pmz_prov .pmz_prov_m{margin:5px 0 0; font:400 13px/1.55 var(--pmz-ui);
  color:var(--pmz-ink-2)}
.pmz_prov .pmz_prov_acts{display:flex; gap:8px; margin-top:12px}
.pmz_prov .pmz_prov_acts button{flex:1; min-height:44px; border-radius:10px; cursor:pointer;
  border:1px solid rgba(217,178,95,.22); background:var(--pmz-fill);
  color:var(--pmz-ink); font:600 13px/1.25 var(--pmz-ui)}
.pmz_prov .pmz_prov_acts .pmz_dl{border-color:rgba(246,227,172,.45); color:#F6E3AC;
  background:rgba(217,178,95,.16)}
/* the chop is a red seal on ivory; on navy it needs its own paper to sit on */
.pmz_prov .pmz_prov_seal{flex:none; width:52px; height:52px; border-radius:6px;
  display:flex; align-items:center; justify-content:center;
  background:var(--pmz-paper-2); border:1px solid rgba(216,205,184,.5)}
.pmz_prov .pmz_prov_seal img{width:40px; height:40px}
.pmz_prov .pmz_empty b{color:var(--pmz-ink)}
.pmz_prov .pmz_empty span{color:var(--pmz-ink-2)}
.pmz_prov .pmz_empty .pmz_seal_sm{background:rgba(176,24,32,.22); color:#F0DCA6;
  border:1px solid rgba(217,178,95,.3)}

/* the reading overlay */
.pmz_ai{background:radial-gradient(120% 70% at 50% 0%,#171208 0%,var(--pmz-ground) 70%)}
.pmz_ai .pmz_ai_top{border-bottom:1px solid rgba(217,178,95,.18)}
.pmz_ai .pmz_ai_top h2{color:var(--pmz-ink)}
.pmz_ai .pmz_ai_back{color:var(--pmz-ink)}
.pmz_ai .pmz_ai_lead{color:var(--pmz-ink-2)}
.pmz_ai .pmz_cat{border-bottom-color:rgba(217,178,95,.14)}
.pmz_ai .pmz_cat_ic{color:#E9C77E}
.pmz_ai .pmz_cat_t b{color:var(--pmz-ink)}
.pmz_ai .pmz_cat_t s{color:var(--pmz-ink-2)}
.pmz_ai .pmz_zhnote{border-color:rgba(217,178,95,.24); color:var(--pmz-ink-3);
  background:var(--pmz-fill)}
.pmz_ai .pmz_leaf, .pmz_ai .pmz_ai_out{color:var(--pmz-ink)}

/* the colophon leaf */
#stSifu .pmz_leaf{margin:0 14px 10px; padding:14px; border-radius:16px;
  background:linear-gradient(180deg,var(--pmz-lacq) 0%,var(--pmz-lacq-2) 58%,var(--pmz-lacq-3) 100%);
  border:1px solid rgba(217,178,95,.22);
  box-shadow:inset 0 1px 0 rgba(246,227,172,.09), 0 20px 40px -24px rgba(0,0,0,.96)}
#stSifu .pmz_ai_t{color:var(--pmz-ink)}
#stSifu .pmz_ai_s{color:var(--pmz-ink-2)}
#stSifu .pmz_meter_t{color:var(--pmz-ink-2)}

/* the certificate's own bar: downloading it is the ACTION, so it takes the gold */
.pmz_pdfbar #pmzPdfDl{border-color:rgba(246,227,172,.55); color:#2A1C08;
  background:linear-gradient(180deg,#F2D591,#D9B25F 62%,#C39A45);
  box-shadow:0 10px 22px -12px rgba(217,178,95,.65); font-weight:700}

/* -- SIFU'S READING IS A LETTER, SO IT IS ON PAPER --------------------------
   ⚠ It had `background:rgba(255,255,255,.48)` and paper-era ink. On the navy card
   that is a translucent grey panel with near-black text on it — the exact
   grey-on-grey the round-24 complaint was about, and it looked broken rather than
   designed. The same rule as the charts settles it: PAPER IS WHERE CONTENT LIVES.
   The meter above it is UI, not content, so it stays navy. */
#stSifu .pmz_prose, .pmz_ai .pmz_prose{
  background:var(--pmz-paper-2); border:1px solid rgba(216,205,184,.5);
  border-radius:12px; padding:15px 14px;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.7), 0 2px 10px -4px rgba(0,0,0,.5)}
#stSifu .pmz_prose p, .pmz_ai .pmz_prose p{color:#15110E; font-size:15px; line-height:1.78}
#stSifu .pmz_prose_sig, .pmz_ai .pmz_prose_sig{color:#7A7066; border-top-color:#D8CDB8}
#stSifu .pmz_prose .pmz_rx, .pmz_ai .pmz_prose .pmz_rx{color:#15110E}
/* the free-reading meter is a control, not the reading */
#stSifu .pmz_meter, .pmz_ai .pmz_meter{border:1px solid rgba(217,178,95,.22);
  background:var(--pmz-fill); border-radius:10px}
#stSifu .pmz_meter_t, .pmz_ai .pmz_meter_t{color:var(--pmz-ink-2)}
#stSifu .pmz_pip, .pmz_ai .pmz_pip{background:var(--pmz-fill);
  border-color:rgba(217,178,95,.45)}
#stSifu .pmz_pip.pmz_on, .pmz_ai .pmz_pip.pmz_on{background:var(--pmz-gold)}
/* while the reading overlay is open you are already in the reading */
.pmz_root[data-ai="1"] .pmz_sifubar{display:none}

/* the certificate's record number, under its two buttons.
   ⚠ ON THE DARK GROUND — the same class of bug as .pmz_secttl and .pmz_ph h1.
   Measured: the LABEL "Nombor rekod" was 2.06:1 while the serial beside it was
   perfectly legible gold. A visible number with an invisible label. */
.pmz_certser, .pmz_certnote{
  --pmz-ink:var(--pmz-on-lacq);
  --pmz-ink-2:var(--pmz-on-lacq-2);
  --pmz-ink-3:var(--pmz-on-lacq-3);
}
.pmz_certser{margin:12px 14px 2px; font:400 13.5px/1.5 var(--pmz-ui);
  color:var(--pmz-ink-2)}
.pmz_certser b{color:#F0DCA6; font-weight:700; letter-spacing:.04em;
  font-variant-numeric:lining-nums tabular-nums}
.pmz_certnote{margin:0 14px 12px; color:var(--pmz-ink-2)}

/* ═════════════════════════════════════════════════════════════════════════════
   ROUND 30 · PASS 4 — what §40 measured.
   Two laws, both from Jim's N1: nothing WE author under 13px, and every line
   clears WCAG AA against its COMPOSITED ground. The gate found six type sizes and
   six contrast failures that no screenshot review would have caught, because
   12.5px grey-on-navy looks fine when you already know what it says.
   ⚠ The ported chart keeps GA's own scale (9–14px) — it is exempt BY NAME in the
   gate (.pmz_pw), because the visual chart is not ours to change.
   ═════════════════════════════════════════════════════════════════════════════ */

/* -- the Chinese TERM beside a Malay label is not decoration ------------------
   It is the word a consultant actually searches for, so it gets read-size type and
   real ink instead of a 12px whisper at 42% opacity (3.49:1). */
.pmz_c_han{font-size:13px; color:var(--pmz-ink-2)}
.pmz_kvh{font-size:13px; color:var(--pmz-ink-2); letter-spacing:.10em}
.pmz_ac_han{font-size:13px; color:var(--pmz-ink-2)}
.pmz_ph_han{font-size:13px; color:var(--pmz-ink-2)}
.pmz_ln_loc{font-size:13px; color:var(--pmz-ink-2)}
.pmz_rt i{font-size:13px; color:var(--pmz-ink-2)}
.pmz_maps{color:var(--pmz-ink-2)}
.pmz_score{font-size:13px; color:var(--pmz-ink-2)}
.pmz_zhonly{font-size:13px; color:var(--pmz-ink-2)}
.pmz_qhd i{color:#6B6157}
.pmz_kvsub{font-size:13px; color:var(--pmz-ink-2)}

/* -- the two chips that carry a fact ---------------------------------------- */
.pmz_uc_sex{font-size:13px}
.pmz_costtag b{font-size:13.5px}
.pmz_root[data-screen="record"] .pmz_cost{font-size:13px}
.pmz_root[data-screen="record"] .pmz_cost .pmz_gem{width:12px; height:12px}

/* the group headings inside a section ("Corak terbentuk · 成格") were 12.5px — they
   name what follows, so they carry meaning and belong above the floor */
/* ⚠ EVERY PAPER SURFACE, NOT JUST THE DRAWER BODY. Item 9 put 流年 inside a CARD
   body and every analysis inside a SUB-ROW body, and these rules named only
   .pmz_ac_b — so the same element fell back to 12.5px/ink-3 under N1's floor
   depending on which drawer it happened to land in. */
.pmz_ac_b .pmz_grp h3, .pmz_c_b .pmz_grp h3, .pmz_sub_b .pmz_grp h3{
  font-size:13px; color:var(--pmz-ink-2)}
/* .pmz_note is 12.5px, which is right on paper inside a chart and wrong inside a
   section where it is carrying the 命卦, the current 大运 and the 调候 note */
.pmz_ac_b .pmz_note, .pmz_c_b .pmz_note, .pmz_sub_b .pmz_note{
  font-size:13px; color:var(--pmz-ink-2)}
.pmz_ac_b .pmz_note b, .pmz_c_b .pmz_note b, .pmz_sub_b .pmz_note b{color:var(--pmz-ink)}

/* ═════════════════════════════════════════════════════════════════════════════
   ROUND 30 · PASS 5 — what the two rival reviews found that the rig did not.
   ═════════════════════════════════════════════════════════════════════════════ */

/* -- the 大运 columns are CONTROLS, and controls clear 44px --------------------
   ⚠ THE ONE PLACE TWO OF JIM'S INSTRUCTIONS COLLIDED. "Dont change the cycle
   visual" (GA's cells are 38px) against N1's 44px floor, which he ticked later and
   called non-negotiable. Both reviewers found it independently.
   The resolution keeps every glyph, colour, weight and border of GA's table and
   widens ONLY the interactive header cells: `th.pmz_dyc` is the 大运 column, and
   its three stacked rows already give ~72px of height, so 44px of width completes
   the target. The 流年 `td` cells below are not controls and are untouched — the
   two row groups list different things and were never column-aligned. */
th.pmz_dyc{min-width:44px}

/* -- 12.5px that carries meaning, outside #pmzRead ---------------------------
   §40 only swept the reading, the user card and the switch. codex found the same
   floor broken on the confirm card's balance line and on the certificate's own
   metadata — both authored, both meaningful. §40 now sweeps those too. */
.pmz_cf_foot{font-size:13px}
.pmz_cover_meta{font-size:13px}

/* -- the reading's own two 12.5px lines --------------------------------------
   Widening §40's sweep to #stSifu found them: the "Membaca rekod <name> · 八字"
   subtitle and the free-reading meter. Both authored, both meaningful. */
#stSifu .pmz_ai_s, .pmz_ai .pmz_ai_s{font-size:13px; color:var(--pmz-ink-2)}
#stSifu .pmz_meter_t, .pmz_ai .pmz_meter_t{font-size:13px}


/* ══ LIVE-APP BRIDGE — not from the prototype ══ */
#s-mingli-scroll{ overflow:hidden; padding-bottom:0; }
#pmzRoot{ position:absolute; inset:0; overflow:hidden; background:var(--pmz-ground); }

/* ⚠ HIDDEN, NOT DELETED. The prototype draws its own Tenaga chip, language pill,
   language menu and tab bar — all four duplicate chrome this app already renders at
   the .device level, so all four must be invisible here. They stay in the DOM because
   mingli-r37.js binds those ids in sixteen unguarded places at init; deleting the
   markup made MZ_INIT throw on `$('pmzBack').addEventListener` before it reached
   `window.MZ`, and the result was a screen that mounted, sized itself 390x844, set its
   own booted flag, and rendered nothing at all.
   ⚠ #pmzBack is deliberately NOT in this list — it is the prototype's in-page
   navigation (record → river), which the live app has no equivalent of. */
#pmzRoot .pmz_chip,
#pmzRoot .pmz_langpill,
#pmzRoot .pmz_langmenu,
#pmzRoot .pmz_tabbar{ display:none !important; }

/* ══ THE AI READING PAGE IS A FULL TAKEOVER ═══════════════════════════════════
   ⚠ THE APP'S TAB BAR WAS SITTING ON THE INPUT. Jim, 24 Aug: "I cant even write and
   send anything out." Measured on production: #pmzAiInput and #pmzAiSend render at the
   right size in the right place (50px tall, y 757-807 of an 844 viewport) and
   elementFromPoint at their centre returns `a.tab`. The prototype was built in a
   sandbox with no app chrome below it, so nothing ever collided there.

   .pmz_ai is z-index 150 and .tabbar is 50, so this is not an ordering problem — they
   are in different stacking contexts, and raising the number would not fix it. 实时盘's
   own AI screen is a full-screen takeover with no tab bar, which is what Jim asked this
   one to match, so the bar is hidden for as long as the reading page is open. The panel
   keeps its own back chevron (#pmzAiBack), so there is always a way out. */
body.pmz-ai-open .tabbar{ display:none !important; }

/* ══ THE READING, LAID OUT LIKE 实时盘's ══════════════════════════════════════
   Jim: "follow exactly how the real time chart ai chatbox present the reading, but we
   just change the background colour to match this page." Structure ported from
   qimen-realtime.js :: drawAI (.ai-q / .ai-doc / .hd / .bd / .cite / .ft); the ground is
   this page's lacquer instead of 实时盘's navy, and the document body stays light paper
   because several thousand words of light-on-dark is a different thing to read. */
#pmzRoot .pmz_ai_q{ display:flex; justify-content:flex-end; margin:0 0 12px; }
#pmzRoot .pmz_ai_q span{
  max-width:86%; padding:10px 14px; border-radius:16px 16px 4px 16px;
  background:rgba(233,199,126,.14); border:1px solid rgba(217,178,95,.28);
  color:var(--pmz-on-lacq); font:15px/1.55 var(--pmz-ui);
  white-space:pre-wrap; word-break:break-word; }
#pmzRoot .pmz_ai_doc{
  margin:0 0 18px; border-radius:14px; overflow:hidden;
  border:1px solid rgba(217,178,95,.30);
  background:rgba(20,15,8,.55); }
#pmzRoot .pmz_ai_doc_hd{
  display:flex; align-items:baseline; gap:8px; padding:10px 14px;
  border-bottom:1px solid rgba(217,178,95,.22); }
#pmzRoot .pmz_ai_doc_hd b{ font:700 15px/1.2 var(--pmz-ui); color:#E9C77E; flex:1; }
#pmzRoot .pmz_ai_doc_hd s{ text-decoration:none; font:12px var(--pmz-ui); color:var(--pmz-on-lacq-3); }
/* the paper the reading is printed on */
#pmzRoot .pmz_ai_doc_bd{ background:var(--pmz-paper,#F7F3EC); padding:14px 15px 16px; }
#pmzRoot .pmz_ai_cite{
  margin:0 0 10px; font:12px/1.4 var(--pmz-ui); color:#7A7066;
  padding-bottom:9px; border-bottom:1px solid rgba(21,17,14,.10); }
#pmzRoot .pmz_ai_doc_body{ color:#15110E; font:15px/1.72 var(--pmz-ui); word-break:break-word; }
#pmzRoot .pmz_ai_doc_body p{ margin:0 0 11px; }
#pmzRoot .pmz_ai_doc_body p:last-child{ margin-bottom:0; }
#pmzRoot .pmz_ai_doc_body strong{ color:#15110E; font-weight:700; }
#pmzRoot .pmz_ai_wait{ display:inline-block; color:#7A7066; font:15px/1.6 var(--pmz-ui); }
#pmzRoot .pmz_ai_doc_ft{
  padding:9px 14px; text-align:right;
  font:12px var(--pmz-ui); color:var(--pmz-on-lacq-3); }

/* the chosen topic card, lit in place (pickTopic toggles aria-current) */
#pmzRoot .pmz_cat[aria-current="true"]{
  border-color:rgba(246,227,172,.55);
  background:rgba(233,199,126,.10); }
/* Send is dead until the box has something in it */
#pmzRoot .pmz_ai_send[disabled]{ opacity:.42; cursor:default; }

/* ══ HOW MANY FREE READINGS ARE LEFT ══════════════════════════════════════════
   Jim, 24 Aug: "please show how many free ai reading per month left? can follow the
   real time chart using the diamond currency to show how many left according to the
   level." 实时盘 draws one gem per monthly slot and dims the spent ones; this is the
   same mark (the app's own diamond path, as used on the Tenaga chip and the 实时盘 FAB)
   at the same size, so the two screens count the same thing the same way.
   ⚠ TWO NAMES WERE ALREADY TAKEN AND I TOOK BOTH OF THEM IN TURN.
     `.pmz_pip` is the prototype's 11px round dot WITH A BORDER — an <svg> carrying it
     came out as a ring drawn around a diamond. So I moved to `.pmz_gem`, WHICH IS THE
     PRICE MARK (costHtml, used on the Tenaga chip, every cost button and the spend
     card), sized per context by the stylesheet: 11 / 12 / 14 / 17 / 19 / 27px. This
     rule is `#pmzRoot .pmz_gem` — specificity (1,0,1) — so it beat every one of those
     class-only selectors and flattened every price gem in 命理 to 13px and gold.
     Third collision in this file (.pmz_chip and .pmz_bento are the other two, both with
     the same warning beside them). `.pmz_alw` is grepped and free. */
#pmzRoot .pmz_alw{ width:13px; height:13px; flex:none; color:var(--pmz-gold, #D9B25F); }
#pmzRoot .pmz_alw_out{ color:var(--pmz-on-lacq-3, #8A7C63); opacity:.45; }
#pmzRoot .pmz_pips{ align-items:center; }

/* ══ THE REGISTER WHILE IT IS STILL LOADING ════════════════════════════
   Jim, 24 Aug: "when user come in to this feature, it loads quite slow". Most of that
   was not milliseconds. Filmstrip on a throttled phone (4x CPU, 4G), the frame at
   539 ms of every cold entry:

       count "0 / 0 rekod"
       EMPTY-STATE: "Tiada rekod sepadan. Ubah tapisan atau kata carian."

   For ~1.5 s the register told a consultant with three clients that their records did
   not match, and suggested they change a filter they had never set. The rows then
   appeared. A screen that answers WRONGLY first and correctly second feels broken, not
   merely slow. These are the placeholder leaves it shows instead — the prototype has
   no rule for this because the prototype's clients were a fixture array in memory. */
#pmzRoot .pmz_row.pmz_skel{
  pointer-events:none; min-height:86px; padding:15px 16px;
  display:flex; flex-direction:column; justify-content:center; gap:9px; }
#pmzRoot .pmz_skel_l{
  display:block; height:11px; border-radius:6px;
  background:linear-gradient(90deg,
    rgba(21,17,14,.07) 0%, rgba(21,17,14,.13) 42%, rgba(21,17,14,.07) 84%);
  background-size:260% 100%; animation:pmz_shim 1.35s linear infinite; }
@keyframes pmz_shim{ from{ background-position:130% 0 } to{ background-position:-130% 0 } }

/* ══ THE READING, WHILE IT IS BEING WRITTEN ═══════════════════════
   Jim: "make it feel like its generating instead of still text, user might be confuse
   or leave feeling the app is broken." It was one frozen sentence held for the whole
   20-40 s the model takes. Ported from 实时盘's own reading room
   (assets/qimen-realtime.css :: .qload) rather than re-invented, so the two screens
   wait the same way: a breathing seal, a step line that advances through what is
   really happening, and four shimmer lines standing in for the paragraphs.
   ⚠ The step line's clock is in mingli-r37.js :: waitEnsure / waitStop — read the
     note there before touching either, it is a documented two-leak function. */
#pmzRoot .pmz_wait{ padding:2px 0 2px; }
#pmzRoot .pmz_wait_top{ display:flex; align-items:flex-start; gap:12px; margin:0 0 15px; }
#pmzRoot .pmz_wait_seal{ position:relative; width:30px; height:30px; flex:none; }
#pmzRoot .pmz_wait_seal i{ position:absolute; inset:0; border-radius:50%;
  border:1.5px solid rgba(176,24,32,.30); animation:pmz_pulse 1.9s ease-out infinite; }
#pmzRoot .pmz_wait_seal b{ position:absolute; inset:8px; border-radius:50%;
  background:#B01820; animation:pmz_breathe 1.9s ease-in-out infinite; }
#pmzRoot .pmz_wait_txt{ min-width:0; flex:1; }
#pmzRoot .pmz_wait_step{ display:block; font:700 14px/1.35 var(--pmz-ui); color:#3B342A;
  transition:opacity .22s ease; }
#pmzRoot .pmz_wait_sub{ display:block; margin-top:3px; font:600 11.5px/1.4 var(--pmz-ui);
  color:#8A7C63; }
#pmzRoot .pmz_wait_lines i{ display:block; height:10px; margin:0 0 12px; border-radius:5px;
  background:linear-gradient(90deg,
    rgba(21,17,14,.06) 0%, rgba(21,17,14,.12) 42%, rgba(21,17,14,.06) 84%);
  background-size:260% 100%; animation:pmz_shim 1.5s linear infinite; }
#pmzRoot .pmz_wait_lines i:nth-child(2){ animation-delay:.13s }
#pmzRoot .pmz_wait_lines i:nth-child(3){ animation-delay:.26s }
#pmzRoot .pmz_wait_lines i:nth-child(4){ animation-delay:.39s; width:72%; margin-bottom:0 }
@keyframes pmz_pulse{ 0%{ transform:scale(.72); opacity:.9 } 100%{ transform:scale(1.28); opacity:0 } }
@keyframes pmz_breathe{ 0%,100%{ transform:scale(.86); opacity:.75 } 50%{ transform:scale(1); opacity:1 } }
/* the first words arriving should feel like an arrival, not a jump cut */
#pmzRoot .pmz_ai_doc_body{ animation:pmz_bodyin .38s cubic-bezier(.22,1,.36,1) backwards; }
@keyframes pmz_bodyin{ from{ opacity:0; transform:translate3d(0,5px,0) } }

/* ⚠ A READER WHO ASKED FOR LESS MOTION STILL NEEDS TO KNOW IT IS WORKING. Everything
   above stops moving; the step line keeps advancing, which carries the whole message
   on its own. */
@media (prefers-reduced-motion: reduce){
  #pmzRoot .pmz_skel_l,
  #pmzRoot .pmz_wait_lines i,
  #pmzRoot .pmz_wait_seal i,
  #pmzRoot .pmz_wait_seal b,
  #pmzRoot .pmz_ai_doc_body{ animation:none !important; }
  #pmzRoot .pmz_wait_seal b{ opacity:.85 }
}

/* ══ THE LOCK (mig 0116, 17 Sep 2026) ═════════════════════════════════════════════
   A record is free and shows the name line, the edit pen and the 四柱 + 九宫 card.
   5,000 once per client opens the rest. root[data-locked="1"] is the ONE switch.
   ⚠ HIDDEN, NEVER DELETED — mingli-r37.js binds every one of these ids at parse time.
   ⚠ THIS IS PRESENTATION. The handlers refuse on their own (isLocked) — a stylesheet
   has never stopped a keyboard, and the 九宫 cells answer Enter. */
#pmzRoot[data-locked="1"] #pmzModeBar,
#pmzRoot[data-locked="1"] #pmzUcSwitch,
#pmzRoot[data-locked="1"] #pmzUcReport,
#pmzRoot[data-locked="1"] #pmzUcHist,
#pmzRoot[data-locked="1"] #pmzSifuBar,
#pmzRoot[data-locked="1"] #pmzNayin,
#pmzRoot[data-locked="1"] #pmzLiuyun,
#pmzRoot[data-locked="1"] #pmzRead .pmz_qtap{ display:none !important; }
/* nothing in the free card is a control while locked */
#pmzRoot[data-locked="1"] #pmzChartCard,
#pmzRoot[data-locked="1"] #pmzChartCard *{ pointer-events:none !important; cursor:default !important; }
/* ⚠ NO EXTRA BOTTOM PADDING. The record stage already reserves the room the AI pill and
   the tab bar need; a further 178px here left 202px of dead page under the offer (Jim,
   17 Sep: "remove the empty spaces"). Measured at 390x844 with none: the offer's last
   line ends ~24px above the bar. Gate: _client-unlock-local-probe section 2. */

/* the offer, under the chart — same gutter as .pmz_c so the two edges line up */
#pmzRoot .pmz_ulcard{ margin:0 14px 12px; padding:16px 16px 14px; border-radius:16px;
  border:1px solid rgba(201,162,75,.55);
  background:linear-gradient(180deg, rgba(201,162,75,.17), rgba(201,162,75,.05));
  color:#F3EAD6; font:500 14px/1.5 var(--pmz-ui); }
#pmzRoot .pmz_ul_t{ margin:0; display:flex; align-items:center; gap:8px;
  font:800 15.5px/1.3 var(--pmz-ui); color:#E7C873; }
#pmzRoot .pmz_ul_ic{ flex:none; }
#pmzRoot .pmz_ul_sub{ margin:4px 0 10px; color:rgba(243,234,214,.8); }
#pmzRoot .pmz_ul_li{ margin:0; padding:0; list-style:none; }
#pmzRoot .pmz_ul_li li{ display:flex; gap:9px; padding:7px 0;
  border-top:1px solid rgba(201,162,75,.2); }
#pmzRoot .pmz_ul_li li i{ flex:none; font-style:normal; color:#C9A24B; font-size:11px; line-height:21px; }
#pmzRoot .pmz_ul_note{ margin:10px 0 0; font-size:12px; color:rgba(243,234,214,.62); }
#pmzRoot .pmz_ul_err{ margin:10px 0 0; padding:9px 11px; border-radius:10px;
  background:rgba(176,24,32,.22); border:1px solid rgba(224,88,96,.6);
  color:#FFD9DB; font:700 13px/1.45 var(--pmz-ui); }
#pmzRoot .pmz_ul_err[hidden]{ display:none; }

/* the bar — full width, in the AI pill's slot, thumb reach. Shown ONLY on a locked
   record; never while the reading room or another screen is up. No entry animation:
   content must never depend on an animation finishing.
   ⚠ SAME MATERIAL AS #pmzDoCast (Jim, 17 Sep: "some depth, high quality feel"): the
   six-stop cast-gold gradient, a lit top edge, a dark lower edge, a hairline rim and a
   warm cast shadow — the first version was a flat two-stop wash and looked like a label. */
#pmzRoot .pmz_unlockbar{ display:none; position:absolute; left:14px; right:14px;
  bottom:calc(94px + env(safe-area-inset-bottom, 0px)); z-index:49;
  min-height:56px; padding:0 14px; align-items:center; justify-content:center; gap:8px;
  border:none; border-radius:14px; cursor:pointer; white-space:nowrap;
  font:800 16px/1 var(--pmz-ui); letter-spacing:.01em; color:#1B1408;
  text-shadow:0 1px 0 rgba(255,255,255,.42);
  background:linear-gradient(180deg,
    #FFF6DC 0%, #F4E3B4 18%, #E3CB86 42%, #CBAE5D 62%, #B08F3E 86%, #9C7B2E 100%);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.85),
             inset 0 -1px 0 rgba(90,66,16,.55),
             inset 0 0 0 1px rgba(140,108,37,.45),
             0 14px 28px -10px rgba(0,0,0,.75),
             0 10px 22px -8px rgba(140,108,37,.70),
             0 2px 5px -2px rgba(0,0,0,.45);
  -webkit-tap-highlight-color:transparent; }
#pmzRoot[data-locked="1"][data-screen="record"] .pmz_unlockbar{ display:flex; }
#pmzRoot[data-ai="1"] .pmz_unlockbar{ display:none !important; }
#pmzRoot .pmz_unlockbar:disabled{ opacity:.72; cursor:default; }
#pmzRoot .pmz_unlockbar:active{ transform:translate3d(0,1px,0);
  box-shadow:inset 0 1px 3px rgba(90,66,16,.45),
             inset 0 0 0 1px rgba(140,108,37,.55),
             0 2px 6px -3px rgba(0,0,0,.4); }
#pmzRoot .pmz_unlockbar .pmz_ul_ic{ width:17px; height:17px; }
#pmzRoot .pmz_unlockbar .pmz_ub_dot{ font-style:normal; opacity:.5; }
/* the price rides in the house cost chip, sized up for a 56px bar */
#pmzRoot .pmz_unlockbar .pmz_ub_tag{ padding:6px 12px 6px 10px; gap:6px; text-shadow:none;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.09), 0 1px 0 rgba(255,255,255,.35); }
#pmzRoot .pmz_unlockbar .pmz_ub_tag .pmz_gem{ width:15px; height:15px; display:inline-flex; flex:none; }
#pmzRoot .pmz_unlockbar .pmz_ub_tag .pmz_gem svg{ width:100%; height:100%; }
#pmzRoot .pmz_unlockbar .pmz_ub_tag b{ font:800 15px/1 var(--pmz-ui); color:#F6DCA0; }
#pmzRoot .pmz_unlockbar .pmz_ub_free{ padding:7px 12px; }
/* "1 percuma bulan ini" is the longest thing this bar ever says, in the language most
   students read. Measured at 390px it left 6px a side; without the dot and a size down
   it clears. Gate: _unlock-polish-shot prints the side margins for zh / ms / en. */
#pmzRoot .pmz_unlockbar[data-free="1"]{ font-size:15px; gap:9px; }
#pmzRoot .pmz_unlockbar[data-free="1"] .pmz_ub_dot{ display:none; }
#pmzRoot .pmz_unlockbar[data-free="1"] .pmz_ub_free{ padding:7px 10px; }
#pmzRoot .pmz_unlockbar[data-free="1"] .pmz_ub_free b{ font-size:12.5px; }
#pmzRoot .pmz_unlockbar .pmz_ub_free b{ font-size:13px; color:#9FE8C4; letter-spacing:.01em; }
@media (max-width:359px){
  #pmzRoot .pmz_unlockbar{ font-size:14.5px; gap:6px; padding:0 10px; }
  #pmzRoot .pmz_unlockbar .pmz_ub_tag b{ font-size:13.5px; }
  #pmzRoot .pmz_unlockbar .pmz_ub_free b{ font-size:12px; }
}

/* Open Record says FREE where the price used to be — in the SAME dark chip the price
   wore (ROUND 28 · 2), so the button keeps its contrast; only the ink changes, to jade. */
#pmzRoot #pmzDoCast .pmz_addcost.pmz_free{ padding:4px 12px; }
#pmzRoot #pmzDoCast .pmz_addcost.pmz_free b{ font:800 12.5px/1.4 var(--pmz-ui);
  letter-spacing:.08em; color:#9FE8C4; text-shadow:none; }


/* ==============================================================================
   THE DELETE CONFIRM (17 Sep 2026). A calm destructive button: muted cinnabar, cream
   ink, no glow. It must out-rank `.pmz_sh_dark .pmz_sh_1st` (gold) on every property
   gold sets — background, ink, text-shadow, box-shadow — or gold leaks back in.
   ============================================================================== */
.pmz_sh_1st.pmz_sh_danger, .pmz_sh_dark .pmz_sh_1st.pmz_sh_danger{
  flex:1; border:0; color:#FFF3EA; font-weight:700; text-shadow:none;
  background:linear-gradient(180deg,#B5322F 0%,#9A2323 100%);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.16),
             inset 0 0 0 1px rgba(0,0,0,.22),
             0 6px 14px -8px rgba(0,0,0,.6)}
.pmz_sh_1st.pmz_sh_danger:active, .pmz_sh_dark .pmz_sh_1st.pmz_sh_danger:active{
  background:#8A1F1F;
  box-shadow:inset 0 1px 3px rgba(0,0,0,.4), inset 0 0 0 1px rgba(0,0,0,.25)}
.pmz_del_who{margin:0 0 8px; font:700 17px/1.4 var(--pmz-ui); overflow-wrap:anywhere}
.pmz_del_b{margin:0; font:14.5px/1.6 var(--pmz-ui); opacity:.78}
