/* Scoped Web plaza presentation uses the native App's generated brand tokens. */
/* R67: the feed's jumps are immediate, as the App's list scrolls are. Under the shell's smooth root scroll a programmatic
   jump on this long feed animates for about half a second, and a tap inside that window lands on whatever passes under it
   (measured in WebKit at 1440: the share tap landed on the sticky header). */
html:has(body:is([data-page=plaza],[data-page=plazaTopic],[data-page=plazaUser])) { scroll-behavior: auto; }
.plaza-page { max-width: var(--narrow); margin: 0 auto; padding: var(--gutter); color: var(--ink); }
/* Owner 2026-10-14 「網頁版廣場的放大鏡改成放在頂部右上角跟廣場同行 不要放在TAB切換頁那一行」: the title row carries the
   App's PlazaHeaderSearchAction at its right end (on a phone the App header itself does, server.mjs .app-plaza-search). */
.plaza-head { display: flex; align-items: center; justify-content: space-between; gap: var(--gap); margin: 0 0 var(--gutter); }
.plaza-title { margin: 0; font-size: var(--headline); }
.plaza-toolbar { position: relative; display: flex; flex-wrap: wrap; gap: var(--gap); align-items: center; margin-bottom: var(--gutter); }
/* R67: 推荐 / 最新 / 关注 are the App's underline tabs (the 比分 page's status row): 48 high, 15/400 muted, the current
   one 800 ink over an 18 × 3 line; no tinted pill. */
.plaza-toolbar nav { display: flex; flex: 1 1 100%; height: 48px; gap: 0; border-bottom: 1px solid var(--hair); }
.plaza-toolbar nav a { position: relative; display: grid; flex: 1 1 auto; min-width: 48px; min-height: 48px; padding: 0 16px; place-items: center; border-radius: 0; color: var(--muted) !important; font-size: 15px; font-weight: 400; line-height: 22px; text-decoration: none; }
.plaza-toolbar nav a.active { color: var(--ink) !important; background: none; font-weight: 800; }
.plaza-toolbar nav a.active::after { content: ""; position: absolute; left: calc(50% - 9px); bottom: 6px; width: 18px; height: 3px; border-radius: 999px; background: var(--gold-ink); }
.plaza-toolbar form { position: relative; display: flex; flex: 1; min-width: 230px; gap: 0; align-items: center; }
/* The App's search field: one rounded field with the magnifier as its action, not a solid 搜索 button beside it. */
.plaza-toolbar form input { height: 40px; padding: 0 48px 0 14px; border-radius: 999px; background: var(--surface-2); border-color: transparent; }
.plaza-page .plaza-toolbar form .plaza-search-go { position: absolute; right: 0; top: 50%; display: grid; width: 48px; height: 48px; min-height: 48px; padding: 0; place-items: center; border: 0; background: none; color: var(--muted); transform: translateY(-50%); }
.plaza-search-go svg { width: 20px; height: 20px; }
.plaza-search-label { position: absolute; width: 1px; height: 1px; clip-path: inset(50%); overflow: hidden; }
.plaza-sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.plaza-page input, .plaza-page textarea { width: 100%; min-width: 0; padding: 12px; border: 1px solid var(--line); border-radius: var(--radius-input); color: var(--ink); background: var(--card); font: inherit; }
.plaza-page button { min-height: var(--touch); padding: 8px 12px; border: 1px solid var(--line); border-radius: var(--radius-input); background: var(--card); color: var(--ink); font: inherit; cursor: pointer; }
.plaza-page button[aria-pressed=true] { border-color: var(--gold); color: var(--gold-ink); background: var(--soft); }
.plaza-page button:disabled { opacity: .6; cursor: wait; }
.plaza-page a { color: var(--gold-ink); }
/* R67: the App's post card (plaza_post_card.dart): avatar column 44, gap 10, then the name row, the body and the actions. */
/* --plaza-origin is where the body column starts inside the card's padding box (the pad, the 44 avatar column and the 10
   gap): the media rail runs the card's full width from there (plaza_media.dart PlazaStoryMedia.bleed). */
