/*!
 * VD20 — pages/auth.css (docs/ui/PAGE-RECIPES.md §3.3, docs/ui/BRAND-SPEC.md §9.1 / §9.2 / Appendix A): the sign-in
 * family. auth/layout and errors/layout load it themselves; in-app pages ask with <x-page-assets css="auth" />.
 *
 *   .auth           the standalone shells — 登入, 兩步驟驗證 (challenge), the error pages: no sidebar. They load
 *                   app.css + brand.css, so every token, field, button, alert, the dark palette and the 高竿
 *                   decoration classes (.gg-stage / .gg-ribbon / .gg-fin / .gg-rule / .gg-logo--*) are the shared
 *                   ones; only the shell geometry and the stage's composition live here.
 *   .auth--stage    登入 / 兩步驟驗證 (auth/layout): ≥1024 px a two-column grid — the 高竿 BRAND STAGE on the left
 *                   (.gg-hero: cover A's ribbon S-pair, headline + fin, tracked tagline, rule, copy, C-portrait;
 *                   or, with 公告欄 bulletins, .auth-board: the opaque bulletin panel on the ribbons under a small
 *                   tagline header), the SIGN-IN COLUMN on the right (group lockup on clean white, the card).
 *                   Below 1024 px: no stage, no ribbon — the lockup above the card, the panel under it.
 *   .auth--error    the error pages (errors/layout): the same stage at reduced strength (g1 + b1 only, no photo)
 *                   behind the centred message card, the lockup above it.
 *   .auth-split / .bltn   登入's 公告欄 (auth/partials/bulletins): the featured slider and the latest-items list
 *                   (pages/auth.js).
 *   .pg-account     變更密碼 / 確認密碼 (in-app, page--form): the live password-rule checklist.
 *   .pg-tfa         兩步驟驗證 setup / status / admin reset (in-app): steps, key, QR, recovery codes.
 *
 * Tokens only — no hex colour except the print block (prints are always light). The setup QR sits on the shared
 * .paper-chip, so it stays dark-on-white (scannable) in dark mode. Decoration rules (BRAND-SPEC §5.2): ribbons only
 * on the stage, opacity from the --gg-ribbon-* tokens (brand.css), only --text-1 / --text-2 over them, every ribbon
 * bleeds off an edge and passes BEHIND opaque cards — never behind the form; the lockup's safe space stays clear.
 * Motion: entrances fill `backwards` and play once; 精簡 drops them, 關閉 / prefers-reduced-motion drop everything
 * (the ribbon drift / rule / fin levels are brand.css §G). No url() here — the stage draws with brand.css classes.
 */

/* ── the standalone shell (body.auth) — mobile first ──────────────────────────────────────── */
.auth { min-height:100vh; min-height:100dvh; display:flex; flex-direction:column; background:var(--canvas); }
.auth-top { display:flex; justify-content:flex-end; align-items:center; gap:4px; min-height:56px; padding:12px 16px 0; }
.auth-main { flex:1; display:flex; flex-direction:column; align-items:center; justify-content:center; width:100%; padding:8px 16px 40px; }

/* the shells' columns: one centred column below 1024 px (the stage is not shown there) */
.auth-shell, .auth-split { display:flex; flex-direction:column; align-items:center; width:100%; }
.auth-col, .auth-primary { display:flex; flex-direction:column; align-items:center; width:100%; min-width:0; }

/* the GROUP lockup (static artwork, BRAND-SPEC §4.2) on clean white, with the manual's safe space X under it
   (≈ 0.6 × the icon height: 36 px under the 56 px lockup). brand.css switches the light / dark pair (display) —
   so nothing here sets `display` on a .gg-logo--* element. */
.auth-brand { display:flex; justify-content:center; width:100%; margin:0 auto 36px; }
.auth-lockup { width:330px; max-width:100%; height:auto; }
.auth-brand picture > img { display:block; }

/* the card: r16 on the white page, soft elevation (--e-2) instead of a border */
.auth-card { width:100%; max-width:420px; padding:30px 32px 28px; background:var(--sheet); border-radius:var(--r-xl); box-shadow:var(--e-2); }
.auth-card--wide { max-width:480px; }
/* its eyebrow: the SCHOOL (公司資訊, AUD-120) · ERP + its English line, beside its own uploaded logo when there is one */
.auth-org { display:flex; align-items:center; gap:12px; margin:0 0 18px; }
.auth-org-t { min-width:0; }
.auth-logo { flex:none; padding:6px 8px; }
.auth-logo img { display:block; max-width:96px; max-height:32px; object-fit:contain; }
.auth-eyebrow { margin:0 0 6px; font-size:var(--fs-sm); line-height:1.5; color:var(--text-3); }
.auth-org .auth-eyebrow { margin:0; }
.auth-school { font-weight:600; color:var(--text-2); overflow-wrap:anywhere; }
.auth-erp::before { content:"·"; margin:0 6px; }
.auth-en { margin-top:1px; font-size:var(--fs-xs); line-height:1.45; color:var(--text-3); overflow-wrap:anywhere; }

