/* UI-018 · standard feed fits width at its natural ratio; no drag transform. */
/* Reserve the outer lanes for sound and the action rail when navigation is revealed. */
.phone:not(.has-drama-player) .pure-navigation {left:calc(68px + env(safe-area-inset-left,0px));right:calc(80px + env(safe-area-inset-right,0px));gap:8px;flex-wrap:wrap;align-items:flex-start;}
.phone:not(.has-drama-player) .pure-navigation button {min-width:0;max-width:100%;min-height:44px;white-space:normal;overflow-wrap:anywhere;line-height:1.25;}
.phone:not(.has-drama-player) .recommend-panel #actionRail {min-width:0;overflow-x:hidden;}
.phone:not(.has-drama-player) .recommend-panel #actionRail>.action-button {box-sizing:border-box;width:100%;min-width:0;max-width:100%;flex-shrink:0;}
.phone:not(.has-drama-player) .recommend-panel #actionRail>.action-button small {display:block;max-width:100%;white-space:normal;overflow-wrap:anywhere;text-align:center;line-height:1.2;}
.phone:not(.has-drama-player) .recommend-panel #actionRail>.action-button[data-action=more] small {white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
.phone:not(.has-drama-player) .recommend-panel #actionRail .action-more-icon {display:block;flex:none;width:24px;height:24px;}
/* The full canvas is the play button; show its glyph only after an explicit
   pause. Immersive drama/fullscreen players render their own play controls. */
.phone:not(.has-drama-player) .recommend-panel[data-user-paused=true] #canvasHit::before {
 content:"";position:absolute;left:50%;top:46%;transform:translate(-50%,-50%);
 width:68px;height:68px;border:1px solid #ffffff99;border-radius:50%;
 background:#15151b33;pointer-events:none;
}
.phone:not(.has-drama-player) .recommend-panel[data-user-paused=true] #canvasHit::after {
 content:"";position:absolute;left:calc(50% + 3px);top:46%;transform:translate(-50%,-50%);
 width:0;height:0;border-top:13px solid transparent;border-bottom:13px solid transparent;
 border-left:21px solid #fff;pointer-events:none;
}
.phone {
 /* 可调：额外上下留白、左右留白、媒体区域高度上限。默认延伸至半透明栏后方。 */
 --feed-extra-top:0px;
 --feed-extra-bottom:0px;
 --feed-media-side:0px;
 --feed-media-max-height:none;
 /* 媒体相对居中的垂直偏移：负值上移，正值下移；当前项和相邻预览共用。 */
 --feed-media-offset-y:-20px;
 /* 顶栏底边的保守基线；若运营改成多行标题，可调整或由测量层提供同名px值。 */
 --feed-header-bottom:calc(88px + env(safe-area-inset-top,0px));
 --feed-dock-rise:24px;
 --feed-caption-dock-gap:12px;
 --feed-caption-progress-height:22px;
 --feed-caption-progress-gap:8px;
 --feed-media-top:var(--feed-extra-top);
 --feed-media-bottom:var(--feed-extra-bottom);
 /* framed独立预设继续使用原上下安全区与Dock净空。 */
 --feed-framed-top:calc(var(--feed-header-bottom) + var(--feed-extra-top));
 --feed-framed-bottom:calc(var(--dock-panel-bottom,calc(var(--front-nav-height,88px) + var(--feed-dock-rise) + 8px)) + var(--feed-extra-bottom));
}
.phone #mediaLayer.media-layer {top:var(--feed-media-top);bottom:var(--feed-media-bottom);left:var(--feed-media-side);right:var(--feed-media-side);max-height:var(--feed-media-max-height);margin-top:auto;margin-bottom:auto;}
.phone #mediaLayer.media-layer>[data-role=current]:is(video,img) {width:100%;height:100%;object-fit:contain!important;}
.phone #mediaLayer.media-layer:not(.framed)>[data-role=current]:is(video,img) {display:block;position:absolute;left:0;top:calc(50% + var(--feed-media-offset-y));width:100%;height:auto;max-height:none;transform:translateY(-50%);}
/* Keep the same poster and geometry visible across pager handoff until the
   first video frame is presented. The overlay never intercepts gestures. */
