/* 3D diorama prototype (docs/rendering-assets.md, "3D diorama prototype"). South Park paper look: flat fills, ink outlines. */
:root{--ink:#252323;--paper:#fffdf6;--sky:#bfe0f5;--accent:#ffd84a;--muted:#5d6b7a}
*{box-sizing:border-box}
html,body{margin:0;height:100%;overflow:hidden;background:var(--sky);font:600 14px/1.3 system-ui,"Segoe UI",sans-serif;color:var(--ink)}
#scene{position:fixed;inset:0;width:100%;height:100%;display:block;touch-action:none;cursor:grab}
#scene.dragging{cursor:grabbing}
#overlay{position:fixed;inset:0;pointer-events:none;overflow:hidden}
.bar{position:fixed;display:flex;gap:8px;align-items:center;z-index:3}
.top{left:12px;top:12px;right:12px;pointer-events:none}
.top>*{pointer-events:auto}
.brand{background:var(--paper);border:3px solid var(--ink);border-radius:12px;padding:4px 10px;font:900 18px/1 system-ui,sans-serif;color:#c8322b;text-decoration:none;letter-spacing:.5px;box-shadow:0 3px 0 var(--ink)}
.brand span{color:#2f6fb5}
/* the town's name keeps its own case inside uppercase labels (city/brand.js setBranded: theKOLony, the capital KOL is the pun) */
.brand-name{text-transform:none}
/* ...and the label's own look: the news card's and room card's span rules (small text, hidden on phones) are for their text
   lines, and they hid the name in a headline ("SpaceX launches from") */
#lower-third .brand-name,.room-card .brand-name{display:inline;font:inherit;color:inherit;letter-spacing:inherit}
.tag{background:var(--ink);color:var(--paper);border-radius:10px;padding:4px 9px;font-size:12px;text-decoration:none}
a.tag:hover,a.tag:focus-visible{background:#2f6fb5}
.chip{margin-left:auto;background:var(--paper);border:2px solid var(--ink);border-radius:10px;padding:4px 10px;font-variant-numeric:tabular-nums}
.chip:empty{display:none}
.controls{left:12px;bottom:40px;flex-wrap:wrap}
button{font:800 14px/1 system-ui,sans-serif;background:var(--paper);color:var(--ink);border:3px solid var(--ink);border-radius:12px;padding:8px 12px;box-shadow:0 3px 0 var(--ink);cursor:pointer}
button:active{transform:translateY(2px);box-shadow:0 1px 0 var(--ink)}
button.on{background:var(--accent)}
.find input{font:700 14px/1 system-ui,sans-serif;border:3px solid var(--ink);border-radius:12px;padding:8px 10px;width:200px;background:var(--paper);color:var(--ink);box-shadow:0 3px 0 var(--ink)}
.sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0)}
.help{position:fixed;left:12px;bottom:10px;font-size:12px;color:var(--muted);background:rgba(255,253,246,.8);border-radius:8px;padding:2px 8px;z-index:3}
.card{position:fixed;right:12px;bottom:40px;z-index:3;background:var(--paper);border:3px solid var(--ink);border-radius:14px;padding:8px 36px 8px 12px;box-shadow:0 3px 0 var(--ink);display:flex;flex-direction:column;gap:2px;max-width:min(320px,70vw)}
.card[hidden]{display:none}
.card span{font-weight:600;color:var(--muted);font-size:13px}
.card button{position:absolute;right:6px;top:6px;padding:2px 7px;box-shadow:none;border-width:2px}
.bubble{position:absolute;transform:translate(-50%,-100%);background:#fff;border:2.5px solid var(--ink);border-radius:14px;padding:5px 9px;font:700 13px/1.25 system-ui,sans-serif;max-width:220px;text-align:center;white-space:normal}
.bubble::after{content:'';position:absolute;left:50%;bottom:-9px;margin-left:-6px;border:6px solid transparent;border-top:7px solid var(--ink)}
.label{position:absolute;transform:translate(-50%,-100%);background:rgba(37,35,35,.82);color:#fff;border-radius:8px;padding:2px 7px;font:700 12px/1.2 system-ui,sans-serif;white-space:nowrap}
.label.below{transform:translate(-50%,6px)}
.label.person{background:var(--accent);color:var(--ink);border:2px solid var(--ink)}
#loading{position:fixed;inset:0;z-index:9;display:flex;flex-direction:column;gap:10px;align-items:center;justify-content:center;background:linear-gradient(#cfe6f3,#eef3f0)}
/* The loading screen (owner, 4 October 2026: "the residents doing something with each other", no new picture): a caller
   points, the FOMO Traders check their phones and cheer, hopping and rocking as the city's walkers do (four held poses a
   stride, southpark/sp-motion.js), the last one is late again. The residents' own pose frames, CSS only. */
.ld-scene{display:flex;align-items:flex-end;justify-content:center;margin-bottom:6px;border-bottom:6px solid #9aa6a8}
.ld-fig{position:relative;display:block;margin:0 -1.2vw}
.ld-fig img{display:block;height:min(150px,11.5vw);width:auto;transform-origin:50% 96%}
.ld-f1 img,.ld-f2 img,.ld-f3 img,.ld-f4 img,.ld-f5 img{animation:ld-rock .36s steps(1,end) infinite}
.ld-f2 img{animation-delay:-.09s}.ld-f3 img{animation-delay:-.18s}.ld-f4 img{animation-delay:-.27s}.ld-f5 img{animation-delay:-.05s}
.ld-caller img{animation:ld-bounce 1.6s steps(1,end) infinite}
@keyframes ld-rock{0%{transform:translateY(-9%) rotate(3deg)}25%{transform:none}50%{transform:translateY(-9%) rotate(-3deg)}75%{transform:none}}
@keyframes ld-bounce{0%{transform:translateY(-3%)}12%,100%{transform:none}}
.ld-say{position:absolute;z-index:2;left:50%;top:6%;transform:translateX(-50%);white-space:nowrap;background:#fffdf4;border:2px solid #1f2127;border-radius:12px;padding:2px 8px;font:800 13px/1.2 system-ui,sans-serif;font-style:normal;color:#1f2127;box-shadow:0 2px 0 #1f2127}
@media (max-width:640px){.ld-fig:nth-child(n+5):not(.ld-late){display:none}.ld-fig img{height:17vw}.ld-say{font-size:10px;padding:1px 5px}}
@media (prefers-reduced-motion:reduce){.ld-fig img{animation:none}}
#loading>b,#loading>span{background:rgba(14,28,52,.72);color:#fff7dc;border-radius:14px;padding:6px 16px}
#loading>b{font-size:22px}
#loading>span{color:#e3edf7;font-weight:600}
#loading.hidden{display:none}
@media(max-width:700px),(max-height:500px){.help{display:none}.controls{bottom:12px}.find input{width:150px}.card{bottom:auto;top:56px}}
/* 28 Sep 2026: the city's bubble layer on its own canvas, the director's lower third; #town-app holds the live client's notices */
/* the canvas is drawn at innerWidth x innerHeight (diorama/main.js sizeBubbles), so it is laid out at exactly that: 100vh is
   the height without a phone browser's bar, which stretched the bubbles and set them below the heads (6 October 2026) */
#bubbles{position:fixed;inset:0;width:100%;height:100%;pointer-events:none;z-index:2}
.lower-third{position:fixed;left:50%;bottom:78px;transform:translateX(-50%);z-index:3;display:grid;gap:2px;min-width:260px;max-width:min(560px,calc(100vw - 32px));padding:9px 16px 10px;background:#fffdf2;color:#273d42;border:2.5px solid var(--ink);border-radius:10px;box-shadow:0 3px 0 var(--ink);pointer-events:none;text-align:left}
.lower-third[hidden]{display:none}
.lower-third small{font:800 10px/1.1 system-ui,Arial,sans-serif;letter-spacing:1.2px;color:#b3562f;text-transform:uppercase}
.lower-third b{font:800 18px/1.15 system-ui,Arial,sans-serif}
.lower-third span{font-size:12px;line-height:1.35}
.lower-third.is-card{text-align:center;background:#fff9e5}.lower-third.is-card small{color:var(--ink);letter-spacing:2px}.lower-third.is-card b{font-size:22px}.lower-third.is-card .lt-dots{display:none}
.lt-dots{display:flex;gap:4px;margin-top:3px}.lt-dots i{width:7px;height:7px;border-radius:50%;border:1.5px solid var(--ink);background:#fffdf2}.lt-dots i.on{background:#398d64}.lt-dots i.now{background:#e7a33c}
.interior-host{position:fixed;inset:0;pointer-events:none;z-index:4}
body.inside-building .card,body.inside-building .help{display:none}
/* the 3D room (diorama/rooms3d.js): where we are and who is here, top left; the way out, top right */
.room-hud{position:fixed;left:12px;right:12px;top:58px;z-index:3;display:flex;justify-content:space-between;align-items:flex-start;gap:10px;pointer-events:none}
.room-hud[hidden]{display:none}
.room-card{display:grid;gap:2px;max-width:min(460px,calc(100vw - 190px));background:var(--paper);border:3px solid var(--ink);border-radius:12px;padding:7px 12px 8px;box-shadow:0 3px 0 var(--ink);pointer-events:auto}
.room-card small{font:800 10px/1.1 system-ui,Arial,sans-serif;letter-spacing:1.2px;color:#b3562f;text-transform:uppercase}
.room-card b{font:900 18px/1.15 system-ui,Arial,sans-serif}
.room-card span{font-size:12.5px;line-height:1.3;color:#34424a}
.room-leave{pointer-events:auto;white-space:nowrap}
@media(max-width:700px),(max-height:500px){.room-hud{top:52px}.room-card{max-width:calc(100vw - 150px)}.room-card b{font-size:15px}.room-leave{padding:6px 9px;font-size:12px}}
@media(max-width:700px),(max-height:500px){.lower-third{left:12px;right:12px;bottom:60px;transform:none;min-width:0;max-width:none;padding:6px 10px}.lower-third b{font-size:14px}.lower-third span,.lower-third .lt-dots{display:none}}

/* the auto director's hard cut: a short dip to paper hides the jump across town (diorama/main.js frameShot) */
/* The narrator (city/narrator.js, diorama/main.js lowerThird; owner, 30 September 2026: "a panel with what is going on, in the
   right place, bright"): the director's lower third grown into a panel - a coloured tag for the kind of scene, the continuity
   line, a headline, why it matters, the influencer's own words for a call - up for the whole shot. At the top, between the logo
   and the clock: at the bottom it covered the speakers of a two-shot and the name tags in a room */
.lower-third.narrator{top:10px;bottom:auto;gap:3px;min-width:min(420px,calc(100vw - 400px));max-width:min(720px,calc(100vw - 400px));padding:9px 18px 11px;background:#fffdf2;border-width:3px;border-radius:14px;box-shadow:0 5px 0 var(--ink)}
body.narrating .room-hud .room-card{display:none}body.narrating .room-hud{justify-content:flex-end}
.lt-top{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.lt-tag:empty,.lt-top small:empty{display:none}
.lt-tag{display:inline-block;padding:3px 10px 4px;border-radius:999px;border:2px solid var(--ink);background:var(--tone,#0ca678);color:#fff;font:900 12px/1.1 system-ui,Arial,sans-serif;letter-spacing:.8px;text-transform:uppercase;text-shadow:0 1px 0 rgba(0,0,0,.35)}
.lower-third.narrator small{font:800 11px/1.1 system-ui,Arial,sans-serif;letter-spacing:1.4px;color:#7a5b16}
.lower-third.narrator b{font:900 21px/1.18 system-ui,Arial,sans-serif;color:#1f2a2e}
.lower-third.narrator #lt-text{font:600 14.5px/1.38 system-ui,Arial,sans-serif;color:#33464b}
.lower-third q{display:block;font:italic 600 14px/1.35 Georgia,serif;color:#2b3a3f;border-left:4px solid var(--tone,#0ca678);padding:2px 0 2px 9px;margin-top:2px}
.lower-third q[hidden]{display:none}
.lower-third.narrator.fresh{animation:narrator-in .38s cubic-bezier(.2,1.4,.4,1) both}
@keyframes narrator-in{from{transform:translate(-50%,-14px) scale(.96);opacity:0}to{transform:translate(-50%,0) scale(1);opacity:1}}
.lower-third[data-tone=call]{--tone:#1f9d55}.lower-third[data-tone=debate]{--tone:#e8a200}.lower-third[data-tone=breaking]{--tone:#e03131}
.lower-third[data-tone=love]{--tone:#e64980}.lower-third[data-tone=drama]{--tone:#d9480f}.lower-third[data-tone=crime]{--tone:#1c7ed6}
.lower-third[data-tone=emergency]{--tone:#f76707}.lower-third[data-tone=mayor]{--tone:#7048e8}.lower-third[data-tone=chat]{--tone:#0ca678}
.lower-third[data-tone=work]{--tone:#5c6b73}.lower-third[data-tone=move]{--tone:#1098ad}.lower-third[data-tone=night]{--tone:#364fc7}
.lower-third[data-tone=episode]{--tone:#252323}.lower-third[data-tone=coin]{--tone:#2f9e44}.lower-third[data-tone=city]{--tone:#4263eb}
.lower-third.narrator[data-tone=breaking],.lower-third.narrator[data-tone=call]{border-color:var(--tone)}
.lower-third.narrator[data-tone=breaking] .lt-tag,.lower-third.narrator[data-tone=call] .lt-tag{animation:tag-pulse 1.1s ease-in-out 3}
@keyframes tag-pulse{50%{transform:scale(1.08)}}
@media(max-width:1000px){.lower-third.narrator{min-width:0;max-width:min(560px,calc(100vw - 380px))}}
@media(max-width:700px),(max-height:500px){body.narrating .room-hud{display:none}.lower-third.narrator{left:12px;right:12px;top:52px;bottom:auto;transform:none;min-width:0;max-width:none;padding:7px 11px 8px}
 .lower-third.narrator .lt-tag:not(:empty){display:inline-block;font-size:10.5px}.lower-third.narrator b{font-size:15px}
 .lower-third.narrator #lt-text{display:block;font-size:12px;line-height:1.3}.lower-third.narrator .lt-dots,.lower-third q{display:none}
 .lower-third.narrator.fresh{animation-name:narrator-in-m}}
@keyframes narrator-in-m{from{transform:translateY(-10px);opacity:0}to{transform:none;opacity:1}}
@media(prefers-reduced-motion:reduce){.lower-third.narrator.fresh,.lower-third.narrator .lt-tag{animation:none}}
/* The paper board (diorama/main.js drawBoard; city/paper-trading.js board; owner, 1 October 2026: "a small leaderboard"):
   the FOMO Traders' paper results and the influencers whose calls paid best, under the logo */
.board{position:fixed;left:12px;top:56px;z-index:3;width:228px;padding:8px 10px 9px;background:var(--paper);border:2.5px solid var(--ink);border-radius:12px;
 box-shadow:0 3px 0 var(--ink);font:600 12px/1.25 system-ui,Arial,sans-serif;color:#26343a}
.board[hidden]{display:none}
.board h3{margin:0 0 4px;font:900 11px/1.1 system-ui,Arial,sans-serif;letter-spacing:1.2px;text-transform:uppercase;color:#2f7d4f}
.board h3 small{font-weight:700;letter-spacing:.4px;color:var(--muted);text-transform:none}
.board ol{margin:0 0 6px;padding:0;list-style:none;counter-reset:row}
.board li{display:grid;grid-template-columns:16px 1fr auto;gap:4px;align-items:baseline;counter-increment:row;white-space:nowrap}
.board li::before{content:counter(row);font-weight:900;color:var(--muted)}
.board li span{overflow:hidden;text-overflow:ellipsis}
.board li b.up{color:#2f9e44}.board li b.down{color:#d9480f}
.board li i{font-style:normal;color:var(--muted);font-weight:600;margin-left:4px}
.board .empty{color:var(--muted);font-weight:600}
body.inside-building:not(.narrating) .board{display:none}
@media(max-width:1000px){.board{display:none}}

/* the coin since the call on the narrator’s panel (coin-chart.js) */
.lower-third .lt-chart{display:block;margin:6px auto 0;width:260px;height:58px;background:rgba(255,251,232,.55);border-radius:8px;padding:2px 4px}
.lower-third .lt-chart[hidden]{display:none}
.lower-third .lt-chart svg{display:block;font-family:Arial,sans-serif}
@media (max-width:600px){.lower-third .lt-chart{width:200px;height:46px}.lower-third .lt-chart svg{width:200px;height:46px}}

/* Phones (owner, 2 October 2026: "a portrait layout of the panels for viewers on a phone"): the camera buttons fold into a ☰
   menu beside the sound button, the panels keep clear of the notch and the home bar, the narrator is a little smaller.
   A phone held sideways (max-height:500px, 6 October 2026) takes the same layout; its own rules are at the end. */
.menu-btn{display:none}
@media(max-width:700px),(max-height:500px){
 .top{top:max(10px,env(safe-area-inset-top));left:10px;right:10px}
 .brand{font-size:16px;padding:4px 8px}.chip{font-size:13px;padding:3px 8px}
 .controls{left:10px;right:10px;bottom:max(10px,env(safe-area-inset-bottom));gap:6px;align-items:flex-end}
 .controls .menu-btn{display:inline-block;font-size:18px;padding:6px 12px}
 .controls:not(.open)>*:not(.menu-btn):not(#sound-btn){display:none}
 .controls.open{background:rgba(255,253,246,.96);border:3px solid var(--ink);border-radius:16px;padding:10px;box-shadow:0 3px 0 var(--ink)}
 .controls.open>button:not(.menu-btn){flex:1 1 calc(50% - 6px)}
 .controls.open .find{flex:1 1 100%}.controls.open .find input{width:100%}
 button{font-size:13px;padding:7px 10px}
 .lower-third.narrator{top:calc(max(10px,env(safe-area-inset-top)) + 40px)}
 .lower-third.narrator b{font-size:15px}.lower-third.narrator span{font-size:12.5px}
}
/* a phone held upright: the board opens as a sheet over the town from the menu */
@media(max-width:700px),(max-height:500px){.board.sheet{display:block;position:fixed;left:10px;right:10px;width:auto;top:calc(max(10px,env(safe-area-inset-top)) + 48px);bottom:auto;max-height:60vh;overflow:auto;z-index:4}.board.sheet[hidden]{display:none}}
/* ?clip=1: the vertical highlights' page (tools/clipper.py) - no buttons, a LIVE tag at the foot */
body.clip .controls,body.clip .help,body.clip .card,body.clip .board{display:none!important}
/* ?embed=1: the live window on the project site (dist/welcome/) - the picture and the followed resident's card */
body.embed .controls,body.embed .help,body.embed .board{display:none!important}
/* ...in a phone's postcard (a frame about 320 x 400, 6 October 2026: the logo, the clock and the narrator's panel covered most
   of the picture): no logo or clock (the site around it has both), the narrator a small strip of its tag and headline, the
   followed resident's card and the room's card small */
@media(max-width:700px){
 body.embed .top{display:none}
 body.embed .lower-third{left:6px;right:6px;bottom:6px;padding:4px 8px 5px;border-width:2px;border-radius:9px;box-shadow:0 2px 0 var(--ink)}
 body.embed .lower-third b{font-size:12.5px}
 body.embed .lower-third.narrator{top:6px;bottom:auto;gap:2px;padding:4px 8px 5px;border-width:2px;border-radius:10px;box-shadow:0 2px 0 var(--ink)}
 body.embed .lower-third.narrator .lt-tag:not(:empty){font-size:9px;padding:2px 7px 3px;border-width:1.5px}
 body.embed .lower-third.narrator small{font-size:9px;letter-spacing:1px}
 body.embed .lower-third.narrator b{font-size:12.5px;line-height:1.2}
 body.embed .lower-third.narrator #lt-text,body.embed .lower-third .lt-chart{display:none}
 body.embed .card{top:auto;left:auto;right:6px;bottom:6px;padding:4px 24px 4px 8px;border-width:2px;border-radius:10px;font-size:11px;max-width:75vw}
 body.embed .room-hud{top:6px;left:6px;right:6px}
 body.embed .room-card{padding:4px 8px 5px;border-width:2px;border-radius:9px}
 body.embed .room-card b{font-size:12.5px}body.embed .room-card span{display:none}
 body.embed .room-leave{font-size:11px;padding:4px 7px;border-width:2px}
}
.clip-tag{position:fixed;left:50%;bottom:calc(max(14px,env(safe-area-inset-bottom)) + 8px);transform:translateX(-50%);z-index:5;background:var(--paper);border:3px solid var(--ink);border-radius:999px;padding:6px 14px;font:900 15px/1 system-ui,sans-serif;letter-spacing:.6px;box-shadow:0 3px 0 var(--ink);white-space:nowrap}
/* A phone held sideways (6 October 2026): the phone layout (☰ menu, small chips), with the narrator between the logo and
   the clock rather than across the whole width, one line of its text and a smaller chart at most, the menu in three
   columns at the left and the board's sheet the same - the picture keeps the middle */
@media(max-height:500px) and (min-width:701px){
 .lower-third.narrator{top:max(8px,env(safe-area-inset-top));left:max(150px,calc(50vw - 280px));right:max(150px,calc(50vw - 280px))}
 .lower-third.narrator b{font-size:14px}
 .lower-third.narrator #lt-text{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:1;overflow:hidden}
 .lower-third .lt-chart,.lower-third .lt-chart svg{width:180px;height:38px}
 .controls.open{right:auto;width:min(560px,calc(100vw - 20px))}
 .controls.open>button:not(.menu-btn){flex:1 1 calc(33% - 6px)}
 .board.sheet{right:auto;width:min(420px,calc(100vw - 20px));max-height:calc(100vh - 70px)}
 .card{top:auto;bottom:max(10px,env(safe-area-inset-bottom))}
}