.auth-ic { width:44px; height:44px; margin-bottom:16px; border-radius:var(--r-md); display:grid; place-items:center;
           background:var(--subtle); color:var(--text-2); box-shadow:inset 0 0 0 1px var(--border); }
.auth-ic .i { width:20px; height:20px; }
.auth-ic--info { background:var(--accent-soft); color:var(--accent-text); box-shadow:inset 0 0 0 1px var(--accent-border); }
.auth-ic--warn { background:var(--warning-soft); color:var(--warning); box-shadow:inset 0 0 0 1px var(--warning-border); }
.auth-ic--bad  { background:var(--danger-soft); color:var(--danger); box-shadow:inset 0 0 0 1px var(--danger-border); }
.auth-title { font:600 var(--fs-2xl)/1.35 var(--font-display); color:var(--text-1); }
.auth-sub { margin:8px 0 24px; font-size:var(--fs-md); line-height:var(--lh-body); color:var(--text-2); }
.auth-form { display:grid; gap:18px; }
.auth-form .fld--check { padding-top:0; }
.auth-form .chk { background:transparent; border-color:transparent; padding:0; min-height:28px; }
.auth-form .chk:hover { border-color:transparent; }
/* the hint lines up with the box's label text: 18px box + the 9px .chk gap (this .chk has no padding / border) */
.auth-form .fld--check > .hint, .auth-form .fld--check > .field-err { margin-top:4px; padding-left:27px; }
.auth-submit { width:100%; margin-top:6px; }
.auth-alt { margin:18px 0 0; padding-top:18px; border-top:1px solid var(--border); text-align:center; }
.auth-alt .btn { width:100%; }
.auth-actions { display:flex; flex-wrap:wrap; gap:8px; margin-top:4px; }
.auth-actions .btn { flex:1 1 auto; }
.auth-help { margin:20px 0 0; font-size:var(--fs-sm); color:var(--text-3); text-align:center; }
.auth-foot { margin:28px 0 0; font-size:13px; color:var(--text-3); text-align:center; }
.auth-meta { margin:-10px 0 22px; padding:10px 14px; border-radius:var(--r-md); background:var(--subtle); box-shadow:inset 0 0 0 1px var(--border);
             font-size:var(--fs-sm); line-height:1.6; color:var(--text-3); }

/* 密碼: 顯示／隱藏 sits at the right end of the label row (auth.js un-hides it) */
.auth-pw { position:relative; }
.auth-pw > .field-fix { position:absolute; top:-3px; right:0; margin:0; }
.auth-reveal { display:inline-flex; align-items:center; gap:4px; height:28px; padding:0 8px; margin-right:-8px; border:0; border-radius:var(--r-sm);
               background:none; color:var(--accent-text); font:13.5px/1 var(--font); cursor:pointer; transition:background-color var(--dur-1); }
.auth-reveal:hover { background:var(--hover); }
.auth-reveal .i { width:15px; height:15px; }
/* Caps Lock warning under the password (auth.js) */
.auth-caps { display:flex; align-items:center; gap:6px; margin:-8px 0 0; font-size:var(--fs-sm); color:var(--warning); }
.auth-caps .i { width:14px; height:14px; }

/* 驗證碼: large tabular digits */
.auth .auth-otp { min-height:48px; padding:6px 12px; font:600 22px/1.2 var(--font-mono); letter-spacing:.25em; text-align:center; }
.auth .auth-otp::placeholder { color:var(--text-4); letter-spacing:.25em; }

/* below the stage breakpoint: the lockup at 180 px (BRAND-SPEC §4.2 phones), 28 px above the card */
@media (max-width:1023px) {
    .auth-brand { margin-bottom:28px; }
    .auth-lockup { width:180px; }
}
@media (max-width:767px) {
    .auth-top { min-height:52px; padding:8px 8px 0; }
    .auth-main { justify-content:flex-start; padding:4px 16px 32px; }
    .auth-form .chk { min-height:44px; }
    .auth-reveal { min-height:44px; padding:0 8px; margin:-10px -8px -10px 0; }   /* 顯示密碼: a 44px touch target */
    /* the error pages' STACKED lockup (180 × 118): its icon is ≈ 68 px tall, so the safe space X ≈ 0.6 × 68 ≈ 41 px
       above (the page edge) and below (the card) — the 180 px horizontal lockup of 登入 needs only ≈ 18 px (28 px) */
    .auth--error .auth-main { padding-top:42px; }
    .auth--error .auth-brand { margin-bottom:42px; }
    .auth-card { padding:22px 18px 22px; box-shadow:var(--e-1); }
    .auth-org { margin-bottom:16px; }
    .auth .auth-otp { font-size:22px; }
}

