/* Affective City demo — bone / porcelain system from the hub app (src/theme.ts).
   Designed for a portrait screen (9:16). One layout unit --u = 1% of the portrait
   column width, so a 1080×1920 kiosk and a phone render the same composition; on a
   landscape monitor the column is centred at 9:16. */
:root{
  --porcelain:#F6F3ED; --bone:#E8DECF; --panel:#FFFFFF; --field:#F3ECDF;
  --line:#ECE1D1; --line-soft:#F0E7D9; --beige:#CCA68B;
  --blush:#BE7669; --blush-dim:#9c5c50; --umber:#4A3B32; --umber-soft:#6F5D50;
  --muted:#9A8977; --faint:#C3B3A1;
  --sans:'Inter Tight',ui-sans-serif,system-ui,-apple-system,sans-serif;
  --serif:var(--sans);
  --col:min(100vw, 56.25svh);
  --u:calc(var(--col) / 100);
  --ease:cubic-bezier(.22,.8,.25,1);
}
*{box-sizing:border-box}
html,body{margin:0;height:100%;background:var(--porcelain);color:var(--umber)}
body{font-family:var(--sans);-webkit-font-smoothing:antialiased;overflow:hidden}
button,input{font:inherit;color:inherit}
#scroller{height:100svh;overflow-y:auto;scroll-snap-type:y mandatory;scroll-behavior:smooth;scrollbar-width:none}
#scroller::-webkit-scrollbar{display:none}
.screen{position:relative;width:var(--col);height:100svh;margin:0 auto;scroll-snap-align:start;overflow:hidden;
  padding:calc(var(--u)*5) calc(var(--u)*6) calc(var(--u)*4);display:flex;flex-direction:column}

/* ── type ── */
.eyebrow{font:700 calc(var(--u)*1.25)/1 var(--sans);letter-spacing:.16em;text-transform:uppercase;color:var(--muted)}
.display{font:600 calc(var(--u)*6.6)/1.02 var(--sans);letter-spacing:-.04em;margin:0;color:var(--umber)}
.display em{font-style:normal;font-weight:600;color:var(--blush)}
.masthead{display:flex;align-items:center;justify-content:space-between;margin-bottom:calc(var(--u)*4)}
.wordmark{display:flex;align-items:center;gap:calc(var(--u)*1.6);color:var(--umber);text-decoration:none;font:600 calc(var(--u)*2.1)/1 var(--sans);letter-spacing:-.01em}
.wordmark i{width:calc(var(--u)*3.2);height:calc(var(--u)*1.7);border:1.5px solid var(--umber);border-radius:100% 0 100% 0;transform:rotate(-45deg);position:relative}
.wordmark i:after{content:'';position:absolute;width:32%;aspect-ratio:1;background:var(--blush);border-radius:50%;left:34%;top:18%}

/* reveal-on-enter */
.reveal{opacity:0;transform:translateY(calc(var(--u)*3));transition:opacity 1s var(--ease),transform 1.1s var(--ease)}
.screen.in .reveal{opacity:1;transform:none}
.screen.in .reveal:nth-of-type(2){transition-delay:.08s}.screen.in .reveal:nth-of-type(3){transition-delay:.16s}
.screen.in .reveal:nth-of-type(4){transition-delay:.24s}.screen.in .reveal:nth-of-type(5){transition-delay:.32s}

/* section dots */
.dots{position:fixed;right:max(calc((100vw - var(--col))/2 + var(--u)*2), 10px);top:50%;transform:translateY(-50%);z-index:20;display:flex;flex-direction:column;gap:10px}
.dots a{width:7px;height:7px;border-radius:50%;background:var(--faint);transition:background .4s,transform .4s}
.dots a.on{background:var(--blush);transform:scale(1.5)}

