/* Products & Tools command room (WP-PT, owner Q111). Loaded only with SITE_PRODUCTS_ROOM (staging).
   The look is the approved mock; the technique is hero B's: the photo and its static art are one
   baked image, the two people are a cut-out top layer, and only small layers move, with CSS
   transform/opacity keyframes. The section's text is today's, as real HTML on the screens. */
.pr{position:relative;overflow:hidden;background:var(--dm-ink);color:var(--dm-paper);isolation:isolate}
.pr-art{position:relative;overflow:hidden}
.pr-photo{display:block;position:absolute;max-width:none}
/* The motion stage, in the mock's photo units (1536×1024); products-room.js scales it to the photo. */
.pr-stage{position:absolute;left:0;top:0;width:1536px;height:1024px;transform-origin:0 0;visibility:hidden;pointer-events:none}
.pr.pr-on .pr-stage{visibility:visible}
.pr-stage>*,.pr-stage img{position:absolute}
.pr-stage>span:not(.pr-scan),.pr-stage picture{display:contents}
.pr-person.pr-left{left:32px;top:304px;width:192px;height:592px}
.pr-person.pr-right{left:1328px;top:288px;width:192px;height:624px}
.pr-c{color:var(--dm-cyan-500)}.pr-v{color:var(--dm-violet-500)}.pr-l{color:var(--dm-lime-500)}
/* Floor: the violet and cyan pools are baked; the lime pool glows and drifts (the mock's blur 28 is a wide gradient here). */
.pr-pool{left:684px;top:784px;width:632px;height:232px;background:radial-gradient(closest-side,color-mix(in srgb,var(--dm-lime-500) 90%,transparent),color-mix(in srgb,var(--dm-lime-500) 35%,transparent) 45%,transparent);opacity:.5;animation:pr-glow 7s linear infinite,pr-drift 16s ease-in-out infinite}
.pr-frame{border:3px solid var(--dm-cyan-500);border-radius:12px;box-shadow:0 0 4px var(--dm-cyan-500),0 0 16px color-mix(in srgb,var(--dm-cyan-500) 60%,transparent),inset 0 0 4px var(--dm-cyan-500),inset 0 0 16px color-mix(in srgb,var(--dm-cyan-500) 50%,transparent);opacity:.3;animation-name:pr-frame;animation-timing-function:linear;animation-iteration-count:infinite}
/* At 1800 px and wider the three frames are large composited layers, and pulsing their opacity cost about
   half the room's frame rate (devdevil 1920: 0.70-0.74x hero A). There they glow steadily at the pulse's mean. */