/* ── 高竿 brand stage — 登入 / 兩步驟驗證 (≥1024 px) ─────────────────────────────────────────────
   BRAND-SPEC §9.1 + Appendix A. The DOM stays card-first (sign-in column, then the stage); the grid puts the stage
   on the LEFT. The stage is cover A: the green seed off the top-left, its blue partner rising from the bottom
   (rotations in brand.css), a third green seed off the bottom-right corner — all 88vh tall at the token opacity. */
.gg-hero { display:none; }
.auth-board > .gg-stage, .auth-board-h { display:none; }   /* < 1024 px: the bulletin panel only, under the card */
.gg-hero, .auth-board { position:relative; min-width:0; }
.gg-hero-in, .auth-board-in { position:relative; z-index:1; }
.gg-hero .gg-ribbon--g1, .auth-board .gg-ribbon--g1 { left:8%; top:14vh; }                 /* cover A: green ring off the top-left */
.gg-hero .gg-ribbon--b1, .auth-board .gg-ribbon--b1 { left:calc(8% + 28vh); top:69vh; }    /* … its blue partner rising from the bottom */
.gg-hero .gg-ribbon--g2, .auth-board .gg-ribbon--g2 { left:calc(100% - 4vh); top:112vh; }  /* a third green seed, mostly off the corner */

/* the words — only --text-1 / --text-2 sit over ribbons (≥ 7.68 : 1 at the strongest tint, BRAND-SPEC §2.4) */
.gg-hero-h { margin:0; font:400 clamp(34px, 3.4vw, 52px)/1.16 var(--font-brand); letter-spacing:.02em; color:var(--text-1); }
.gg-hero-h .gg-fin { margin-left:.22em; }
/* the CJK tracking exception (BRAND-SPEC §8): .gg-tagline and .gg-hero-d only — never nav, tables, forms, buttons */
.gg-tagline { margin:14px 0 18px; font:400 clamp(17px, 1.45vw, 22px)/1.5 var(--font); letter-spacing:.24em; color:var(--text-1); }
.gg-tagline--sm { margin:0 0 12px; font-size:var(--fs-lg); }
.gg-tagline .gg-fin { margin-left:.1em; }
.gg-hero-d { max-width:26em; margin:22px 0 0; font-size:var(--fs-md); line-height:2; letter-spacing:.12em; color:var(--text-2); }
/* the C-portrait (decorative, models — never a real student; BRAND-SPEC §6): bottom-right, bleeding off the bottom */
.gg-hero-photo { position:absolute; right:4%; bottom:-5%; z-index:1; width:min(40%, 480px); height:auto; }
:root[data-theme="dark"] .gg-hero-photo { filter:brightness(.9); }

@media (min-width:1024px) {
    .auth--stage .auth-top { position:absolute; top:0; right:0; z-index:5; padding:16px 20px 0; }
    .auth--stage .auth-main { display:block; padding:0; }
    .auth-shell, .auth-split { display:grid; grid-template-columns:minmax(0, 1.25fr) minmax(440px, 1fr); align-items:stretch;
                               min-height:100vh; min-height:100dvh; }
    /* the sign-in column: centred in the viewport; the © line pinned to its foot */
    .auth-col, .auth-primary { grid-area:1 / 2; justify-content:center; min-height:100vh; min-height:100dvh; padding:72px clamp(24px, 4vw, 56px) 28px; }
    .auth-col::before, .auth-primary::before { content:""; flex:1 1 0; max-height:64px; }
    .auth-col > .auth-foot, .auth-primary > .auth-foot { margin-top:auto; padding-top:28px; }
    /* with a long 公告欄 the stage grows: the sign-in column stays in view while the bulletins scroll */
    .auth-primary { position:sticky; top:0; align-self:start; }

    /* the stage column, behind a 1 px hairline; it clips its ribbons (below 1024 px nothing is clipped — the panel's
       ring and focus edges stay whole) */
    .gg-hero, .auth-board { grid-area:1 / 1; isolation:isolate; overflow:hidden; min-height:100vh; min-height:100dvh;
                            background:var(--sheet); box-shadow:inset -1px 0 0 var(--border); }
    .gg-hero { display:flex; flex-direction:column; padding:clamp(72px, 17vh, 168px) clamp(32px, 6vw, 96px) 48px; }
    .gg-hero--quiet { justify-content:center; padding-top:48px; padding-bottom:12vh; }

    /* 公告欄 on the stage: the tagline + rule as a small header, then the OPAQUE panel (lifted off the ribbons) */
    .auth-board { padding:clamp(56px, 11vh, 112px) clamp(32px, 6vw, 96px) 56px; }
    .auth-board > .gg-stage { display:block; }
    .auth-board-in { max-width:600px; margin:0 auto; }
    .auth-board-h { display:block; margin:0 0 22px; }
    .auth-board .bltn { box-shadow:var(--e-2); }
}
/* the C-portrait only where it has room (≥1200 × 760; `sizes` is 0px elsewhere, so it is never downloaded there) */
@media (max-width:1199px), (max-height:759px) { .gg-hero-photo { display:none; } }
/* a short desktop window (a 1366 × 768 counter PC leaves ≈ 650 px): the sign-in column tightens so the whole column
   (lockup → card → help → ©) fits a 1366 × 657 viewport with no scrollbar — the lockup at 264 px keeps its safe space
   X ≈ 0.6 × its 45 px icon = 27 px clear above AND below (28 px here); the card's own rhythm gives the room back */