.plaza-post { --plaza-pad-l: 20px; --plaza-pad-r: 20px; --plaza-origin: calc(var(--plaza-pad-l) + 54px); display: grid; grid-template-columns: 44px minmax(0, 1fr); column-gap: 10px; margin: 0 0 var(--gutter); padding: 20px var(--plaza-pad-r) 20px var(--plaza-pad-l); border: 1px solid var(--line); border-radius: var(--radius-card); background: var(--card); overflow-wrap: anywhere; }
.plaza-main { min-width: 0; }
.plaza-av { position: relative; display: flex; width: 44px; height: 48px; align-items: center; }
.plaza-av-link { display: block; border-radius: 50%; }
.plaza-av-face { position: relative; display: block; width: 40px; height: 40px; border-radius: 50%; overflow: hidden; box-shadow: 0 0 0 1px var(--act-line); }
.plaza-av-face svg { display: block; width: 100%; height: 100%; }
/* The App's + on the avatar's corner (follow), ✓ once followed. 2026-10-14 (P3-14): its target is the App's 48 × 48 with the
   dot in its bottom-right corner (plaza_post_card.dart _authorRow: JybTouch.min), over the face as in the App. */
.plaza-page .plaza-follow { position: absolute; right: 0; bottom: 4px; display: grid; width: 48px; height: 48px; min-height: 0; padding: 0; place-items: end; border: 0; border-radius: 0; background: none; color: var(--on-dark); }
.plaza-follow i { display: grid; width: 16px; height: 16px; place-items: center; border-radius: 50%; background: var(--gold-ink); box-shadow: 0 0 0 1.5px var(--card); }
.plaza-follow svg { width: 16px; height: 16px; }
/* The name row is not a page header: no rule under it (the shell's generic header{border-bottom} drew one; the App has none). */
.plaza-post header { display: flex; flex-direction: column; justify-content: center; gap: 2px; min-height: 48px; border-bottom: 0; background: none; }
.plaza-post time { color: var(--muted); font-size: var(--caption); white-space: nowrap; }
.plaza-author { color: var(--ink) !important; font-weight: 600; text-decoration: none; }
.plaza-badges { display: inline-flex; flex-wrap: wrap; gap: 6px; margin-left: 8px; color: var(--gold-ink); font-size: var(--caption); }
.plaza-badges span { padding: 2px 6px; background: var(--soft); border-radius: 6px; }
.plaza-body-link { display: block; color: var(--ink) !important; text-decoration: none; }
.plaza-post-text { white-space: pre-wrap; line-height: 22px; margin: 4px 0 8px; font-size: 15px; }
.plaza-media-label { display: block; margin: 12px 0; font-size: var(--caption); color: var(--muted); }
/* 2026-10-14 (Owner 「網頁版廣場的圖片跟影片顯示問題沒對其APP的做法」) · the App's PlazaPostMedia, rule for rule:
   8 under the body (plaza_media.dart _mediaBlockInsets), rows 8 apart, every surface on surface2 with the 12 media corner. */
.plaza-media-block { display: grid; grid-template-columns: minmax(0, 1fr); gap: 8px; margin-top: 8px; }
.plaza-media { position: relative; min-width: 0; margin: 0; border-radius: var(--radius-media); background: var(--surface-2); overflow: hidden; }
/* One picture or one video (singleMediaFrame): the true ratio, the frame narrows above the column width, top-left. */
.plaza-frame { justify-self: start; max-width: 100%; }
.plaza-page .plaza-cell { position: absolute; inset: 0; display: block; width: 100%; height: 100%; min-height: 0; margin: 0; padding: 0; border: 0; border-radius: 0; background: var(--surface-2); color: var(--link); font: inherit; cursor: zoom-in; }
.plaza-cell img { display: block; width: 100%; height: 100%; object-fit: cover; object-position: center; -webkit-user-drag: none; user-select: none; }
.plaza-media[data-long] .plaza-cell img { object-position: top; }
/* Loading is JybSkeleton (skelBase → skelShine sweep, 1.2 s); a failed picture says so and the whole cell retries. */
.plaza-cell[data-state=loading] { background: linear-gradient(105deg, var(--surface-2) 30%, var(--skel-shine) 50%, var(--surface-2) 70%) 0 0/400% 100%; animation: plaza-shimmer 1.2s ease-in-out infinite; }
@keyframes plaza-shimmer { from { background-position: 100% 0; } to { background-position: 0 0; } }
.plaza-page .plaza-cell[data-state=error] { display: grid; place-items: center; padding: 8px; font-size: 13px; line-height: 19px; cursor: pointer; }
/* JybPhotoChip: the 长图 mark, 8 in from the bottom right. */
.plaza-chip { position: absolute; right: 8px; bottom: 8px; padding: 4px 8px; border-radius: 4px; background: var(--photo-scrim); color: var(--photo-scrim-ink); font-size: 11px; line-height: 14px; font-weight: 600; letter-spacing: .6px; white-space: nowrap; pointer-events: none; }
/* Two or more (PlazaMediaRail): one row across the card from the body's left edge, equal heights, each cell as wide as
   its ratio, 8 apart, 16 of the next cell showing; one cell per swipe, snapped to the body's left edge. */