@media(min-width:1800px){.pr-frame{animation:none;opacity:.38}}
/* The violet scan sweeps the map: an 80-unit band moved inside the map's clip box. */
.pr-scan{left:300px;top:470px;width:940px;height:290px;overflow:hidden}
.pr-scan>i{position:absolute;left:-50px;top:0;width:80px;height:100%;background:linear-gradient(90deg,transparent,color-mix(in srgb,var(--dm-violet-300) 80%,transparent),transparent);animation:pr-scan 8s linear infinite}
.pr-pin{width:48px;height:48px;margin:-24px 0 0 -24px;border-radius:50%;background:radial-gradient(closest-side,var(--dm-white),var(--dm-cyan-500) 35%,transparent);opacity:.2;animation-name:pr-twinkle;animation-timing-function:linear;animation-iteration-count:infinite}
.pr-lime{left:933px;top:470px;width:150px;height:150px;border-radius:50%;background:radial-gradient(closest-side,var(--dm-lime-500),color-mix(in srgb,var(--dm-lime-500) 40%,transparent) 50%,transparent);transform:scale(.733);animation:pr-breathe 6s linear infinite}
/* Rings are drawn at r 60 and scaled 16 → 120, so the stroke reads 3 px mid-ripple. */
.pr-ring{left:948px;top:500px;width:120px;height:120px;border-radius:50%;border:3px solid var(--dm-lime-500);box-shadow:0 0 4px var(--dm-lime-500),0 0 12px color-mix(in srgb,var(--dm-lime-500) 60%,transparent),inset 0 0 4px var(--dm-lime-500);opacity:0;animation:pr-ring 5s linear infinite}
/* Data threads: a neon dash and one light travel each path (offset-path, no trails). */
.pr-dash,.pr-dot{position:absolute;left:0;top:0;offset-anchor:50% 50%;opacity:0;animation-name:pr-travel;animation-timing-function:linear;animation-iteration-count:infinite}
.pr-dash{width:30px;height:5px;border-radius:3px;offset-rotate:auto;background:linear-gradient(90deg,transparent,currentColor 30%,var(--dm-white) 50%,currentColor 70%,transparent);box-shadow:0 0 9px currentColor}
.pr-dot{width:14px;height:14px;border-radius:50%;offset-rotate:0deg;background:radial-gradient(closest-side,var(--dm-white),var(--dm-cyan-500) 35%,transparent)}
.pr-dot.pr-v{background:radial-gradient(closest-side,var(--dm-white),var(--dm-violet-500) 35%,transparent)}
/* Sparks rise from the floor and fade out under the screens, so none passes behind the copy. */
.pr-spark{top:1036px;width:8px;height:8px;margin-left:-4px;border-radius:50%;background:radial-gradient(closest-side,var(--dm-white),currentColor 40%,transparent);opacity:0;animation-name:pr-rise;animation-timing-function:linear;animation-iteration-count:infinite}
@keyframes pr-glow{0%,100%{opacity:.3}50%{opacity:.7}}
@keyframes pr-drift{0%,100%{transform:translateX(-40px)}50%{transform:translateX(60px)}}
@keyframes pr-frame{0%,100%{opacity:.15}50%{opacity:.6}}
@keyframes pr-scan{to{transform:translateX(1000px)}}
@keyframes pr-twinkle{0%,100%{opacity:.1}50%{opacity:.85}}
@keyframes pr-breathe{0%,100%{transform:scale(.533)}50%{transform:scale(1)}}
@keyframes pr-ring{from{transform:scale(.267);opacity:.9}to{transform:scale(2);opacity:0}}
@keyframes pr-travel{from{offset-distance:0%;opacity:1}to{offset-distance:100%;opacity:1}}
@keyframes pr-rise{0%{transform:translateY(0);opacity:0}33%{opacity:.9}67%{opacity:.7}100%{transform:translateY(-610px);opacity:0}}

/* Screens: today's copy, as real HTML. Sizes follow the section width (cqw) and never go under their px
   floors; --pr-k (1, .92, .85 or .8, set by the fit check) tightens a screen set that would not fit otherwise. */
.pr-screens{position:relative;--pr-u:calc(1cqw * var(--pr-k,1));--pr-lh:calc(var(--pr-k,1) - 1)}
.pr-screen{color:var(--dm-paper)}
.pr .pr-screen .eyebrow{font:700 max(14px,calc(.95 * var(--pr-u)))/1.25 var(--dm-font-body);letter-spacing:.12em;text-transform:uppercase;color:var(--dm-cyan-500);margin:0 0 calc(.4 * var(--pr-u))}
/* No pulsing dot (site.css, section .eyebrow::after): every motion in the room stops with its control. */
.pr .pr-screens .pr-screen .eyebrow::after{content:none}
.pr .pr-screen h2{font:var(--dm-font-heading-weight) 34px/1.05 var(--dm-font-heading);letter-spacing:-.01em;margin:0 0 calc(.6 * var(--pr-u));color:var(--dm-paper)}
.pr .pr-screen .lead{font:400 max(14px,calc(1.12 * var(--pr-u)))/calc(1.4 + var(--pr-lh)) var(--dm-font-body);margin:0 0 calc(.8 * var(--pr-u));max-width:none;color:var(--dm-line)}
.pr .pr-screen .work-group-head{margin:0;padding:0}
.pr .pr-screen p:has(>.btn){margin:0}
.pr .pr-screen .btn{min-height:44px;padding:0 max(16px,calc(1.2 * var(--pr-u)));font-size:max(14px,var(--pr-u))}
.pr-item{display:flex;flex-direction:column;justify-content:center;height:100%;color:var(--dm-paper);text-decoration:none;border-radius:var(--dm-radius-card)}
.pr .pr-item .kind{align-self:flex-start;border:1px solid var(--dm-violet-500);color:var(--dm-violet-300);font:600 max(14px,calc(.8 * var(--pr-u)))/1.25 var(--dm-font-body);letter-spacing:.05em;text-transform:uppercase;padding:calc(.25 * var(--pr-u)) calc(.5 * var(--pr-u));border-radius:4px}
.pr .pr-s3 .pr-item .kind{border-color:var(--dm-lime-500);color:var(--dm-lime-300)}
.pr .pr-item h3{font:var(--dm-font-heading-weight) max(18px,calc(1.55 * var(--pr-u)))/1.15 var(--dm-font-heading);margin:calc(.5 * var(--pr-u)) 0 calc(.3 * var(--pr-u));color:var(--dm-paper)}
.pr .pr-item .muted{font:400 max(14px,calc(.95 * var(--pr-u)))/calc(1.38 + var(--pr-lh)) var(--dm-font-body);margin:0;color:var(--dm-line)}
.pr .pr-screen .work-group-head>.muted{font:400 max(14px,calc(.9 * var(--pr-u)))/calc(1.4 + var(--pr-lh)) var(--dm-font-body);margin:0;color:var(--dm-muted)}
/* /work: screens 2 and 3 jump to the product entries below; the arrow is CSS so it needs no font glyph. */
.pr .pr-jump .pr-go{margin-top:calc(.6 * var(--pr-u));font:600 max(14px,calc(.9 * var(--pr-u)))/1.3 var(--dm-font-body);color:var(--dm-cyan-500)}
.pr .pr-jump .pr-go::after{content:" \2193"}
.pr .pr-jump:is(:hover,:focus-visible) .pr-go{text-decoration:underline}
.pr .pr-screen a:focus-visible{outline:var(--dm-focus-width) solid var(--dm-lime-500);outline-offset:var(--dm-focus-offset)}