.phone #mediaLayer>[data-video-cover] {position:absolute;inset:0;z-index:1;pointer-events:none;background:var(--bg,#100c1c);}
.phone #mediaLayer>[data-video-cover]>img {display:block;width:100%;height:100%;object-fit:contain;}
.phone #mediaLayer:not(.framed)>[data-video-cover]>img {position:absolute;left:0;top:calc(50% + var(--feed-media-offset-y));height:auto;max-height:none;transform:translateY(-50%);}
/* Retain the framed preset's own minimum insets, corners and clipping. */
.phone #mediaLayer.media-layer.framed {top:max(90px,var(--feed-framed-top));bottom:max(126px,var(--feed-framed-bottom));left:max(16px,var(--feed-media-side));right:max(16px,var(--feed-media-side));}
.phone.nav-hidden {--feed-framed-top:env(safe-area-inset-top,0px);--feed-framed-bottom:env(safe-area-inset-bottom,0px);}
/* The pager copies the current media box geometry; fit its neighbour to the same width.
   Leave pager transforms/clipping and the framed preview's contain sizing untouched. */
.phone:not(:has(#mediaLayer.framed)) .vertical-preview-media>img {position:absolute;left:0;top:calc(50% + var(--feed-media-offset-y));width:100%;height:auto;max-height:none;object-fit:contain!important;transform:translateY(-50%);}
@media(max-height:600px){.phone{--feed-header-bottom:calc(70px + env(safe-area-inset-top,0px));}}

/* The measured dock clearance includes 8px above its crest/character. Keep the
   caption 12px above that visible edge, without adding the nav growth twice.
   Reminder states share this same baseline; immersive playback owns its controls. */
.phone:not(.has-drama-player) .recommend-panel #caption {
 bottom:calc(var(--dock-panel-bottom,calc(var(--front-nav-height,88px) + var(--feed-dock-rise) + 8px)) - 8px + var(--feed-caption-dock-gap));
 translate:none;
}
.phone:not(.has-drama-player) .recommend-panel #playback {
 bottom:calc(var(--dock-panel-bottom,calc(var(--front-nav-height,88px) + var(--feed-dock-rise) + 8px)) - 8px + var(--feed-caption-dock-gap));
}
/* Reserve the existing range's 22px box only while it is actually shown. */
.phone:not(.has-drama-player) .recommend-panel[data-user-paused=true] #caption {
 bottom:calc(var(--dock-panel-bottom,calc(var(--front-nav-height,88px) + var(--feed-dock-rise) + 8px)) - 8px + var(--feed-caption-dock-gap) + var(--feed-caption-progress-height) + var(--feed-caption-progress-gap));
}
/* Preserve the normal no-range baseline where :has is available. Older engines
   keep the conservative paused clearance using the plain paused attribute. */