.plaza-rail-wrap { --plaza-rail-h: 240px; container-type: inline-size; margin: 0 calc(-1 * var(--plaza-pad-r)) 0 calc(-1 * var(--plaza-origin)); }
@supports (width: 1cqw) {
  /* plazaRailHeight: the widest cell is the row less the body origin, the gap and the peek (at least half the row);
     the row is 8/9 of it at most, the widest ratio's height below that, and never over 0.6 of the screen. */
  .plaza-rail-wrap { --plaza-rail-max: max(100cqw - var(--plaza-origin) - 24px, 50cqw); --plaza-rail-h: min(var(--plaza-rail-max) * 8 / 9, var(--plaza-rail-max) / var(--plaza-widest), 60vh); }
}
.plaza-rail { display: flex; gap: 8px; padding: 0 var(--plaza-pad-r) 0 var(--plaza-origin); overflow-x: auto; overflow-y: hidden; overscroll-behavior-x: contain; scroll-padding-inline: var(--plaza-origin) var(--plaza-pad-r); scroll-snap-type: x mandatory; scrollbar-width: none; }
.plaza-rail::-webkit-scrollbar { display: none; }
.plaza-rail.dragging { scroll-snap-type: none; cursor: grabbing; }
.plaza-rail-cell { flex: none; width: calc(var(--plaza-rail-h) * var(--plaza-r)); height: var(--plaza-rail-h); scroll-snap-align: start; scroll-snap-stop: always; }
/* A video (PlazaInlineVideo): the dark placeholder until its first frame, the poster until playback moves, the picture
   top-left in its frame; no bar, no play glyph — the mute dot (26 on a 48 target, 12 in) is the one control. */
.plaza-video { position: absolute; inset: 0; overflow: hidden; background: var(--video-placeholder); }
.plaza-video video, .plaza-video-poster { position: absolute; inset: 0; display: block; width: 100%; height: 100%; object-fit: contain; object-position: left top; }
.plaza-video-poster { transition: opacity .22s ease-out; pointer-events: none; }
.plaza-video[data-progressed] .plaza-video-poster { opacity: 0; }
.plaza-page .plaza-video-open { position: absolute; inset: 0; display: grid; width: 100%; height: 100%; min-height: 0; padding: 8px; place-items: center; border: 0; border-radius: 0; background: none; color: var(--on-dark); cursor: pointer; }
.plaza-video-fail { display: none; font-size: 13px; line-height: 19px; }
.plaza-video[data-state=error] .plaza-video-fail { display: block; }
.plaza-page .plaza-video-mute { position: absolute; right: 1px; bottom: 1px; display: grid; width: 48px; height: 48px; min-height: 0; padding: 0; place-items: center; border: 0; border-radius: 50%; background: none; color: var(--icon-on-photo); }
.plaza-video-mute > span { display: grid; width: 26px; height: 26px; place-items: center; border-radius: 50%; background: var(--photo-scrim); }
.plaza-video-mute svg { width: 16px; height: 16px; }
.plaza-video[data-state=error] .plaza-video-mute { display: none; }
/* Voice clips stay rows of their own under the pictures. */
.plaza-voice { display: grid; min-height: 72px; place-items: center; color: var(--muted); font-size: var(--caption); background: var(--paper); }
.plaza-voice audio { width: 100%; }
.plaza-match, .plaza-repost { margin: 12px 0; padding: 12px; border-left: 3px solid var(--gold); border-radius: 0 var(--radius-input) var(--radius-input) 0; background: var(--paper); }
/* plaza_post_card.dart: the repost card sits 8 under the body (SizedBox(JybSpace.s)), the media 8 under it. */
.plaza-repost { margin: 8px 0; }
.plaza-match p, .plaza-repost p { margin: 6px 0; white-space: pre-wrap; }
.plaza-match small { color: var(--muted); }
.plaza-repost a { text-decoration: none; color: var(--ink); }
.plaza-tags { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 12px; font-size: var(--caption); }
.plaza-rating { color: var(--gold-ink); letter-spacing: 2px; }
.plaza-rating span { margin-left: 8px; color: var(--muted); font-size: var(--caption); letter-spacing: normal; }
/* R67: one row of App actions (each at least 48 × 48, glyph 20, count 11/600 tabular), never wrapping. The App spaces its three
   faces 3 apart; here five 48 boxes touch (their faces still stand apart) so the row fits a 360 phone beside the entry clearance. */