/* Layout. Up to 900 px the dedicated static phone scene fills the column, then glass panels.
   Above 900 px a band on the map and the lime pin, then the panels, is the
   fallback whenever a screen's copy would not fit the photo's screens at that width and locale
   (products-room.js measures; the room is .pr-room). */
.pr-art{height:clamp(300px,30vw,420px)}
.pr-photo{top:50%;left:50%;width:max(100%,630px);height:auto;transform:translate(-50%,-52.3%)}
@media(max-width:900px){
 .pr-art{height:auto;aspect-ratio:1536/1024}
 .pr-art .pr-photo{top:0;left:0;width:100%;height:100%;transform:none}
 .pr .pr-stage,.pr .pr-toggle{display:none}
 /* The status tags get 2 px more room inside their border on the panels. */
 .pr .pr-item .kind{padding-left:calc(.5 * var(--pr-u) + 2px);padding-right:calc(.5 * var(--pr-u) + 2px)}
}
.pr-screens{padding:20px clamp(20px,4vw,48px) 76px}
.pr-screen{margin:0 0 14px;padding:20px;border:1.5px solid color-mix(in srgb,var(--dm-cyan-500) 70%,transparent);border-radius:14px;background:color-mix(in srgb,var(--dm-ink-soft) 85%,transparent);box-shadow:0 0 22px color-mix(in srgb,var(--dm-cyan-500) 25%,transparent)}
.pr-screen:has(>.pr-item){padding:0}
.pr-item{padding:20px}
@media(min-width:901px){
 .pr:not(.pr-room)>.pr-screens{display:grid;grid-template-columns:1.4fr 1fr 1fr;align-items:start;gap:16px;max-width:1320px;margin:0 auto}
 .pr:not(.pr-room)>.pr-screens>.pr-screen{margin:0}
 /* The room: the copy sits on the photo's three screens. */
 .pr.pr-room{aspect-ratio:1536/1024;container-type:inline-size}
 .pr-room>.pr-art{position:absolute;inset:0;height:auto}
 .pr-room>.pr-art>picture>.pr-photo{inset:0;width:100%;height:100%;transform:none}
 .pr-room>.pr-screens{position:absolute;inset:0;padding:0;pointer-events:none}
 .pr-room>.pr-screens>.pr-screen{position:absolute;display:flex;flex-direction:column;justify-content:center;margin:0;padding:calc(.9 * var(--pr-u)) calc(1.4 * var(--pr-u));border:0;border-radius:0;background:none;box-shadow:none;pointer-events:auto}
 /* Screen 1's top edge slopes down to the right (photo y 110 to 142) and its bottom edge sits just under the box,
    so its padding moves down: same total, the kicker clears the edge (products-room.js checks every line). */
 .pr-room>.pr-screens>.pr-s1{left:12%;top:11%;width:31.4%;height:29%;padding-top:calc(1.6 * var(--pr-u));padding-bottom:calc(.2 * var(--pr-u))}
 .pr-room>.pr-screens>.pr-s2{left:44.9%;top:15%;width:21%;height:25%}
 .pr-room>.pr-screens>.pr-s3{left:67.6%;top:13.6%;width:20.7%;height:26.4%}
 .pr-room>.pr-screens>.pr-screen:has(>.pr-item){padding:0}
 .pr-room>.pr-screens>.pr-screen .pr-item{padding:calc(.9 * var(--pr-u)) calc(1.4 * var(--pr-u))}
 .pr-room>.pr-screens>.pr-screen h2{font-size:max(26px,calc(2.4 * var(--pr-u)))}
 /* The photo's screen bezels glow cyan, so a screen link's ring sits inside its screen on an ink band
    (as on the motion control) instead of over the bezel. */
 .pr-room>.pr-screens .pr-item:focus-visible{outline-offset:calc(-2 * var(--dm-focus-width));box-shadow:inset 0 0 0 calc(var(--dm-focus-width) * 3) var(--dm-ink)}
 /* The fit check measures a hidden copy of the screens in the room's geometry. */
 .pr-probe{position:absolute;left:0;top:0;width:100%;visibility:hidden;pointer-events:none;z-index:-1}
}
/* Until the first measurement the screens' text is hidden (layout unchanged); a script failure still reveals it. */
@media(scripting:enabled) and (min-width:901px){.pr:not(.pr-fit)>.pr-screens{visibility:hidden;animation:pr-reveal 0s 3s forwards}}
@keyframes pr-reveal{to{visibility:visible}}