@media (min-width:1024px) and (max-height:820px) {
    .auth-col, .auth-primary { padding-top:28px; padding-bottom:12px; }
    .auth-col::before, .auth-primary::before { max-height:16px; }
    .auth-brand { margin-bottom:28px; }
    .auth-lockup { width:264px; }
    .auth-card { padding:20px 32px 20px; }
    .auth-org { margin-bottom:12px; }
    .auth-sub { margin:6px 0 16px; }
    .auth-form { gap:12px; }
    .auth-help { margin-top:12px; }
    .auth-col > .auth-foot, .auth-primary > .auth-foot { padding-top:12px; }
    .gg-hero { padding-top:clamp(48px, 12vh, 96px); }
    .auth-board { padding-top:clamp(40px, 8vh, 72px); }
}

/* ── the error pages (errors/layout) — the stage at reduced strength ────────────────────────
   g1 + b1 only (no third seed, no photo), behind the centred message card; the lockup above it keeps its safe
   space (cover A's S-pair sits at the left edge and bleeds off it and the bottom). */
.auth--error { position:relative; isolation:isolate; overflow-x:clip; }
.auth--error .auth-main { position:relative; z-index:1; }
.auth-err-stage .gg-ribbon--g1 { left:6%; top:16vh; }
.auth-err-stage .gg-ribbon--b1 { left:calc(6% + 28vh); top:71vh; }
.auth-err-top { display:flex; align-items:center; gap:14px; margin:0 0 14px; }
.auth-err-top .auth-ic { margin:0; flex:none; }
.auth-err-top .auth-eyebrow { margin:0; }
.auth-err .gg-rule { margin:14px 0 0; }
.auth-err .auth-sub { margin-top:16px; }
/* the line under the card can cross a seed on a tablet / phone: only --text-1 / --text-2 sit over ribbons */
.auth--error .auth-foot { color:var(--text-2); }
@media (max-width:1023px) {
    /* a tablet / phone: the same S-pair, smaller (h 60vh, the cover-A offsets 0.32h / 0.62h), rising from the
       bottom-left corner under the card — the lockup at the top stays clear */
    .auth-err-stage .gg-ribbon { --gg-h:60vh; }
    .auth-err-stage .gg-ribbon--g1 { left:10%; top:66vh; }
    .auth-err-stage .gg-ribbon--b1 { left:calc(10% + 19vh); top:103vh; }
}

/* ── entrances (once per load) ────────────────────────────────────────────────────────────
   The sign-in column cascades (lockup → card → help); on the stage the ribbons fade in, the words rise in turn
   (the rule grows and the fin rises — brand.css), the C-portrait rises last. A failed sign-in re-render
   (.no-enter) and a bfcache restore (html.no-enter) never replay; 精簡 / 關閉 / reduce drop them (below). */