.plaza-actions { display: flex; flex-wrap: nowrap; align-items: center; gap: 0; margin-top: 4px; padding: 0; border: 0; }
.plaza-page .plaza-act { position: relative; display: inline-flex; flex: none; min-width: 48px; min-height: 48px; padding: 0 2px; gap: 4px; align-items: center; justify-content: center; border: 0; border-radius: 8px; background: none; color: var(--icon-muted); font-size: 11px; font-weight: 600; line-height: 16px; font-variant-numeric: tabular-nums; text-decoration: none; }
.plaza-act svg { flex: none; width: 20px; height: 20px; }
.plaza-page .plaza-act[aria-pressed=true] { border: 0; background: none; color: var(--icon-muted); }
.plaza-page .plaza-act[data-plaza-action=like][aria-pressed=true] { color: var(--like-on); }
.plaza-page .plaza-act[data-plaza-action=save][aria-pressed=true] { color: var(--club-navy); }
.plaza-act-gap { flex: 1 1 0; min-width: 0; }
@media (hover: hover) { .plaza-page .plaza-act:hover { background: var(--press); } }
.plaza-report-dialog { max-width: calc(100vw - 32px); border: 1px solid var(--line); border-radius: var(--radius-card); color: var(--ink); background: var(--card); }
.plaza-report-dialog label { display: grid; gap: 8px; margin-bottom: 16px; }
.plaza-report-dialog select { min-height: var(--touch); max-width: 100%; padding: 8px 12px; font: inherit; color: var(--ink); background: var(--card); border: 1px solid var(--line); border-radius: var(--radius-input); }
.plaza-replies { grid-column: 1 / -1; margin-top: 20px; border-top: 1px solid var(--line); }
.plaza-replies h2 { font-size: var(--title); }
.plaza-replies ol { list-style: none; margin: 0; padding: 0; }
.plaza-replies li { padding: 12px 0; border-bottom: 1px solid var(--line); }
.plaza-replies li > div { display: flex; justify-content: space-between; gap: 12px; }
.plaza-replies li p { white-space: pre-wrap; line-height: 1.6; margin: 8px 0 0; }
.plaza-replies li small, .plaza-replies form small { color: var(--muted); }
.plaza-replies form { display: grid; gap: 8px; margin-top: 16px; }
.plaza-replies form button { justify-self: end; }
/* R67: the fan page leads with the face (the App's profile cover avatar, 72 with a hairline ring). */
.plaza-profile { display: flex; gap: 16px; align-items: center; margin-bottom: 16px; padding: 20px; border-radius: var(--radius-card); background: var(--card); border: 1px solid var(--line); }
.plaza-profile > div { min-width: 0; }
.plaza-profile-face { position: relative; flex: none; display: block; width: 72px; height: 72px; border-radius: 50%; overflow: hidden; box-shadow: 0 0 0 1px var(--act-line); }
.plaza-profile-face svg { display: block; width: 100%; height: 100%; }
/* R68 ② · the uploaded face covers the generated one (plaza_avatar.dart Stack: the persona, then the image). */
.plaza-av-img { position: absolute; inset: 0; display: block; width: 100%; height: 100%; border-radius: 50%; object-fit: cover; }
.plaza-profile h1 { margin: 0; font-size: var(--headline); }
.plaza-profile-stats, .plaza-core-note { color: var(--muted); font-size: var(--caption); line-height: 1.6; }
/* 2026-10-14 · the fan page's 关注 is the App's action row under the figures (PlazaProfileHead: 8 below, 48 high, across the
   page): 关注 wears the primary face (layer ①: btnGradient, btnShadow, the light type, radius 14, 15/600 at .04em),
   已关注 the neutral one (layer ③: surface, a btnLine frame, ink) — plaza_profile_cover.dart _FollowButton / _SecondaryAction.
   处理中 keeps the face without its lift; a locked (unconfirmed) one wears the App's disabled pair (JybDisabledButton). */