/* Motion control (owner Q65), as on hero B: a soft round icon, bottom right, 16 px inset. */
.pr-toggle{display:grid;place-items:center;position:absolute;z-index:2;right:10px;bottom:10px;width:44px;height:44px;padding:0;border:0;border-radius:50%;background:none;color:var(--dm-white);cursor:pointer}
.pr-toggle::before{content:"";position:absolute;inset:6px;border-radius:50%;background:color-mix(in srgb,var(--dm-ink) 55%,transparent);border:1px solid color-mix(in srgb,var(--dm-white) 40%,transparent)}
.pr-toggle svg{position:relative;width:14px;height:14px;fill:currentColor;opacity:.7}
.pr-toggle:hover svg,.pr-toggle:focus-visible svg{opacity:1}
.pr-toggle .pr-i-play,.pr-toggle[aria-pressed="true"] .pr-i-pause{display:none}
.pr-toggle[aria-pressed="true"] .pr-i-play{display:inline}
.pr-toggle:focus-visible{outline:var(--dm-focus-width) solid var(--dm-lime-500);outline-offset:0;box-shadow:0 0 0 calc(var(--dm-focus-width) * 2) var(--dm-ink)}

/* Paused (control, off-screen, hidden tab, before the script runs): all motion holds (it lives in .pr-art). */
.pr:not(.pr-run) .pr-art *,.pr:not(.pr-run) .pr-art *::before,.pr:not(.pr-run) .pr-art *::after{animation-play-state:paused!important}
/* Reduced motion: a complete static scene from the first frame; no travelling lights, rings, scan or sparks. */
.pr[data-pr-static="true"] .pr-art *{animation:none!important;transition:none!important}
.pr[data-pr-static="true"] :is(.pr-dash,.pr-dot,.pr-ring,.pr-spark,.pr-scan){display:none}
@media(prefers-reduced-motion:reduce){
 .pr .pr-art *{animation:none!important;transition:none!important}
 .pr :is(.pr-dash,.pr-dot,.pr-ring,.pr-spark,.pr-scan),.pr-toggle{display:none}
}
/* Owner Q133: crop the desktop bottom while preserving the full inner canvases. */
@media(min-width:901px){
 .pr.pr-room:not(.pr-probe){aspect-ratio:1536/768;overflow:hidden}
 .pr.pr-room:not(.pr-probe)>.pr-art,
 .pr.pr-room:not(.pr-probe)>.pr-screens{inset:0 0 auto;height:auto;aspect-ratio:1536/1024}
}