.page-in > .auth-shell, .page-in > .auth-split { animation:none; }
.auth-col > *, .auth-primary > *, .gg-hero-in > :not(.gg-rule), .auth-board-in > * { animation:rise var(--dur-4) var(--ease-out) backwards; }
.auth-col > :nth-child(2), .auth-primary > :nth-child(2), .gg-hero-in > :nth-child(2), .auth-board-in > :nth-child(2) { animation-delay:60ms; }
.auth-col > :nth-child(n+3), .auth-primary > :nth-child(n+3), .gg-hero-in > :nth-child(n+3), .auth-board-in > :nth-child(n+3) { animation-delay:120ms; }
.gg-hero > .gg-stage, .auth-board > .gg-stage, .auth-err-stage { animation:fade-in 900ms var(--ease-out) backwards; }
.gg-hero-photo { animation:auth-photo-in var(--dur-5) var(--ease-out) 200ms backwards; }
@keyframes auth-photo-in { from { opacity:0; transform:translateY(calc(var(--m-rise) * 3)); } to { opacity:1; transform:none; } }
.page-in.no-enter .auth-col > *, .page-in.no-enter .auth-primary > *, .page-in.no-enter .gg-hero-in > *, .page-in.no-enter .auth-board-in > *,
.page-in.no-enter .gg-stage, .page-in.no-enter .gg-hero-photo, .page-in.no-enter .gg-fin, .page-in.no-enter .gg-rule,
html.no-enter .auth-col > *, html.no-enter .auth-primary > *, html.no-enter .gg-hero-in > *, html.no-enter .auth-board-in > *,
html.no-enter .gg-stage, html.no-enter .gg-hero-photo, html.no-enter .gg-fin, html.no-enter .gg-rule { animation:none; }
html[data-motion="calm"] .auth-col > *, html[data-motion="calm"] .auth-primary > *, html[data-motion="calm"] .gg-hero-in > :not(.gg-rule),
html[data-motion="calm"] .auth-board-in > *, html[data-motion="calm"] .gg-hero > .gg-stage, html[data-motion="calm"] .auth-board > .gg-stage,
html[data-motion="calm"] .auth-err-stage, html[data-motion="calm"] .gg-hero-photo { animation:none; }
html[data-motion="off"] .auth-col > *, html[data-motion="off"] .auth-primary > *, html[data-motion="off"] .gg-hero-in > :not(.gg-rule),
html[data-motion="off"] .auth-board-in > *, html[data-motion="off"] .gg-hero > .gg-stage, html[data-motion="off"] .auth-board > .gg-stage,
html[data-motion="off"] .auth-err-stage, html[data-motion="off"] .gg-hero-photo { animation:none !important; }
@media (prefers-reduced-motion: reduce) {
    .auth-col > *, .auth-primary > *, .gg-hero-in > :not(.gg-rule), .auth-board-in > *, .gg-hero > .gg-stage, .auth-board > .gg-stage,
    .auth-err-stage, .gg-hero-photo { animation:none !important; }
}

/* print: never decoration on paper (BRAND-SPEC §5.2) — the stage and its words stay off the sheet */
@media print {
    .gg-hero, .auth-board > .gg-stage, .auth-board-h, .auth-err-stage, .auth-top { display:none !important; }
}

/* ── 登入 · 公告欄 (auth/partials/bulletins; the slider + 顯示全文 run in pages/auth.js) ─────────────────── */
/* the shell with an aside (.auth-split): the card (+ help) first, the panel second — on the brand stage from 1024 px
   (above), below that stacked UNDER the card (card FIRST). Without bulletins none of this is rendered. */
@media (max-width:1023px) {
    .auth-split > .auth-board { width:100%; max-width:420px; margin-top:28px; }
    /* the © line closes the page under the panel (the column box steps aside; the DOM stays card-first) */
    .auth-primary { display:contents; }
    .auth-split > .auth-board { order:1; }
    .auth-primary > .auth-foot { order:2; }
}

/* the panel: an opaque sheet on the ring elevation (DESIGN-SPEC-v2), design C's type scale — nothing under 13.5 px */
.bltn { min-width:0; padding:22px; background:var(--sheet); border-radius:var(--r-xl); box-shadow:var(--e-1); }
.bltn-t { margin:0 0 16px; font-size:var(--fs-lg); line-height:1.35; font-weight:600; color:var(--text-1); }

/* one bulletin (a slide or a list row) */
.bltn-meta { display:flex; align-items:center; flex-wrap:wrap; gap:4px 10px; margin:0; font-size:var(--fs-sm); line-height:1.5; color:var(--text-3); }
.bltn-date { white-space:nowrap; }
.bltn-h { margin:0; font-size:var(--fs-md); line-height:1.5; font-weight:600; color:var(--text-1); overflow-wrap:anywhere; }
.bltn-text { font-size:var(--fs-md); line-height:var(--lh-body, 1.65); color:var(--text-2); overflow-wrap:anywhere;
             display:-webkit-box; -webkit-box-orient:vertical; -webkit-line-clamp:2; line-clamp:2; overflow:hidden; }
.bltn-text--3 { -webkit-line-clamp:3; line-clamp:3; }
.bltn-text.is-open { display:block; -webkit-line-clamp:unset; line-clamp:none; overflow:visible; }
/* the model's safe markdown: keep it body text (no big headings, no pictures inside a bulletin's text) */
.bltn-text p, .bltn-text ul, .bltn-text ol, .bltn-text blockquote, .bltn-text pre { margin:0; }
.bltn-text p + p, .bltn-text p + ul, .bltn-text p + ol { margin-top:4px; }
.bltn-text ul, .bltn-text ol { padding-left:20px; }
.bltn-text h1, .bltn-text h2, .bltn-text h3, .bltn-text h4, .bltn-text h5, .bltn-text h6 { margin:0; font-size:inherit; color:var(--text-1); }
.bltn-text img { display:none; }
.bltn-acts { display:flex; align-items:center; flex-wrap:wrap; gap:4px 14px; margin-top:4px; }
.bltn-acts:not(:has(> :not([hidden]))) { display:none; }   /* no link, nothing cut off → no empty row */
.bltn-more { min-height:28px; padding:0; border:0; background:none; font:inherit; font-size:var(--fs-sm); color:var(--accent-text); cursor:pointer; }
.bltn-more:hover, .bltn-link:hover { text-decoration:underline; text-underline-offset:2px; }
.bltn-link { display:inline-flex; align-items:center; gap:4px; min-height:28px; font-size:var(--fs-label); font-weight:600; }
.bltn-link .i, .bltn-cta .i { width:14px; height:14px; }