@supports selector(:has(*)) {
 .phone:not(.has-drama-player) .recommend-panel[data-user-paused=true]:not(:has(#mediaLayer>video[data-role=current])) #caption,
 .phone:not(.has-drama-player) .recommend-panel[data-user-paused=true]:has(#playback[hidden]) #caption {
  bottom:calc(var(--dock-panel-bottom,calc(var(--front-nav-height,88px) + var(--feed-dock-rise) + 8px)) - 8px + var(--feed-caption-dock-gap));
 }
}

/* ENG-017 owns readiness + 1500ms timing. CSS owns only the 500ms reveal. */
.recommend-panel[data-media-details=waiting] :is(#caption,#actionRail) {opacity:0;visibility:hidden;pointer-events:none;transition:none;}
.recommend-panel[data-media-details=waiting] #caption :is(button,a) {pointer-events:none;}
.recommend-panel[data-media-details=visible] :is(#caption,#actionRail) {opacity:1;visibility:visible;transition:opacity .5s ease-out;}
/* Hidden preset items remain hidden; playStatus is deliberately outside the reveal selectors. */
/* R145: hide the badge while retaining its former sound-position reference. */
.phone:not(.has-drama-player) .recommend-panel #demoBadge {visibility:hidden!important;pointer-events:none;}
/* R143: keep status legible over bright posters/frames without an empty backdrop. */
.phone .recommend-panel #playStatus:not(:empty) {color:#fff;text-shadow:0 1px 2px #000,0 0 5px #000c;pointer-events:none;}
#elapsed,#duration {display:none!important;}
.recommend-panel #playback {gap:0;}
.recommend-panel #playback input {flex:1;min-width:0;width:100%;margin:0;}
.recommend-panel:not([data-user-paused=true]) #playback,
.recommend-panel:not(:has(#mediaLayer>video[data-role=current])) #playback {opacity:0;visibility:hidden;pointer-events:none;}
.recommend-panel[data-user-paused=true]:has(#mediaLayer>video[data-role=current]) #playback:not([hidden]) {opacity:1;visibility:visible;pointer-events:auto;}
@media(prefers-reduced-motion:reduce){.recommend-panel[data-media-details=visible] :is(#caption,#actionRail){transition:none;}}

/* R55: hidden navigation gives information its own safe-edge baseline. Keep
   normal dock/reminder geometry and all media boxes untouched. Geometry changes
   immediately so the fullscreen entry can measure the final layout in one frame. */
.phone.nav-hidden:not(.has-drama-player) .recommend-panel {
 --feed-hidden-safe-top:calc(12px + env(safe-area-inset-top,0px));
 --feed-hidden-safe-bottom:calc(12px + env(safe-area-inset-bottom,0px));
}
.phone.nav-hidden:not(.has-drama-player) .recommend-panel #demoBadge {
 top:var(--feed-hidden-safe-top);left:calc(20px + env(safe-area-inset-left,0px));
}
.phone.nav-hidden:not(.has-drama-player) .recommend-panel #caption {
 bottom:var(--feed-hidden-safe-bottom);left:calc(22px + env(safe-area-inset-left,0px));right:calc(82px + env(safe-area-inset-right,0px));translate:none;
}
.phone.nav-hidden:not(.has-drama-player) .recommend-panel #playback {
 bottom:var(--feed-hidden-safe-bottom);left:calc(22px + env(safe-area-inset-left,0px));right:calc(22px + env(safe-area-inset-right,0px));
}
.phone.nav-hidden:not(.has-drama-player) .recommend-panel[data-user-paused=true] :is(#caption,#actionRail) {
 bottom:calc(var(--feed-hidden-safe-bottom) + var(--feed-caption-progress-height) + var(--feed-caption-progress-gap));
}
@supports selector(:has(*)) {
 .phone.nav-hidden:not(.has-drama-player) .recommend-panel[data-user-paused=true]:not(:has(#mediaLayer>video[data-role=current])) :is(#caption,#actionRail),
 .phone.nav-hidden:not(.has-drama-player) .recommend-panel[data-user-paused=true]:has(#playback[hidden]) :is(#caption,#actionRail) {bottom:var(--feed-hidden-safe-bottom);}
}
/* A flexible spacer anchors short stacks at the bottom. For long stacks it
   yields to zero, leaving the first and last actions reachable by local scroll. */
.phone.nav-hidden:not(.has-drama-player) .recommend-panel #actionRail {
 top:calc(var(--feed-hidden-safe-top) + 24px);bottom:var(--feed-hidden-safe-bottom);right:calc(12px + env(safe-area-inset-right,0px));
 min-height:0;justify-content:flex-start;overflow-x:hidden;overflow-y:auto;overscroll-behavior:contain;-webkit-overflow-scrolling:touch;scroll-behavior:auto;scrollbar-width:thin;touch-action:pan-y pinch-zoom;
}
.phone.nav-hidden:not(.has-drama-player) .recommend-panel #actionRail::before {content:"";flex:1 0 0;min-height:0;pointer-events:none;}
.phone.nav-hidden:not(.has-drama-player) .recommend-panel #actionRail>.action-button {flex-shrink:0;}
.phone.nav-hidden:not(.has-drama-player) .recommend-panel #actionRail>.action-button small {max-width:100%;white-space:normal;overflow-wrap:anywhere;text-align:center;}

/* R148: reveal the result over a complete reference, using disposable progress.
   Masks/filter never change the picture box or the caption's measured edge. */
.phone #mediaLayer.media-layer>img[data-feed-reference] {position:absolute;inset:0;z-index:1;width:100%;height:100%;object-fit:contain!important;pointer-events:none;background:var(--bg);opacity:1;}
.phone #mediaLayer.media-layer:not(.framed)>img[data-feed-reference] {inset:auto;left:0;top:calc(50% + var(--feed-media-offset-y));height:auto;max-height:none;transform:translateY(-50%);}
.phone #mediaLayer.media-layer>img[data-feed-image-transition] {z-index:2;transition:none;}
.phone #mediaLayer.media-layer>img[data-feed-image-transition=reference],
.phone #mediaLayer.media-layer>img[data-feed-reference][data-phase=loading] {opacity:0;transition:none;}
.phone #mediaLayer.media-layer>img[data-feed-image-transition=generated] {opacity:var(--feed-image-progress,1);}
.phone #mediaLayer.media-layer>img[data-feed-reference][data-phase=generated] {opacity:1;}
.phone #mediaLayer.media-layer>img[data-feed-image-transition=generated][data-feed-image-effect=blur] {filter:blur(calc((1 - var(--feed-image-progress,1)) * 6px));}
.phone #mediaLayer.media-layer>img[data-feed-reference][data-phase=generated][data-feed-image-effect=blur] {filter:blur(calc(var(--feed-image-progress,1) * 3px));}
/* Engines without image masks retain the gentle opacity fallback above. */
@supports ((mask-image:linear-gradient(#000,transparent)) or (-webkit-mask-image:linear-gradient(#000,transparent))) {
 .phone #mediaLayer.media-layer>img[data-feed-image-transition=generated]:is([data-feed-image-effect=wipe-horizontal],[data-feed-image-effect=wipe-vertical],[data-feed-image-effect=center],[data-feed-image-effect=iris]) {opacity:1;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-position:center;mask-position:center;}
 .phone #mediaLayer.media-layer>img[data-feed-image-effect=wipe-horizontal] {--feed-image-wipe-angle:90deg;}
 .phone #mediaLayer.media-layer>img[data-feed-image-effect=wipe-horizontal][data-feed-image-direction=reverse] {--feed-image-wipe-angle:270deg;}
 .phone #mediaLayer.media-layer>img[data-feed-image-effect=wipe-vertical] {--feed-image-wipe-angle:180deg;}
 .phone #mediaLayer.media-layer>img[data-feed-image-effect=wipe-vertical][data-feed-image-direction=reverse] {--feed-image-wipe-angle:0deg;}
 .phone #mediaLayer.media-layer>img[data-feed-image-transition=generated]:is([data-feed-image-effect=wipe-horizontal],[data-feed-image-effect=wipe-vertical]) {
  -webkit-mask-image:linear-gradient(var(--feed-image-wipe-angle),#000 calc(var(--feed-image-progress,1) * 140% - 40%),transparent calc(var(--feed-image-progress,1) * 140%));
  mask-image:linear-gradient(var(--feed-image-wipe-angle),#000 calc(var(--feed-image-progress,1) * 140% - 40%),transparent calc(var(--feed-image-progress,1) * 140%));
 }
 .phone #mediaLayer.media-layer>img[data-feed-image-transition=generated][data-feed-image-effect=center] {
  -webkit-mask-image:linear-gradient(90deg,transparent,#000 10%,#000 90%,transparent);mask-image:linear-gradient(90deg,transparent,#000 10%,#000 90%,transparent);
  -webkit-mask-size:calc(var(--feed-image-progress,1) * 125%) 100%;mask-size:calc(var(--feed-image-progress,1) * 125%) 100%;
 }
 .phone #mediaLayer.media-layer>img[data-feed-image-transition=generated][data-feed-image-effect=iris] {
  -webkit-mask-image:radial-gradient(circle farthest-corner at center,#000 calc(var(--feed-image-progress,1) * 180% - 80%),transparent calc(var(--feed-image-progress,1) * 180%));
  mask-image:radial-gradient(circle farthest-corner at center,#000 calc(var(--feed-image-progress,1) * 180% - 80%),transparent calc(var(--feed-image-progress,1) * 180%));
 }
}
@media(prefers-reduced-motion:reduce){
 .phone #mediaLayer.media-layer>img[data-feed-image-transition] {opacity:1;transition:none;filter:none;-webkit-mask-image:none;mask-image:none;}
 .phone #mediaLayer.media-layer>img[data-feed-reference] {display:none;transition:none;}
 /* Keep a loaded reference available when the result failed or is pending. */
 .phone #mediaLayer.media-layer>img[data-feed-image-transition=reference] {opacity:0;}
 .phone #mediaLayer.media-layer>img[data-feed-reference][data-phase=reference] {display:block;}
}

/* R145: the measured picture edge owns this marked work caption, including
   paused/clean/square modes. Independent drama and unmarked media stay unchanged. */
.phone:not(.has-drama-player) .recommend-panel[data-work-caption-positioned=true] #caption {bottom:var(--work-caption-bottom)!important;translate:none!important;margin-bottom:0;}
.phone:not(.has-drama-player) .recommend-panel[data-work-caption-positioned=true] #caption>:last-child,
.phone:not(.has-drama-player) .recommend-panel[data-work-caption-positioned=true] #caption>[data-ui-block="publicWork.caption"]>:last-child {margin-bottom:0;}

/* The measured caption boundary applies in revealed and clean playback modes. */
.phone[data-rail-caption-bound=true]:not(.has-drama-player) .recommend-panel #actionRail,
.phone.nav-hidden[data-rail-caption-bound=true]:not(.has-drama-player) .recommend-panel #actionRail {
 bottom:min(var(--action-rail-bottom),calc(100% - var(--feed-header-bottom,88px) - 44px));
}