.plaza-profile { flex-wrap: wrap; row-gap: 8px; }
.plaza-profile > div { flex: 1 1 0; }
.plaza-page .plaza-profile-follow { display: flex; flex: 1 0 100%; align-items: center; justify-content: center; box-sizing: border-box; min-width: 48px; min-height: 48px; margin: 0; padding: 0 8px; border: 1px solid transparent; border-radius: 14px; background: var(--btn-face); box-shadow: var(--btn-glow); color: var(--pill-fg); font: inherit; font-size: 15px; line-height: 22px; font-weight: 600; letter-spacing: .6px; cursor: pointer; }
.plaza-page .plaza-profile-follow[data-following=true] { padding: 0 16px; border-color: var(--btn-line); background: var(--card); box-shadow: none; color: var(--ink); }
.plaza-page .plaza-profile-follow[aria-disabled=true] { box-shadow: none; cursor: default; }
.plaza-page .plaza-profile-follow:disabled { opacity: 1; border-color: var(--border-2); background: var(--surface-3); box-shadow: none; color: var(--muted); cursor: default; }
.plaza-page .plaza-profile-follow[data-following=true]:disabled { border-color: var(--hair); background: var(--surface-2); }
.plaza-page .plaza-profile-follow:focus-visible { outline: 2px solid var(--gold-ink); outline-offset: 2px; }
.plaza-page .plaza-profile-follow:not([aria-disabled=true]):not(:disabled):active { background: linear-gradient(var(--press), var(--press)), var(--btn-face); }
.plaza-page .plaza-profile-follow[data-following=true]:not([aria-disabled=true]):not(:disabled):active { background: linear-gradient(var(--press), var(--press)), var(--card); }
@media (hover: hover) {
  .plaza-page .plaza-profile-follow:not([aria-disabled=true]):not(:disabled):not(:active):hover { background: linear-gradient(var(--press-splash), var(--press-splash)), var(--btn-face); }
  .plaza-page .plaza-profile-follow[data-following=true]:not([aria-disabled=true]):not(:disabled):not(:active):hover { background: linear-gradient(var(--press), var(--press)), var(--card); }
}
.plaza-return { display: inline-flex; align-items: center; min-height: var(--touch); margin-bottom: 12px; }
.plaza-empty { display: grid; justify-items: center; gap: 12px; padding: 32px 16px; color: var(--muted); text-align: center; }
.plaza-pagination { display: flex; justify-content: center; margin: 16px 0; }
/* Owner 2026-10-13 「網頁版的廣場頁面排版沒有對其使用APP的那個樣子」 — measured against the App on the Redmi (R78, 广场 as a guest):
   the name and the date share one line; the guest entry card heads the feed; on a phone the magnifier sits in the header row
   (the App's PlazaHeaderSearchAction) and the posts are white rows split by a hairline, not cards on 8 px bands. */
.plaza-post header { flex-direction: row; flex-wrap: wrap; align-items: baseline; column-gap: 8px; justify-content: flex-start; }
.plaza-post header > div { min-width: 0; }
/* 2026-10-14 (P3-14): the name row is the App's 48 author row (plaza_post_card.dart _Head, JybTouch.min) and the name a 48
   high target in it, the date on the same line; the body starts under it as in the App. */