/* the featured slider — without JS the slides simply stack (and the controls stay hidden) */
.bltn-slides { display:grid; gap:12px; }
.bltn-slide { display:flex; flex-direction:column; min-width:0; overflow:hidden; border-radius:var(--r-lg); background:var(--subtle);
              box-shadow:inset 0 0 0 1px var(--border); }
.bltn-media { aspect-ratio:16 / 9; overflow:hidden; background:var(--inset); }
.bltn-media img { display:block; width:100%; height:100%; object-fit:cover; }
.bltn-body { flex:1; display:flex; flex-direction:column; gap:8px; padding:16px 18px 18px; }
.bltn-slide .bltn-h { font-size:var(--fs-lg); }
/* a slide without a picture keeps the same anatomy: a quiet dotted poster with the category's icon tile */
.bltn-slide--text .bltn-media { display:grid; place-items:center;
                                background-image:radial-gradient(var(--border-strong) 1px, transparent 1.5px); background-size:16px 16px; }
.bltn-ic { display:grid; place-items:center; width:64px; height:64px; border-radius:var(--r-lg); background:var(--sheet); color:var(--text-2);
           box-shadow:inset 0 0 0 1px var(--border-strong), var(--e-1); }
.bltn-ic .i { width:30px; height:30px; stroke-width:1.5; }
.bltn-ic--info { background:var(--accent-soft); color:var(--accent-text); box-shadow:inset 0 0 0 1px var(--accent-border), var(--e-1); }
.bltn-ic--ok   { background:var(--success-soft); color:var(--success); box-shadow:inset 0 0 0 1px var(--success-border), var(--e-1); }
.bltn-ic--warn { background:var(--warning-soft); color:var(--warning); box-shadow:inset 0 0 0 1px var(--warning-border), var(--e-1); }
.bltn-cta { align-self:flex-start; }

/* pages/auth.js: one slide at a time — every slide in the same grid cell (the tallest sets the height, nothing jumps) */
.bltn-feat.is-live .bltn-slides { gap:0; }
.bltn-feat.is-live .bltn-slide { grid-area:1 / 1; visibility:hidden; }
.bltn-feat.is-live .bltn-slide.is-current, .bltn-feat.is-live .bltn-slide.is-leaving { visibility:visible; }
.bltn-feat.is-live .bltn-slide.is-current { z-index:1; }
.bltn-feat.is-live .bltn-slide.is-leaving { pointer-events:none; }
.bltn-slide.bltn-in-next  { animation:bltn-in-next var(--dur-3) var(--ease-out) both; }
.bltn-slide.bltn-in-prev  { animation:bltn-in-prev var(--dur-3) var(--ease-out) both; }
.bltn-slide.bltn-out-next { animation:bltn-out-next var(--dur-3) var(--ease-in) both; }
.bltn-slide.bltn-out-prev { animation:bltn-out-prev var(--dur-3) var(--ease-in) both; }
@keyframes bltn-in-next  { from { opacity:0; transform:translateX(16px); } to { opacity:1; transform:none; } }
@keyframes bltn-in-prev  { from { opacity:0; transform:translateX(-16px); } to { opacity:1; transform:none; } }
@keyframes bltn-out-next { from { opacity:1; transform:none; } to { opacity:0; transform:translateX(-16px); } }
@keyframes bltn-out-prev { from { opacity:1; transform:none; } to { opacity:0; transform:translateX(16px); } }

/* controls: 暫停 · dots · ‹ › (rendered hidden; pages/auth.js shows them) */
.bltn-ctrl { display:flex; align-items:center; gap:4px; margin-top:10px; }
.bltn-dots { flex:1; display:flex; align-items:center; flex-wrap:wrap; min-width:0; }
.bltn-dot { display:inline-grid; place-items:center; width:24px; height:24px; padding:0; border:0; border-radius:var(--r-full);
            background:none; cursor:pointer; }
.bltn-dot::before { content:""; width:8px; height:8px; border-radius:var(--r-full); background:var(--border-control);
                    transition:background-color var(--dur-1) linear; }
.bltn-dot:hover::before { background:var(--border-control-hover); }
.bltn-dot[aria-current="true"]::before { width:20px; background:var(--accent); }

