<!-- SOLID CITY · part 2877 -->
live.js =====
/* Solid City — ✧ PROVOLTA ALIVE (window.CityProvolta) — the King, 2026-10-10.
   Her look, voice and prophecies come from the King's design page 'PROVOLTA — The Oracle' (/provolta):
   sovereign, razor-witted and genuine; she holds the eastern height, turns to face visitors and never wanders.
   Runs by itself under the Hyper Controller (no scripts, no manual control), client-side and light:
     - home: the oracle's step at the centre of her sanctuary (sanctuary-place.js, 735,165); her schedule is pinned there
     - idle: slow breathing + a subtle sway; turns to face the player or a citizen who comes near (else faces the city)
     - approach: a greeting bubble, the teal beacon brightens (sanctuary userData.glow), an 'Approach the Oracle' link
     - prophecies: every ~75 s she speaks one line from the SHARED pool (GET /api/city/provolta/prophecies: AI lines
       through the citizens' rate-limited brain + a fallback set from her page). Line = f(server time), so everyone
       sees the same prophecy at the same moment. Speech bubble + Hyper Controller narration text.
   Per frame: a few distance checks over the nearest citizens; nothing when she is out of range. Any error = the
   sanctuary and the stock citizen carry on unchanged. */
(function () {
'use strict';
if (!window.SC || !SC.api || !window.CitySanctuary || !window.CityCitizens) return;
var A = SC.api, S = A.S, T = A.T, POS = CitySanctuary.pos, HOME = { x: POS.x, z: POS.z }, STEP_Y = 0.3;
var c = CityCitizens.get('provolta'); if (!c) return;
c.sched = [['sanctum', 1e7]]; c.role = 'The Oracle';                       // presence without pursuit: she never wanders
c.hi = ['I saw you before you reached the gate.', 'Stand where I can see you. Good.', 'You climbed. Ask what you came to ask.'];
var FALLBACK = ['A pattern is a memory that action has not yet understood.', 'Every choice casts a shadow before it becomes a road.',
  'The future is not waiting. It is listening for your next act.', 'Bring me the question beneath your question.'];
var GREET = ['She turns to face you. The sanctuary is listening.', 'You climbed. Good. Bring me the question beneath your question.',
  'I see you. Truth before comfort; are you ready?', 'Stand in the light. I am listening.'];
var CZ_GREET = ['The tide brought you, {n}.', '{n}. I knew you would come.', '{n}, your shadow arrived first.'];
var R_SEE = 34, R_IN = 30, R_OUT = 46, R_CZ = 14, R_TALK = 320, PAGE = '/provolta';
var st = { pool: FALLBACK.map(function (t) { return { text: t, ai: false }; }), period: 75, off: 0, slot: -1, line: null, saidAt: 0,
  inside: false, greetT: -99, glow: 0, spike: 0, face: null, faceName: 'the city', mood: 'listening', czSeen: {}, loaded: false, pending: 0 };

/* ---------- shared pool (server time decides the line) ---------- */
function load() {
  if (document.hidden && st.loaded) return;
  fetch('/api/city/provolta/prophecies', { credentials: 'same-origin', cache: 'no-store' }).then(function (r) { return r.ok ? r.json() : null; }).then(function (j) {
    if (!j || !Array.isArray(j.pool) || !j.pool.length) return;
    st.pool = j.pool.filter(function (p) { return p && typeof p.text === 'string' && p.text.length < 220; }).slice(0, 48);
    st.period = Math.max(30, +j.period || 75); st.off = (+j.now || Date.now()) - Date.now(); st.loaded = true;
  }).catch(function () {});
}
function slotNow() { return Math.floor((Date.now() + st.off) / 1000 / st.period); }
function lineFor(s) { return st.pool[((s % st.pool.length) + st.pool.length) % st.pool.length]; }

/* ---------- her own bubble (teal glass, gold rim, serif) ---------- */
var bub = null, bubCv = null, bubTex = null, bubUntil = 0;
function say(text, sec, kind) {
  if (!c.g) return;
  if (!bub) {
    bubCv = document.createElement('canvas'); bubCv.width = 768; bubCv.height = 232; bubTex = new T.CanvasTexture(bubCv);
    bub = new T.Sprite(new T.SpriteMaterial({ map: bubTex, depthWrite: false, transparent: true })); bub.scale.set(5.4, 1.63, 1); bub.position.y = 4.15; bub.renderOrder = 5; c.g.add(bub);
  }
  var g = bubCv.getContext('2d'), W = 768, H = 232; g.clearRect(0, 0, W, H);
  g.fillStyle = 'rgba(4,28,23,.93)'; g.strokeStyle = '#d8b567'; g.lineWidth = 4;
  g.beginPath(); g.moveTo(22, 6); g.lineTo(W - 22, 6); g.quadraticCurveTo(W - 6, 6, W - 6, 22); g.lineTo(W - 6, 190); g.quadraticCurveTo(W - 6, 206, W - 22, 206);
  g.lineTo(W / 2 + 18, 206); g.lineTo(W / 2, 228); g.lineTo(W / 2 - 18, 206); g.lineTo(22, 206); g.quadraticCurveTo(6, 206, 6, 190); g.lineTo(6, 22); g.quadraticCurveTo(6, 6, 22, 6); g.closePath(); g.fill(); g.stroke();
  g.textAlign = 'center'; g.fillStyle = '#71f7d9'; g.font = '700 24px system-ui, sans-serif'; g.fillText(kind === 'prophecy' ? '\u2727  PROVOLTA \u00b7 PROPHECY' : '\u2727  PROVOLTA', W / 2, 38);
  g.fillStyle = '#eafff9'; g.font = 'italic 600 40px "Cormorant Garamond", Georgia, serif';
  var words = String(text).split(/\s+/), lines = [''], li = 0;
  word