/* ═════════ 01 · moment ═════════ */
.moment .display{margin-bottom:calc(var(--u)*4)}
.stage{position:relative;width:calc(var(--u)*72);aspect-ratio:1;margin:0 auto;border-radius:calc(var(--u)*3.4);overflow:hidden;
  background:#2a221d;box-shadow:0 calc(var(--u)*2) calc(var(--u)*6) #4a3b3226}
#gazeCanvas{width:100%;height:100%;display:block}
.stage-chip{position:absolute;display:flex;align-items:center;gap:calc(var(--u)*1);padding:calc(var(--u)*1) calc(var(--u)*1.6);border-radius:99px;
  background:#f6f3edd9;backdrop-filter:blur(6px);font:600 calc(var(--u)*1.25)/1 var(--sans);letter-spacing:.1em;text-transform:uppercase;color:var(--umber-soft)}
.stage-chip b{font-variant-numeric:tabular-nums;color:var(--umber)}
.stage-chip.tl{left:calc(var(--u)*2.2);top:calc(var(--u)*2.2)}.stage-chip.tr{right:calc(var(--u)*2.2);top:calc(var(--u)*2.2);padding:calc(var(--u)*.6)}
.stage-chip.bl{left:calc(var(--u)*2.2);bottom:calc(var(--u)*2.2)}.stage-chip.br{right:calc(var(--u)*2.2);bottom:calc(var(--u)*2.2);transition:color .3s}
.stage-chip.br.off{color:var(--blush)}
.source-toggle{gap:calc(var(--u)*.4);padding:calc(var(--u)*.5) calc(var(--u)*.5) calc(var(--u)*.5) calc(var(--u)*1.4)}
.source-toggle .live{margin-right:calc(var(--u)*.6)}
.source-toggle button{border:0;background:transparent;border-radius:99px;padding:calc(var(--u)*.7) calc(var(--u)*1.3);cursor:pointer;
  font:inherit;letter-spacing:inherit;text-transform:inherit;color:var(--muted);transition:background .35s var(--ease),color .35s}
.source-toggle button[aria-pressed=true]{background:var(--umber);color:var(--porcelain)}
.source-toggle button:not([aria-pressed=true]):not(:disabled):hover{color:var(--umber)}
.source-toggle button:disabled{color:var(--faint);cursor:not-allowed}
.source-toggle #sourceLabel:not([hidden]){margin:0 calc(var(--u)*.8);text-transform:none;letter-spacing:0}
.stage canvas{transition:opacity .35s}.stage.switching canvas{opacity:0}
.live{width:calc(var(--u)*1);height:calc(var(--u)*1);border-radius:50%;background:var(--blush);animation:pulse 1.6s infinite}
@keyframes pulse{50%{opacity:.25}}
.loop-ring{width:calc(var(--u)*3.4);height:calc(var(--u)*3.4);transform:rotate(-90deg)}
.loop-ring circle{fill:none;stroke-width:3}.loop-ring circle:first-child{stroke:var(--line)}
#loopArc{stroke:var(--blush);stroke-linecap:round;stroke-dasharray:94.25;stroke-dashoffset:94.25}
.shutter{position:absolute;inset:0;background:#fff;opacity:0;pointer-events:none}
.shutter.flash{animation:flash .7s ease-out}
@keyframes flash{0%{opacity:.85}100%{opacity:0}}

.score{display:grid;grid-template-columns:calc(var(--u)*20) 1fr;gap:calc(var(--u)*3);align-items:center;margin:calc(var(--u)*4) 0 calc(var(--u)*3)}
.score-num{display:flex;flex-direction:column;gap:calc(var(--u)*.8)}
.score-num b{font:200 calc(var(--u)*11)/.9 var(--sans);font-variant-numeric:tabular-nums;letter-spacing:-.04em;transition:color .5s}
.score-num small{font:500 calc(var(--u)*1.9)/1 var(--sans);color:var(--muted);transition:color .5s}
.score.med .score-num b{color:var(--beige)}.score.high .score-num b,.score.high .score-num small{color:var(--blush)}
.traces{display:flex;flex-direction:column;gap:calc(var(--u)*1.2)}
.trace{display:grid;grid-template-columns:calc(var(--u)*6) 1fr;align-items:center}
.trace span{font:700 calc(var(--u)*1.15)/1 var(--sans);letter-spacing:.12em;text-transform:uppercase;color:var(--muted)}
.trace canvas{width:100%;height:auto;display:block}

.pipeline{list-style:none;padding:0;margin:0 0 calc(var(--u)*3);display:grid;grid-template-columns:repeat(4,1fr);position:relative}
.pipeline:before{content:'';position:absolute;left:12.5%;right:12.5%;top:calc(var(--u)*1.1);border-top:1px dashed var(--faint)}
.pipeline li{position:relative;display:flex;flex-direction:column;align-items:center;gap:calc(var(--u)*.6);text-align:center;
  font:600 calc(var(--u)*1.35)/1.2 var(--sans);letter-spacing:.08em;text-transform:uppercase;color:var(--faint);transition:color .5s}
.pipeline li small{font:400 calc(var(--u)*1.5)/1.2 var(--sans);letter-spacing:0;text-transform:none}
.pipeline li i{width:calc(var(--u)*2.2);height:calc(var(--u)*2.2);border-radius:50%;background:var(--porcelain);border:1.5px solid var(--faint);margin-bottom:calc(var(--u)*.6);transition:all .5s var(--ease)}
.pipeline li.on{color:var(--umber)}.pipeline li.on i{background:var(--blush);border-color:var(--blush);box-shadow:0 0 0 calc(var(--u)*1) #be766926}
.pipeline li.busy i{animation:pulse 1s infinite}

.exchange{flex:1;min-height:0;display:grid;grid-template-columns:calc(var(--u)*30) 1fr;grid-template-rows:1fr auto;gap:calc(var(--u)*2) calc(var(--u)*3);position:relative}
.scene-card{margin:0;grid-row:1/3;align-self:start;opacity:0;transform:translateY(calc(var(--u)*4)) rotate(-2deg);transition:opacity .8s var(--ease),transform 1s var(--ease)}
.scene-card.show{opacity:1;transform:rotate(-1.5deg)}
.scene-card img{width:100%;aspect-ratio:4/3;object-fit:cover;display:block;border-radius:calc(var(--u)*1.4);background:var(--bone);
  border:calc(var(--u)*.8) solid var(--panel);box-shadow:0 calc(var(--u)*1.5) calc(var(--u)*4) #4a3b3224}
.scene-card figcaption{margin-top:calc(var(--u)*1.4);font:600 calc(var(--u)*1.15)/1.4 var(--sans);letter-spacing:.1em;text-transform:uppercase;color:var(--muted)}
.convo{overflow-y:auto;display:flex;flex-direction:column;gap:calc(var(--u)*1.6);scrollbar-width:none;mask-image:linear-gradient(transparent,#000 12%)}
.convo:before{content:'';flex:1}
.msg{max-width:100%;opacity:0;transform:translateY(calc(var(--u)*1.5));animation:msgIn .7s var(--ease) forwards}
@keyframes msgIn{to{opacity:1;transform:none}}
.msg.ai{font:500 calc(var(--u)*2.9)/1.25 var(--sans);letter-spacing:-.015em;color:var(--umber)}
.msg.ai:before{content:'Affective City';display:block;font:700 calc(var(--u)*1.1)/1 var(--sans);letter-spacing:.14em;text-transform:uppercase;color:var(--blush);margin-bottom:calc(var(--u)*.9)}
.msg.user{align-self:flex-end;background:var(--field);padding:calc(var(--u)*1.4) calc(var(--u)*2);border-radius:calc(var(--u)*2) calc(var(--u)*2) calc(var(--u)*.5) calc(var(--u)*2);
  font:400 calc(var(--u)*2.1)/1.4 var(--sans);color:var(--umber-soft)}
.msg.close{color:var(--muted)}
.typing span{display:inline-block;width:calc(var(--u)*1);height:calc(var(--u)*1);margin-right:calc(var(--u)*.6);border-radius:50%;background:var(--blush);animation:bob 1.1s infinite}
.typing span:nth-child(2){animation-delay:.15s}.typing span:nth-child(3){animation-delay:.3s}
@keyframes bob{40%{transform:translateY(-60%);opacity:.5}}
.answer{display:flex;gap:calc(var(--u)*1.2);opacity:0;pointer-events:none;transform:translateY(calc(var(--u)*2));transition:all .6s var(--ease)}
.answer.show{opacity:1;pointer-events:auto;transform:none}
.answer input{flex:1;min-width:0;border:1px solid var(--line);background:var(--panel);border-radius:99px;padding:calc(var(--u)*1.8) calc(var(--u)*2.6);
  font:400 calc(var(--u)*2.1)/1 var(--sans);outline:none;transition:border-color .3s}
.answer input:focus{border-color:var(--blush)}
.answer button{width:calc(var(--u)*6.4);border:0;border-radius:50%;background:var(--umber);color:var(--porcelain);font-size:calc(var(--u)*2.6);cursor:pointer}
.waiting{position:absolute;inset:0;margin:0;display:flex;align-items:center;justify-content:center;text-align:center;
  font:400 calc(var(--u)*2.2)/1.3 var(--sans);color:var(--muted);transition:opacity .6s;pointer-events:none}
.waiting.hide{opacity:0}
.exchange.clearing .scene-card,.exchange.clearing .convo,.exchange.clearing .answer{opacity:0;transition:opacity .8s}
.ble-btn{position:absolute;right:calc(var(--u)*6);top:calc(var(--u)*5);display:none}
.ble-btn{display:flex;align-items:center;gap:calc(var(--u)*1);border:1px solid var(--line);background:var(--panel);border-radius:99px;
  padding:calc(var(--u)*.9) calc(var(--u)*1.6);font:600 calc(var(--u)*1.15)/1 var(--sans);letter-spacing:.1em;text-transform:uppercase;color:var(--umber-soft);cursor:pointer;
  right:calc(var(--u)*6);top:calc(var(--u)*4.4)}
.moment .masthead .eyebrow{margin-right:calc(var(--u)*24)}
.ble-btn i{width:calc(var(--u)*1);height:calc(var(--u)*1);border-radius:50%;background:var(--faint)}
.ble-btn.on i{background:#6f9a7c}.ble-btn.on{color:var(--umber)}
.ble-btn[hidden]{display:none}

/* ═════════ 02 · ecology ═════════ */
.ecology{padding-bottom:calc(var(--u)*3)}
.eco-intro{position:absolute;left:calc(var(--u)*6);top:calc(var(--u)*13);z-index:3;max-width:calc(var(--u)*88);pointer-events:none}
.eco-intro p{font:400 calc(var(--u)*2)/1.5 var(--sans);color:var(--umber-soft);max-width:calc(var(--u)*46);margin:calc(var(--u)*2.2) 0 0}
.map-wrap{position:absolute;inset:0;z-index:1}
#ecoMap{width:100%;height:100%;display:block;color:var(--line)}
#ecoMap .grid{fill:url(#grain);opacity:.9}
.river{fill:#e9e1d3;opacity:.9}
.corridor{fill:none;stroke:var(--bone);stroke-width:14;stroke-linecap:round;stroke-dasharray:var(--len);stroke-dashoffset:var(--len);transition:stroke-dashoffset 2.6s var(--ease)}
.ecology.in .corridor{stroke-dashoffset:0}
.area-label text{font-family:var(--sans);fill:var(--umber)}
.area-label .big{font-size:56px;font-weight:600;letter-spacing:-2px}
.area-label .small{font:700 15px var(--sans);letter-spacing:4px;fill:var(--muted)}
.area-label .count{font:500 21px var(--sans);fill:var(--blush)}
.area-label line{stroke:var(--faint);stroke-width:1}
.area-label{opacity:0;transition:opacity 1.6s ease .6s}.ecology.in .area-label{opacity:1}
.ecology.in #ecoMap.zoomed .area-label{opacity:0;transition:opacity .5s}
.halo{fill:url(#glow);opacity:0;transition:opacity 1.2s}
.halo.on{opacity:1}
.edge{fill:none;stroke:var(--blush);stroke-width:var(--w,2.4);stroke-linecap:round;opacity:.55;stroke-dasharray:var(--len);stroke-dashoffset:var(--len);transition:stroke-dashoffset 1.6s var(--ease),opacity .6s,stroke-width .6s}
.edge.drawn{stroke-dashoffset:0}
.edge.inferred{opacity:.4}
.edge.dim{opacity:.07}.edge.hot{opacity:1;stroke-width:calc(var(--w,2.4) + 2.5px)}
.node{cursor:pointer;transition:opacity .6s}
.node .body{transform:scale(0);transform-box:fill-box;transform-origin:center;transition:transform .9s cubic-bezier(.34,1.56,.64,1)}
.node.on .body{transform:scale(1)}
.node .ring{fill:var(--panel);stroke:var(--panel);stroke-width:3;filter:drop-shadow(0 3px 5px #4a3b3233)}
.node.hes .ring{stroke:var(--blush)}
.node .ripple{fill:none;stroke:var(--blush);stroke-width:2;opacity:0}
.node.pop .ripple{animation:ripple 1.6s ease-out}
@keyframes ripple{0%{opacity:.8;r:14}100%{opacity:0;r:54}}
.node.src .disc{fill:var(--umber)}
.node.src .mic{fill:none;stroke:var(--porcelain);stroke-width:2;stroke-linecap:round}
.node.dim{opacity:.12}.node.hot .ring{stroke:var(--blush);stroke-width:6}
.node.src.hot .disc{fill:var(--blush)}
.ticker{position:absolute;right:calc(var(--u)*6);bottom:calc(var(--u)*9);z-index:3;text-align:right;display:flex;flex-direction:column;gap:calc(var(--u)*.8);transition:opacity .6s}
.ticker b{font:300 calc(var(--u)*4.4)/1 var(--sans);font-variant-numeric:tabular-nums}
.ticker small{font:500 calc(var(--u)*1.7)/1 var(--sans);color:var(--muted)}
.ticker.hide{opacity:0}
.story-sheet{position:absolute;left:calc(var(--u)*4);right:calc(var(--u)*4);bottom:calc(var(--u)*8);z-index:4;background:#fffffff2;backdrop-filter:blur(8px);
  border-radius:calc(var(--u)*3);padding:calc(var(--u)*3.6) calc(var(--u)*4);box-shadow:0 calc(var(--u)*2) calc(var(--u)*7) #4a3b322e;
  opacity:0;transform:translateY(calc(var(--u)*5));transition:opacity .8s var(--ease),transform .9s var(--ease);pointer-events:none}
.story-sheet.show{opacity:1;transform:none;pointer-events:auto}
.story-sheet .kicker{display:flex;justify-content:space-between;align-items:center;margin-bottom:calc(var(--u)*1.6)}
.story-sheet .kicker .eyebrow{color:var(--blush)}
.story-sheet .kicker small{font:500 calc(var(--u)*1.6)/1 var(--sans);color:var(--muted)}
.story-sheet blockquote{margin:0;font:400 calc(var(--u)*2.5)/1.38 var(--sans);letter-spacing:-.01em;color:var(--umber)}
.story-sheet blockquote.src{font-weight:500}
.story-sheet .resp{display:grid;grid-template-columns:calc(var(--u)*11) 1fr;gap:calc(var(--u)*2.4);align-items:start}
.story-sheet .resp img{width:100%;aspect-ratio:1;object-fit:cover;border-radius:50%;border:3px solid var(--panel);box-shadow:0 0 0 2px var(--blush)}
.story-sheet .q{font:400 calc(var(--u)*1.7)/1.4 var(--sans);color:var(--muted);margin:0 0 calc(var(--u)*1)}
.story-sheet .fade{animation:msgIn .8s var(--ease)}
.legend{position:absolute;left:calc(var(--u)*6);right:calc(var(--u)*6);bottom:calc(var(--u)*3);z-index:3;display:flex;gap:calc(var(--u)*3.6);
  font:600 calc(var(--u)*1.15)/1 var(--sans);letter-spacing:.12em;text-transform:uppercase;color:var(--umber-soft)}
.legend span{display:flex;align-items:center;gap:calc(var(--u)*1)}
.lg-account{width:calc(var(--u)*1.8);height:calc(var(--u)*1.8);border-radius:50%;background:var(--bone);border:2px solid var(--blush)}
.lg-source{width:calc(var(--u)*1.6);height:calc(var(--u)*1.6);border-radius:50%;background:var(--umber)}
.lg-arc{width:calc(var(--u)*3.4);height:calc(var(--u)*1.6);border-top:2px solid var(--blush);border-radius:50% 50% 0 0}

/* ═════════ 03 · patterns ═════════ */
.stats{display:grid;grid-template-columns:repeat(4,1fr);gap:calc(var(--u)*2);padding-bottom:calc(var(--u)*3.6);border-bottom:1px solid var(--line);margin-bottom:calc(var(--u)*4.4)}
.stat b{display:block;font:200 calc(var(--u)*8)/1 var(--sans);letter-spacing:-.03em;font-variant-numeric:tabular-nums}
.stat span{font:600 calc(var(--u)*1.2)/1.3 var(--sans);letter-spacing:.12em;text-transform:uppercase;color:var(--muted)}
.swarm-head p{font:400 calc(var(--u)*1.9)/1.5 var(--sans);color:var(--umber-soft);max-width:calc(var(--u)*72);margin:calc(var(--u)*2) 0 0}
.swarm-wrap{flex:1;min-height:0;margin-top:calc(var(--u)*2)}
#swarm{width:100%;height:100%;display:block;overflow:visible}
#swarm .row-label{font:600 28px var(--sans);letter-spacing:-.5px;fill:var(--umber)}
#swarm .row-sub{font:600 12px var(--sans);letter-spacing:2.5px;fill:var(--muted)}
#swarm .axis text{font:600 12px var(--sans);letter-spacing:1.5px;fill:var(--muted)}
#swarm .axis line{stroke:var(--line)}
#swarm .band{stroke:var(--blush);stroke-dasharray:4 6;opacity:.5}
#swarm .band-label{font:500 14px var(--sans);fill:var(--blush)}
#swarm .dot{transition:transform 1.1s var(--ease),opacity .8s;cursor:pointer}
#swarm .dot circle{stroke:var(--panel);stroke-width:1.5}
#swarm .dot.hot circle{stroke:var(--umber);stroke-width:3}
#swarm .median{stroke:var(--umber);stroke-width:1.5;stroke-dasharray:2 5;opacity:.55}
#swarm .median-label{font:600 12px var(--sans);letter-spacing:1.5px;fill:var(--umber)}
.pull{margin:calc(var(--u)*3.4) 0 calc(var(--u)*1);min-height:calc(var(--u)*17);padding:calc(var(--u)*2.4);background:var(--panel);border-radius:calc(var(--u)*2.4);box-shadow:0 calc(var(--u)*1) calc(var(--u)*4) #4a3b3214;display:grid;grid-template-columns:calc(var(--u)*13) 1fr;gap:calc(var(--u)*3);align-items:center}
.pull img{width:100%;aspect-ratio:1;object-fit:cover;border-radius:calc(var(--u)*1.4);border:calc(var(--u)*.6) solid var(--panel);box-shadow:0 8px 24px #4a3b3222}
.pull p{margin:0;font:500 calc(var(--u)*2.3)/1.4 var(--sans);letter-spacing:-.01em}
.pull small{display:block;margin-top:calc(var(--u)*1.2);font:600 calc(var(--u)*1.15)/1 var(--sans);font-style:normal;letter-spacing:.12em;text-transform:uppercase;color:var(--blush)}
.pull .fade{animation:msgIn .9s var(--ease)}
.foot{font:400 calc(var(--u)*1.4)/1.5 var(--sans);color:var(--muted);border-top:1px solid var(--line);padding-top:calc(var(--u)*2)}

@media (prefers-reduced-motion:reduce){*{animation-duration:.01ms!important;transition-duration:.01ms!important}}