.plaza-post header { align-items: center; min-height: 48px; padding-top: 0; }
.plaza-post .plaza-author { display: inline-flex; align-items: center; min-height: 48px; vertical-align: middle; }
.plaza-entry { display: flex; align-items: center; gap: 12px; margin: 0 0 var(--gutter); padding: 10px 10px 10px 12px; border: 1px solid var(--line); border-radius: var(--radius-card); background: var(--card); color: var(--ink) !important; text-decoration: none; box-shadow: var(--tabbar-shadow); }
.plaza-entry i { display: grid; flex: none; width: 32px; height: 32px; place-items: center; border-radius: 50%; background: var(--surface-2); color: var(--muted); }
.plaza-entry i svg { width: 18px; height: 18px; }
.plaza-entry span { flex: 1; min-width: 0; font-size: 14px; line-height: 20px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.plaza-entry b { flex: none; min-height: 36px; padding: 0 18px; display: grid; place-items: center; border-radius: 999px; background: var(--club-navy); color: var(--on-dark); font-size: 14px; font-weight: 700; }
/* The search row opens from the magnifier at every width (and stays open while a search is shown). The checkbox is the
   keyboard control; the title row's magnifier and the phone header's are its labels and wear its focus and open state. */
.plaza-search-open { position: absolute; left: 0; top: 0; width: 1px; height: 1px; margin: 0; opacity: 0; clip-path: inset(50%); overflow: hidden; pointer-events: none; }
.plaza-search-open:not(:checked) ~ form[data-plaza-search] { display: none; }
.plaza-search-toggle, .app-header .app-plaza-search { display: grid; flex: none; width: 48px; height: 48px; place-items: center; border-radius: 50%; color: var(--muted); cursor: pointer; }
.plaza-search-toggle svg, .app-header .app-plaza-search svg { width: 24px; height: 24px; }
.app-header .app-plaza-search { display: none; }
html:has(#plaza-search-open:checked) :is(.plaza-search-toggle, .app-plaza-search) { color: var(--gold-ink); }
html:has(#plaza-search-open:focus-visible) :is(.plaza-search-toggle, .app-plaza-search) { outline: 2px solid var(--club-navy); outline-offset: -4px; }
:is(.plaza-search-toggle, .app-plaza-search):active { background: var(--press); }
@media (hover: hover) { :is(.plaza-search-toggle, .app-plaza-search):hover { background: var(--press); } }
.plaza-notice, .plaza-search-summary { padding: 12px; background: var(--soft); border-radius: var(--radius-input); line-height: 1.6; }
/* 2026-10-14 (P3-14): a sign-in prompt is the whole notice (48 high), the empty state's link a 48 high target. */
.plaza-notice > a { display: flex; align-items: center; min-height: 48px; margin: -12px; padding: 0 12px; }
.plaza-empty > a { display: inline-flex; align-items: center; min-height: 48px; padding: 0 12px; }
.plaza-empty > p { margin: 0; }
/* The fan page's 帖子 / 现场故事 tabs: the App's underline tabs (JybUnderlineTabs), the same face as 推荐 / 最新 / 关注. */
.plaza-profile-tabs { display: flex; height: 48px; margin: 0 0 var(--gutter); border-bottom: 1px solid var(--hair); }
.plaza-page .plaza-profile-tabs button { position: relative; display: flex; flex: 1 1 auto; min-width: 48px; min-height: 48px; padding: 0 16px; gap: 4px; align-items: center; justify-content: center; border: 0; border-radius: 0; background: none; color: var(--muted); font-size: 15px; font-weight: 400; line-height: 22px; }
.plaza-page .plaza-profile-tabs button.active { color: var(--ink); font-weight: 800; }
.plaza-profile-tabs button.active::after { content: ""; position: absolute; left: calc(50% - 9px); bottom: 6px; width: 18px; height: 3px; border-radius: 999px; background: var(--gold-ink); }
.plaza-profile-tabs .plaza-n { color: var(--muted); font-size: 11px; font-weight: 600; line-height: 16px; font-variant-numeric: tabular-nums; }
#plaza-content[data-tab=stories] :is(.plaza-post:not([data-story]), .plaza-empty:not([data-plaza-stories-empty])),
#plaza-content:not([data-tab=stories]) [data-plaza-stories-empty] { display: none; }
#plaza-message:empty { display: none; }
#plaza-message { margin: 12px 0; padding: 12px; border-radius: var(--radius-input); background: var(--soft); }
@media (max-width: 650px) {
  .plaza-head { margin: 0; }
  .plaza-title { position: absolute; width: 1px; height: 1px; clip-path: inset(50%); overflow: hidden; }
  /* On a phone the 广场 row is the App header: its right slot is the magnifier (the scores search is not drawn here). */
  .plaza-search-toggle { display: none; }
  body[data-page=plaza] .app-header .app-plaza-search { display: grid; grid-column: 5; grid-row: 1; }
  body[data-page=plaza] .app-header .app-search { display: none; }
  /* The phone list is the App's: full width rows, 12 / 4 / 8 padding, an 8 band of surface-2 between posts. */
  .plaza-page { padding: 0 0 12px; }
  .plaza-toolbar { gap: 8px; margin: 0; padding: 0 16px 8px; background: var(--card); }
  .plaza-toolbar nav { margin: 0 -16px; padding: 0 4px; }
  .plaza-toolbar form { flex: 1 1 100%; width: 100%; min-width: 0; }
  .plaza-toolbar:has(.plaza-search-open:not(:checked)) { padding-bottom: 0; }
  .plaza-entry { margin: 8px 16px; }
  .plaza-toolbar nav a { flex: 1; }
  /* The right edge is the persistent download entry's clearance (runtime.css R67): text and actions never sit under it. */
  .plaza-post { --plaza-pad-l: 4px; --plaza-pad-r: 16px; margin: 0; padding: 12px var(--plaza-pad-r) 8px var(--plaza-pad-l); border: 0; border-bottom: 1px solid var(--hair); border-radius: 0; background: var(--card); }
  .plaza-badges { margin-left: 6px; }
  /* 2026-10-14 (P3-12): on a phone the App header's back arrow (#app-back) is the way back to 广场; no second 返回广场 row. */
  .plaza-return { display: none; }
  .plaza-profile-tabs { margin: 0; background: var(--card); }
  .plaza-profile { margin: 0; border: 0; border-bottom: 8px solid var(--surface-2); border-radius: 0; padding: 16px; }
  #plaza-content > :is(.plaza-search-summary, #plaza-message, .plaza-notice) { margin: 8px 16px; }
  .plaza-empty, .plaza-pagination, .plaza-core-note { margin-left: 16px; margin-right: 16px; }
}
/* 2026-10-14 · the avatar ＋ opens the App's post menu (plaza_sheets.dart showPlazaPostMenu → jyb_sheet.dart
   showJybActionSheet): a bottom sheet over the scrim, the author's face and name, then 查看作者主页 and 关注作者 as 52 high
   rows (JybSheet.actionRowHeight) split by a hairline, then 取消 on surface2; the page under it does not scroll. */
html:has(dialog.plaza-sheet[open]) { overflow: hidden; }
dialog.plaza-sheet { position: fixed; inset: auto 0 0; width: 100%; max-width: 640px; max-height: 85vh; margin: 0 auto; padding: 0 8px calc(8px + env(safe-area-inset-bottom)); border: 0; border-radius: 20px 20px 0 0; background: var(--card); color: var(--ink); box-shadow: var(--md-sheet-shadow); }
dialog.plaza-sheet::backdrop { background: var(--scrim); }
.plaza-sheet-handle { width: 36px; height: 4px; margin: 8px auto 4px; border-radius: 999px; background: var(--border-2); }
.plaza-sheet-head { display: flex; align-items: center; gap: 8px; margin: 0; padding: 4px 8px 8px; font-size: 15px; line-height: 22px; font-weight: 600; }
.plaza-sheet-face { position: relative; display: block; flex: none; width: 24px; height: 24px; border-radius: 50%; overflow: hidden; }
.plaza-sheet-face :is(svg, img) { position: absolute; inset: 0; display: block; width: 100%; height: 100%; object-fit: cover; }
dialog.plaza-sheet .plaza-sheet-row { display: flex; align-items: center; gap: 12px; box-sizing: border-box; width: 100%; min-height: 52px; margin: 0; padding: 8px 16px; border: 0; border-radius: 0; background: none; color: var(--ink); font: inherit; font-size: 15px; line-height: 22px; font-weight: 400; text-align: left; text-decoration: none; cursor: pointer; }
dialog.plaza-sheet .plaza-sheet-row + .plaza-sheet-row { border-top: 1px solid var(--hair); }
.plaza-sheet-row svg { flex: none; width: 20px; height: 20px; }
dialog.plaza-sheet .plaza-sheet-cancel { display: grid; box-sizing: border-box; width: 100%; min-height: 52px; margin: 8px 0 0; padding: 0 16px; place-items: center; border: 0; border-radius: var(--radius-card); background: var(--surface-2); color: var(--ink); font: inherit; font-size: 15px; line-height: 22px; font-weight: 600; cursor: pointer; }
dialog.plaza-sheet :is(.plaza-sheet-row, .plaza-sheet-cancel):active { background: var(--press); }
@media (hover: hover) { dialog.plaza-sheet .plaza-sheet-row:hover { background: var(--press); } }
/* 2026-10-14 · the image viewer (jyb_image_viewer.dart, jyb_image_gallery.dart) and the full-screen video
   (plaza_video_fullscreen.dart): the black lightbox ground, controls on round photo scrims (48 targets, 24 glyphs) with
   the close at the top left, the gallery's i / n chip at the top right; the page under them does not scroll. */
html.plaza-locked { overflow: hidden; }
/* 100vw: on a desktop the page keeps its scrollbar gutter (runtime.css scrollbar-gutter) and the ground covers it too. */
dialog:is(.plaza-viewer, .plaza-player) { position: fixed; inset: 0; width: 100vw; height: 100%; max-width: none; max-height: none; margin: 0; padding: 0; border: 0; background: var(--lightbox); color: var(--icon-on-photo); overflow: hidden; overscroll-behavior: contain; touch-action: none; user-select: none; -webkit-user-select: none; }
dialog:is(.plaza-viewer, .plaza-player)::backdrop { background: var(--lightbox); }
.plaza-viewer-track { display: flex; width: 100%; height: 100%; will-change: transform; }
.plaza-viewer-track.settling { transition: transform .22s ease-out; }
.plaza-viewer-page { position: relative; display: grid; flex: none; width: 100%; height: 100%; place-items: center; overflow: hidden; }
.plaza-viewer-zoom { position: absolute; inset: 0; display: grid; place-items: center; transform-origin: 0 0; }
.plaza-viewer-zoom img { display: block; max-width: 100%; max-height: 100%; object-fit: contain; -webkit-user-drag: none; }
.plaza-viewer-spin { width: 28px; height: 28px; box-sizing: border-box; border: 2px solid var(--icon-on-photo); border-right-color: transparent; border-radius: 50%; animation: plaza-spin .8s linear infinite; }
@keyframes plaza-spin { to { transform: rotate(1turn); } }
.plaza-viewer-page:not([data-state=loading]) .plaza-viewer-spin { display: none; }
:is(.plaza-viewer-retry, .plaza-player-retry) { display: none; min-width: 48px; min-height: 48px; padding: 12px; border: 0; border-radius: 0; background: none; color: var(--on-dark); font: inherit; font-size: 13px; line-height: 19px; cursor: pointer; }
.plaza-viewer-page[data-state=error] .plaza-viewer-retry { display: block; }
.plaza-ctl { position: absolute; z-index: 1; display: grid; width: 48px; height: 48px; min-height: 0; padding: 0; place-items: center; border: 0; border-radius: 50%; background: var(--photo-scrim); color: var(--icon-on-photo); cursor: pointer; }
.plaza-ctl svg { width: 24px; height: 24px; }
:is(.plaza-viewer-close, .plaza-player-close) { top: calc(8px + env(safe-area-inset-top)); left: calc(8px + env(safe-area-inset-left)); }
.plaza-viewer-count { position: absolute; z-index: 1; top: calc(8px + env(safe-area-inset-top)); right: calc(16px + env(safe-area-inset-right)); display: flex; height: 48px; margin: 0; align-items: center; pointer-events: none; }
.plaza-viewer-count > span[aria-hidden] { padding: 4px 8px; border-radius: 4px; background: var(--photo-scrim); color: var(--photo-scrim-ink); font-size: 11px; line-height: 14px; font-weight: 600; letter-spacing: .6px; white-space: nowrap; }
.plaza-player-stage { position: absolute; inset: env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left); display: grid; place-items: center; }
.plaza-player-stage video { display: block; width: 100%; height: 100%; object-fit: contain; }
.plaza-player-stage :is(.plaza-viewer-spin, .plaza-player-retry) { position: absolute; }
.plaza-player:not([data-state=loading]) .plaza-viewer-spin { display: none; }
.plaza-player[data-state=error] .plaza-player-retry { display: block; }
.plaza-player[data-state=error] .plaza-player-stage video { visibility: hidden; }
.plaza-player-bar { position: absolute; left: calc(16px + env(safe-area-inset-left)); right: calc(16px + env(safe-area-inset-right)); bottom: calc(16px + env(safe-area-inset-bottom)); display: flex; justify-content: space-between; pointer-events: none; }
.plaza-player-bar .plaza-ctl { position: static; pointer-events: auto; }
.plaza-player:is([data-state=loading], [data-state=error]) .plaza-player-bar { display: none; }
:is(.plaza-viewer, .plaza-player) button:focus-visible { outline: 2px solid var(--icon-on-photo); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) {
  .plaza-cell[data-state=loading] { animation: none; background: var(--surface-2); }
  .plaza-video-poster, .plaza-viewer-track.settling { transition: none; }
  .plaza-viewer-spin { animation: none; }
}