/* the latest items: hairline rows with a soft staggered entrance (CSS only; reduced motion → instant) */
.bltn-list { margin:0; padding:0; list-style:none; }
.bltn-feat + .bltn-list { margin-top:8px; }
.bltn-it { padding:14px 0; border-top:1px solid var(--border); animation:rise-row var(--dur-3) var(--ease-out) backwards; }
.bltn-list > .bltn-it:first-child { padding-top:0; border-top:0; }
.bltn-feat + .bltn-list > .bltn-it:first-child { padding-top:14px; border-top:1px solid var(--border); }
.bltn-list > .bltn-it:last-child { padding-bottom:0; }
.bltn-art { display:flex; flex-direction:column; gap:4px; min-width:0; }
.bltn-it:nth-child(1) { animation-delay:150ms; }
.bltn-it:nth-child(2) { animation-delay:200ms; }
.bltn-it:nth-child(3) { animation-delay:250ms; }
.bltn-it:nth-child(4) { animation-delay:300ms; }
.bltn-it:nth-child(5) { animation-delay:350ms; }
.bltn-it:nth-child(n+6) { animation-delay:400ms; }

/* 精簡 drops the entrances; 關閉 / the OS reduced-motion setting drop the entrances AND the slide transitions
   (pages/auth.js stops autoplay there too) */
.page-in.no-enter .bltn-it, html.no-enter .bltn-it { animation:none; }   /* a failed sign-in re-render never replays */
html[data-motion="calm"] .bltn-it { animation:none; }
html[data-motion="off"] .bltn-it,
html[data-motion="off"] .bltn-slide.bltn-in-next, html[data-motion="off"] .bltn-slide.bltn-in-prev,
html[data-motion="off"] .bltn-slide.bltn-out-next, html[data-motion="off"] .bltn-slide.bltn-out-prev { animation:none !important; }
@media (prefers-reduced-motion: reduce) {
    .bltn-it, .bltn-slide.bltn-in-next, .bltn-slide.bltn-in-prev,
    .bltn-slide.bltn-out-next, .bltn-slide.bltn-out-prev { animation:none !important; }
}

@media (max-width:767px) {
    .auth-split > .auth-board { margin-top:24px; }
    .bltn { padding:18px; }
    .bltn-body { padding:12px 14px 14px; }
    .bltn-dot { width:32px; height:40px; }
    .bltn-more, .bltn-link { min-height:40px; }
}

/* ── 變更密碼 / 確認密碼 (in-app) ───────────────────────────────────────────────────────── */
/* the checklist sits under the two new-password fields (2 of the grid's columns, the whole row on a phone) */
.pg-account .pw-rules { grid-column:span 2; display:grid; grid-template-columns:repeat(2, minmax(0, 1fr)); gap:6px 16px; margin:0; padding:10px 12px;
                        list-style:none; border-radius:var(--r-md); background:var(--subtle); box-shadow:inset 0 0 0 1px var(--border); }
.pg-account .pw-rule { display:flex; align-items:center; gap:8px; font-size:var(--fs-sm); color:var(--text-3); }
.pg-account .pw-rule .i { width:14px; height:14px; color:var(--text-4); }
.pg-account .pw-rule .pw-ok { display:none; }
.pg-account .pw-rule.is-ok { color:var(--success); }
.pg-account .pw-rule.is-ok .pw-ok { display:inline; color:var(--success-dot); animation:pop-in var(--dur-2) var(--ease-spring) backwards; }
.pg-account .pw-rule.is-ok .pw-no { display:none; }
/* the tick pops in as a rule is met (state feedback — kept under 精簡; 關閉 / reduce: it simply appears) */
html[data-motion="off"] .pg-account .pw-rule.is-ok .pw-ok { animation:none !important; }
@media (prefers-reduced-motion: reduce) { .pg-account .pw-rule.is-ok .pw-ok { animation:none !important; } }

/* ── 兩步驟驗證 (in-app) ─────────────────────────────────────────────────────────────────── */
/* the three setup steps: numbered section titles (a neutral step chip, like <x-steps>) */
.pg-tfa .tfa-steps { counter-reset:tfa; }
.pg-tfa .tfa-steps .fsec-t::before { counter-increment:tfa; content:counter(tfa); display:inline-grid; place-items:center; width:22px; height:22px;
                                     margin-right:8px; border-radius:50%; vertical-align:1px; background:var(--neutral-soft); color:var(--text-2);
                                     box-shadow:inset 0 0 0 1px var(--border-strong); font-size:12.5px; font-weight:600; }
.pg-tfa .tfa-apps { display:flex; flex-wrap:wrap; gap:8px; margin:0; padding:0; list-style:none; }
/* the authenticator apps are a plain list (they are not buttons) */
.pg-tfa .tfa-apps { gap:4px 18px; }
.pg-tfa .tfa-app { display:inline-flex; align-items:center; gap:6px; font-size:13px; color:var(--text-2); }
.pg-tfa .tfa-app .i { color:var(--text-3); }
.pg-tfa .tfa-pair { display:grid; grid-template-columns:auto minmax(0,1fr); gap:24px; align-items:start; }
.pg-tfa .tfa-qr { padding:10px; line-height:0; }
.pg-tfa .tfa-qr svg { display:block; width:200px; height:200px; }
.pg-tfa .tfa-kv { display:grid; gap:14px; min-width:0; }
.pg-tfa .tfa-k { margin:0 0 4px; font-size:12.5px; color:var(--text-3); }
.pg-tfa .tfa-v { font-size:14px; color:var(--text-1); overflow-wrap:anywhere; }
.pg-tfa .tfa-key { display:flex; align-items:center; gap:8px; flex-wrap:wrap; }
.pg-tfa .tfa-secret { padding:8px 12px; border-radius:var(--r-md); background:var(--inset); box-shadow:inset 0 0 0 1px var(--border-strong);
                      font:600 16px/1.5 var(--font-mono); letter-spacing:.04em; color:var(--text-1); overflow-wrap:anywhere; user-select:all; }
.pg-tfa .tfa-uri > summary { display:inline-flex; align-items:center; gap:4px; font-size:12.5px; color:var(--accent-text); cursor:pointer; list-style:none; }
.pg-tfa .tfa-uri > summary::-webkit-details-marker { display:none; }
.pg-tfa .tfa-uri > summary .i { width:14px; height:14px; transition:transform var(--dur-2) var(--ease-out); transform:rotate(-90deg); }
.pg-tfa .tfa-uri[open] > summary .i { transform:none; }
.pg-tfa .tfa-uri .fld { margin-top:8px; }
.pg-tfa .tfa-uri input { font:12px/1.4 var(--font-mono); }
.pg-tfa .tfa-acts { display:flex; align-items:center; flex-wrap:wrap; gap:8px; margin-top:16px; }
.pg-tfa .tfa-acts .hint { margin:0; }
/* the box stays narrow; its error / hint may run the full width (a long message never wraps at 240px) */
.pg-tfa .tfa-code input { max-width:240px; font:600 18px/1.2 var(--font-mono); letter-spacing:.2em; text-align:center; }
.pg-tfa .tfa-code input::placeholder { color:var(--text-4); }
.pg-tfa .card + .card { margin-top:16px; }
.pg-tfa .card-d { margin:0 0 14px; font-size:13px; line-height:1.65; color:var(--text-2); }
.pg-tfa .tfa-form { max-width:560px; }
.pg-tfa .tfa-disclose > summary { list-style:none; }
.pg-tfa .tfa-disclose > summary::-webkit-details-marker { display:none; }
.pg-tfa .tfa-disclose[open] > summary { display:none; }
/* the one-time recovery codes */
.pg-tfa .tfa-codes { display:grid; grid-template-columns:repeat(auto-fill, minmax(140px, 1fr)); gap:8px; margin:14px 0 0; padding:0; list-style:none; counter-reset:rc; }
.pg-tfa .tfa-codes li { display:flex; align-items:center; gap:10px; padding:8px 12px; border-radius:var(--r-md); background:var(--subtle);
                        box-shadow:inset 0 0 0 1px var(--border-strong); font:600 15px/1.4 var(--font-mono); color:var(--text-1); }
.pg-tfa .tfa-codes li::before { counter-increment:rc; content:counter(rc); min-width:14px; font:400 12px/1 var(--font); color:var(--text-3); text-align:right; }
.pg-tfa .tfa-print-meta { display:none; }

@media (max-width:767px) {
    .pg-tfa .tfa-pair { grid-template-columns:minmax(0,1fr); }
    .pg-tfa .tfa-qr { justify-self:start; }
    .pg-tfa .tfa-code input { max-width:none; }
    .pg-tfa .tfa-acts .btn { flex:1 1 auto; }
}

/* 列印復原碼: only the codes card goes to paper (light, like every print) */
@media print {
    /* only while the one-time codes are on the page (Ctrl+P elsewhere prints the page as usual; app.css keeps the
       banner strip off every sheet) */
    .pg-tfa:has(.tfa-print) > :not(.tfa-print) { display:none !important; }
    .pg-tfa .tfa-print { border:0; box-shadow:none; }
    .pg-tfa .tfa-print .card-x, .pg-tfa .tfa-print .alert { display:none !important; }
    .pg-tfa .tfa-codes li { box-shadow:inset 0 0 0 1px #999; background:#fff; color:#000; }
    .pg-tfa .tfa-print-meta { display:block; margin-top:16px; font-size:12px; color:#444; }
}

