<!-- VANCERTS FULL CURRENT BUILD • AUDIO ENGINEER STORY FLOW • BUILD 2026.08.05-R36B52P --> <!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no,viewport-fit=cover"> <meta name="theme-color" content="#171514"> <title>VANCERTS: Build the Scene</title> <style> :root{--ink:#171514;--paper:#f4e6be;--red:#e64a38;--gold:#f1b83e;--green:#4c9a65;--blue:#3f84a5;--cream:#fff8e5;--road:#41464a} *{box-sizing:border-box}html,body{margin:0;width:100%;height:100%;overflow:hidden;overscroll-behavior:none;touch-action:none;background:#111;color:#fff;font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif}button{font:inherit;font-weight:900;border:3px solid #111;background:var(--gold);padding:10px 14px;box-shadow:3px 3px 0 #111;cursor:pointer}button.secondary{background:#ddd}button.red{background:var(--red);color:#fff}button.green{background:#79c88e}button:disabled{opacity:.4;cursor:not-allowed}.hidden{display:none!important} #game{width:100vw;height:100vh;display:block;background:#9ec884;image-rendering:pixelated;outline:none;touch-action:none}.hud{position:fixed;inset:0;pointer-events:none;padding:10px}.top{display:grid;grid-template-columns:190px minmax(420px,1fr) minmax(310px,auto);align-items:stretch;gap:10px}.brand,.panel,.controlBar{background:rgba(18,17,16,.93);border:3px solid var(--paper);box-shadow:4px 4px 0 #000}.brand{padding:9px 13px;font-weight:1000;letter-spacing:.055em;white-space:nowrap;display:flex;align-items:center;justify-content:center;text-align:center;line-height:1.08}.controlBar{padding:7px 10px;text-align:center;font-size:11px;font-weight:900;line-height:1.35;display:flex;align-items:center;justify-content:center;flex-wrap:wrap;gap:4px 0}.controlBar span{white-space:nowrap;margin:0 7px}.musicControl{pointer-events:auto;display:inline-flex;align-items:center;gap:7px;margin:0 7px;padding-left:10px;border-left:2px solid #777}.musicLabel{font-size:9px;letter-spacing:.1em;color:var(--paper)}.stats{display:grid;grid-template-columns:repeat(3,minmax(88px,1fr));gap:6px;align-content:start;min-width:310px}.chip{background:#222;border:2px solid #777;padding:6px 8px;font-size:11px;font-weight:900;white-space:nowrap;text-align:center}.chip #clock{font-variant-numeric:tabular-nums}#musicToggle{pointer-events:auto;min-width:104px;border:2px solid var(--paper);background:var(--green);color:#fff;box-shadow:2px 2px 0 #000;padding:5px 9px;font-size:10px;line-height:1;cursor:pointer}#musicToggle.off{background:#555;color:#ddd}#musicToggle:focus{outline:2px solid var(--gold);outline-offset:2px}#spotifyToggle{pointer-events:auto;min-width:92px;border:2px solid var(--paper);background:#1db954;color:#fff;box-shadow:2px 2px 0 #000;padding:5px 9px;font-size:10px;line-height:1;cursor:pointer}.nowPlaying{pointer-events:auto;display:flex;align-items:center;gap:7px;max-width:330px;min-width:210px;height:24px;overflow:hidden;border:2px solid #777;background:#090909;padding:0 7px}.nowPlaying b{flex:0 0 auto;color:#1db954;font-size:9px;letter-spacing:.08em}.tickerWindow{overflow:hidden;white-space:nowrap;min-width:0}.tickerText{display:inline-block;padding-left:100%;animation:spotifyTicker 18s linear infinite;font-size:9px;color:var(--paper);letter-spacing:.04em}@keyframes spotifyTicker{from{transform:translateX(0)}to{transform:translateX(-100%)}}.spotifyPanel{position:fixed;z-index:65;top:92px;left:50%;transform:translateX(-50%);width:min(410px,calc(100vw - 24px));background:#111;border:3px solid var(--paper);box-shadow:6px 6px 0 #000;padding:8px;pointer-events:auto}.spotifyPanelHead{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:7px;font-size:11px;font-weight:1000;letter-spacing:.05em}.spotifyPanelHead span{color:#1db954}.spotifyClose{padding:3px 8px;border:2px solid #777;background:#333;color:#fff;box-shadow:none;font-size:10px}.spotifyPanel iframe{display:block;width:100%;height:152px;border:0;border-radius:12px}.objective{position:fixed;left:10px;bottom:10px;padding:9px;max-width:min(560px,calc(100vw - 245px));font-size:12px}.toast{position:fixed;top:82px;left:50%;transform:translateX(-50%);background:#111;border:3px solid var(--gold);padding:9px 13px;font-weight:900;opacity:0;transition:.2s;max-width:90vw;text-align:center;z-index:80}.toast.show{opacity:1}.gameError{display:none;position:fixed;left:50%;top:50%;transform:translate(-50%,-50%);z-index:100;background:#171514;color:#fff;border:4px solid var(--red);box-shadow:7px 7px 0 #000;padding:18px;max-width:min(620px,90vw);font-weight:800;line-height:1.4}.gameError.show{display:block} .phone{position:fixed;right:12px;bottom:10px;width:214px;height:392px;box-sizing:border-box;overflow:hidden;background:linear-gradient(#9b9d8c,#777a69);border:5px solid #26271f;border-radius:25px 25px 42px 42px;box-shadow:7px 7px 0 rgba(0,0,0,.55);pointer-events:auto;z-index:8;padding:11px 13px 13px}.phoneBrand{text-align:center;color:#1d201a;font-weight:1000;font-size:14px;letter-spacing:.14em;margin:0 0 5px;text-shadow:0 1px #c9cbbd}.phoneScreen{box-sizing:border-box;height:145px;background:#a9bd86;border:6px inset #4d5142;padding:5px;color:#172016;position:relative;border-radius:5px}.phoneScreen canvas{width:100%;height:95px;display:block;image-rendering:pixelated}.phoneStatus{font:900 10px monospace;border-top:2px solid #5b6a4b;padding-top:3px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.phoneNav{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));align-items:center;gap:7px;margin:8px 2px 7px}.phoneCall,.phoneReset,.phoneMail{box-sizing:border-box;width:100%;height:28px;padding:0;color:#fff;border:2px solid #222;border-radius:14px;box-shadow:none;font-size:9px;letter-spacing:.04em}.phoneCall{background:#3e8f53}.phoneReset{background:#c7352d}.phoneMail{background:#3f84a5}.phoneMail.alert{background:#f1b83e;color:#171514;animation:mailPulse .8s steps(2,end) infinite;outline:3px solid #fff;outline-offset:2px}@keyframes mailPulse{50%{filter:brightness(1.45);transform:translateY(-1px)}}.phoneKeys{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:6px 8px;padding:0 5px}.phoneKeys button{box-sizing:border-box;width:100%;height:28px;padding:0 2px;border:2px solid #3d3e36;border-radius:11px 11px 8px 8px;background:linear-gradient(#d7d8cc,#aeb0a3);box-shadow:0 2px 0 #3c3d35;font-size:9px;line-height:1;color:#222;letter-spacing:.02em}.phoneKeys button:active{transform:translateY(2px);box-shadow:none}.phoneHint{text-align:center;color:#222;font-size:8px;font-weight:1000;margin:7px 3px 0;line-height:1.15;letter-spacing:.02em} .modalWrap{position:fixed;inset:0;background:rgba(0,0,0,.82);display:none;align-items:center;justify-content:center;padding:12px;z-index:70}.modalWrap.show{display:flex}.modal{width:min(900px,100%);max-height:94vh;overflow:auto;background:var(--paper);color:var(--ink);border:5px solid #111;box-shadow:9px 9px 0 var(--red);padding:18px}.modal h1,.modal h2,.modal h3{margin-top:0}.grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:9px}.card{background:var(--cream);border:3px solid #222;padding:10px}.btns{display:flex;gap:8px;flex-wrap:wrap;margin-top:13px}.small{font-size:12px;color:#4d4741}.tag{display:inline-block;padding:3px 6px;margin:2px;background:#222;color:#fff;font-size:11px;font-weight:900}.good{color:#16723a;font-weight:900}.bad{color:#ad2028;font-weight:900}.stageWrap{display:grid;grid-template-columns:minmax(0,1fr) 230px;gap:12px}.stage{position:relative;min-height:410px;background:#303237;border:5px solid #111;overflow:hidden}.stage:before{content:"AUDIENCE / PARKING LOT";position:absolute;left:0;right:0;bottom:0;height:70px;background:#8e7650;color:#fff;text-align:center;padding-top:22px;font-weight:1000;letter-spacing:.12em}.slot{position:absolute;border:3px dashed #e8d9aa;background:rgba(255,255,255,.08);display:flex;align-items:center;justify-content:center;text-align:center;color:#fff;font-size:11px;font-weight:900;padding:4px;cursor:pointer}.slot.filled{border-style:solid;background:#222}.slot.good{outline:4px solid #79c88e}.equipment button{width:100%;margin:4px 0;text-align:left}.scorebox{background:#fff8e5;border:3px solid #222;padding:9px;margin-top:8px}.mobile{display:none;position:fixed;inset:0;pointer-events:none;z-index:9}.dpad{position:absolute;left:13px;bottom:13px;width:130px;height:130px;pointer-events:auto}.dpad button{position:absolute;width:48px;height:48px;padding:0;opacity:.88}.up{left:41px}.down{left:41px;bottom:0}.left{left:0;top:41px}.right{right:0;top:41px}.splash{position:fixed;inset:0;z-index:50;background:linear-gradient(#1a1714,#050505);display:flex;align-items:center;justify-content:center;padding:20px}.splashBox{max-width:780px;text-align:center}.logo{font-size:clamp(38px,11vw,84px);line-height:.82;font-weight:1000;color:var(--paper);text-shadow:6px 6px 0 var(--red)}.tagline{font-size:clamp(17px,4vw,27px);font-weight:900;margin:18px 0} @media(max-width:980px){.top{grid-template-columns:auto 1fr}.controlBar{grid-column:1/-1;grid-row:2}.stats{max-width:none}.toast{top:125px}} @media(max-width:760px),(pointer:coarse){.mobile{display:block}.top{grid-template-columns:auto 1fr}.controlBar{font-size:9px;padding:4px}.controlBar span{margin:0 3px}.objective{bottom:151px;max-width:calc(100vw - 225px)}.stats{max-width:none}.chip{font-size:8px;padding:3px}.brand{font-size:11px}.phone{transform:scale(.78);transform-origin:bottom right}.phoneScreen{height:145px}.stageWrap{grid-template-columns:1fr}.stage{min-height:360px}.modal{padding:13px}} /* Stability pass: responsive HUD, reliable media dock, and fullscreen support. */ .keyRow,.audioRow{display:flex;align-items:center;justify-content:center;flex-wrap:wrap;gap:5px 0;min-width:0}.audioRow{width:100%;gap:7px}.controlBar{min-width:0;overflow:hidden}.musicControl{margin:0;padding-left:0;border-left:0}.nowPlaying{flex:1 1 230px;max-width:460px;min-width:170px}.tickerText{padding-left:100%}#fullscreenToggle{pointer-events:auto;min-width:78px;border:2px solid var(--paper);background:#3f84a5;color:#fff;box-shadow:2px 2px 0 #000;padding:5px 9px;font-size:10px;line-height:1;cursor:pointer}#hudHowTo,#hudLoad{pointer-events:auto;min-width:72px;border:2px solid var(--paper);background:#f1b83e;color:#171514;box-shadow:2px 2px 0 #000;padding:5px 9px;font-size:10px;line-height:1;cursor:pointer;margin:0 3px}#hudLoad{background:#ddd}#hudHowTo:focus,#hudLoad:focus{outline:2px solid var(--gold);outline-offset:2px}#hudSave{pointer-events:auto;min-width:66px;border:2px solid var(--paper);background:#3e8f53;color:#fff;box-shadow:2px 2px 0 #000;padding:5px 9px;font-size:10px;line-height:1;cursor:pointer;margin:0 5px}#hudSave:focus{outline:2px solid var(--gold);outline-offset:2px}.keyRow{column-gap:4px}.keyRow>span,.keyRow>button{display:inline-flex;align-items:center;justify-content:center;min-height:27px}.spotifyPanel{top:86px;width:min(440px,calc(100vw - 24px));max-height:calc(100vh - 110px);overflow:auto}.spotifyPanelHead>div{display:flex;gap:6px;align-items:center}.spotifyPlay{padding:4px 8px;border:2px solid #0b5;background:#1db954;color:#fff;box-shadow:none;font-size:10px}.spotifyPlay:disabled{opacity:.55}.spotifyEmbed{width:100%;min-height:152px;border-radius:12px;overflow:hidden;background:#191414;display:flex;align-items:center;justify-content:center}.spotifyEmbed iframe{display:block;width:100%!important;height:152px!important;border:0;border-radius:12px}.spotifyLoading{padding:24px;color:#fff;text-align:center;font-size:12px;line-height:1.45}.spotifyHelp{margin:7px 2px 0;color:#ddd;font-size:10px;line-height:1.35}.modal{-webkit-overflow-scrolling:touch}.splashBox{width:min(780px,100%)} @media(max-width:1120px){.top{grid-template-columns:165px minmax(0,1fr) 300px}.controlBar span{margin:0 4px}.keyRow{font-size:10px}.nowPlaying{max-width:360px}.spotifyPanel{top:126px}} @media(max-width:980px){.top{grid-template-columns:minmax(150px,1fr) minmax(280px,1.5fr)}.brand{grid-column:1}.stats{grid-column:2}.controlBar{grid-column:1/-1;grid-row:2}.spotifyPanel{top:132px}} @media(max-width:760px),(pointer:coarse){.hud{padding:6px}.top{gap:6px;grid-template-columns:minmax(115px,.8fr) minmax(220px,1.5fr)}.brand{padding:6px;font-size:10px}.stats{min-width:0;gap:3px}.chip{font-size:7.5px;padding:3px 2px}.controlBar{padding:4px 5px}.keyRow{font-size:8px;line-height:1.2}.keyRow span{margin:0 3px}.audioRow{gap:4px}.musicControl{gap:4px}.musicLabel{display:none}#musicToggle,#spotifyToggle,#fullscreenToggle,#hudSave,#hudHowTo,#hudLoad{min-width:0;padding:5px 6px;font-size:8px}.nowPlaying{height:22px;min-width:120px;flex-basis:150px}.nowPlaying b,.tickerText{font-size:7px}.spotifyPanel{top:150px;width:calc(100vw - 12px);max-height:calc(100vh - 158px);padding:6px}.spotifyPanelHead{font-size:9px}.spotifyPanelHead>div{gap:4px}.spotifyPlay,.spotifyClose{font-size:8px;padding:4px 6px}.objective{left:6px;bottom:148px;max-width:calc(100vw - 185px);font-size:9px;padding:6px}.phone{right:5px;bottom:5px;transform:scale(.72)}.modalWrap{align-items:flex-start;padding:8px;overflow:auto}.modal{margin:auto 0;max-height:none;min-height:0;padding:12px}.modal h2{font-size:22px}.grid{grid-template-columns:1fr}.btns button{flex:1 1 150px}.spotifyEmbed,.spotifyEmbed iframe{min-height:152px;height:152px!important}} /* BUILD 2026.07.19-R36B39A CONTROLLER REFINEMENT: compact CC0 rotary road radio; no Spotify or login. */ #fullscreenToggle{pointer-events:auto;min-width:82px;border:2px solid var(--paper);background:#3f84a5;color:#fff;box-shadow:2px 2px 0 #000;padding:5px 9px;font-size:10px;line-height:1;cursor:pointer;margin-left:8px} .objective{left:10px;bottom:10px;width:clamp(250px,29vw,430px);max-width:none;max-height:132px;overflow:auto;font-size:11px;z-index:8} .rotaryRadio{position:fixed;left:50%;bottom:10px;transform:translateX(-50%);width:clamp(225px,20vw,270px);height:116px;z-index:9;pointer-events:auto;color:#201a12;filter:drop-shadow(4px 4px 0 rgba(0,0,0,.55))} .radioCabinet{position:absolute;inset:0;padding:5px 6px 4px;background:repeating-linear-gradient(90deg,rgba(255,255,255,.035) 0 2px,rgba(0,0,0,.035) 2px 5px),linear-gradient(#8a512c,#5c2f18);border:3px solid #21150e;border-radius:10px 10px 15px 15px;box-shadow:inset 0 0 0 2px #ba7543,inset 0 -7px 12px rgba(0,0,0,.24)} .radioTop{display:grid;grid-template-columns:65px minmax(0,1fr);gap:4px;height:27px;align-items:stretch} .radioBrand{display:flex;align-items:center;justify-content:center;text-align:center;background:#d5bd80;border:2px solid #281b10;border-radius:3px;font:1000 6px/1.05 monospace;letter-spacing:.06em;box-shadow:inset 0 0 0 1px #f1dda6} .radioDisplay{min-width:0;background:#8eaa73;border:3px inset #34422d;color:#172216;padding:1px 4px;font:900 6px/1.05 monospace;overflow:hidden} .radioDisplay small{display:block;color:#31462e;font-size:5px;letter-spacing:.07em}.radioTicker{white-space:nowrap;overflow:hidden}.radioTicker span{display:inline-block;min-width:100%;animation:radioScroll 14s linear infinite;padding-left:100%;font-size:6px} @keyframes radioScroll{from{transform:translateX(0)}to{transform:translateX(-100%)}} .radioMain{display:grid;grid-template-columns:34px minmax(0,1fr) 34px;gap:4px;height:65px;margin-top:3px;align-items:center} .knobStack{height:100%;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px;background:radial-gradient(circle at center,#4d2a18 0 40%,transparent 41%),repeating-radial-gradient(circle,#302116 0 2px,#5d412a 3px 4px);border:2px solid #26180f;border-radius:5px} .radioKnob{position:relative;width:25px;height:25px;padding:0;border:3px solid #17110c;border-radius:50%;background:repeating-conic-gradient(#c9b98c 0 7deg,#514b3d 7deg 14deg);box-shadow:inset 0 0 0 3px #6e6859,1px 1px 0 #111;color:#111;cursor:pointer} .radioKnob:after{content:"";position:absolute;left:50%;top:1px;width:2px;height:7px;background:#f3dc83;transform:translateX(-50%);border-radius:2px}.radioKnob.off{filter:grayscale(.8);opacity:.72}.radioKnob.playing{transform:rotate(24deg)} .knobStack small{color:#f2dfb5;font:1000 4.5px monospace;letter-spacing:.05em;text-shadow:1px 1px #111}.knobIcon{position:absolute;inset:0;display:grid;place-items:center;font:1000 7px monospace;color:#f8e9bd;text-shadow:1px 1px #111} .radioCenter{min-width:0;height:100%;display:grid;grid-template-rows:12px minmax(0,1fr);gap:2px} .tuningScale{position:relative;border:2px solid #25180f;background:linear-gradient(#e4d29d,#b8995f);overflow:hidden;color:#2a2117;font:900 4px monospace} .tuningScale .marks{display:flex;align-items:center;justify-content:space-around;height:100%;padding:0 3px}.tuningScale:after{content:"";position:absolute;left:58%;top:0;bottom:0;width:2px;background:#e13d30} .spotifyEmbed{width:100%;height:100%;min-height:45px;border:2px solid #24170f;border-radius:4px;overflow:hidden;background:#191414;display:flex;align-items:center;justify-content:center} .spotifyLoading,.radioOff{padding:4px;color:#fff;text-align:center;font:900 5.5px monospace;line-height:1.2}.radioOff small{font-size:4.5px;color:#cfcfcf} .radioFooter{height:10px;margin-top:1px;display:flex;align-items:center;justify-content:space-between;gap:4px;color:#f3dfb9;font:900 3.8px monospace;letter-spacing:.02em;white-space:nowrap;overflow:hidden} .radioFooter button{min-width:29px;padding:1px 3px;border:1px solid #22170e;box-shadow:none;font-size:4.6px;line-height:1;background:#d9c178}.radioFooter .radioButtons{display:flex;align-items:center;justify-content:flex-end;gap:2px;flex:0 0 auto}.radioFooter #radioHowTo{min-width:49px}.radioFooter #radioStation{min-width:62px} @media(max-width:1080px){.rotaryRadio{width:235px;height:112px}.objective{width:clamp(220px,26vw,310px)}} @media(max-width:820px),(pointer:coarse){.objective{left:6px;bottom:138px;width:calc(100vw - 178px);max-height:76px;font-size:9px}.rotaryRadio{left:auto;right:154px;bottom:6px;transform:none;width:205px;height:104px}.radioCabinet{padding:4px}.radioTop{grid-template-columns:55px minmax(0,1fr);height:24px}.radioMain{height:58px;grid-template-columns:30px minmax(0,1fr) 30px}.radioKnob{width:22px;height:22px}.phone{right:5px;bottom:5px;transform:scale(.70);transform-origin:bottom right}.dpad{bottom:145px}.top{gap:5px}.controlBar{padding:3px}.keyRow{font-size:7px}.keyRow span{margin:0 2px}#fullscreenToggle,#hudSave,#hudHowTo,#hudLoad{font-size:7px;padding:4px 5px;min-width:0;margin-left:2px}} @media(max-width:560px){.rotaryRadio{left:145px;right:158px;width:auto;min-width:178px}.objective{width:calc(100vw - 170px)}.radioFooter span{display:none}} /* BUILD R28: sponsor queue audited across every original business; intro-only badge, station-select radio, shopping-cart collector to Gig Bag */ .phoneTop{display:flex;align-items:center;justify-content:center;position:relative}.phoneTop .phoneBrand{flex:1}.phoneCollapse{position:absolute;right:-4px;top:-6px;width:28px;height:25px;padding:0;border:2px solid #292a23;border-radius:5px;background:#c9cbbd;color:#222;box-shadow:none;line-height:1;font-size:15px}.phone.collapsed{width:58px!important;height:44px!important;padding:5px 7px!important;border-radius:11px!important;overflow:hidden}.phone.collapsed .phoneTop{height:28px}.phone.collapsed .phoneBrand{font-size:0;margin:0}.phone.collapsed .phoneBrand:after{content:'☎';font-size:20px}.phone.collapsed .phoneCollapse{position:static;width:26px}.phone.collapsed .phoneScreen,.phone.collapsed .phoneNav,.phone.collapsed .phoneKeys,.phone.collapsed .phoneHint{display:none} .mobileSteer,.mobileDrive{position:absolute;bottom:20px;display:flex;gap:10px;pointer-events:auto}.mobileSteer{left:max(14px,env(safe-area-inset-left))}.mobileDrive{right:max(14px,env(safe-area-inset-right));flex-direction:column-reverse}.mobileSteer button,.mobileDrive button,.mobileAction,.landscapeToggle{width:58px;height:58px;padding:0;border:3px solid #f4e6be;background:rgba(18,17,16,.82);color:#fff;box-shadow:3px 3px 0 #000;border-radius:12px;font-size:23px;pointer-events:auto;touch-action:none}.mobileAction{position:absolute;left:50%;bottom:22px;transform:translateX(-50%);width:78px;height:48px;font-size:11px;background:rgba(230,74,56,.9)}.landscapeToggle{position:absolute;right:max(14px,env(safe-area-inset-right));top:112px;width:auto;height:34px;padding:0 10px;font-size:9px;background:rgba(63,132,165,.94)}.rotateHint{display:none;position:fixed;inset:0;z-index:48;pointer-events:none;align-items:center;justify-content:center;text-align:center;background:rgba(0,0,0,.56);font-weight:1000;letter-spacing:.05em}.rotateHint>div{background:#171514;border:3px solid #f4e6be;padding:15px;box-shadow:5px 5px 0 #000}.rotateHint small{font-size:10px;color:#f4e6be} @media(max-width:760px),(pointer:coarse){.dpad{display:none}.phone{transition:width .18s,height .18s,transform .18s}.objective{bottom:88px;max-width:calc(100vw - 24px);font-size:10px}.rotaryRadio{transform:scale(.72);transform-origin:bottom center}.mobile{display:block}.top{padding-right:0}.landscapeToggle{display:block}} @media(max-width:760px) and (orientation:portrait){.rotateHint{display:flex}.rotateHint.hiddenByUser{display:none}.phone{transform:scale(.65);transform-origin:bottom right}.hud{padding:5px}.top{opacity:.78}} @media(orientation:landscape) and (pointer:coarse){.rotateHint{display:none!important}.phone{transform:scale(.66);transform-origin:bottom right}.phone.collapsed{transform:scale(1)}.objective{bottom:10px;max-width:43vw}.rotaryRadio{transform:scale(.58);transform-origin:bottom center}.mobileSteer,.mobileDrive{bottom:max(12px,env(safe-area-inset-bottom))}.mobileAction{bottom:max(16px,env(safe-area-inset-bottom))}} /* BUILD R28: phone fullscreen HUD, radio station controls, collector route. */ :root{--safe-top:max(4px,env(safe-area-inset-top));--safe-right:max(6px,env(safe-area-inset-right));--safe-bottom:max(6px,env(safe-area-inset-bottom));--safe-left:max(6px,env(safe-area-inset-left))} html.mobileFullscreen,html.mobileFullscreen body{width:100vw;height:100dvh;min-height:100dvh;position:fixed;inset:0;overflow:hidden;background:#111} html.mobileFullscreen #game{width:100vw;height:100dvh} html.mobileFullscreen .hud{padding:var(--safe-top) var(--safe-right) var(--safe-bottom) var(--safe-left)} #fullscreenToggle.active,.landscapeToggle.active{background:#e64a38} /* Expanded radio is twice the original visual size. */ .rotaryRadio{width:540px;height:232px;transition:width .18s,height .18s,left .18s,right .18s,transform .18s} .rotaryRadio .radioCabinet{width:270px;height:116px;transform:scale(2);transform-origin:top left} .radioCollapse{position:absolute;z-index:4;right:3px;top:3px;width:22px;height:18px;padding:0;border:2px solid #21150e;border-radius:4px;background:#d9c178;color:#21150e;box-shadow:none;font:1000 11px/1 monospace;cursor:pointer} .rotaryRadio.collapsed{width:64px!important;height:50px!important;left:50%!important;right:auto!important;transform:translateX(-50%)!important;filter:drop-shadow(3px 3px 0 rgba(0,0,0,.55))} .rotaryRadio.collapsed .radioCabinet{width:64px;height:50px;transform:none;padding:4px;border-radius:9px;background:linear-gradient(#8a512c,#5c2f18)} .rotaryRadio.collapsed .radioTop,.rotaryRadio.collapsed .radioMain,.rotaryRadio.collapsed .radioFooter{display:none} .rotaryRadio.collapsed .radioCollapse{position:static;width:54px;height:40px;font-size:0;display:grid;place-items:center;margin:0} .rotaryRadio.collapsed .radioCollapse:after{content:'📻';font-size:22px} .objective{max-width:clamp(240px,25vw,360px)} /* Mobile controls: steering on the left, forward above reverse on the right. */ .mobileDrive{flex-direction:column} .mobileSteer,.mobileDrive{bottom:var(--safe-bottom)} .mobileSteer{left:var(--safe-left)}.mobileDrive{right:var(--safe-right)} .mobileSteer button,.mobileDrive button,.landscapeToggle{user-select:none;-webkit-user-select:none;-webkit-touch-callout:none} .mobileAction{display:none!important} .mobileTapHint{display:none;position:fixed;left:50%;bottom:74px;transform:translateX(-50%);z-index:10;pointer-events:none;background:rgba(18,17,16,.88);border:2px solid #f4e6be;padding:4px 8px;font:900 8px system-ui;color:#fff;white-space:nowrap} .mobileTapHint.show{display:block} @media(max-width:820px),(pointer:coarse){ .rotaryRadio{width:405px;height:174px;left:50%;right:auto;bottom:6px;transform:translateX(-50%)} .rotaryRadio .radioCabinet{transform:scale(1.5)} .rotaryRadio.collapsed{bottom:6px} .objective{bottom:78px;max-width:calc(100vw - 24px)} } @media(max-width:760px) and (orientation:portrait){ .rotaryRadio{width:359px;height:155px;transform:translateX(-50%)} .rotaryRadio .radioCabinet{transform:scale(1.33)} } @media(orientation:landscape) and (pointer:coarse){ .hud{padding:var(--safe-top) var(--safe-right) var(--safe-bottom) var(--safe-left)} .top{grid-template-columns:112px minmax(270px,1fr) minmax(220px,270px);grid-template-rows:auto;gap:4px;align-items:stretch} .brand{grid-column:1;grid-row:1;font-size:8px;padding:3px;line-height:1.05} .controlBar{grid-column:2;grid-row:1;padding:3px 4px;min-height:48px} .keyRow{font-size:6.5px;line-height:1.08;gap:1px} .keyRow span{margin:0 2px} .stats{grid-column:3;grid-row:1;grid-template-columns:repeat(3,minmax(58px,1fr));gap:2px;min-width:0} .chip{font-size:6.5px;padding:2px 1px} #fullscreenToggle{font-size:6px;padding:3px 4px;margin-left:2px} .phone{right:var(--safe-right);bottom:var(--safe-bottom);transform:scale(.62);transform-origin:bottom right} .phone.collapsed{transform:scale(1)} .objective{left:var(--safe-left);bottom:var(--safe-bottom);width:34vw;max-width:290px;max-height:58px;overflow:hidden;font-size:8px;padding:5px} .rotaryRadio{width:405px;height:174px;bottom:var(--safe-bottom);transform:translateX(-50%)} .rotaryRadio .radioCabinet{transform:scale(1.5)} .rotaryRadio.collapsed{transform:translateX(-50%)!important} .mobileSteer,.mobileDrive{bottom:var(--safe-bottom)} .landscapeToggle{top:62px;right:var(--safe-right)} .mobileTapHint{bottom:70px} } @media(max-width:680px) and (orientation:landscape){ .top{grid-template-columns:92px minmax(190px,1fr) 190px} .keyRow{font-size:5.5px}.chip{font-size:5.8px} .rotaryRadio:not(.collapsed){transform:translateX(-50%) scale(.82);transform-origin:bottom center} } /* BUILD R18: true mobile viewport fullscreen and safe HUD docking. */ html.mobileFullscreen .hud{z-index:55!important;inset:0!important;box-sizing:border-box!important} html.mobileFullscreen .top{position:fixed!important;z-index:58!important;left:var(--safe-left)!important;right:var(--safe-right)!important;top:var(--safe-top)!important;width:auto!important;max-width:none!important} html.mobileFullscreen .objective{z-index:57!important;box-sizing:border-box!important} html.mobileFullscreen .phone,html.mobileFullscreen .rotaryRadio,html.mobileFullscreen .mobileSteer,html.mobileFullscreen .mobileDrive,html.mobileFullscreen .landscapeToggle{z-index:60!important} @media (pointer:coarse){ html.mobileFullscreen .top{display:grid!important;grid-template-columns:1fr!important;grid-template-rows:auto auto!important;gap:3px!important} html.mobileFullscreen .brand{display:none!important} html.mobileFullscreen .stats{grid-row:1!important;grid-column:1!important;display:grid!important;grid-template-columns:repeat(6,minmax(0,1fr))!important;gap:2px!important;min-width:0!important} html.mobileFullscreen .chip{font-size:clamp(5.5px,1.55vw,8px)!important;padding:3px 1px!important;overflow:hidden!important;text-overflow:ellipsis!important} html.mobileFullscreen .controlBar{grid-row:2!important;grid-column:1!important;min-height:30px!important;padding:3px!important} html.mobileFullscreen .keyRow{font-size:clamp(5px,1.35vw,7px)!important;line-height:1.05!important;max-height:34px!important;overflow:hidden!important} html.mobileFullscreen .keyRow span{margin:0 2px!important} html.mobileFullscreen #fullscreenToggle,html.mobileFullscreen #hudSave,html.mobileFullscreen #hudHowTo,html.mobileFullscreen #hudLoad{font-size:6px!important;padding:3px 5px!important} html.mobileFullscreen .landscapeToggle{top:76px!important;right:var(--safe-right)!important;width:auto!important;height:32px!important;font-size:8px!important} html.mobileFullscreen .mobileSteer,html.mobileFullscreen .mobileDrive{bottom:calc(var(--safe-bottom) + 4px)!important} html.mobileFullscreen .mobileSteer button,html.mobileFullscreen .mobileDrive button{width:56px!important;height:56px!important} html.mobileFullscreen .mobileTapHint{bottom:72px!important} } @media (pointer:coarse) and (orientation:portrait){ html.mobileFullscreen .objective{left:72px!important;right:72px!important;bottom:calc(var(--safe-bottom) + 4px)!important;width:auto!important;max-width:none!important;max-height:70px!important;overflow:auto!important;font-size:8px!important;padding:5px!important} html.mobileFullscreen .phone{right:var(--safe-right)!important;bottom:72px!important;transform:scale(.49)!important;transform-origin:bottom right!important} html.mobileFullscreen .phone.collapsed{right:var(--safe-right)!important;bottom:72px!important;transform:scale(1)!important} html.mobileFullscreen .rotaryRadio{left:50%!important;right:auto!important;bottom:78px!important;width:405px!important;height:174px!important;transform:translateX(-50%) scale(.72)!important;transform-origin:bottom center!important} html.mobileFullscreen .rotaryRadio.collapsed{left:50%!important;right:auto!important;bottom:78px!important;transform:translateX(-50%)!important} } @media (pointer:coarse) and (orientation:landscape){ html.mobileFullscreen .top{grid-template-columns:1fr!important;grid-template-rows:auto auto!important} html.mobileFullscreen .stats{grid-template-columns:repeat(6,minmax(0,1fr))!important} html.mobileFullscreen .objective{left:72px!important;right:72px!important;bottom:var(--safe-bottom)!important;width:auto!important;max-width:none!important;max-height:54px!important;overflow:auto!important;font-size:7px!important;padding:4px!important} html.mobileFullscreen .phone{right:var(--safe-right)!important;bottom:68px!important;transform:scale(.52)!important;transform-origin:bottom right!important} html.mobileFullscreen .phone.collapsed{bottom:68px!important;transform:scale(1)!important} html.mobileFullscreen .rotaryRadio{left:50%!important;right:auto!important;bottom:68px!important;width:405px!important;height:174px!important;transform:translateX(-50%) scale(.66)!important;transform-origin:bottom center!important} html.mobileFullscreen .rotaryRadio.collapsed{left:50%!important;bottom:68px!important;transform:translateX(-50%)!important} html.mobileFullscreen .landscapeToggle{top:70px!important} } /* BUILD R28: compact all radio footer controls so every button stays inside the cabinet. */ .radioFooter{gap:2px} .radioFooter>span:first-child{flex:0 1 47px;min-width:0;max-width:47px;overflow:hidden;text-overflow:clip} .radioFooter .radioButtons{display:grid;grid-template-columns:30px 43px 23px 47px 31px 23px;gap:1px;flex:0 0 auto;align-items:center;justify-content:end} .radioFooter button,.radioFooter #radioHowTo,.radioFooter #radioStation{box-sizing:border-box;width:100%;min-width:0!important;max-width:none;padding:1px 1px!important;border-width:1px;font-size:3.55px;line-height:1;letter-spacing:0;white-space:nowrap;overflow:hidden} @media(max-width:560px){.radioFooter>span:first-child{display:none}.radioFooter .radioButtons{display:grid!important;width:100%;grid-template-columns:30px 43px 23px 47px 31px 23px;justify-content:center}} /* BUILD R28: Community projects and city-upgrade visuals. */ .communityShop .card{display:flex;flex-direction:column;min-height:168px}.communityShop .card button{margin-top:auto}.projectOwned{display:inline-block;background:#16723a;color:#fff;padding:3px 6px;font-size:10px;font-weight:1000}.projectLevel{display:inline-block;background:#222;color:#fff;padding:3px 6px;font-size:10px;font-weight:1000}.communityLegend{background:#e8f2df;border:3px solid #315d3b;padding:10px;margin:10px 0}.stoplightPixel{filter:drop-shadow(2px 2px 0 #111)} /* BUILD R30: Black Star cars ignore signals and roam the full snake road graph while respecting BYOB safe ground. */ /* Legacy left-side geometry correction retained for save compatibility. */ /* BUILD R36A7 SPONSOR FILL FLAGS: corrected intersection markings, standardized curbs/property spacing, valid-grass trees, clear loading access, and sponsor-wall placement. */ /* BUILD R36B38B HUD + 100 RIDER SOCIAL RIDE: west businesses moved fully off the traffic lane onto one continuous five-business grass strip, plus a separated lower future parcel. */ /* BUILD R36B40A AUTO-FIT FIX: continuous parcel-edge curbs with pull-in openings, NPC/bicycle developer codes, and four centered south-parcel hashtag signs. */ /* BUILD R36B40B PARCEL STANDARDIZATION PASS: parcel curbs render above roads on all four sides with only pull-in cuts; four hashtag boards sit centered inside the south grass parcels. */ /* BUILD R36B40C FULL LAND-PARCEL EDGE PASS: every complete city land block, including all four long south development lots, uses the same full outer concrete edge as Leftway. */ /* BUILD R36B40D ALL-DISTRICT PARCEL EDGE PASS: standardized edges render above property art and extend across the full west/east parcel rows. */ /* BUILD R36B40E SOLID FOUR-SIDE PARCEL BANDS: thick concrete bands are inset onto every north/west/east/south parcel side so no edge disappears at full-city zoom. */ /* BUILD R36B40F EXPLICIT MISSING-EDGE REPAIR: directly paints every exterior edge named in the screenshot review at its exact city-block boundary. */ /* BUILD R36B40G FUTURE EAST PARCEL SIGN: mirrors the lower-west future-parcel marker onto the lower-east grass parcel with EAST wording. */ /* BUILD R36B40K BUS STOPS TEMPORARILY DISABLED: removes all shelters, waiting riders, pickup markers, passenger jobs, stop-based poster sites, and the shop entry while preserving the system behind one reversible flag. */ .howHero{background:#171514;color:#fff;border:4px solid #111;padding:12px;margin-bottom:12px;box-shadow:5px 5px 0 #e64a38}.howHero b{color:#f1b83e}.howSection{margin:14px 0 7px;font-size:14px;letter-spacing:.08em}.iconKey{display:grid;grid-template-columns:repeat(auto-fit,minmax(118px,1fr));gap:8px}.iconCard{background:#fff8e5;border:3px solid #222;min-height:116px;padding:8px;text-align:center;display:flex;flex-direction:column;align-items:center;justify-content:flex-start}.iconPic{width:58px;height:50px;display:grid;place-items:center;font-size:34px;line-height:1;margin-bottom:4px;background:#ece0bd;border:2px solid #222;box-shadow:2px 2px 0 #999}.iconCard b{font-size:11px;line-height:1.05}.iconCard small{font-size:9px;line-height:1.15;margin-top:4px;color:#4d4741}.chapterStrip{display:grid;grid-template-columns:repeat(4,1fr);gap:7px;margin:8px 0}.chapterBox{border:3px solid #222;background:#fff;padding:8px;text-align:center;font-size:10px}.chapterBox strong{display:block;font-size:12px}.chapterArrow{color:#e64a38;font-weight:1000}.permitPath{background:#e8f2df;border:3px solid #315d3b;padding:9px;text-align:center;font-size:11px;font-weight:900}.permitPath span{display:inline-block;margin:2px 3px}.mapGateTag{font:1000 10px system-ui;letter-spacing:.05em} @media(max-width:600px){.iconKey{grid-template-columns:repeat(3,minmax(0,1fr))}.iconCard{min-height:105px;padding:5px}.iconPic{width:46px;height:42px;font-size:28px}.iconCard b{font-size:9px}.iconCard small{font-size:8px}.chapterStrip{grid-template-columns:1fr}} /* BUILD R36B7: phone UX polish — readable HUD, larger touch targets, and non-overlapping mobile docks. */ @media (pointer:coarse){ .hud{padding:var(--safe-top) var(--safe-right) var(--safe-bottom) var(--safe-left)} .top{gap:4px} .brand{display:none} .stats{grid-column:1/-1!important;grid-row:1!important;grid-template-columns:repeat(6,minmax(0,1fr))!important;gap:3px!important;min-width:0!important} .chip{font-size:8.5px!important;line-height:1.1!important;padding:4px 2px!important;overflow:hidden;text-overflow:ellipsis} .controlBar{grid-column:1/-1!important;grid-row:2!important;min-height:48px!important;padding:3px 5px!important;overflow:visible} .keyRow{width:100%;gap:6px;justify-content:center} .keyRow>span{display:none!important} .keyRow:before{content:"TOUCH CONTROLS";display:inline-flex;align-items:center;min-height:44px;padding:0 8px;font-size:9px;letter-spacing:.06em;color:var(--paper)} #hudSave,#hudHowTo,#hudLoad,#fullscreenToggle{min-width:82px!important;min-height:44px!important;height:44px!important;padding:0 10px!important;margin:0!important;font-size:10px!important;border-width:2px!important} .landscapeToggle{top:104px!important;right:var(--safe-right)!important;min-width:112px!important;width:auto!important;height:44px!important;padding:0 10px!important;font-size:10px!important;z-index:63!important} .mobileSteer button,.mobileDrive button{width:62px!important;height:62px!important;font-size:25px!important} .mobileSteer,.mobileDrive{bottom:calc(var(--safe-bottom) + 4px)!important;z-index:64!important} .mobileTapHint{bottom:78px!important;font-size:10px!important;padding:6px 10px!important;z-index:64!important} .objective{left:76px!important;right:76px!important;bottom:var(--safe-bottom)!important;width:auto!important;max-width:none!important;max-height:70px!important;overflow:auto!important;font-size:10px!important;line-height:1.25!important;padding:6px!important;z-index:57!important} .phone{right:var(--safe-right)!important;bottom:76px!important;width:214px!important;height:456px!important;transform:none!important;transform-origin:bottom right!important;z-index:62!important} .phoneScreen{height:145px} .phoneNav{gap:6px;margin:8px 1px} .phoneCall,.phoneReset,.phoneMail{height:44px!important;min-height:44px!important;border-radius:12px!important;font-size:11px!important} .phoneKeys{gap:6px 7px;padding:0 3px} .phoneKeys button{height:36px!important;min-height:36px!important;font-size:10px!important;border-radius:9px!important} .phoneHint{font-size:9px!important;margin-top:6px!important} .phoneCollapse{width:34px!important;height:34px!important;font-size:18px!important;right:-5px!important;top:-8px!important} .phone.collapsed{width:64px!important;height:52px!important;padding:5px!important;bottom:76px!important;transform:none!important} .phone.collapsed .phoneCollapse{width:52px!important;height:40px!important} .rotaryRadio:not(.collapsed){left:50%!important;right:auto!important;bottom:82px!important;width:405px!important;height:174px!important;transform:translateX(-50%) scale(.84)!important;transform-origin:bottom center!important;z-index:61!important} .rotaryRadio.collapsed{bottom:76px!important;z-index:61!important} .modalWrap{align-items:flex-start!important;overflow:auto!important;padding:8px!important} .modal{margin:auto 0!important;width:100%!important;max-height:none!important;padding:13px!important} .modal .grid{grid-template-columns:1fr!important} .modal button{min-height:44px} .btns{gap:9px} .btns button{flex:1 1 145px} .iconKey{grid-template-columns:repeat(2,minmax(0,1fr))!important} .iconCard{min-height:112px!important} .iconCard b{font-size:10px!important} .iconCard small{font-size:9px!important} .rotateHint{display:none;inset:auto!important;left:50%!important;top:104px!important;transform:translateX(-50%)!important;width:min(290px,calc(100vw - 140px))!important;height:auto!important;background:transparent!important;pointer-events:none!important;align-items:flex-start!important;z-index:62!important} .rotateHint>div{width:100%;padding:7px 9px!important;border-width:2px!important;box-shadow:3px 3px 0 #000!important;font-size:9px!important;line-height:1.15!important;background:rgba(23,21,20,.94)!important} .rotateHint small{font-size:8px!important} } @media (pointer:coarse) and (orientation:portrait){ .rotateHint{display:flex} .rotateHint.hiddenByUser{display:none!important} .phone:not(.collapsed){bottom:76px!important} .rotaryRadio:not(.collapsed){bottom:82px!important;transform:translateX(-50%) scale(.68)!important} } @media (pointer:coarse) and (orientation:landscape){ .rotateHint{display:none!important} .top{grid-template-columns:1fr!important;grid-template-rows:auto auto!important} .phone:not(.collapsed){width:214px!important;height:264px!important;bottom:70px!important} .phone:not(.collapsed) .phoneKeys{display:none!important} .phone:not(.collapsed) .phoneHint{margin-top:8px!important} .phone.collapsed{bottom:70px!important} .rotaryRadio:not(.collapsed){bottom:70px!important;transform:translateX(-50%) scale(.70)!important} .rotaryRadio.collapsed{bottom:70px!important} .objective{bottom:var(--safe-bottom)!important;max-height:58px!important} .landscapeToggle{top:100px!important} } @media (pointer:coarse) and (max-width:430px){ .chip{font-size:7.8px!important} .keyRow:before{font-size:8px;padding:0 4px} #hudSave,#hudHowTo,#hudLoad,#fullscreenToggle{min-width:74px!important;padding:0 7px!important;font-size:9px!important} .landscapeToggle{min-width:98px!important;font-size:9px!important} .objective{left:70px!important;right:70px!important;font-size:9px!important} } /* R36B7A: visible-viewport fullscreen fallback for iPhone Safari and embedded Squarespace. */ html.mobileFullscreen, html.mobileFullscreen body{ width:100%!important; height:100%!important; height:100dvh!important; min-height:100dvh!important; margin:0!important; padding:0!important; overflow:hidden!important; overscroll-behavior:none!important; background:#111!important; } html.mobileFullscreen #game{ position:fixed!important; inset:0!important; width:100vw!important; height:100vh!important; height:100dvh!important; max-width:none!important; max-height:none!important; } html.mobileFullscreen .hud{ position:fixed!important; width:100vw!important; height:100vh!important; height:100dvh!important; overflow:hidden!important; } @supports(height:100svh){ html.mobileFullscreen, html.mobileFullscreen body, html.mobileFullscreen #game, html.mobileFullscreen .hud{height:100svh!important;min-height:100svh!important} } /* R36B7B: landscape mobile HUD placement fix. */ @media (pointer:coarse) and (orientation:landscape){ /* Reserve the lower-left lane for both horizontal steering buttons. */ html.mobileFullscreen .objective, .objective{ left:calc(var(--safe-left) + 154px)!important; right:calc(var(--safe-right) + 78px)!important; bottom:calc(var(--safe-bottom) + 4px)!important; width:auto!important; max-width:none!important; max-height:68px!important; overflow:auto!important; box-sizing:border-box!important; z-index:57!important; } /* Keep the vertical drive arrows alone in the lower-right control lane. */ html.mobileFullscreen .mobileDrive, .mobileDrive{ right:var(--safe-right)!important; bottom:calc(var(--safe-bottom) + 4px)!important; z-index:64!important; } /* Put both collapsed devices in a dedicated right-side dock. This dock sits below EXIT and above the up-arrow control. */ html.mobileFullscreen .phone.collapsed, .phone.collapsed{ position:fixed!important; left:auto!important; right:calc(var(--safe-right) + 5px)!important; top:174px!important; bottom:auto!important; width:64px!important; height:52px!important; transform:none!important; z-index:66!important; } html.mobileFullscreen .rotaryRadio.collapsed, .rotaryRadio.collapsed{ position:fixed!important; left:auto!important; right:calc(var(--safe-right) + 5px)!important; top:232px!important; bottom:auto!important; width:64px!important; height:50px!important; transform:none!important; z-index:65!important; } /* Keep EXIT above the device dock and leave a clear vertical gap. */ html.mobileFullscreen .landscapeToggle, .landscapeToggle{ right:var(--safe-right)!important; top:104px!important; z-index:67!important; } } @media (pointer:coarse) and (orientation:landscape) and (max-height:430px){ html.mobileFullscreen .phone.collapsed, .phone.collapsed{top:166px!important} html.mobileFullscreen .rotaryRadio.collapsed, .rotaryRadio.collapsed{top:222px!important} html.mobileFullscreen .objective, .objective{ left:calc(var(--safe-left) + 154px)!important; right:calc(var(--safe-right) + 78px)!important; max-height:62px!important; font-size:9px!important; line-height:1.16!important; } } /* R36B7C: draggable mobile device dock + phone-readable expanded radio. */ @media (pointer:coarse){ .phone.collapsed,.rotaryRadio.collapsed{ touch-action:none!important; user-select:none!important; -webkit-user-select:none!important; -webkit-touch-callout:none!important; cursor:grab!important; } .phone.dragging,.rotaryRadio.dragging{ cursor:grabbing!important; transition:none!important; filter:drop-shadow(5px 5px 0 rgba(0,0,0,.7))!important; } /* Expanded radio becomes a real touch panel instead of a scaled desktop miniature. */ .rotaryRadio:not(.collapsed){ position:fixed!important; left:50%!important; right:auto!important; top:calc(var(--safe-top) + 98px)!important; bottom:auto!important; width:min(440px,calc(100vw - 24px))!important; height:min(286px,calc(100dvh - 112px))!important; transform:translateX(-50%)!important; transform-origin:center!important; z-index:72!important; } .rotaryRadio:not(.collapsed) .radioCabinet{ width:100%!important; height:100%!important; transform:none!important; padding:8px!important; border-radius:14px!important; display:grid!important; grid-template-rows:54px minmax(96px,1fr) auto!important; gap:7px!important; box-sizing:border-box!important; } .rotaryRadio:not(.collapsed) .radioCollapse{ width:44px!important; height:44px!important; right:5px!important; top:5px!important; font-size:22px!important; border-width:3px!important; border-radius:9px!important; } .rotaryRadio:not(.collapsed) .radioTop{ grid-template-columns:112px minmax(0,1fr)!important; gap:7px!important; height:54px!important; } .rotaryRadio:not(.collapsed) .radioBrand{ font-size:11px!important; line-height:1.05!important; border-width:3px!important; } .rotaryRadio:not(.collapsed) .radioDisplay{ padding:5px 50px 4px 7px!important; font-size:11px!important; line-height:1.15!important; border-width:3px!important; } .rotaryRadio:not(.collapsed) .radioDisplay small{ font-size:9px!important; } .rotaryRadio:not(.collapsed) .radioTicker span{ font-size:10px!important; } .rotaryRadio:not(.collapsed) .radioMain{ grid-template-columns:70px minmax(0,1fr) 70px!important; gap:7px!important; height:auto!important; min-height:96px!important; margin:0!important; } .rotaryRadio:not(.collapsed) .knobStack{ gap:5px!important; border-width:3px!important; } .rotaryRadio:not(.collapsed) .radioKnob{ width:48px!important; height:48px!important; border-width:4px!important; } .rotaryRadio:not(.collapsed) .knobIcon{ font-size:12px!important; } .rotaryRadio:not(.collapsed) .knobStack small{ font-size:9px!important; } .rotaryRadio:not(.collapsed) .radioCenter{ grid-template-rows:25px minmax(0,1fr)!important; gap:5px!important; } .rotaryRadio:not(.collapsed) .tuningScale{ font-size:8px!important; border-width:3px!important; } .rotaryRadio:not(.collapsed) .spotifyEmbed{ min-height:62px!important; border-width:3px!important; } .rotaryRadio:not(.collapsed) .spotifyLoading, .rotaryRadio:not(.collapsed) .radioOff{ font-size:10px!important; line-height:1.25!important; } .rotaryRadio:not(.collapsed) .radioOff small{ font-size:8px!important; } .rotaryRadio:not(.collapsed) .radioFooter{ height:auto!important; margin:0!important; overflow:visible!important; white-space:normal!important; display:block!important; } .rotaryRadio:not(.collapsed) .radioFooter>span:first-child{ display:none!important; } .rotaryRadio:not(.collapsed) .radioButtons{ width:100%!important; display:grid!important; grid-template-columns:repeat(3,minmax(0,1fr))!important; gap:6px!important; } .rotaryRadio:not(.collapsed) .radioFooter button, .rotaryRadio:not(.collapsed) .radioFooter #radioHowTo, .rotaryRadio:not(.collapsed) .radioFooter #radioStation{ width:100%!important; min-width:0!important; min-height:44px!important; padding:5px 4px!important; font-size:9px!important; line-height:1.05!important; border-width:2px!important; border-radius:7px!important; } /* Use only one map-interaction prompt on touch devices. */ .mobileTapHint{display:none!important} } @media (pointer:coarse) and (orientation:landscape) and (max-height:430px){ .rotaryRadio:not(.collapsed){ top:calc(var(--safe-top) + 90px)!important; height:min(274px,calc(100dvh - 100px))!important; } .rotaryRadio:not(.collapsed) .radioCabinet{ grid-template-rows:48px minmax(88px,1fr) auto!important; gap:5px!important; padding:6px!important; } .rotaryRadio:not(.collapsed) .radioTop{height:48px!important} .rotaryRadio:not(.collapsed) .radioFooter button, .rotaryRadio:not(.collapsed) .radioFooter #radioHowTo, .rotaryRadio:not(.collapsed) .radioFooter #radioStation{ min-height:40px!important; } } /* R36B7D: free two-axis device placement with centered expanded overlays. */ @media (pointer:coarse){ .phone.collapsed, .rotaryRadio.collapsed{ position:fixed!important; right:auto!important; bottom:auto!important; transform:none!important; touch-action:none!important; cursor:grab!important; transition:box-shadow .12s ease,filter .12s ease!important; } .phone.collapsed.dragging, .rotaryRadio.collapsed.dragging{ cursor:grabbing!important; transition:none!important; filter:drop-shadow(6px 6px 0 rgba(0,0,0,.72))!important; } /* Expanded devices never inherit a dragged collapsed position. */ .phone:not(.collapsed){ position:fixed!important; left:50%!important; right:auto!important; top:50%!important; bottom:auto!important; transform:translate(-50%,-50%)!important; z-index:73!important; } .rotaryRadio:not(.collapsed){ position:fixed!important; left:50%!important; right:auto!important; top:50%!important; bottom:auto!important; transform:translate(-50%,-50%)!important; z-index:72!important; } } @media (pointer:coarse) and (orientation:landscape){ .phone:not(.collapsed){ width:min(300px,calc(100vw - 30px))!important; height:min(300px,calc(100dvh - 28px))!important; } .rotaryRadio:not(.collapsed){ width:min(540px,calc(100vw - 30px))!important; height:min(300px,calc(100dvh - 28px))!important; } } @media (pointer:coarse) and (orientation:portrait){ .phone:not(.collapsed){ width:min(300px,calc(100vw - 24px))!important; height:min(520px,calc(100dvh - 32px))!important; } .rotaryRadio:not(.collapsed){ width:min(440px,calc(100vw - 24px))!important; height:min(360px,calc(100dvh - 32px))!important; } } /* R36B7E: restore classic desktop device placement without changing touch layouts. */ @media (pointer:fine){ /* Desktop Nookia: original bottom-right home. */ .phone, html.mobileFullscreen .phone{ position:fixed!important; left:auto!important; right:12px!important; top:auto!important; bottom:10px!important; width:214px!important; height:392px!important; transform:none!important; transform-origin:bottom right!important; z-index:63!important; } .phone.collapsed, html.mobileFullscreen .phone.collapsed{ left:auto!important; right:12px!important; top:auto!important; bottom:10px!important; width:58px!important; height:44px!important; transform:none!important; } /* Desktop Road Radio: original bottom-center home. */ .rotaryRadio, html.mobileFullscreen .rotaryRadio{ position:fixed!important; left:50%!important; right:auto!important; top:auto!important; bottom:10px!important; width:540px!important; height:232px!important; transform:translateX(-50%)!important; transform-origin:bottom center!important; z-index:62!important; } .rotaryRadio .radioCabinet, html.mobileFullscreen .rotaryRadio .radioCabinet{ width:270px!important; height:116px!important; transform:scale(2)!important; transform-origin:top left!important; } .rotaryRadio.collapsed, html.mobileFullscreen .rotaryRadio.collapsed{ left:50%!important; right:auto!important; top:auto!important; bottom:10px!important; width:64px!important; height:50px!important; transform:translateX(-50%)!important; } .rotaryRadio.collapsed .radioCabinet, html.mobileFullscreen .rotaryRadio.collapsed .radioCabinet{ width:64px!important; height:50px!important; transform:none!important; } /* Desktop uses the map prompt only; never show the touch-only helper. */ .mobileTapHint, .mobileTapHint.show{ display:none!important; } } /* Give the radio and Nookia separate desktop lanes on narrower computers. */ @media (pointer:fine) and (max-width:1050px){ .rotaryRadio, html.mobileFullscreen .rotaryRadio{ left:calc(50% - 95px)!important; width:486px!important; height:209px!important; } .rotaryRadio .radioCabinet, html.mobileFullscreen .rotaryRadio .radioCabinet{ transform:scale(1.8)!important; } } /* R36B7F: stable mobile landscape reset after Safari viewport changes. */ @media (pointer:coarse) and (orientation:landscape){ .objective{ left:calc(var(--safe-left) + 150px)!important; right:calc(var(--safe-right) + 86px)!important; bottom:calc(var(--safe-bottom) + 8px)!important; max-height:58px!important; font-size:9px!important; line-height:1.14!important; } } /* R36B13: four-level camera zoom dial on the Nookia phone. */ .phoneZoomDial{ position:absolute;left:-4px;top:-6px;width:28px;height:25px;padding:0; border:2px solid #292a23;border-radius:50%; background:linear-gradient(#d9dbcf,#aeb0a3); color:#171914;box-shadow:none; font:1000 13px/1 system-ui;z-index:4; touch-action:none;user-select:none } .phoneZoomDial .zoomIcon{display:block;line-height:21px;font-size:13px;transform:translateY(-1px)} .phoneZoomDial:active{transform:translateY(1px)} .phoneZoomDialLabel{ position:absolute;left:-8px;top:22px;width:38px;text-align:center; color:#23251f;font:1000 6px/1 system-ui;letter-spacing:.08em; pointer-events:none } .phone.collapsed .phoneZoomDial,.phone.collapsed .phoneZoomDialLabel{display:none} .zoomHelp{ position:absolute;left:-150px;top:-8px;width:132px;padding:7px 8px; border:3px solid #292a23;border-radius:7px; background:#f3ead1;color:#171914;box-shadow:4px 4px 0 rgba(0,0,0,.45); font:900 8px/1.25 system-ui;text-align:left;z-index:6; pointer-events:none;opacity:0;transform:translateX(8px); transition:opacity .18s linear,transform .18s linear } .zoomHelp.show{opacity:1;transform:translateX(0)} .zoomHelp b{display:block;font-size:9px;margin-bottom:2px} .zoomHelp:after{ content:'';position:absolute;right:-9px;top:10px; border-width:7px 0 7px 9px;border-style:solid; border-color:transparent transparent transparent #292a23 } .phone.collapsed .zoomHelp{display:none} @media(max-width:760px),(pointer:coarse){ .phoneZoomDial{left:-4px;top:-6px;width:28px;height:25px} .phoneZoomDial .zoomIcon{font-size:13px} .zoomHelp{left:-142px;top:-7px;width:124px} } .phoneZoomDial{width:34px;height:25px;border-radius:6px;font-size:8px;letter-spacing:-.04em} .phoneZoomDial .zoomIcon{display:block;line-height:21px;font-size:8px;transform:none} .phoneZoomDialLabel{left:-5px;width:36px} .zoomChoices{position:absolute;left:-7px;top:26px;width:42px;padding:3px;border:2px solid #292a23;border-radius:6px;background:#d6dac8;box-shadow:3px 3px 0 rgba(0,0,0,.38);z-index:7;display:none} .zoomChoices.show{display:grid;gap:2px} .zoomChoices button{width:34px;height:21px;padding:0;border:1px solid #4a4d43;border-radius:4px;background:#f0f0e8;color:#171914;font:1000 8px/1 system-ui;box-shadow:none} .zoomChoices button.active{background:#56bf78;color:#102216} .phone.collapsed .zoomChoices{display:none} .gigBagCollectibleGrid{display:grid;grid-template-columns:repeat(auto-fit,minmax(135px,1fr));gap:8px;margin:10px 0 16px} .gigBagCollectibleSlot{min-height:64px;padding:9px;border:2px solid #554b37;border-radius:6px;background:#eee6cd;color:#171717;text-align:center} .gigBagCollectibleSlot b{display:block;font-size:12px} .gigBagCollectibleSlot span{display:block;font-size:19px;font-weight:1000;margin-top:4px} /* R36B17F: expanded and collapsed phone/radio are freely movable and viewport-safe. */ .phoneTop,.radioTop{-webkit-user-select:none;user-select:none} .phoneBrand,.radioBrand{cursor:grab;touch-action:none} .phone.dragging,.rotaryRadio.dragging{transition:none!important;filter:brightness(1.06);cursor:grabbing} .phone.deviceFreePosition,.rotaryRadio.deviceFreePosition{right:auto!important;bottom:auto!important;margin:0!important} .phone.deviceFreePosition{transform-origin:top left!important} .rotaryRadio.deviceFreePosition{transform-origin:top left!important} .phone.collapsed.deviceFreePosition,.rotaryRadio.collapsed.deviceFreePosition{transform:scale(1)!important;transform-origin:top left!important} .rotaryRadio.collapsed.deviceFreePosition{left:auto!important} @media (pointer:coarse) and (orientation:portrait){ html.mobileFullscreen .phone.deviceFreePosition:not(.collapsed){transform:scale(.49)!important} html.mobileFullscreen .rotaryRadio.deviceFreePosition:not(.collapsed){transform:scale(.72)!important} } @media (pointer:coarse) and (orientation:landscape){ html.mobileFullscreen .phone.deviceFreePosition:not(.collapsed){transform:scale(.52)!important} html.mobileFullscreen .rotaryRadio.deviceFreePosition:not(.collapsed){transform:scale(.66)!important} } @media (pointer:coarse) and (orientation:portrait){ html:not(.mobileFullscreen) .phone.deviceFreePosition:not(.collapsed){transform:scale(.65)!important} html:not(.mobileFullscreen) .rotaryRadio.deviceFreePosition:not(.collapsed){transform:scale(.72)!important} } @media (pointer:coarse) and (orientation:landscape){ html:not(.mobileFullscreen) .phone.deviceFreePosition:not(.collapsed){transform:scale(.66)!important} html:not(.mobileFullscreen) .rotaryRadio.deviceFreePosition:not(.collapsed){transform:scale(.58)!important} } html.mobileFullscreen .phone.deviceFreePosition, html.mobileFullscreen .rotaryRadio.deviceFreePosition, .phone.deviceFreePosition, .rotaryRadio.deviceFreePosition{ right:auto!important; bottom:auto!important; transform:none!important; transform-origin:top left!important; pointer-events:auto!important; touch-action:none!important; z-index:92!important; } .phone.deviceFreePosition.collapsed, .rotaryRadio.deviceFreePosition.collapsed{transform:none!important} .phoneTop,.radioTop,.phoneBrand,.radioBrand,.phoneCollapse,.radioCollapse{ touch-action:none!important; -webkit-user-select:none!important; user-select:none!important; } .phoneTop,.radioTop{cursor:grab} .phone.dragging .phoneTop,.rotaryRadio.dragging .radioTop{cursor:grabbing} .phoneCollapse,.radioCollapse{pointer-events:auto!important;z-index:99!important} /* R36B17H — compact mobile HUD, one fullscreen exit, compact notifications */ @media (pointer:coarse){ /* Remove the large TOUCH CONTROLS banner entirely. */ .controlBar{ position:fixed!important; top:calc(var(--safe-top) + 42px)!important; left:calc(var(--safe-left) + 8px)!important; width:auto!important; min-height:0!important; padding:3px!important; margin:0!important; border-width:2px!important; display:block!important; z-index:66!important; background:rgba(18,17,16,.86)!important; box-shadow:2px 2px 0 #000!important; } .keyRow{ width:auto!important; display:flex!important; gap:4px!important; align-items:center!important; justify-content:flex-start!important; } .keyRow:before{content:none!important;display:none!important} .keyRow>span{display:none!important} #hudSave,#fullscreenToggle{ min-width:0!important; width:72px!important; height:30px!important; min-height:30px!important; padding:0 6px!important; margin:0!important; border-width:2px!important; font-size:8px!important; line-height:1!important; box-shadow:1px 1px 0 #000!important; } /* Keep only the Save + fullscreen button pair. */ html.mobileFullscreen .landscapeToggle, .landscapeToggle.active{ display:none!important; pointer-events:none!important; } /* Compact event notification that never blankets the map. */ .toast{ top:calc(var(--safe-top) + 82px)!important; left:50%!important; right:auto!important; width:auto!important; min-width:0!important; max-width:min(320px,62vw)!important; max-height:82px!important; overflow:hidden!important; padding:6px 9px!important; border-width:2px!important; box-shadow:2px 2px 0 #000!important; font-size:10px!important; line-height:1.18!important; letter-spacing:0!important; text-align:center!important; white-space:normal!important; transform:translateX(-50%)!important; z-index:79!important; } /* The statistics remain readable, while the map begins sooner. */ .stats{ position:fixed!important; top:var(--safe-top)!important; left:var(--safe-left)!important; right:var(--safe-right)!important; height:36px!important; z-index:65!important; } .chip{ height:30px!important; padding:3px 2px!important; display:flex!important; align-items:center!important; justify-content:center!important; } /* Clear the old two-row top-grid height. */ .top{ display:block!important; height:0!important; min-height:0!important; gap:0!important; } } @media (pointer:coarse) and (orientation:portrait){ .controlBar{ top:calc(var(--safe-top) + 40px)!important; left:calc(var(--safe-left) + 7px)!important; } #hudSave,#fullscreenToggle{ width:68px!important; height:28px!important; min-height:28px!important; font-size:7.5px!important; } .toast{ top:calc(var(--safe-top) + 76px)!important; max-width:min(280px,68vw)!important; max-height:72px!important; font-size:9.5px!important; } } /* R36B17I — phone doughnut cannon button */ .mobileDonut{ display:none; position:absolute; right:calc(max(14px,env(safe-area-inset-right)) + 70px); bottom:calc(max(14px,env(safe-area-inset-bottom)) + 70px); width:58px; height:58px; padding:0; border:3px solid #f4e6be; border-radius:50%; background:#c92828; color:#fff; box-shadow:3px 3px 0 #000; font-size:27px; line-height:1; pointer-events:auto; touch-action:manipulation; z-index:67; } .mobileDonut.ready{display:block} .mobileDonut:active, .mobileDonut.firing{ transform:translate(2px,2px) scale(.94); box-shadow:1px 1px 0 #000; background:#ff3434; } .mobileDonut[disabled]{ opacity:.45; filter:grayscale(.8); } @media(pointer:coarse){ html.mobileFullscreen .mobileDonut{ right:calc(var(--safe-right) + 70px)!important; bottom:calc(var(--safe-bottom) + 70px)!important; width:56px!important; height:56px!important; font-size:25px!important; } } @media(pointer:coarse) and (orientation:portrait){ html.mobileFullscreen .mobileDonut{ right:calc(var(--safe-right) + 67px)!important; bottom:calc(var(--safe-bottom) + 67px)!important; width:54px!important; height:54px!important; font-size:24px!important; } } /* R36B17J — dependable shared phone/radio controller */ @media(pointer:coarse){ .phone.deviceReliable,.rotaryRadio.deviceReliable{ right:auto!important;bottom:auto!important;transform:none!important; transition:none!important;pointer-events:auto!important;touch-action:none!important; z-index:92!important; } .phone.deviceReliable .phoneTop,.rotaryRadio.deviceReliable .radioTop{ touch-action:none!important;user-select:none!important;-webkit-user-select:none!important; } .phone.deviceReliable .phoneCollapse,.rotaryRadio.deviceReliable .radioCollapse{ pointer-events:auto!important;touch-action:manipulation!important;z-index:100!important; } .phone.deviceSuppressed,.rotaryRadio.deviceSuppressed{display:none!important} @media(orientation:portrait){ .rotaryRadio.deviceReliable:not(.collapsed){width:min(359px,calc(100vw - 14px))!important;height:155px!important} .rotaryRadio.deviceReliable:not(.collapsed) .radioCabinet{transform:scale(1.33)!important;transform-origin:top left!important} } } /* R36B17K — collapsed phone/radio icons remain draggable */ @media(pointer:coarse){ .phone.deviceReliable.collapsed .phoneCollapse, .rotaryRadio.deviceReliable.collapsed .radioCollapse{ cursor:grab!important;touch-action:none!important;pointer-events:auto!important; } .phone.deviceReliable.collapsed.dragging .phoneCollapse, .rotaryRadio.deviceReliable.collapsed.dragging .radioCollapse{cursor:grabbing!important} } /* R36B17K final radio sizing correction */ @media(pointer:coarse){ .phone.deviceReliable.collapsed{width:64px!important;height:50px!important;transform:none!important} .rotaryRadio.deviceReliable.collapsed{width:64px!important;height:50px!important;transform:none!important} .rotaryRadio.deviceReliable.collapsed .radioCabinet{width:64px!important;height:50px!important;transform:none!important} .rotaryRadio.deviceReliable:not(.collapsed) .radioCabinet{width:100%!important;height:100%!important;transform:none!important;transform-origin:top left!important} .rotaryRadio.deviceReliable:not(.collapsed) .radioCollapse{right:5px!important;top:5px!important} } /* R36B38B HUD + 100 RIDER SOCIAL RIDE: stable desktop/mobile HUD control layout. */ .controlBar .keyRow{width:100%;row-gap:6px} #hudSave,#hudLoad,#hudHowTo,#fullscreenToggle{flex:0 0 auto;white-space:nowrap} @media(min-width:981px){ .controlBar .keyRow{justify-content:center} .controlBar .keyRow>span{flex:0 1 auto} } @media(max-width:760px),(pointer:coarse){ .controlBar{overflow:visible} .controlBar .keyRow{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:4px;width:100%} .controlBar .keyRow>span{margin:0!important;min-width:0;text-align:center;white-space:normal;line-height:1.05} #hudSave,#hudLoad,#hudHowTo,#fullscreenToggle{width:100%;min-width:0!important;margin:0!important;padding:5px 3px!important} } @media (pointer:coarse){ .controlBar{left:calc(var(--safe-left) + 7px)!important;right:calc(var(--safe-right) + 7px)!important;width:auto!important} .controlBar .keyRow{display:grid!important;grid-template-columns:repeat(4,minmax(0,1fr))!important;gap:4px!important;width:100%!important} #hudSave,#hudLoad,#hudHowTo,#fullscreenToggle{width:100%!important;min-width:0!important;margin:0!important;padding:4px 2px!important;font-size:7.5px!important} } @media(max-width:430px) and (pointer:coarse){ .controlBar .keyRow{grid-template-columns:repeat(4,minmax(0,1fr))!important} #hudSave,#hudLoad,#hudHowTo,#fullscreenToggle{min-height:32px!important;height:32px!important;font-size:7px!important} } /* R36B38B: invariant two-row HUD in normal and fullscreen modes. */ .controlBar .keyRow{display:flex!important;flex-direction:column!important;align-items:stretch!important;justify-content:center!important;gap:7px!important;width:100%!important} .driveDirections,.hudActions{display:flex!important;align-items:center!important;justify-content:center!important;width:100%!important;gap:12px!important;flex-wrap:nowrap!important} .driveDirections span{display:inline-flex!important;align-items:center!important;justify-content:center!important;white-space:nowrap!important;margin:0!important;min-height:25px!important} .hudActions button{order:initial!important;display:inline-flex!important;align-items:center!important;justify-content:center!important;flex:0 1 132px!important;width:auto!important;min-width:88px!important;height:34px!important;min-height:34px!important;margin:0!important;padding:5px 10px!important;white-space:nowrap!important} #hudSave{order:1!important}#hudLoad{order:2!important}#hudHowTo{order:3!important}#fullscreenToggle{order:4!important} :fullscreen .controlBar .keyRow,.mobileFullscreen .controlBar .keyRow{display:flex!important;flex-direction:column!important} :fullscreen .driveDirections,:fullscreen .hudActions,.mobileFullscreen .driveDirections,.mobileFullscreen .hudActions{display:flex!important;flex-wrap:nowrap!important} @media(max-width:760px),(pointer:coarse){ .controlBar .keyRow{display:flex!important;flex-direction:column!important;gap:4px!important} .driveDirections{gap:5px!important} .driveDirections span{font-size:7px!important;line-height:1.05!important;white-space:nowrap!important} .hudActions{display:grid!important;grid-template-columns:repeat(4,minmax(0,1fr))!important;gap:4px!important} .hudActions button{width:100%!important;min-width:0!important;height:32px!important;min-height:32px!important;padding:3px 2px!important;font-size:7px!important} :fullscreen .hudActions,.mobileFullscreen .hudActions{display:grid!important;grid-template-columns:repeat(4,minmax(0,1fr))!important} } /* R36B39 — full controller support, first-press activation, and remappable controls. */ .controllerWake{position:fixed;inset:0;z-index:120;display:none;align-items:center;justify-content:center;background:rgba(5,5,5,.86);padding:18px;pointer-events:auto} .controllerWake.show{display:flex}.controllerWakeBox{width:min(620px,94vw);background:var(--paper);color:var(--ink);border:5px solid #111;box-shadow:9px 9px 0 var(--green);padding:22px;text-align:center}.controllerWakeTitle{font-size:clamp(24px,6vw,44px);font-weight:1000;line-height:1}.controllerWakeSub{margin-top:12px;font-weight:850}.controllerBadge{display:inline-block;margin-top:12px;padding:6px 10px;background:#171514;color:#fff;border:2px solid var(--gold);font:900 12px monospace} .controllerStatus{position:fixed;left:50%;bottom:140px;transform:translateX(-50%);z-index:91;display:none;background:#111;color:#fff;border:3px solid var(--green);box-shadow:4px 4px 0 #000;padding:8px 12px;font-weight:900;text-align:center;max-width:90vw}.controllerStatus.show{display:block} .controllerGrid{display:grid;grid-template-columns:repeat(auto-fit,minmax(210px,1fr));gap:9px}.controllerMapRow{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:8px;align-items:center;width:100%;text-align:left;background:var(--cream);color:var(--ink);border:3px solid #222;padding:10px;box-shadow:none}.controllerMapRow:focus,.controllerMapRow.listening{outline:4px solid var(--green);outline-offset:1px}.controllerMapRow .binding{font:900 11px monospace;background:#222;color:#fff;padding:5px 7px;white-space:nowrap}.controllerHelp{background:#fff8e5;border:3px solid #222;padding:10px;margin:10px 0}.controllerFocus{outline:4px solid var(--green)!important;outline-offset:2px!important} @media(max-width:760px),(pointer:coarse){.controllerStatus{bottom:94px;font-size:10px}.controllerWakeBox{padding:16px}.controllerGrid{grid-template-columns:1fr}} /* R36B40R — PS4-friendly right-stick pointer. Cross/A taps click; Cross/A hold opens the Nookia. */ .controllerPointer{position:fixed;left:0;top:0;width:30px;height:30px;z-index:119;display:block;opacity:0;pointer-events:none;transform:translate(-50%,-50%) scale(.82);transition:opacity .12s,transform .12s;box-sizing:border-box;border:3px solid #f1b83e;border-radius:50%;background:rgba(17,21,14,.82);box-shadow:0 0 0 2px #171514,0 0 0 4px rgba(255,248,229,.92),3px 3px 0 rgba(0,0,0,.55)} .controllerPointer:before,.controllerPointer:after{content:'';position:absolute;left:50%;top:50%;background:#fff8e5;transform:translate(-50%,-50%)}.controllerPointer:before{width:14px;height:2px}.controllerPointer:after{width:2px;height:14px}.controllerPointer.show{opacity:1;transform:translate(-50%,-50%) scale(1)}.controllerPointer.action{border-color:#3e8f53;background:rgba(24,82,45,.92);box-shadow:0 0 0 2px #171514,0 0 0 5px rgba(241,184,62,.95),3px 3px 0 rgba(0,0,0,.55)} .controllerPointerTarget{outline:4px solid #f1b83e!important;outline-offset:3px!important;filter:brightness(1.08)} @media(max-width:760px),(pointer:coarse){.controllerPointer{width:27px;height:27px}.controllerPointerTarget{outline-width:3px!important;outline-offset:2px!important}} /* R36B40M — 512 Jams is an isolated Spotify iframe with a game-safe playlist submission mail button. */ #rotaryRadio.spotify512Radio:not(.collapsed){width:min(460px,calc(100vw - 24px))!important;height:min(510px,calc(100vh - 130px))!important;min-width:320px!important;filter:drop-shadow(7px 7px 0 rgba(0,0,0,.7))!important;z-index:66!important} #rotaryRadio.spotify512Radio:not(.collapsed) .radioCabinet{box-sizing:border-box!important;width:100%!important;height:100%!important;transform:none!important;display:flex!important;flex-direction:column!important;gap:8px!important;padding:10px!important;background:linear-gradient(145deg,#171514,#2a2622)!important;border:4px solid #f1b83e!important;border-radius:14px!important;box-shadow:inset 0 0 0 2px #f4e6be!important;overflow:hidden!important} #rotaryRadio.spotify512Radio:not(.collapsed) .radioTop{box-sizing:border-box!important;display:grid!important;grid-template-columns:86px minmax(0,1fr)!important;gap:8px!important;align-items:stretch!important;width:100%!important;height:54px!important;min-height:54px!important;padding-right:118px!important;cursor:grab!important} #rotaryRadio.spotify512Radio:not(.collapsed) .radioBrand{display:flex!important;align-items:center!important;justify-content:center!important;background:#f1b83e!important;color:#171514!important;border:3px solid #f4e6be!important;border-radius:6px!important;font:1000 14px/1 system-ui!important;letter-spacing:.06em!important;text-shadow:none!important} #rotaryRadio.spotify512Radio:not(.collapsed) .radioDisplay{display:flex!important;flex-direction:column!important;justify-content:center!important;min-width:0!important;background:#0b0b0b!important;color:#fff!important;border:3px solid #777!important;border-radius:6px!important;padding:5px 8px!important;font:900 12px/1.15 system-ui!important;overflow:hidden!important} #rotaryRadio.spotify512Radio:not(.collapsed) .radioDisplay small{display:block!important;color:#f1b83e!important;font-size:9px!important;letter-spacing:.12em!important} #rotaryRadio.spotify512Radio:not(.collapsed) .radioTicker span{display:block!important;min-width:0!important;padding:0!important;animation:none!important;font-size:12px!important;white-space:nowrap!important;overflow:hidden!important;text-overflow:ellipsis!important} #rotaryRadio.spotify512Radio:not(.collapsed) .radioCollapse{position:absolute!important;right:10px!important;top:10px!important;width:108px!important;height:54px!important;padding:0 8px!important;border:3px solid #f4e6be!important;border-radius:6px!important;background:#f1b83e!important;color:#171514!important;box-shadow:none!important;font-size:0!important;letter-spacing:.04em!important;cursor:pointer!important} #rotaryRadio.spotify512Radio:not(.collapsed) .radioCollapse:after{content:'MINIMIZE'!important;font:1000 10px/1 system-ui!important;color:#171514!important} .spotifySafety{display:flex;align-items:center;justify-content:center;min-height:36px;background:#fff8e5;color:#171514;border:3px solid #3e8f53;padding:5px 8px;text-align:center;font:1000 10px/1.2 system-ui;letter-spacing:.025em} #rotaryRadio.spotify512Radio:not(.collapsed) .spotifyEmbed{box-sizing:border-box!important;display:block!important;flex:1 1 auto!important;width:100%!important;height:auto!important;min-height:250px!important;background:#121212!important;border:3px solid #777!important;border-radius:12px!important;overflow:hidden!important} #rotaryRadio.spotify512Radio:not(.collapsed) .spotifyEmbed iframe{display:block!important;width:100%!important;height:100%!important;min-height:250px!important;border:0!important;border-radius:9px!important;background:#121212!important} .spotify512Actions{display:grid;grid-template-columns:1.05fr .95fr 1.3fr;gap:7px;min-height:38px}.spotify512Actions button{width:100%;min-width:0;height:38px;padding:4px 6px;border:2px solid #f4e6be;box-shadow:none;font-size:9px;line-height:1}.spotify512Actions .spotifyStop{background:#e64a38;color:#fff}.spotify512Actions .spotifyRestore{background:#3e8f53;color:#fff}.spotify512Actions .spotifyJoin{background:#f1b83e;color:#171514}.spotify512Foot{color:#ddd;text-align:center;font:800 9px/1.25 system-ui;letter-spacing:.02em} #rotaryRadio.spotify512Radio.collapsed{width:94px!important;height:60px!important;min-width:94px!important;z-index:66!important} #rotaryRadio.spotify512Radio.collapsed .radioCabinet{box-sizing:border-box!important;width:94px!important;height:60px!important;transform:none!important;padding:4px!important;background:linear-gradient(#f1b83e,#d88719)!important;border:3px solid #171514!important;border-radius:10px!important} #rotaryRadio.spotify512Radio.collapsed .radioTop,#rotaryRadio.spotify512Radio.collapsed .spotifySafety,#rotaryRadio.spotify512Radio.collapsed .spotifyEmbed,#rotaryRadio.spotify512Radio.collapsed .spotify512Actions,#rotaryRadio.spotify512Radio.collapsed .spotify512Foot{display:none!important} #rotaryRadio.spotify512Radio.collapsed .radioCollapse{position:static!important;display:grid!important;place-items:center!important;width:80px!important;height:48px!important;margin:0!important;padding:0!important;border:2px solid #f4e6be!important;border-radius:7px!important;background:#171514!important;color:#fff!important;box-shadow:none!important;font-size:0!important;cursor:grab!important} #rotaryRadio.spotify512Radio.collapsed .radioCollapse:after{content:'♫ 512'!important;font:1000 14px/1 system-ui!important;letter-spacing:.04em!important;color:#f1b83e!important} @media(max-width:760px),(pointer:coarse){#rotaryRadio.spotify512Radio:not(.collapsed){width:min(430px,calc(100vw - 12px))!important;height:min(470px,calc(100vh - 92px))!important;min-width:280px!important}#rotaryRadio.spotify512Radio:not(.collapsed) .radioCabinet{padding:7px!important;gap:6px!important}#rotaryRadio.spotify512Radio:not(.collapsed) .radioTop{height:48px!important;min-height:48px!important;grid-template-columns:72px minmax(0,1fr)!important;padding-right:96px!important}#rotaryRadio.spotify512Radio:not(.collapsed) .radioBrand{font-size:11px!important}#rotaryRadio.spotify512Radio:not(.collapsed) .radioDisplay{font-size:10px!important}#rotaryRadio.spotify512Radio:not(.collapsed) .radioCollapse{right:7px!important;top:7px!important;width:90px!important;height:48px!important;font-size:8px!important}.spotifySafety{min-height:32px;font-size:8px}.spotify512Actions{grid-template-columns:1fr 1fr;min-height:0}.spotify512Actions .spotifyJoin{grid-column:1/-1}.spotify512Actions button{height:32px;font-size:8px}.spotify512Foot{font-size:7px}#rotaryRadio.spotify512Radio:not(.collapsed) .spotifyEmbed,#rotaryRadio.spotify512Radio:not(.collapsed) .spotifyEmbed iframe{min-height:190px!important}} /* R36B40O — persistent tutorial missions and player-controlled Training Wheels. */ body.trainingWheelsActive .objective{width:clamp(290px,34vw,520px);max-height:215px;border-color:#f1b83e;box-shadow:5px 5px 0 #000;overflow:auto} .trainingHeader{display:none;align-items:center;justify-content:space-between;gap:8px;margin:-2px -2px 5px;padding-bottom:5px;border-bottom:2px solid #777}.trainingHeader.show{display:flex}.trainingBadge{display:inline-block;background:#f1b83e;color:#171514;border:2px solid #fff8e5;padding:3px 6px;font:1000 8px/1 system-ui;letter-spacing:.08em}.trainingProgress{color:#f4e6be;font:900 8px/1 system-ui;text-align:right}.trainingActions{display:flex;flex-wrap:wrap;gap:5px;margin-top:7px;pointer-events:auto}.trainingActions button{min-width:0;padding:4px 7px;border:2px solid #f4e6be;box-shadow:2px 2px 0 #000;font-size:8px;line-height:1}.trainingActions .trainingGuide{background:#3f84a5;color:#fff}.trainingActions .trainingToggle{background:#f1b83e;color:#171514}.trainingActions.off .trainingGuide{display:none}.trainingActions.off .trainingToggle{background:#555;color:#fff}.trainingPulse{animation:trainingPulse 1s steps(2,end) infinite!important;outline:5px solid #f1b83e!important;outline-offset:3px!important}@keyframes trainingPulse{50%{outline-color:#fff8e5;filter:brightness(1.3)}} @media(max-width:760px),(pointer:coarse){body.trainingWheelsActive .objective{left:6px;bottom:138px;width:calc(100vw - 178px);max-height:145px;font-size:8px;padding:6px}.trainingHeader{margin:0 0 4px}.trainingBadge,.trainingProgress{font-size:6px}.trainingActions{gap:3px;margin-top:4px}.trainingActions button{padding:3px 4px;font-size:6px}} /* R36B40P — compact old-van 512 Jams radio. The full Spotify player remains functional at roughly half the former panel height. */ #rotaryRadio.spotify512Radio:not(.collapsed){ width:min(330px,calc(var(--app-vw,100vw) - 18px))!important; height:300px!important; max-height:calc(var(--app-vh,100vh) - 18px)!important; min-width:0!important; filter:drop-shadow(5px 5px 0 rgba(0,0,0,.72))!important; z-index:66!important; } #rotaryRadio.spotify512Radio:not(.collapsed) .radioCabinet{ box-sizing:border-box!important;width:100%!important;height:100%!important; display:flex!important;flex-direction:column!important;gap:5px!important; padding:7px!important;position:relative!important; background:repeating-linear-gradient(90deg,rgba(255,255,255,.025) 0 2px,rgba(0,0,0,.045) 2px 5px),linear-gradient(#4b443d,#211d19)!important; border:4px solid #171514!important;border-radius:6px!important; box-shadow:inset 0 0 0 2px #9a9185,inset 0 0 0 5px #34302b,inset 0 -9px 14px rgba(0,0,0,.38)!important; overflow:hidden!important; } #rotaryRadio.spotify512Radio:not(.collapsed) .radioTop{ box-sizing:border-box!important;display:grid!important; grid-template-columns:44px minmax(0,1fr)!important;gap:6px!important; align-items:center!important;width:100%!important;height:42px!important;min-height:42px!important; padding:0 47px 0 0!important;cursor:grab!important; } #rotaryRadio.spotify512Radio:not(.collapsed) .radioBrand{ display:grid!important;place-items:center!important;width:40px!important;height:40px!important; background:radial-gradient(circle at 38% 32%,#aaa196 0 8%,#5d5750 26%,#25221f 64%,#0b0a09 68%)!important; color:#f1b83e!important;border:2px solid #bbb2a6!important;border-radius:50%!important; box-shadow:inset 0 0 0 3px #171514,1px 1px 0 #000!important; font:1000 7px/1 system-ui!important;letter-spacing:.055em!important;text-shadow:1px 1px #000!important; } #rotaryRadio.spotify512Radio:not(.collapsed) .radioDisplay{ display:flex!important;flex-direction:column!important;justify-content:center!important;min-width:0!important;height:38px!important; background:linear-gradient(#1f271c,#10150e)!important;color:#dce8ac!important; border:3px inset #756e64!important;border-radius:2px!important;padding:4px 7px!important; box-shadow:inset 0 0 8px rgba(151,181,92,.18)!important; font:900 9px/1.1 monospace!important;overflow:hidden!important; } #rotaryRadio.spotify512Radio:not(.collapsed) .radioDisplay small{color:#f1b83e!important;font:1000 7px/1 monospace!important;letter-spacing:.1em!important} #rotaryRadio.spotify512Radio:not(.collapsed) .radioTicker span{font:900 9px/1.1 monospace!important} #rotaryRadio.spotify512Radio:not(.collapsed) .radioCollapse{ position:absolute!important;right:7px!important;top:7px!important;width:40px!important;height:40px!important;padding:0!important; border:2px solid #bbb2a6!important;border-radius:50%!important; background:radial-gradient(circle at 38% 32%,#aaa196 0 8%,#5d5750 26%,#25221f 64%,#0b0a09 68%)!important; color:#f4e6be!important;box-shadow:inset 0 0 0 3px #171514,1px 1px 0 #000!important; font-size:0!important;cursor:pointer!important; } #rotaryRadio.spotify512Radio:not(.collapsed) .radioCollapse:after{content:'MIN'!important;color:#f4e6be!important;font:1000 7px/1 monospace!important;letter-spacing:.04em!important} #rotaryRadio.spotify512Radio:not(.collapsed) .spotifySafety{ min-height:22px!important;height:22px!important;padding:3px 5px!important; background:#c7b98d!important;color:#171514!important;border:2px solid #3e4932!important; font:1000 6.5px/1.05 monospace!important;letter-spacing:.015em!important; } #rotaryRadio.spotify512Radio:not(.collapsed) .spotifyEmbed{ display:block!important;flex:0 0 152px!important;width:100%!important;height:152px!important;min-height:152px!important; background:#121212!important;border:3px inset #777!important;border-radius:3px!important;overflow:hidden!important; } #rotaryRadio.spotify512Radio:not(.collapsed) .spotifyEmbed iframe{display:block!important;width:100%!important;height:152px!important;min-height:152px!important;border:0!important;border-radius:0!important} #rotaryRadio.spotify512Radio:not(.collapsed) .spotify512Actions{display:grid!important;grid-template-columns:.9fr .95fr 1.3fr!important;gap:4px!important;min-height:28px!important;height:28px!important} #rotaryRadio.spotify512Radio:not(.collapsed) .spotify512Actions button{ height:28px!important;padding:2px 3px!important;border:2px outset #a9a195!important;border-radius:2px!important; background:linear-gradient(#777067,#3e3934)!important;color:#fff8e5!important;box-shadow:none!important; font:1000 6.5px/1 monospace!important; } #rotaryRadio.spotify512Radio:not(.collapsed) .spotify512Actions .spotifyStop{border-bottom-color:#e64a38!important} #rotaryRadio.spotify512Radio:not(.collapsed) .spotify512Actions .spotifyRestore{border-bottom-color:#79c88e!important} #rotaryRadio.spotify512Radio:not(.collapsed) .spotify512Actions .spotifyJoin{border-bottom-color:#f1b83e!important;color:#f1b83e!important} #rotaryRadio.spotify512Radio:not(.collapsed) .spotify512Foot{height:15px!important;overflow:hidden!important;color:#c7b98d!important;font:800 5.5px/1.15 monospace!important;letter-spacing:0!important} #rotaryRadio.spotify512Radio.collapsed{width:104px!important;height:48px!important;min-width:104px!important} #rotaryRadio.spotify512Radio.collapsed .radioCabinet{ width:104px!important;height:48px!important;padding:4px!important; background:linear-gradient(#4b443d,#211d19)!important;border:3px solid #171514!important;border-radius:5px!important; box-shadow:inset 0 0 0 2px #8f877c!important; } #rotaryRadio.spotify512Radio.collapsed .radioCollapse{ width:90px!important;height:34px!important;border:2px inset #756e64!important;border-radius:2px!important; background:linear-gradient(#1f271c,#10150e)!important; } #rotaryRadio.spotify512Radio.collapsed .radioCollapse:after{content:'♫ 512 JAMS'!important;color:#dce8ac!important;font:1000 9px/1 monospace!important;letter-spacing:.02em!important} @media(max-width:760px),(pointer:coarse){ #rotaryRadio.spotify512Radio:not(.collapsed){width:min(312px,calc(var(--app-vw,100vw) - 14px))!important;height:286px!important;min-width:0!important;max-height:calc(var(--app-vh,100vh) - 14px)!important} #rotaryRadio.spotify512Radio:not(.collapsed) .radioCabinet{padding:6px!important;gap:4px!important} #rotaryRadio.spotify512Radio:not(.collapsed) .radioTop{height:40px!important;min-height:40px!important;grid-template-columns:42px minmax(0,1fr)!important;padding-right:45px!important} #rotaryRadio.spotify512Radio:not(.collapsed) .radioBrand,#rotaryRadio.spotify512Radio:not(.collapsed) .radioCollapse{width:38px!important;height:38px!important} #rotaryRadio.spotify512Radio:not(.collapsed) .radioCollapse{right:6px!important;top:6px!important} #rotaryRadio.spotify512Radio:not(.collapsed) .spotifySafety{height:20px!important;min-height:20px!important;font-size:6px!important} #rotaryRadio.spotify512Radio:not(.collapsed) .spotifyEmbed,#rotaryRadio.spotify512Radio:not(.collapsed) .spotifyEmbed iframe{height:152px!important;min-height:152px!important;flex-basis:152px!important} #rotaryRadio.spotify512Radio:not(.collapsed) .spotify512Actions{grid-template-columns:.9fr .95fr 1.3fr!important;height:27px!important;min-height:27px!important} #rotaryRadio.spotify512Radio:not(.collapsed) .spotify512Actions .spotifyJoin{grid-column:auto!important} #rotaryRadio.spotify512Radio:not(.collapsed) .spotify512Actions button{height:27px!important;font-size:5.8px!important} #rotaryRadio.spotify512Radio:not(.collapsed) .spotify512Foot{font-size:5px!important;height:13px!important} } /* R36B40Q — woodgrain/chrome vintage dashboard radio with a live Spotify tuning display. */ #rotaryRadio.spotify512Radio:not(.collapsed){width:min(370px,calc(var(--app-vw,100vw) - 18px))!important;height:300px!important} #rotaryRadio.spotify512Radio:not(.collapsed) .radioCabinet{ padding:7px!important;gap:5px!important; background:repeating-linear-gradient(7deg,rgba(255,218,152,.045) 0 2px,rgba(36,14,4,.055) 2px 5px),linear-gradient(90deg,#4a2715 0%,#86502c 25%,#a66c3a 52%,#65381e 76%,#3b2012 100%)!important; border:4px solid #171514!important;border-radius:5px!important; box-shadow:inset 0 0 0 2px #d7cbb8,inset 0 0 0 5px #67615a,inset 0 0 0 7px #211d19,inset 0 -9px 14px rgba(0,0,0,.36)!important; } #rotaryRadio.spotify512Radio:not(.collapsed) .radioTop{grid-template-columns:50px minmax(0,1fr)!important;height:50px!important;min-height:50px!important;padding-right:53px!important;gap:6px!important} #rotaryRadio.spotify512Radio:not(.collapsed) .radioBrand, #rotaryRadio.spotify512Radio:not(.collapsed) .radioCollapse{ width:46px!important;height:46px!important;border:3px solid #cfc8bc!important;border-radius:50%!important; background:repeating-conic-gradient(#d8d2c8 0 5deg,#6b665f 5deg 10deg)!important; box-shadow:inset 0 0 0 4px #2a2724,inset 0 0 0 8px #8d867c,1px 2px 0 #000!important; } #rotaryRadio.spotify512Radio:not(.collapsed) .radioBrand{color:#171514!important;text-shadow:0 1px #f4e6be!important;font:1000 7px/1 monospace!important} #rotaryRadio.spotify512Radio:not(.collapsed) .radioCollapse{right:7px!important;top:7px!important;color:#171514!important} #rotaryRadio.spotify512Radio:not(.collapsed) .radioCollapse:after{content:'MIN'!important;color:#171514!important;text-shadow:0 1px #f4e6be!important;font:1000 7px/1 monospace!important} #rotaryRadio.spotify512Radio:not(.collapsed) .radioDisplay{ height:46px!important;padding:3px 7px 4px!important;justify-content:flex-start!important; background:linear-gradient(#171815,#272b22 48%,#12130f 49%,#090a08)!important;color:#eef3c8!important; border:3px inset #b8afa2!important;border-radius:1px!important; box-shadow:inset 0 0 9px rgba(204,221,139,.2),0 0 0 1px #171514!important; } .radioDialScale{display:flex!important;align-items:center!important;justify-content:space-between!important;height:10px!important;min-height:10px!important;margin:0 0 1px!important;color:#c8cba9!important;border-bottom:1px solid #767b61!important;font:700 5px/1 monospace!important;letter-spacing:0!important} .radioDialScale i{display:block!important;width:1px!important;height:5px!important;background:#9ca17d!important;box-shadow:7px 0 #9ca17d,-7px 0 #9ca17d!important} #rotaryRadio.spotify512Radio:not(.collapsed) .radioDisplay small{height:8px!important;color:#f1b83e!important;font:1000 6px/1 monospace!important;letter-spacing:.12em!important} #rotaryRadio.spotify512Radio:not(.collapsed) .radioTicker{height:15px!important;line-height:15px!important} #rotaryRadio.spotify512Radio:not(.collapsed) .radioTicker span{ display:inline-block!important;min-width:100%!important;padding-left:100%!important;overflow:visible!important;text-overflow:clip!important; color:#eef3c8!important;font:1000 9px/15px monospace!important;white-space:nowrap!important; animation:vintageTuneScroll 13s linear infinite!important; } @keyframes vintageTuneScroll{from{transform:translateX(0)}to{transform:translateX(-100%)}} #rotaryRadio.spotify512Radio:not(.collapsed) .spotifySafety{height:20px!important;min-height:20px!important;border-color:#847c70!important;background:#d9cdaa!important;font-size:6px!important} #rotaryRadio.spotify512Radio:not(.collapsed) .spotifyEmbed,#rotaryRadio.spotify512Radio:not(.collapsed) .spotifyEmbed iframe{height:152px!important;min-height:152px!important;flex-basis:152px!important;border-radius:1px!important} #rotaryRadio.spotify512Radio:not(.collapsed) .spotify512Actions{height:27px!important;min-height:27px!important;gap:4px!important} #rotaryRadio.spotify512Radio:not(.collapsed) .spotify512Actions button{ height:27px!important;background:linear-gradient(#eee7da 0 18%,#8a8379 20% 52%,#38342f 54% 100%)!important; border:2px outset #c8c0b4!important;color:#fff8e5!important;text-shadow:1px 1px #000!important;font-size:6.5px!important; } #rotaryRadio.spotify512Radio:not(.collapsed) .spotify512Foot{height:12px!important;color:#e3d5ac!important;font-size:5px!important} #rotaryRadio.spotify512Radio.collapsed{width:214px!important;height:64px!important;min-width:214px!important} #rotaryRadio.spotify512Radio.collapsed .radioCabinet{ position:relative!important;display:flex!important;align-items:center!important;justify-content:center!important; width:214px!important;height:64px!important;padding:6px 48px!important; background:repeating-linear-gradient(7deg,rgba(255,218,152,.05) 0 2px,rgba(36,14,4,.06) 2px 5px),linear-gradient(90deg,#4a2715,#a66c3a 50%,#3b2012)!important; border:3px solid #171514!important;border-radius:5px!important;box-shadow:inset 0 0 0 2px #d7cbb8,inset 0 0 0 5px #57514a!important; } #rotaryRadio.spotify512Radio.collapsed .radioCabinet:before, #rotaryRadio.spotify512Radio.collapsed .radioCabinet:after{ content:'';position:absolute;top:9px;width:40px;height:40px;border:3px solid #cfc8bc;border-radius:50%; background:repeating-conic-gradient(#d8d2c8 0 5deg,#6b665f 5deg 10deg); box-shadow:inset 0 0 0 4px #2a2724,inset 0 0 0 8px #8d867c,1px 2px 0 #000; } #rotaryRadio.spotify512Radio.collapsed .radioCabinet:before{left:7px}#rotaryRadio.spotify512Radio.collapsed .radioCabinet:after{right:7px} #rotaryRadio.spotify512Radio.collapsed .radioCollapse{ position:relative!important;z-index:2!important;width:112px!important;height:40px!important;margin:0!important;padding:4px 6px!important; border:3px inset #b8afa2!important;border-radius:1px!important;background:linear-gradient(#22271d,#0b0d09)!important; box-shadow:inset 0 0 8px rgba(204,221,139,.2)!important;overflow:hidden!important; } #rotaryRadio.spotify512Radio.collapsed .radioCollapse:after{ content:attr(data-now-playing)!important;display:block!important;width:100%!important;overflow:hidden!important;text-overflow:ellipsis!important;white-space:nowrap!important; color:#e8efbd!important;font:1000 7px/1.15 monospace!important;letter-spacing:.01em!important; } @media(max-width:760px),(pointer:coarse){ #rotaryRadio.spotify512Radio:not(.collapsed){width:min(340px,calc(var(--app-vw,100vw) - 14px))!important;height:292px!important} #rotaryRadio.spotify512Radio:not(.collapsed) .radioTop{grid-template-columns:46px minmax(0,1fr)!important;height:46px!important;min-height:46px!important;padding-right:49px!important} #rotaryRadio.spotify512Radio:not(.collapsed) .radioBrand,#rotaryRadio.spotify512Radio:not(.collapsed) .radioCollapse{width:42px!important;height:42px!important} #rotaryRadio.spotify512Radio:not(.collapsed) .spotifySafety{height:18px!important;min-height:18px!important;font-size:5.5px!important} #rotaryRadio.spotify512Radio.collapsed{width:190px!important;height:58px!important;min-width:190px!important} #rotaryRadio.spotify512Radio.collapsed .radioCabinet{width:190px!important;height:58px!important;padding:5px 43px!important} #rotaryRadio.spotify512Radio.collapsed .radioCabinet:before,#rotaryRadio.spotify512Radio.collapsed .radioCabinet:after{top:8px;width:35px;height:35px} #rotaryRadio.spotify512Radio.collapsed .radioCabinet:before{left:6px}#rotaryRadio.spotify512Radio.collapsed .radioCabinet:after{right:6px} #rotaryRadio.spotify512Radio.collapsed .radioCollapse{width:98px!important;height:36px!important} #rotaryRadio.spotify512Radio.collapsed .radioCollapse:after{font-size:6px!important} } @media(prefers-reduced-motion:reduce){#rotaryRadio.spotify512Radio:not(.collapsed) .radioTicker span{animation:none!important;padding-left:0!important;overflow:hidden!important;text-overflow:ellipsis!important}} /* R36B40S — Training control in the Vancerts brand box plus a quieter phone HUD. */ .brand{flex-direction:column;gap:6px} .brandTitle{font-weight:1000;line-height:1.05;letter-spacing:.055em} .brandTrainingToggle{ pointer-events:auto;box-sizing:border-box;width:100%;min-width:0;height:25px;min-height:25px; margin:0;padding:2px 7px;border:2px solid var(--paper);background:#79c88e;color:#171514; box-shadow:2px 2px 0 #000;font:1000 9px/1 system-ui;letter-spacing:.025em;cursor:pointer } .brandTrainingToggle.off{background:#555;color:#fff} .brandTrainingToggle:focus{outline:2px solid var(--gold);outline-offset:2px} .trainingActions{margin-top:5px} @media(max-width:760px),(pointer:coarse){ .hud,html.mobileFullscreen .hud{padding:4px!important} .top,html.mobileFullscreen .top{ position:relative!important;display:grid!important;box-sizing:border-box!important; grid-template-columns:132px minmax(0,1fr)!important;grid-template-rows:38px 28px!important; width:100%!important;height:auto!important;min-height:0!important;gap:3px!important;align-items:stretch!important } .brand,html.mobileFullscreen .brand{ position:static!important;display:flex!important;box-sizing:border-box!important; grid-column:1!important;grid-row:1!important;flex-direction:row!important;align-items:center!important; gap:4px!important;min-width:0!important;height:38px!important;padding:3px 4px!important; font-size:7px!important;line-height:1!important;overflow:hidden!important } .brandTitle{flex:1 1 auto;min-width:0;font-size:7px!important;line-height:1.02!important;white-space:nowrap!important} .brandTrainingToggle{ flex:0 0 61px!important;width:61px!important;height:28px!important;min-height:28px!important; padding:2px!important;border-width:2px!important;box-shadow:1px 1px 0 #000!important; font-size:7px!important;letter-spacing:0!important } .stats,html.mobileFullscreen .stats{ position:static!important;display:grid!important;box-sizing:border-box!important; grid-column:2!important;grid-row:1!important;grid-template-columns:repeat(6,minmax(0,1fr))!important; width:auto!important;height:38px!important;min-width:0!important;gap:2px!important;align-content:stretch!important } .chip,html.mobileFullscreen .chip{ box-sizing:border-box!important;width:auto!important;height:38px!important;min-width:0!important; padding:2px 1px!important;border-width:2px!important;font-size:clamp(5.5px,1.2vw,7.5px)!important; line-height:1.05!important;overflow:hidden!important;text-overflow:ellipsis!important;white-space:nowrap!important } .controlBar,html.mobileFullscreen .controlBar{ position:static!important;display:block!important;box-sizing:border-box!important; grid-column:1/-1!important;grid-row:2!important;top:auto!important;left:auto!important;right:auto!important; width:auto!important;height:28px!important;min-height:28px!important;margin:0!important;padding:1px 2px!important; border-width:2px!important;box-shadow:2px 2px 0 #000!important;overflow:hidden!important } .controlBar .keyRow,html.mobileFullscreen .controlBar .keyRow{ display:block!important;width:100%!important;height:100%!important;min-height:0!important; margin:0!important;padding:0!important;overflow:hidden!important } .driveDirections,:fullscreen .driveDirections,html.mobileFullscreen .driveDirections, .keyRow:before{display:none!important;content:none!important} .hudActions,html.mobileFullscreen .hudActions{ display:grid!important;grid-template-columns:repeat(4,minmax(0,1fr))!important; width:100%!important;height:100%!important;gap:3px!important;align-items:stretch!important } .hudActions button,#hudSave,#hudLoad,#hudHowTo,#fullscreenToggle, html.mobileFullscreen .hudActions button{ display:flex!important;box-sizing:border-box!important;align-items:center!important;justify-content:center!important; flex:none!important;width:100%!important;min-width:0!important;height:22px!important;min-height:22px!important; margin:0!important;padding:1px 2px!important;border-width:2px!important;box-shadow:1px 1px 0 #000!important; font-size:6.5px!important;line-height:1!important;white-space:nowrap!important;overflow:hidden!important } .landscapeToggle,html.mobileFullscreen .landscapeToggle{ display:none!important;pointer-events:none!important } .mobileSteer,.mobileDrive,html.mobileFullscreen .mobileSteer,html.mobileFullscreen .mobileDrive{ bottom:calc(var(--safe-bottom) + 3px)!important;gap:6px!important;z-index:64!important } .mobileSteer{left:var(--safe-left)!important}.mobileDrive{right:var(--safe-right)!important} .mobileSteer button,.mobileDrive button, html.mobileFullscreen .mobileSteer button,html.mobileFullscreen .mobileDrive button{ width:48px!important;height:48px!important;padding:0!important;border-radius:10px!important; font-size:19px!important;box-shadow:2px 2px 0 #000!important } .objective,body.trainingWheelsActive .objective, html.mobileFullscreen .objective,html.mobileFullscreen body.trainingWheelsActive .objective{ box-sizing:border-box!important;left:110px!important;right:55px!important; bottom:calc(var(--safe-bottom) + 3px)!important;width:auto!important;max-width:none!important;max-height:64px!important; padding:4px 5px!important;border-width:2px!important;box-shadow:2px 2px 0 #000!important; font-size:7.5px!important;line-height:1.13!important;overflow:auto!important;z-index:57!important } .trainingHeader{margin:0 0 3px!important;padding-bottom:3px!important;gap:4px!important;border-bottom-width:1px!important} .trainingBadge,.trainingProgress{font-size:5.5px!important} .trainingBadge{padding:2px 3px!important;border-width:1px!important} .trainingActions{gap:3px!important;margin-top:3px!important} .trainingActions button{ height:21px!important;min-height:21px!important;margin:0!important;padding:1px 4px!important; border-width:1px!important;box-shadow:1px 1px 0 #000!important;font-size:5.5px!important } .phone.deviceReliable.collapsed,html.mobileFullscreen .phone.deviceReliable.collapsed{ width:54px!important;height:44px!important;min-width:54px!important;padding:4px!important;transform:none!important } .phone.deviceReliable.collapsed .phoneCollapse, html.mobileFullscreen .phone.deviceReliable.collapsed .phoneCollapse{ width:44px!important;height:34px!important;min-height:34px!important;font-size:16px!important } #rotaryRadio.spotify512Radio.collapsed{ width:160px!important;height:50px!important;min-width:160px!important } #rotaryRadio.spotify512Radio.collapsed .radioCabinet{ width:160px!important;height:50px!important;padding:4px 37px!important } #rotaryRadio.spotify512Radio.collapsed .radioCabinet:before, #rotaryRadio.spotify512Radio.collapsed .radioCabinet:after{ top:7px!important;width:30px!important;height:30px!important;border-width:2px!important } #rotaryRadio.spotify512Radio.collapsed .radioCabinet:before{left:5px!important} #rotaryRadio.spotify512Radio.collapsed .radioCabinet:after{right:5px!important} #rotaryRadio.spotify512Radio.collapsed .radioCollapse{ width:86px!important;height:32px!important;padding:3px 5px!important;border-width:2px!important } #rotaryRadio.spotify512Radio.collapsed .radioCollapse:after{font-size:5.5px!important} #rotaryRadio.spotify512Radio:not(.collapsed){ width:min(320px,calc(var(--app-vw,100vw) - 10px))!important; height:min(286px,calc(var(--app-vh,100vh) - 10px))!important;min-width:0!important } .phone.deviceReliable:not(.collapsed){ max-width:calc(var(--app-vw,100vw) - 10px)!important;max-height:calc(var(--app-vh,100vh) - 10px)!important } .toast,html.mobileFullscreen .toast{ top:74px!important;max-width:min(290px,70vw)!important;max-height:56px!important; padding:5px 8px!important;font-size:8px!important;line-height:1.12!important } .modalWrap,html.mobileFullscreen .modalWrap{padding:5px!important;align-items:center!important;overflow:hidden!important} .modal,html.mobileFullscreen .modal{ box-sizing:border-box!important;width:min(680px,100%)!important;max-height:calc(var(--app-vh,100vh) - 10px)!important; min-height:0!important;margin:auto!important;padding:10px!important;overflow:auto!important } .modal h2{font-size:clamp(18px,5vw,26px)!important;margin-bottom:7px!important} .modal button{min-height:40px!important} .splash{padding:5px!important;overflow:auto!important} .splashBox{box-sizing:border-box!important;width:min(680px,100%)!important;max-height:calc(100dvh - 10px)!important;padding:12px!important;overflow:auto!important} .splashBox .logo{font-size:clamp(28px,8vw,48px)!important} } @media(pointer:coarse) and (orientation:portrait){ .top,html.mobileFullscreen .top{ grid-template-columns:102px minmax(0,1fr)!important;grid-template-rows:50px 28px!important } .brand,html.mobileFullscreen .brand{ height:50px!important;flex-direction:column!important;gap:2px!important;padding:3px!important } .brandTitle{font-size:6.5px!important;line-height:1!important} .brandTrainingToggle{ flex:0 0 22px!important;width:100%!important;height:22px!important;min-height:22px!important;font-size:6.5px!important } .stats,html.mobileFullscreen .stats{ height:50px!important;grid-template-columns:repeat(3,minmax(0,1fr))!important;grid-template-rows:repeat(2,minmax(0,1fr))!important } .chip,html.mobileFullscreen .chip{height:24px!important;font-size:clamp(6px,2.1vw,8px)!important} .objective,body.trainingWheelsActive .objective, html.mobileFullscreen .objective,html.mobileFullscreen body.trainingWheelsActive .objective{ left:110px!important;right:55px!important;max-height:76px!important } .toast,html.mobileFullscreen .toast{top:86px!important} } @media(pointer:coarse) and (orientation:landscape) and (max-height:430px){ .top,html.mobileFullscreen .top{grid-template-rows:34px 25px!important} .brand,html.mobileFullscreen .brand{height:34px!important;padding:2px 3px!important} .brandTitle{font-size:6.5px!important} .brandTrainingToggle{height:24px!important;min-height:24px!important;font-size:6.5px!important} .stats,html.mobileFullscreen .stats{height:34px!important} .chip,html.mobileFullscreen .chip{height:34px!important;font-size:clamp(5px,1.1vw,6.5px)!important} .controlBar,html.mobileFullscreen .controlBar{height:25px!important;min-height:25px!important} .hudActions button,#hudSave,#hudLoad,#hudHowTo,#fullscreenToggle, html.mobileFullscreen .hudActions button{height:19px!important;min-height:19px!important;font-size:6px!important} .objective,body.trainingWheelsActive .objective, html.mobileFullscreen .objective,html.mobileFullscreen body.trainingWheelsActive .objective{ max-height:58px!important;font-size:7px!important;line-height:1.1!important } .toast,html.mobileFullscreen .toast{top:66px!important} } /* R36B41A — staff roster, receipt archive, deduction school, automatic show costs, and Paul’s white VANCERTS-magnet truck. */ .modalWrap{z-index:110} .phoneNav{grid-template-columns:repeat(4,minmax(0,1fr))!important;gap:4px!important;margin-left:0!important;margin-right:0!important} .phoneCall,.phoneReset,.phoneMail,.phoneWaygo{box-sizing:border-box;width:100%;height:28px;padding:0 1px;color:#fff;border:2px solid #222;border-radius:14px;box-shadow:none;font-size:7.5px;letter-spacing:.02em} .phoneWaygo{background:var(--gold);color:var(--ink)} .waygoIntro{border:4px solid var(--blue);background:#e8f4ed;padding:10px;margin-bottom:10px} .waygoGrid{grid-template-columns:repeat(auto-fit,minmax(210px,1fr))} .waygoCard{position:relative;border-color:#244f63}.waygoCard h3{padding-right:52px;margin-bottom:5px}.waygoFare{position:absolute;right:7px;top:7px;background:var(--gold);border:2px solid #111;padding:4px 6px;font-weight:1000}.waygoCard button{width:100%} .waygoFade{position:fixed;inset:0;z-index:120;display:grid;place-items:center;background:#111;color:var(--gold);font-size:clamp(30px,9vw,76px);font-weight:1000;letter-spacing:.12em;opacity:0;visibility:hidden;pointer-events:none;transition:opacity .22s ease,visibility 0s linear .45s}.waygoFade.show{opacity:1;visibility:visible;pointer-events:auto;transition:opacity .22s ease}.waygoFade small{display:block;color:var(--paper);font-size:clamp(10px,2vw,15px);letter-spacing:.08em;text-align:center;margin-top:8px} .financeHero{display:grid;grid-template-columns:repeat(4,minmax(120px,1fr));gap:7px;margin:9px 0}.financeMetric{border:3px solid #222;background:#fff8e5;padding:8px;min-height:76px}.financeMetric span{display:block;font-size:10px;font-weight:900;letter-spacing:.04em}.financeMetric b{display:block;font-size:clamp(18px,3vw,28px);line-height:1.15;margin-top:4px}.financeMetric.earned{border-color:#287944}.financeMetric.spent{border-color:#b2362c}.financeMetric.debt{border-color:#b78415} .financeSplit{display:grid;grid-template-columns:1fr 1fr;gap:9px}.financeList{margin:0;padding-left:18px}.financeList li{margin:3px 0}.ledger{border:3px solid #222;background:#fff8e5;max-height:250px;overflow:auto}.ledgerRow{display:grid;grid-template-columns:76px minmax(140px,1fr) 95px;gap:7px;align-items:center;padding:7px 8px;border-bottom:1px solid #b8aa83;font-size:11px}.ledgerRow:last-child{border-bottom:0}.ledgerRow .ledgerAmount{text-align:right;font-weight:1000}.ledgerRow.income .ledgerAmount{color:#16723a}.ledgerRow.expense .ledgerAmount{color:#ad2028}.ledgerRow.loan .ledgerAmount{color:#8a5a00}.ledgerRow.repayment .ledgerAmount{color:#3f6078}.ledgerEmpty{padding:12px;text-align:center}.bankDaily{border:4px solid var(--gold);background:#fff3c8;padding:11px}.bankAmountDisplay{background:#171514;color:#f5dc7c;border:4px inset #666;padding:9px;text-align:right;font:1000 24px monospace;min-height:54px;overflow:hidden}.bankKeypad{display:grid;grid-template-columns:repeat(3,minmax(58px,1fr));gap:7px;margin-top:10px}.bankKeypad button{min-height:46px;font-size:17px}.bankKeypad .wide{grid-column:span 2}.loanRow{border:3px solid #222;background:#fff8e5;padding:8px;margin-top:7px}.loanProgress{height:9px;background:#d0c6a8;border:1px solid #222;margin:7px 0}.loanProgress i{display:block;height:100%;background:var(--green)} @media(max-width:760px),(pointer:coarse){.financeHero{grid-template-columns:repeat(2,minmax(0,1fr))}.financeSplit{grid-template-columns:1fr}.ledgerRow{grid-template-columns:61px minmax(96px,1fr) 72px;font-size:9px}.waygoGrid{grid-template-columns:1fr}.bankKeypad button{min-height:48px}.phoneNav{gap:3px!important}.phoneCall,.phoneReset,.phoneMail,.phoneWaygo{height:44px!important;min-height:44px!important;font-size:7px}} @media(max-width:420px){.financeHero{grid-template-columns:1fr 1fr}.financeMetric{min-height:62px;padding:6px}.financeMetric b{font-size:17px}.waygoCard h3{font-size:15px}} /* R36B41A • staff, receipts, expense tracking, and deduction teaching. */ .receiptGrid{display:grid;grid-template-columns:repeat(auto-fit,minmax(225px,1fr));gap:9px}.receiptCard{background:#fffef2;border:3px solid #222;box-shadow:3px 3px 0 #b8aa83;padding:10px;position:relative}.receiptCard.estimate{border-style:dashed;background:#f1eee1}.receiptHead{display:flex;justify-content:space-between;align-items:flex-start;gap:8px;border-bottom:2px dashed #8b8064;padding-bottom:6px;margin-bottom:7px}.receiptHead b{font-size:12px}.receiptNo{font:900 9px monospace;color:#5d5747;text-align:right}.receiptLine{display:flex;justify-content:space-between;gap:10px;font-size:11px;margin:3px 0}.receiptLine span:first-child{color:#5d5747}.receiptPurpose{margin-top:7px;padding:7px;border:2px solid #b8aa83;background:#fff8e5;font-size:10px;line-height:1.35}.deductionBadge{display:inline-block;margin-top:7px;padding:4px 7px;border:2px solid #222;background:#79c88e;font-size:10px;font-weight:1000}.deductionBadge.partial{background:#f1b83e}.deductionBadge.review{background:#ddd}.deductionBadge.income{background:#3f84a5;color:#fff}.receiptMini{padding:3px 6px!important;min-height:0!important;border:1px solid #222!important;box-shadow:none!important;font-size:8px!important;margin-top:4px}.taxSchool{border:4px solid #315d3b;background:#e8f2df;padding:11px;margin:10px 0}.taxSchool h3{margin:0 0 6px}.staffRoster{display:grid;grid-template-columns:minmax(180px,1fr) minmax(220px,1.6fr);gap:10px}.staffPortrait{background:#f4e6be;border:4px solid #222;min-height:165px;display:flex;align-items:center;justify-content:center;position:relative;overflow:hidden}.staffPortrait:before{content:'PAUL';position:absolute;left:8px;bottom:7px;background:#111;color:#fff;padding:4px 7px;font-weight:1000}.staffTruckPreview{width:150px;height:70px;position:relative;background:#fff;border:4px solid #222;border-radius:10px 18px 7px 7px;box-shadow:7px 7px 0 rgba(0,0,0,.25)}.staffTruckPreview:before{content:'VANCERTS';position:absolute;left:48px;top:30px;background:#f4e6be;border:2px solid #111;padding:2px 5px;font-size:9px;font-weight:1000}.staffTruckPreview:after{content:'';position:absolute;left:15px;right:15px;bottom:-12px;height:22px;background:radial-gradient(circle at 15px 11px,#111 0 9px,transparent 10px),radial-gradient(circle at calc(100% - 15px) 11px,#111 0 9px,transparent 10px)}.staffStatus{display:inline-block;padding:4px 7px;border:2px solid #222;background:#ddd;font-size:10px;font-weight:1000}.staffStatus.hired{background:#79c88e}.staffStatus.scheduled{background:#f1b83e}.financeMetric.deduction{border-color:#315d3b}.financeMetric.estimate{border-color:#777}.ledgerRow.estimate .ledgerAmount{color:#666}.ledgerRow{grid-template-columns:76px minmax(140px,1fr) 95px}.expenseActions{display:flex;gap:7px;flex-wrap:wrap;margin:9px 0}.expenseActions button{flex:1 1 180px}.receiptNote{font-size:9px;color:#5d5747;line-height:1.35} @media(max-width:760px),(pointer:coarse){.staffRoster{grid-template-columns:1fr}.receiptGrid{grid-template-columns:1fr}.receiptCard{padding:8px}.receiptLine{font-size:10px}.ledgerRow{grid-template-columns:61px minmax(96px,1fr) 72px}.receiptMini{font-size:7px!important}} /* R36B43A — mandatory city driver-permit gate shown after Play. */ .permitGateShell{max-width:820px;margin:auto;background:linear-gradient(145deg,#efe5bb,#d5c485);border:6px solid #171514;box-shadow:10px 10px 0 #e64a38;color:#171514;padding:16px;position:relative;overflow:hidden} .permitGateShell:before{content:"CITY OF AUSTIN • MOBILE EVENT OPERATIONS";display:block;background:#171514;color:#f4e6be;padding:8px 12px;margin:-16px -16px 14px;font:1000 11px/1 system-ui;letter-spacing:.12em;text-align:center} .permitGateTitle{display:flex;align-items:flex-end;justify-content:space-between;gap:10px;border-bottom:5px solid #171514;padding-bottom:9px;margin-bottom:12px}.permitGateTitle h2{margin:0!important;font-size:clamp(24px,5vw,42px);line-height:.95}.permitGateTitle b{background:#e64a38;color:#fff;border:3px solid #171514;padding:6px 9px;white-space:nowrap} .permitGateGrid{display:grid;grid-template-columns:minmax(220px,42%) 1fr;gap:15px}.permitGatePhoto{position:relative;background:#111;border:5px solid #171514;min-height:250px;overflow:hidden}.permitGatePhoto img{display:block;width:100%;height:100%;min-height:250px;object-fit:cover;object-position:center;image-rendering:auto}.permitGatePhoto:after{content:"BACKUP ID PHOTO • VANCERTS VAN";position:absolute;left:7px;right:7px;bottom:7px;background:rgba(23,21,20,.86);color:#fff8e5;border:2px solid #f4e6be;padding:5px;text-align:center;font:1000 9px/1.1 system-ui;letter-spacing:.06em} .permitGateFields{display:flex;flex-direction:column;gap:9px}.permitGateFields label{font-weight:1000;letter-spacing:.05em}.permitGateFields input{width:100%;padding:12px;border:4px solid #171514;background:#fffef2;font-size:18px;font-weight:1000}.permitGateId{background:#fff8e5;border:3px dashed #171514;padding:10px;font:1000 11px/1.35 monospace}.permitGateNote{background:#e8f2df;border:3px solid #315d3b;padding:9px;font-size:11px;line-height:1.35}.permitGateActions{display:grid;grid-template-columns:1fr 1fr;gap:8px}.permitGateActions button{min-height:52px}.permitGateIssue{grid-column:1/-1;background:#4c9a65!important;color:#fff;font-size:17px!important}.permitGateLock{text-align:center;margin-top:10px;font:1000 10px/1.25 system-ui;letter-spacing:.06em} .permitLetterLaunch{width:100%;margin-top:6px;background:#3f84a5;color:#fff}.permitLetterBox{margin-top:8px;padding:10px;background:#171514;color:#fff;border:4px solid #e64a38}.permitLetterBox.hidden{display:none!important}.permitLetterDisplay{min-height:45px;background:#fffef2;color:#171514;border:3px solid #f1b83e;padding:9px;font:1000 20px/1.15 monospace;word-break:break-word;margin-bottom:8px}.permitKeyboard{display:grid;grid-template-columns:repeat(7,minmax(38px,1fr));gap:6px}.permitKeyboard button{min-height:42px;padding:6px 4px;box-shadow:2px 2px 0 #000}.permitKeyboard .wide{grid-column:span 2}.permitKeyboard .done{grid-column:span 3;background:#79c88e}.permitKeyboard .back{background:#ddd}.permitKeyboard .clear{background:#e64a38;color:#fff}.equipment button.gearPartial{background:#f1df8a;color:#171514}.equipment button.gearEnough{background:#79c88e;color:#17351f;opacity:.68;filter:saturate(.8)}.equipment button.gearEnough:after{content:" ✓"}.controllerScrollHint{display:block;margin:7px 0 0;font:1000 10px/1.2 system-ui;color:#315d3b;letter-spacing:.04em} @media(max-width:700px){.permitKeyboard{grid-template-columns:repeat(6,minmax(36px,1fr))}.permitKeyboard button{min-height:40px}} .permitCareerGrid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:7px}.permitCareerChoice{display:block;border:3px solid #171514;background:#fff8e5;padding:8px;font-size:10px;font-weight:1000;cursor:pointer}.permitCareerChoice input{width:auto!important;margin-right:5px}.permitCareerChoice:has(input:checked){background:#79c88e;box-shadow:3px 3px 0 #171514}.permitBandName{display:none}.permitBandName.show{display:block} @media(max-width:700px){.permitGateShell{padding:11px}.permitGateShell:before{margin:-11px -11px 11px}.permitGateGrid{grid-template-columns:1fr}.permitGatePhoto{min-height:170px;max-height:220px}.permitGatePhoto img{min-height:170px}.permitGateTitle{align-items:center}.permitGateTitle b{font-size:9px}.permitGateActions{grid-template-columns:1fr 1fr}.permitGateIssue{font-size:14px!important}} /* R36B41B — restored intro permit setup + Nookia touchscreen app launcher. */ .introPermitSetup{margin:14px auto 10px;max-width:700px;border:4px solid #171514;background:#efe5bb;padding:12px;text-align:left;box-shadow:5px 5px 0 #e64a38} .introPermitSetup h3{margin:0 0 8px}.introPermitGrid{display:grid;grid-template-columns:minmax(150px,220px) 1fr;gap:12px;align-items:stretch}.introPermitPreview{border:4px solid #171514;background:#d8c88f;min-height:125px;display:grid;place-items:center;text-align:center;font-weight:1000;overflow:hidden}.introPermitPreview img{width:100%;height:100%;min-height:125px;object-fit:cover;image-rendering:pixelated}.introPermitFields input{box-sizing:border-box;width:100%;padding:11px;border:3px solid #171514;background:#fffef2;font-weight:900;margin:5px 0 8px}.introPermitId{padding:7px;border:2px dashed #171514;background:#fff8e5;font:900 10px monospace}.introPermitSetup .small{display:block;margin-top:6px} .phone{background:linear-gradient(145deg,#1e2427,#080b0c)!important;border-color:#0b0d0e!important;border-radius:24px!important;padding:10px!important;box-shadow:7px 7px 0 rgba(0,0,0,.55),inset 0 0 0 2px #69767b!important}.phoneBrand{color:#e7f4f5!important;text-shadow:none!important;letter-spacing:.18em!important}.phoneScreen{height:157px!important;background:#9fc6bb!important;border:4px solid #3b4c4d!important;border-radius:10px!important;box-shadow:inset 0 0 12px rgba(0,0,0,.25)!important}.phoneScreen canvas{height:105px!important}.phoneStatus{border-top-color:#466d64!important;color:#10211e!important}.phoneNav{display:none!important}.phoneKeys{display:grid!important;grid-template-columns:repeat(3,minmax(0,1fr))!important;gap:6px!important;padding:7px 0 0!important}.phoneKeys .phoneApp{height:50px!important;min-height:50px!important;border:2px solid #d9e3e1!important;border-radius:11px!important;background:linear-gradient(#eff7f5,#aac8c1)!important;color:#10211e!important;box-shadow:0 3px 0 #334443!important;font:1000 8px/1.05 system-ui!important;display:flex!important;flex-direction:column!important;align-items:center!important;justify-content:center!important;gap:3px!important}.phoneKeys .phoneApp span{font-size:18px;line-height:1}.phoneKeys .phoneApp.alert{background:#f1b83e!important;outline:2px solid #fff}.phoneHint{color:#dce8e8!important;margin-top:7px!important}.phone.collapsed .phoneBrand:after{content:'▣'!important}.phone.collapsed .phoneKeys{display:none!important} .dialerDisplay{background:#9fc6bb;border:4px solid #263637;border-radius:9px;padding:12px;font:1000 22px/1.1 monospace;text-align:center;min-height:48px;overflow-wrap:anywhere}.dialerPad{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:9px;margin:12px 0}.dialerPad button{min-height:54px;font-size:20px}.dialerActions{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:9px}.phone{height:494px!important}.phoneKeys{overflow:auto!important;max-height:292px!important} @media(max-width:760px),(pointer:coarse){.introPermitGrid{grid-template-columns:1fr}.phone{width:230px!important;height:510px!important}.phoneScreen{height:165px!important}.phoneKeys .phoneApp{height:58px!important;min-height:58px!important;font-size:9px!important}.phoneKeys .phoneApp span{font-size:21px}} /* R36B42A — Community Radio behaves as a true Nookia app and returns to the phone home screen. */ .phone.radioAppOpen{height:510px!important} .phone.radioAppOpen>.phoneScreen,.phone.radioAppOpen>.phoneNav,.phone.radioAppOpen>.phoneKeys,.phone.radioAppOpen>.phoneHint,.phone.radioAppOpen>.phoneBigReset{display:none!important} #rotaryRadio.inPhoneApp{ position:absolute!important;left:8px!important;right:8px!important;top:43px!important;bottom:8px!important; width:auto!important;height:auto!important;min-width:0!important;max-height:none!important; transform:none!important;margin:0!important;z-index:30!important;display:block!important; } #rotaryRadio.inPhoneApp .radioCabinet{width:100%!important;height:100%!important;box-sizing:border-box!important;border-radius:12px!important} #rotaryRadio.inPhoneApp .radioCollapse{font-size:0!important} #rotaryRadio.inPhoneApp .radioCollapse:after{content:'BACK'!important;font:1000 6.5px/1 monospace!important} #rotaryRadio.inPhoneApp.collapsed{width:auto!important;height:auto!important;min-width:0!important} #rotaryRadio.inPhoneApp.collapsed .radioCabinet{display:flex!important} .phoneKeys .spotifyAppIcon{width:18px;height:18px;display:block!important} .phoneKeys .spotifyAppIcon circle{fill:#1ed760} .phoneKeys .spotifyAppIcon path{fill:none;stroke:#07120b;stroke-width:2.2;stroke-linecap:round} .phoneNowPlayingPrefix{font-weight:1000} /* R36B41I — compact phone home: Community Radio label, no Map app, Reset moved to Map position, plus large bottom Reset. */ .controlBar{display:none!important} .phoneKeys{grid-template-columns:repeat(4,minmax(0,1fr))!important;gap:4px!important;padding-top:5px!important} .phoneKeys .phoneApp{height:39px!important;min-height:39px!important;padding:2px 1px!important;border-width:1px!important;border-radius:8px!important;box-shadow:0 2px 0 #334443!important;font-size:6.5px!important;line-height:1!important;gap:1px!important} .phoneKeys .phoneApp span{font-size:14px!important;line-height:1!important} #phoneFullscreenApp.active{background:#e64a38!important;color:#fff!important;outline:2px solid #fff} .phoneBigReset{box-sizing:border-box;width:100%;min-height:42px;margin:7px 0 0;padding:8px 10px;border:3px solid #f3d7d2;border-radius:12px;background:linear-gradient(#e95d50,#ae241c);color:#fff;box-shadow:0 3px 0 #3b0907;font:1000 11px/1 system-ui;letter-spacing:.08em}.phoneBigReset:active{transform:translateY(2px);box-shadow:0 1px 0 #3b0907}.phoneBigReset span{font-size:15px;margin-right:6px}.phoneHint{margin-top:5px!important} @media(max-width:760px),(pointer:coarse){.phone{height:510px!important}.phoneKeys .phoneApp{height:41px!important;min-height:41px!important;font-size:6.4px!important}.phoneKeys .phoneApp span{font-size:15px!important}.phoneBigReset{min-height:46px;font-size:12px}} @media(max-width:430px){.phone{width:224px!important}.phoneKeys{gap:3px!important}.phoneKeys .phoneApp{font-size:5.8px!important;padding:1px!important}} /* R36B42B — symmetrical Nookia app grid, fitted Community Radio app, and full landscape phone visibility. */ #phoneResetApp{display:none!important} .phoneKeys{ grid-template-columns:repeat(4,minmax(0,1fr))!important; grid-auto-rows:41px!important; gap:4px!important; overflow:visible!important; max-height:none!important; } .phoneKeys .phoneApp{ width:100%!important;height:41px!important;min-height:41px!important; margin:0!important;padding:2px!important;box-sizing:border-box!important; overflow:hidden!important;text-align:center!important; } .phoneKeys .phoneApp svg,.phoneKeys .phoneApp span{flex:0 0 auto!important} .phoneKeys .phoneApp#phoneFullscreenApp{font-size:5.7px!important;letter-spacing:-.01em!important} /* Radio is a real fitted phone app: never wider or taller than the Nookia screen. */ .phone.radioAppOpen{height:510px!important;overflow:hidden!important} #rotaryRadio.inPhoneApp{ position:absolute!important;inset:45px 10px 10px 10px!important; width:auto!important;height:auto!important;max-width:none!important;max-height:none!important; min-width:0!important;transform:none!important;filter:none!important;overflow:hidden!important; } #rotaryRadio.inPhoneApp .radioCabinet{ width:100%!important;height:100%!important;min-width:0!important; display:grid!important;grid-template-rows:32px 22px minmax(0,1fr) 38px 22px!important; padding:5px!important;box-sizing:border-box!important;overflow:hidden!important; transform:none!important;transform-origin:top left!important; } #rotaryRadio.inPhoneApp .radioTop{height:auto!important;min-height:0!important;grid-template-columns:38px minmax(0,1fr)!important} #rotaryRadio.inPhoneApp .radioBrand{font-size:7px!important;line-height:.9!important} #rotaryRadio.inPhoneApp .radioDisplay{min-width:0!important;height:28px!important;padding:2px 4px!important} #rotaryRadio.inPhoneApp .radioDialScale{font-size:5px!important} #rotaryRadio.inPhoneApp .radioDisplay small,#rotaryRadio.inPhoneApp .radioTicker span{font-size:6px!important} #rotaryRadio.inPhoneApp .spotifySafety{height:auto!important;min-height:0!important;padding:3px!important;font-size:5.2px!important;white-space:normal!important;overflow:hidden!important} #rotaryRadio.inPhoneApp .spotifyEmbed,#rotaryRadio.inPhoneApp .spotifyEmbed iframe{ width:100%!important;height:100%!important;min-height:0!important;max-height:none!important; border:0!important;display:block!important;overflow:hidden!important; } #rotaryRadio.inPhoneApp .spotify512Actions{display:grid!important;grid-template-columns:repeat(3,minmax(0,1fr))!important;gap:3px!important;padding:3px 0!important;min-width:0!important} #rotaryRadio.inPhoneApp .spotify512Actions button{min-width:0!important;height:30px!important;min-height:30px!important;padding:2px!important;font-size:5.6px!important;white-space:normal!important;line-height:1!important;overflow:hidden!important} #rotaryRadio.inPhoneApp .spotify512Foot{font-size:4.8px!important;line-height:1.1!important;height:auto!important;overflow:hidden!important;padding:2px!important} #rotaryRadio.inPhoneApp .radioCollapse{top:3px!important;right:3px!important;width:38px!important;height:24px!important;z-index:8!important} /* Full landscape mode keeps the entire phone, apps, labels and reset control visible. */ @media (pointer:coarse) and (orientation:landscape){ .phone:not(.collapsed),html.mobileFullscreen .phone:not(.collapsed){ display:block!important;width:230px!important;height:510px!important; right:max(6px,env(safe-area-inset-right))!important; bottom:max(6px,env(safe-area-inset-bottom))!important; transform:scale(var(--landscape-phone-scale,.62))!important; transform-origin:bottom right!important;overflow:hidden!important; } .phone:not(.collapsed) .phoneScreen{display:block!important;height:165px!important} .phone:not(.collapsed) .phoneKeys{display:grid!important;grid-template-columns:repeat(4,minmax(0,1fr))!important;grid-auto-rows:41px!important;max-height:none!important;overflow:visible!important} .phone:not(.collapsed) .phoneHint{display:block!important;margin-top:5px!important} .phone:not(.collapsed) .phoneBigReset{display:block!important} .phone.radioAppOpen:not(.collapsed)>.phoneScreen,.phone.radioAppOpen:not(.collapsed)>.phoneKeys,.phone.radioAppOpen:not(.collapsed)>.phoneHint,.phone.radioAppOpen:not(.collapsed)>.phoneBigReset{display:none!important} } @media (pointer:coarse) and (orientation:landscape) and (max-height:430px){ .phone:not(.collapsed),html.mobileFullscreen .phone:not(.collapsed){--landscape-phone-scale:.55} } @media (pointer:coarse) and (orientation:landscape) and (max-height:380px){ .phone:not(.collapsed),html.mobileFullscreen .phone:not(.collapsed){--landscape-phone-scale:.49} } /* R36B42C — radio opens only from the phone, floats above the game, and is fully off-screen when closed. */ .phone.radioAppOpen{height:494px!important;overflow:visible!important} .phone.radioAppOpen>.phoneScreen,.phone.radioAppOpen>.phoneKeys,.phone.radioAppOpen>.phoneHint,.phone.radioAppOpen>.phoneBigReset{display:initial!important} .rotaryRadio.radioOverlayOpen{ position:fixed!important;z-index:140!important;width:min(620px,92vw)!important;height:min(560px,82vh)!important; max-width:92vw!important;max-height:82vh!important;display:block!important;overflow:hidden!important; } .rotaryRadio.radioOverlayOpen .radioCabinet{ box-sizing:border-box!important;width:100%!important;height:100%!important;transform:none!important;transform-origin:center!important; display:flex!important;flex-direction:column!important;padding:10px!important; } .rotaryRadio.radioOverlayOpen .radioTop{flex:0 0 auto!important;height:62px!important;grid-template-columns:100px minmax(0,1fr)!important} .rotaryRadio.radioOverlayOpen .spotifySafety{flex:0 0 auto!important} .rotaryRadio.radioOverlayOpen .spotifyEmbed{flex:1 1 auto!important;min-height:0!important;height:auto!important;overflow:hidden!important} .rotaryRadio.radioOverlayOpen .spotifyEmbed iframe{width:100%!important;height:100%!important;min-height:0!important;border:0!important} .rotaryRadio.radioOverlayOpen .spotify512Actions{flex:0 0 auto!important} .rotaryRadio.radioOverlayOpen .spotify512Foot{flex:0 0 auto!important} .rotaryRadio.hidden{display:none!important;visibility:hidden!important;pointer-events:none!important} @media (orientation:landscape) and (max-height:560px){ .rotaryRadio.radioOverlayOpen{width:min(760px,88vw)!important;height:min(430px,88vh)!important} .rotaryRadio.radioOverlayOpen .radioTop{height:48px!important;grid-template-columns:82px minmax(0,1fr)!important} .rotaryRadio.radioOverlayOpen .spotify512Foot{font-size:7px!important} } /* R36B42D — tape radio + universal Nookia fit. */ .phoneKeys .tapeAppIcon{display:grid!important;place-items:center;width:18px;height:14px!important;border:2px solid #10211e;border-radius:3px;background:#d6c39a;color:#10211e;font:1000 10px/1 monospace!important;box-shadow:inset 0 -3px 0 #7f6845} .phoneKeys{grid-template-columns:repeat(4,minmax(0,1fr))!important;grid-auto-rows:41px!important;overflow:visible!important;max-height:none!important} .phoneKeys .phoneApp{min-width:0!important;width:100%!important;overflow:hidden!important;text-align:center!important;white-space:normal!important} .phone:not(.collapsed){right:10px!important;bottom:10px!important;left:auto!important;top:auto!important;width:230px!important;height:510px!important;transform:scale(var(--phone-fit-scale,1))!important;transform-origin:bottom right!important;max-width:none!important;max-height:none!important} .phone:not(.collapsed) .phoneScreen{height:165px!important}.phone:not(.collapsed) .phoneBigReset{display:block!important;margin-top:7px!important}.phone.collapsed{transform:none!important} #rotaryRadio.radioOverlayOpen .radioCabinet{background:linear-gradient(145deg,#c9b386,#8f754c)!important;border-color:#211b13!important;box-shadow:inset 0 0 0 5px #4f3e29,8px 8px 0 rgba(0,0,0,.65)!important} #rotaryRadio.radioOverlayOpen .radioTop{background:linear-gradient(#26231d,#111)!important;border:4px solid #493b28!important;position:relative!important;overflow:hidden!important} #rotaryRadio.radioOverlayOpen .radioTop:before,#rotaryRadio.radioOverlayOpen .radioTop:after{content:'';position:absolute;top:50%;width:34px;height:34px;margin-top:-17px;border:5px solid #d8c59b;border-radius:50%;background:radial-gradient(circle,#17130e 0 5px,#9b845b 6px 10px,#231d15 11px 16px,#c9b386 17px);box-sizing:border-box;opacity:.95} #rotaryRadio.radioOverlayOpen .radioTop:before{left:52px}#rotaryRadio.radioOverlayOpen .radioTop:after{right:52px} #rotaryRadio.radioOverlayOpen .radioBrand{background:#d8c59b!important;color:#1f1a13!important;border-color:#211b13!important;text-shadow:none!important} #rotaryRadio.radioOverlayOpen .radioDisplay{background:#171a13!important;border-color:#d8c59b!important;color:#efcf67!important} #rotaryRadio.radioOverlayOpen .spotifySafety{background:#e4d4ad!important;color:#2b2318!important;border-color:#4f3e29!important} #rotaryRadio.radioOverlayOpen .spotify512Actions button{background:linear-gradient(#e0d0a9,#9e8459)!important;color:#1d1811!important;border-color:#211b13!important;box-shadow:0 3px 0 #211b13!important} #rotaryRadio.radioOverlayOpen .spotify512Foot{background:#2a241b!important;color:#e7d5ab!important} @media(max-height:620px){.phone:not(.collapsed){bottom:6px!important;right:6px!important}} /* R36B42H — universal Nookia aspect-fit hotfix. One complete phone in every viewport. */ .phone:not(.collapsed),html.mobileFullscreen .phone:not(.collapsed){ position:fixed!important; width:230px!important; height:510px!important; left:auto!important; right:var(--nookia-right,10px)!important; top:var(--nookia-top,10px)!important; bottom:auto!important; transform:scale(var(--phone-fit-scale,1))!important; transform-origin:top right!important; overflow:hidden!important; max-width:none!important; max-height:none!important; z-index:73!important; } .phone:not(.collapsed) .phoneScreen{display:block!important;height:165px!important} .phone:not(.collapsed) .phoneKeys{ display:grid!important; grid-template-columns:repeat(4,minmax(0,1fr))!important; grid-auto-rows:41px!important; gap:4px!important; max-height:none!important; overflow:visible!important; } .phone:not(.collapsed) .phoneHint{display:block!important;margin-top:5px!important} .phone:not(.collapsed) .phoneBigReset{display:block!important;margin-top:7px!important} .phone:not(.collapsed).radioAppOpen>.phoneScreen, .phone:not(.collapsed).radioAppOpen>.phoneKeys, .phone:not(.collapsed).radioAppOpen>.phoneHint, .phone:not(.collapsed).radioAppOpen>.phoneBigReset{display:block!important} @media (orientation:landscape){ .phone:not(.collapsed),html.mobileFullscreen .phone:not(.collapsed){width:230px!important;height:510px!important} } /* R36B42H — remove unused black space below Reset Story while preserving universal phone scaling. */ .phone:not(.collapsed),html.mobileFullscreen .phone:not(.collapsed){height:430px!important} @media (orientation:landscape){.phone:not(.collapsed),html.mobileFullscreen .phone:not(.collapsed){height:430px!important}} /* R36B46A — animated VANCERTS brand intro and in-game watermark. */ #vancertsBrandIntro{position:fixed;inset:0;z-index:140;background:#080808;display:flex;align-items:center;justify-content:center;overflow:hidden;cursor:pointer;transition:opacity .42s ease,visibility .42s ease} #vancertsBrandIntro.done{opacity:0;visibility:hidden;pointer-events:none} .vbiScene{position:relative;width:min(980px,96vw);height:min(520px,72vh);overflow:hidden} .vbiRoad{position:absolute;left:0;right:0;top:58%;height:5px;background:rgba(255,255,255,.18);box-shadow:0 24px 0 rgba(255,255,255,.05)} .vbiTrail{position:absolute;left:10%;right:15%;top:50%;height:8px;background:linear-gradient(90deg,transparent,#e33b2f 20%,#f4e6be 78%,transparent);transform:scaleX(0);transform-origin:left;animation:vbiPaint 1.55s .45s cubic-bezier(.2,.7,.2,1) forwards;filter:drop-shadow(0 0 12px rgba(230,74,56,.75))} .vbiVan{position:absolute;top:22%;left:0;width:min(620px,68vw);max-height:58%;object-fit:contain;filter:drop-shadow(0 18px 16px rgba(0,0,0,.55));transform:translateX(-110%);animation:vbiDrive 1.75s .18s cubic-bezier(.18,.78,.2,1) forwards} .vbiTag{position:absolute;left:0;right:0;bottom:9%;text-align:center;font-weight:1000;font-size:clamp(18px,3.7vw,38px);letter-spacing:.055em;color:#f4e6be;text-shadow:4px 4px 0 #e64a38;opacity:0;transform:translateY(16px);animation:vbiTagIn .55s 1.58s ease forwards} .vbiSkip{position:absolute;right:18px;bottom:16px;color:rgba(255,255,255,.55);font:800 11px system-ui;letter-spacing:.09em} @keyframes vbiDrive{0%{transform:translateX(-110%) rotate(-2deg)}70%{transform:translateX(26%) rotate(1deg)}100%{transform:translateX(18%) rotate(0)}} @keyframes vbiPaint{to{transform:scaleX(1)}} @keyframes vbiTagIn{to{opacity:1;transform:translateY(0)}} #vancertsHudMark{position:fixed;z-index:7;right:20px;top:108px;width:clamp(150px,16vw,285px);height:auto;opacity:.24;pointer-events:none;user-select:none;filter:drop-shadow(0 8px 8px rgba(0,0,0,.5));mix-blend-mode:screen;animation:vmarkBreathe 9s ease-in-out infinite;transition:opacity .3s ease,filter .3s ease,transform .3s ease} #vancertsHudMark.pulse{opacity:.62;filter:drop-shadow(0 0 16px rgba(244,230,190,.95)) drop-shadow(0 10px 10px rgba(0,0,0,.7));transform:scale(1.045)} @keyframes vmarkBreathe{0%,100%{opacity:.2}50%{opacity:.29}} @media(max-width:760px),(pointer:coarse){#vancertsHudMark{top:126px;right:8px;width:128px;opacity:.2}.vbiVan{width:84vw;top:28%}.vbiTag{bottom:16%;font-size:clamp(16px,5vw,24px)}} @media(prefers-reduced-motion:reduce){.vbiVan,.vbiTrail,.vbiTag,#vancertsHudMark{animation:none!important}.vbiVan{transform:translateX(18%)}.vbiTrail{transform:scaleX(1)}.vbiTag{opacity:1;transform:none}} /* R36B46D — exact supplied logo in left HUD, phone training control, save-center reset, unified van shadows. */ .brandLogoSlot{padding:2px 5px!important;background:transparent!important;border:0!important;box-shadow:none!important;overflow:visible!important;display:flex!important;align-items:center!important;justify-content:flex-start!important} .brandExactLogo{display:block;width:min(100%,230px);height:auto;max-height:74px;object-fit:contain;object-position:left center;opacity:.24;filter:drop-shadow(0 5px 5px rgba(0,0,0,.55));pointer-events:none;user-select:none} #vancertsHudMark{display:none!important} .phoneReset{font-size:7px!important;line-height:1!important;white-space:normal!important} .phoneReset.off{background:#555!important;color:#fff!important} .phoneHint{font-size:12px!important;letter-spacing:.14em!important;font-weight:1000!important;text-align:center!important} @media(max-width:760px),(pointer:coarse){.brandLogoSlot{height:38px!important;padding:1px 3px!important}.brandExactLogo{width:124px!important;max-height:35px!important;opacity:.24}.phoneHint{font-size:9px!important}} /* R36B46F — top HUD objective, exact-center Training key, transparent bottom-left logo. */ .top{grid-template-columns:minmax(420px,1fr) minmax(310px,auto)!important;align-items:stretch!important} .objectiveTop{position:relative!important;left:auto!important;right:auto!important;top:auto!important;bottom:auto!important;width:auto!important;max-width:none!important;min-height:96px!important;max-height:132px!important;overflow:auto!important;padding:12px 15px!important;font-size:15px!important;line-height:1.35!important;z-index:9!important;display:block!important} .objectiveTop #objectiveTitle{font-size:17px!important;letter-spacing:.08em} .objectiveTop #objectiveText{font-size:14px!important} .hudBottomLogoPlate{position:fixed;left:10px;bottom:10px;z-index:7;width:clamp(180px,18vw,310px);padding:7px 9px;background:rgba(72,75,78,.42);border:2px solid rgba(244,230,190,.32);box-shadow:4px 4px 0 rgba(0,0,0,.34);pointer-events:none;user-select:none} .hudBottomLogo{display:block;width:100%;height:auto;opacity:.24;filter:drop-shadow(0 5px 5px rgba(0,0,0,.5))} .phoneNav{grid-template-columns:repeat(3,minmax(0,1fr))!important} .phoneCall,.phoneReset,.phoneMail{width:100%!important;height:28px!important;min-height:28px!important;font-size:9px!important;border-radius:14px!important} .phoneReset{grid-column:auto!important;grid-row:auto!important;padding:0!important;white-space:nowrap!important} @media(max-width:760px),(pointer:coarse){ .top{grid-template-columns:1fr!important;grid-template-rows:auto auto!important} .stats{grid-column:1!important;grid-row:1!important} .objectiveTop{grid-column:1!important;grid-row:2!important;min-height:82px!important;max-height:96px!important;width:100%!important;font-size:11px!important;padding:8px 10px!important} .objectiveTop #objectiveTitle{font-size:12px!important} .objectiveTop #objectiveText{font-size:10px!important} .hudBottomLogoPlate{left:8px;bottom:148px;width:126px;padding:4px 5px;background:rgba(72,75,78,.38);border-width:1px;box-shadow:2px 2px 0 rgba(0,0,0,.32)} .hudBottomLogo{opacity:.24} .phoneCall,.phoneReset,.phoneMail{height:44px!important;min-height:44px!important;font-size:10px!important} } @media(pointer:coarse) and (orientation:landscape){ .objectiveTop{min-height:56px!important;max-height:68px!important;font-size:9px!important;padding:5px 8px!important} .objectiveTop #objectiveTitle{font-size:10px!important} .objectiveTop #objectiveText{font-size:8px!important} .hudBottomLogoPlate{bottom:76px;width:112px} } /* R36B46F mobile objective full-width correction. */ @media(max-width:760px),(pointer:coarse){ .objectiveTop{position:fixed!important;left:6px!important;right:6px!important;top:54px!important;bottom:auto!important;width:auto!important;max-width:none!important;min-height:76px!important;max-height:94px!important;z-index:58!important} } @media(pointer:coarse) and (orientation:landscape){ .objectiveTop{top:48px!important;min-height:52px!important;max-height:66px!important} } /* R36B46F restore the three-button quick row so Training occupies the former Reset key. */ .phoneNav{display:grid!important;grid-template-columns:repeat(3,minmax(0,1fr))!important;gap:7px!important;margin:7px 2px 6px!important} .phone:not(.collapsed){height:456px!important} .phoneKeys .phoneApp{height:43px!important;min-height:43px!important} @media(max-width:760px),(pointer:coarse){ .phoneNav{display:grid!important;gap:6px!important;margin:6px 1px 5px!important} .phoneKeys .phoneApp{height:42px!important;min-height:42px!important} } @media(pointer:coarse) and (orientation:landscape){ .phone:not(.collapsed){height:264px!important} .phoneNav{display:grid!important} } /* R36B46F — restore phone-first objective, remove logo treatment, clean vans, notifications, and home borders. */ #vancertsBrandIntro,#vancertsHudMark,.hudBottomLogoPlate,.brandLogoSlot,.brandExactLogo{display:none!important} .objectiveTop{display:none!important} .top{grid-template-columns:1fr!important} .stats{width:min(620px,100%);margin-left:auto!important} .phone:not(.collapsed){height:500px!important} .phoneScreen{height:188px!important;padding:5px!important} .phoneScreen canvas{height:76px!important} .phoneObjective{height:74px;margin-top:2px;padding:4px 5px;background:rgba(23,32,22,.12);border-top:2px solid #5b6a4b;overflow:hidden;font:900 8px/1.18 monospace;color:#172016} .phoneObjective b{display:block;font-size:9px;letter-spacing:.05em;margin-bottom:2px} .phoneObjective span{display:block} .phoneStatus{font-size:8px;padding-top:2px} .phoneLegacyQuick{display:none!important} .phoneHint{margin-top:6px!important;margin-bottom:4px!important} .phoneTraining{display:block;width:calc(100% - 10px);height:31px;margin:0 5px;padding:0;border:2px solid #222;border-radius:14px;box-shadow:none;background:#c7352d;color:#fff;font-size:9px;font-weight:1000;letter-spacing:.06em} .phoneTraining.off{background:#555!important} .phoneApp{position:relative} .appBadge{position:absolute;right:-5px;top:-6px;min-width:17px;height:17px;padding:0 4px;border-radius:10px;background:#e64a38;color:#fff;border:2px solid #fff8e5;font:1000 9px/13px system-ui;text-align:center;font-style:normal;box-shadow:1px 1px 0 #111} .appBadge[hidden]{display:none!important} @media(max-width:760px),(pointer:coarse){.phone:not(.collapsed){height:500px!important}.phoneTraining{height:39px;font-size:10px}.stats{width:100%}.phoneObjective{font-size:8px}} @media(pointer:coarse) and (orientation:landscape){.phone:not(.collapsed){height:325px!important}.phoneScreen{height:130px!important}.phoneScreen canvas{height:52px!important}.phoneObjective{height:46px;font-size:6px}.phoneObjective b{font-size:7px}.phoneKeys .phoneApp{height:30px!important;min-height:30px!important}.phoneTraining{height:26px;font-size:7px}.phoneHint{font-size:7px!important;margin:2px 0!important}} /* R36B46G — final HUD alignment, responsive objective placement, wider home streets, and tighter Nookia shell. */ .top{display:block!important;height:0!important;min-height:0!important} .stats{position:fixed!important;top:10px!important;left:390px!important;right:10px!important;width:auto!important;min-width:0!important;margin:0!important;display:grid!important;grid-template-columns:repeat(6,minmax(0,1fr))!important;gap:6px!important;z-index:64!important} .chip{min-width:0!important;overflow:hidden!important;text-overflow:ellipsis!important;padding:7px 4px!important;font-size:clamp(8px,1vw,11px)!important;display:flex!important;align-items:center!important;justify-content:center!important} .objectiveTop{display:block!important;position:fixed!important;left:10px!important;top:10px!important;right:auto!important;bottom:auto!important;width:365px!important;max-width:365px!important;min-height:72px!important;max-height:122px!important;overflow:auto!important;padding:10px 13px!important;background:rgba(18,17,16,.94)!important;border:3px solid var(--paper)!important;box-shadow:4px 4px 0 #000!important;font-size:12px!important;line-height:1.25!important;z-index:63!important} .objectiveTop #objectiveTitle{font-size:14px!important;letter-spacing:.08em!important} .objectiveTop #objectiveText{font-size:12px!important} .phoneObjective{display:none!important} .phoneScreen{height:118px!important} .phoneScreen canvas{height:82px!important} .phoneStatus{font-size:8px!important} .phone:not(.collapsed){height:432px!important;padding-bottom:9px!important} .phoneKeys{gap:5px!important;padding-top:6px!important} .phoneKeys .phoneApp{height:42px!important;min-height:42px!important} .phoneHint{margin:4px 0 3px!important;font-size:10px!important;line-height:1!important} .phoneTraining{width:100%!important;height:48px!important;min-height:48px!important;margin:3px 0 0!important;border-radius:18px!important;font-size:12px!important;letter-spacing:.08em!important} @media(max-width:980px) and (pointer:fine){ .objectiveTop{width:300px!important;max-width:300px!important} .stats{left:320px!important} .chip{font-size:8px!important} } @media(max-width:760px),(pointer:coarse){ .hud{padding:0!important} .stats{top:calc(env(safe-area-inset-top,0px) + 4px)!important;left:4px!important;right:4px!important;width:auto!important;grid-template-columns:repeat(6,minmax(0,1fr))!important;gap:2px!important;height:38px!important} .chip{height:34px!important;padding:2px 1px!important;font-size:clamp(5.5px,1.65vw,8px)!important;border-width:2px!important;white-space:nowrap!important} .objectiveTop{left:8px!important;right:auto!important;top:auto!important;bottom:calc(env(safe-area-inset-bottom,0px) + 82px)!important;width:min(58vw,360px)!important;max-width:min(58vw,360px)!important;min-height:64px!important;max-height:102px!important;padding:7px 9px!important;font-size:10px!important;z-index:58!important} .objectiveTop #objectiveTitle{font-size:11px!important} .objectiveTop #objectiveText{font-size:9px!important} .phone:not(.collapsed){height:438px!important} .phoneTraining{height:52px!important;min-height:52px!important;font-size:12px!important} } @media(pointer:coarse) and (orientation:landscape){ .stats{height:34px!important} .chip{height:30px!important;font-size:7px!important} .objectiveTop{left:8px!important;bottom:74px!important;width:min(42vw,390px)!important;max-width:min(42vw,390px)!important;min-height:52px!important;max-height:78px!important;padding:5px 7px!important} .objectiveTop #objectiveTitle{font-size:9px!important} .objectiveTop #objectiveText{font-size:8px!important} .phone:not(.collapsed){height:300px!important} .phoneScreen{height:92px!important} .phoneScreen canvas{height:62px!important} .phoneKeys .phoneApp{height:31px!important;min-height:31px!important} .phoneHint{font-size:7px!important;margin:2px 0!important} .phoneTraining{height:34px!important;min-height:34px!important;font-size:8px!important} } /* R36B46H — evenly spaced Nookia apps, larger map, scrolling track credit, and tighter shell. */ html body .phone:not(.collapsed){height:468px!important;padding:9px 10px 8px!important} html body .phoneScreen{height:156px!important;padding:4px!important} html body .phoneScreen canvas{height:126px!important;width:100%!important} html body .phoneStatus{height:20px!important;line-height:18px!important;padding:1px 0 0!important;border-top:2px solid #466d64!important;overflow:hidden!important;white-space:nowrap!important;text-overflow:clip!important;animation:nookiaTrackScroll 16s linear infinite!important} @keyframes nookiaTrackScroll{0%,12%{text-indent:0}88%,100%{text-indent:-145%}} html body .phoneKeys{display:grid!important;grid-template-columns:repeat(4,minmax(0,1fr))!important;grid-template-rows:repeat(3,44px)!important;gap:5px!important;padding:6px 0 0!important;align-items:stretch!important} html body .phoneKeys .phoneApp{height:44px!important;min-height:44px!important;width:100%!important;margin:0!important;padding:2px 1px!important;display:flex!important;align-items:center!important;justify-content:center!important} html body .phoneHint{margin:5px 0 2px!important;line-height:1!important} html body .phoneTraining{height:47px!important;min-height:47px!important;margin:2px 0 0!important} html body .appBadge{right:-4px!important;top:-5px!important;z-index:4!important} @media(max-width:760px),(pointer:coarse){ html body .phone:not(.collapsed){height:472px!important} html body .phoneScreen{height:158px!important} html body .phoneScreen canvas{height:128px!important} html body .phoneKeys{grid-template-rows:repeat(3,45px)!important;gap:5px!important} html body .phoneKeys .phoneApp{height:45px!important;min-height:45px!important} html body .phoneTraining{height:49px!important;min-height:49px!important} } @media(pointer:coarse) and (orientation:landscape){ html body .phone:not(.collapsed){height:314px!important;padding:7px 8px!important} html body .phoneScreen{height:104px!important} html body .phoneScreen canvas{height:77px!important} html body .phoneStatus{height:16px!important;line-height:14px!important;font-size:7px!important} html body .phoneKeys{grid-template-rows:repeat(3,31px)!important;gap:3px!important;padding-top:4px!important} html body .phoneKeys .phoneApp{height:31px!important;min-height:31px!important} html body .phoneHint{margin:2px 0 1px!important;font-size:7px!important} html body .phoneTraining{height:31px!important;min-height:31px!important;font-size:8px!important} } /* R36B46I — compact Nookia shell, larger notification ticker, overlapping badges, and objective map marker. */ html body #phone.phone:not(.collapsed){height:430px!important;padding:9px 10px 7px!important} html body #phone .phoneScreen{height:170px!important;padding:4px!important} html body #phone .phoneScreen #miniCanvas{display:block!important;width:100%!important;height:126px!important;max-height:none!important} html body #phone .phoneStatus{display:block!important;height:36px!important;line-height:17px!important;padding:1px 3px!important;border-top:2px solid #466d64!important;overflow:hidden!important;white-space:nowrap!important;text-overflow:clip!important;font-size:9px!important;letter-spacing:.02em!important;animation:nookiaTrackScrollI 15s linear infinite!important} @keyframes nookiaTrackScrollI{0%,14%{text-indent:0}86%,100%{text-indent:-170%}} html body #phone .phoneKeys{grid-template-columns:repeat(4,minmax(0,1fr))!important;grid-template-rows:repeat(3,43px)!important;gap:5px!important;padding:5px 0 0!important} html body #phone .phoneKeys .phoneApp{height:43px!important;min-height:43px!important;margin:0!important} html body #phone .phoneHint{margin:4px 0 2px!important;line-height:1!important} html body #phone .phoneTraining{height:47px!important;min-height:47px!important;margin:2px 0 0!important} html body #phone .phoneApp{overflow:visible!important;position:relative!important} html body #phone .appBadge{right:-9px!important;top:-10px!important;z-index:20!important;min-width:22px!important;height:22px!important;padding:0 5px!important;border-radius:13px!important;border:2px solid #fff8e5!important;font:1000 10px/18px system-ui!important;box-shadow:2px 2px 0 rgba(0,0,0,.72)!important} @media(max-width:760px),(pointer:coarse){ html body #phone.phone:not(.collapsed){height:434px!important} html body #phone .phoneScreen{height:172px!important} html body #phone .phoneScreen #miniCanvas{height:128px!important} html body #phone .phoneStatus{height:36px!important;font-size:9px!important} html body #phone .phoneKeys{grid-template-rows:repeat(3,44px)!important} html body #phone .phoneKeys .phoneApp{height:44px!important;min-height:44px!important} html body #phone .phoneTraining{height:48px!important;min-height:48px!important} } @media(pointer:coarse) and (orientation:landscape){ html body #phone.phone:not(.collapsed){height:286px!important} html body #phone .phoneScreen{height:112px!important} html body #phone .phoneScreen #miniCanvas{height:76px!important} html body #phone .phoneStatus{height:28px!important;line-height:13px!important;font-size:7px!important} html body #phone .phoneKeys{grid-template-rows:repeat(3,29px)!important;gap:3px!important;padding-top:3px!important} html body #phone .phoneKeys .phoneApp{height:29px!important;min-height:29px!important} html body #phone .phoneHint{margin:2px 0 1px!important;font-size:7px!important} html body #phone .phoneTraining{height:30px!important;min-height:30px!important;font-size:8px!important} html body #phone .appBadge{right:-6px!important;top:-7px!important;min-width:17px!important;height:17px!important;font:1000 8px/13px system-ui!important} } /* R36B46L — unified manifest, permit camera, compact intro */ .equipmentManifest{margin:10px 0;padding:10px;border:3px solid #171514;background:#fff8e5;color:#171514}.equipmentManifest h4{margin:0 0 8px}.manifestLine{display:flex;justify-content:space-between;gap:12px;padding:5px 7px;border-bottom:1px dashed #6b624e}.manifestLine:last-child{border-bottom:0}.introBuildNotes{max-width:720px;margin:14px auto!important;line-height:1.45!important;color:#f4e6be!important;opacity:1!important}.permitGateActions button{min-height:48px} /* R36B46N: edit the portrait inside a live permit preview; keep every control visible. */ .permitGateActions{display:grid!important;grid-template-columns:repeat(2,minmax(0,1fr))!important;gap:9px!important;align-items:stretch!important} .permitGateActions button{width:100%!important;min-height:54px!important;margin:0!important;display:flex!important;align-items:center!important;justify-content:center!important;text-align:center!important} .permitGateCamera,.permitGateIssue{grid-column:1/-1!important} .permitGateCamera{min-height:60px!important;font-size:16px!important} .permitGateIssue{min-height:62px!important} .permitGatePhoto img{object-position:center center!important} .permitPhotoEditor{position:fixed;inset:0;z-index:190;background:rgba(0,0,0,.92);display:flex;align-items:center;justify-content:center;padding:14px;pointer-events:auto;overflow:auto} .permitPhotoEditor.hidden{display:none!important} .permitPhotoEditorPanel{width:min(920px,100%);max-height:94dvh;overflow:auto;background:#f4e6be;color:#171514;border:5px solid #171514;box-shadow:9px 9px 0 #e64a38;padding:16px} .permitPhotoEditorPanel h3{margin:0 0 5px;font-size:24px}.permitPhotoEditorHelp{margin:0 0 12px;font-size:12px;font-weight:800;line-height:1.35} .permitPhotoEditorLayout{display:grid;grid-template-columns:minmax(360px,1.2fr) minmax(250px,.8fr);gap:16px;align-items:start} .permitPhotoCard{background:#efe3bd;border:5px solid #171514;padding:12px;box-shadow:5px 5px 0 rgba(0,0,0,.28);min-width:0} .permitPhotoCardHead{display:flex;justify-content:space-between;align-items:start;gap:10px;padding-bottom:8px;border-bottom:3px solid #171514} .permitPhotoCardHead strong{font:1000 22px/1 system-ui;letter-spacing:.03em}.permitPhotoCardHead span{background:#df3d3b;color:#fff;padding:6px 8px;border:3px solid #171514;font:1000 10px/1 system-ui;white-space:nowrap} .permitPhotoCardBody{display:grid;grid-template-columns:minmax(150px,190px) 1fr;gap:12px;padding-top:11px;align-items:stretch} .permitPhotoCanvasWrap{position:relative;background:#111;border:4px solid #171514;display:flex;align-items:center;justify-content:center;overflow:hidden;aspect-ratio:3/4;min-height:0} #permitPhotoCanvas{display:block;width:100%;height:100%;background:#222;image-rendering:auto;touch-action:none;object-fit:cover} .permitPhotoCardInfo{display:grid;align-content:start;gap:8px;min-width:0}.permitPhotoCardLabel{font:1000 10px/1 system-ui;letter-spacing:.08em}.permitPhotoCardValue{border:3px solid #171514;background:#f8f1dc;padding:9px;font:900 14px/1.15 system-ui;min-height:38px}.permitPhotoCardMeta{border:2px dashed #6c6658;background:rgba(255,255,255,.35);padding:9px;font:800 10px/1.45 ui-monospace,monospace}.permitPhotoCardFoot{margin-top:10px;border-top:4px solid #df3d3b;padding-top:7px;text-align:center;font:1000 9px/1 system-ui;letter-spacing:.08em} .permitPhotoControls{display:grid;gap:12px;background:#fff3cf;border:4px solid #171514;padding:13px;position:relative;z-index:2}.permitPhotoControls label{display:grid;gap:6px;font-size:12px;font-weight:1000;letter-spacing:.04em}.permitPhotoControls input[type=range]{width:100%;margin:0;position:relative;z-index:3} .permitPhotoEditorButtons{display:grid;grid-template-columns:1fr 1fr;gap:9px;margin-top:3px}.permitPhotoEditorButtons button{min-height:52px}.permitPhotoEditorButtons .save{background:#79c88e}.permitPhotoEditorButtons .cancel{background:#ddd} .permitCameraModal{position:fixed;inset:0;z-index:195;background:rgba(0,0,0,.94);display:flex;align-items:center;justify-content:center;padding:14px;pointer-events:auto}.permitCameraModal.hidden{display:none!important}.permitCameraPanel{width:min(780px,100%);background:#f4e6be;color:#171514;border:5px solid #171514;box-shadow:9px 9px 0 #e64a38;padding:16px}.permitCameraPanel h3{margin:0 0 6px;font-size:24px}.permitCameraHelp{margin:0 0 12px;font-size:12px;font-weight:800}.permitCameraStage{position:relative;width:100%;aspect-ratio:4/3;background:#090909;border:4px solid #171514;overflow:hidden}.permitCameraStage video{display:block;width:100%;height:100%;object-fit:cover;transform:scaleX(-1)}.permitCameraGuide{position:absolute;inset:8%;border:3px solid rgba(244,230,190,.88);pointer-events:none}.permitCameraGuide:before,.permitCameraGuide:after{content:"";position:absolute;background:rgba(244,230,190,.38)}.permitCameraGuide:before{left:33.333%;top:0;width:1px;height:100%;box-shadow:calc(33.333% + 1px) 0 0 rgba(244,230,190,.38)}.permitCameraGuide:after{left:0;top:33.333%;width:100%;height:1px;box-shadow:0 calc(33.333% + 1px) 0 rgba(244,230,190,.38)}.permitCameraStatus{min-height:24px;margin:9px 0 0;font-size:12px;font-weight:900}.permitCameraButtons{display:grid;grid-template-columns:1fr 1fr;gap:9px;margin-top:10px}.permitCameraButtons button{min-height:54px}.permitCameraCapture{background:#79c88e}.permitCameraCancel{background:#ddd}@media(max-width:640px){.permitCameraModal{padding:6px;align-items:flex-start}.permitCameraPanel{padding:10px;border-width:4px;box-shadow:5px 5px 0 #e64a38}.permitCameraPanel h3{font-size:20px}.permitCameraButtons{grid-template-columns:1fr}.permitCameraStage{aspect-ratio:3/4}} @media(max-width:680px),(pointer:coarse){ .permitGateGrid{grid-template-columns:1fr!important}.permitGatePhoto{min-height:220px!important} .permitPhotoEditor{align-items:flex-start;padding:6px} .permitPhotoEditorPanel{width:100%;max-height:none;margin:0;padding:10px;border-width:4px;box-shadow:5px 5px 0 #e64a38} .permitPhotoEditorPanel h3{font-size:20px;line-height:1.05}.permitPhotoEditorHelp{font-size:10px;margin-bottom:8px} .permitPhotoEditorLayout{grid-template-columns:1fr;gap:10px} .permitPhotoCard{padding:8px;border-width:4px}.permitPhotoCardHead{padding-bottom:6px}.permitPhotoCardHead strong{font-size:17px}.permitPhotoCardHead span{font-size:8px;padding:5px} .permitPhotoCardBody{grid-template-columns:132px 1fr;gap:8px;padding-top:8px} .permitPhotoCanvasWrap{width:132px;height:176px;aspect-ratio:auto} .permitPhotoCardValue{padding:6px;font-size:11px;min-height:31px}.permitPhotoCardMeta{padding:6px;font-size:8px;line-height:1.3}.permitPhotoCardFoot{font-size:7px;margin-top:7px} .permitPhotoControls{padding:10px;gap:10px}.permitPhotoControls label{font-size:11px;gap:4px} .permitPhotoEditorButtons{grid-template-columns:1fr 1fr}.permitPhotoEditorButtons button{min-height:48px;font-size:12px} .permitGateActions button{font-size:13px!important}.permitGateCamera{font-size:15px!important} } @media(max-width:390px){.permitPhotoCardBody{grid-template-columns:112px 1fr}.permitPhotoCanvasWrap{width:112px;height:150px}.permitPhotoCardMeta{font-size:7px}.permitPhotoEditorButtons{grid-template-columns:1fr}} <style> /* R36B47B — permit full-image and symmetrical action layout */ .permitGateShell{max-width:900px!important;overflow:visible!important} .permitGateGrid{grid-template-columns:minmax(280px,44%) minmax(0,1fr)!important;align-items:stretch!important} .permitGatePhoto{min-height:520px!important;max-height:none!important;display:flex!important;align-items:center!important;justify-content:center!important;background:#111!important} .permitGatePhoto img{width:100%!important;height:100%!important;min-height:520px!important;object-fit:cover!important;object-position:center center!important} .permitGatePhoto.permitGatePhotoFallback{background:#171514!important} .permitGatePhoto.permitGatePhotoFallback img{object-fit:contain!important;object-position:center center!important;background:#171514!important} .permitGateActionsWide{margin-top:14px!important;display:grid!important;grid-template-columns:repeat(2,minmax(0,1fr))!important;gap:10px!important;width:100%!important} .permitGateActionsWide button{min-height:58px!important;font-size:15px!important} .permitGateActionsWide .permitGateCamera,.permitGateActionsWide .permitGateIssue{grid-column:1/-1!important} .permitGateActionsWide .permitGateCamera{min-height:64px!important} .permitGateActionsWide .permitGateIssue{min-height:66px!important;font-size:18px!important} @media(max-width:700px){ .permitGateShell{max-width:100%!important;padding:10px!important} .permitGateGrid{grid-template-columns:1fr!important;gap:10px!important} .permitGatePhoto{min-height:300px!important;max-height:46vh!important} .permitGatePhoto img{min-height:300px!important;max-height:46vh!important} .permitGatePhoto.permitGatePhotoFallback img{object-fit:contain!important} .permitGateActionsWide{grid-template-columns:1fr 1fr!important;margin-top:10px!important} .permitGateActionsWide button{min-height:52px!important;font-size:12px!important} .permitGateActionsWide .permitGateCamera{min-height:58px!important;font-size:14px!important} .permitGateActionsWide .permitGateIssue{min-height:60px!important;font-size:15px!important} } </style> </style> <style id="r36b46g-final-layout"> /* Loaded last on purpose: final responsive layout authority. */ html body .top{display:block!important;height:0!important;min-height:0!important} html body .stats{position:fixed!important;top:10px!important;left:390px!important;right:10px!important;width:auto!important;min-width:0!important;margin:0!important;display:grid!important;grid-template-columns:repeat(6,minmax(0,1fr))!important;grid-template-rows:1fr!important;gap:6px!important;z-index:64!important;transform:none!important} html body .chip{min-width:0!important;width:auto!important;overflow:hidden!important;text-overflow:ellipsis!important;padding:7px 4px!important;font-size:clamp(8px,1vw,11px)!important;display:flex!important;align-items:center!important;justify-content:center!important} html body .objectiveTop{display:block!important;position:fixed!important;left:10px!important;top:10px!important;right:auto!important;bottom:auto!important;width:365px!important;max-width:365px!important;min-height:72px!important;max-height:122px!important;overflow:auto!important;padding:10px 13px!important;background:rgba(18,17,16,.94)!important;border:3px solid var(--paper)!important;box-shadow:4px 4px 0 #000!important;font-size:12px!important;line-height:1.25!important;z-index:63!important;transform:none!important} html body .objectiveTop #objectiveTitle{font-size:14px!important;letter-spacing:.08em!important} html body .objectiveTop #objectiveText{font-size:12px!important} html body .phoneObjective{display:none!important} html body .phoneScreen{height:118px!important} html body .phoneScreen canvas{height:82px!important} html body .phoneStatus{font-size:8px!important} html body .phone:not(.collapsed){height:432px!important;padding-bottom:9px!important} html body .phoneKeys{gap:5px!important;padding-top:6px!important} html body .phoneKeys .phoneApp{height:42px!important;min-height:42px!important} html body .phoneHint{margin:4px 0 3px!important;font-size:10px!important;line-height:1!important} html body .phoneTraining{width:100%!important;height:48px!important;min-height:48px!important;margin:3px 0 0!important;border-radius:18px!important;font-size:12px!important;letter-spacing:.08em!important} @media(max-width:980px) and (pointer:fine){ html body .objectiveTop{width:300px!important;max-width:300px!important} html body .stats{left:320px!important} html body .chip{font-size:8px!important} } @media(max-width:760px),(pointer:coarse){ html body .hud{padding:0!important} html body .stats,html.mobileFullscreen body .stats{position:fixed!important;top:calc(env(safe-area-inset-top,0px) + 4px)!important;left:4px!important;right:4px!important;width:auto!important;height:36px!important;margin:0!important;display:grid!important;grid-template-columns:repeat(6,minmax(0,1fr))!important;grid-template-rows:1fr!important;gap:2px!important;transform:none!important} html body .chip,html.mobileFullscreen body .chip{height:34px!important;min-width:0!important;padding:2px 1px!important;font-size:clamp(5px,1.6vw,7.5px)!important;border-width:2px!important;white-space:nowrap!important} html body .objectiveTop,html.mobileFullscreen body .objectiveTop{display:block!important;position:fixed!important;left:8px!important;right:auto!important;top:auto!important;bottom:calc(env(safe-area-inset-bottom,0px) + 82px)!important;width:min(58vw,360px)!important;max-width:min(58vw,360px)!important;min-height:64px!important;max-height:102px!important;padding:7px 9px!important;font-size:10px!important;z-index:58!important;transform:none!important} html body .objectiveTop #objectiveTitle{font-size:11px!important} html body .objectiveTop #objectiveText{font-size:9px!important} html body .phone:not(.collapsed){height:438px!important} html body .phoneTraining{height:52px!important;min-height:52px!important;font-size:12px!important} } @media(pointer:coarse) and (orientation:landscape){ html body .stats,html.mobileFullscreen body .stats{height:32px!important} html body .chip,html.mobileFullscreen body .chip{height:30px!important;font-size:7px!important} html body .objectiveTop,html.mobileFullscreen body .objectiveTop{left:8px!important;bottom:74px!important;width:min(42vw,390px)!important;max-width:min(42vw,390px)!important;min-height:52px!important;max-height:78px!important;padding:5px 7px!important} html body .objectiveTop #objectiveTitle{font-size:9px!important} html body .objectiveTop #objectiveText{font-size:8px!important} html body .phone:not(.collapsed){height:300px!important} html body .phoneScreen{height:92px!important} html body .phoneScreen canvas{height:62px!important} html body .phoneKeys .phoneApp{height:31px!important;min-height:31px!important} html body .phoneHint{font-size:7px!important;margin:2px 0!important} html body .phoneTraining{height:34px!important;min-height:34px!important;font-size:8px!important} } </style> <style id="r36b46g-objective-specificity-fix"> @media(max-width:760px),(pointer:coarse){ html.mobileFullscreen body.trainingWheelsActive .objective.objectiveTop, html body.trainingWheelsActive .objective.objectiveTop, html.mobileFullscreen body .objective.objectiveTop, html body .objective.objectiveTop{left:8px!important;right:auto!important;top:auto!important;bottom:calc(env(safe-area-inset-bottom,0px) + 86px)!important;width:min(58vw,360px)!important;max-width:min(58vw,360px)!important;transform:none!important} } @media(pointer:coarse) and (orientation:landscape){ html.mobileFullscreen body.trainingWheelsActive .objective.objectiveTop, html body.trainingWheelsActive .objective.objectiveTop, html.mobileFullscreen body .objective.objectiveTop, html body .objective.objectiveTop{left:8px!important;right:auto!important;bottom:76px!important;width:min(42vw,390px)!important;max-width:min(42vw,390px)!important;transform:none!important} } /* R36B46H FINAL CASCADE — preserve the larger Nookia map and equal app geometry after all legacy styles. */ html body #phone.phone:not(.collapsed){height:486px!important;padding:9px 10px 8px!important} html body #phone .phoneScreen{height:176px!important;padding:4px!important} html body #phone .phoneScreen #miniCanvas{display:block!important;width:100%!important;height:142px!important;max-height:none!important} html body #phone .phoneStatus{height:22px!important;line-height:19px!important;padding:1px 0 0!important;overflow:hidden!important;white-space:nowrap!important;text-overflow:clip!important;animation:nookiaTrackScroll 16s linear infinite!important} html body #phone .phoneKeys{display:grid!important;grid-template-columns:repeat(4,minmax(0,1fr))!important;grid-template-rows:repeat(3,44px)!important;gap:5px!important;padding:6px 0 0!important;max-height:none!important;overflow:visible!important} html body #phone .phoneKeys .phoneApp{box-sizing:border-box!important;width:100%!important;height:44px!important;min-height:44px!important;margin:0!important;padding:2px 1px!important} html body #phone .phoneHint{margin:5px 0 2px!important} html body #phone .phoneTraining{height:47px!important;min-height:47px!important;margin:2px 0 0!important} @media(max-width:760px),(pointer:coarse){html body #phone.phone:not(.collapsed){height:490px!important}html body #phone .phoneScreen{height:178px!important}html body #phone .phoneScreen #miniCanvas{height:144px!important}html body #phone .phoneKeys{grid-template-rows:repeat(3,45px)!important}html body #phone .phoneKeys .phoneApp{height:45px!important;min-height:45px!important}} @media(pointer:coarse) and (orientation:landscape){html body #phone.phone:not(.collapsed){height:322px!important}html body #phone .phoneScreen{height:112px!important}html body #phone .phoneScreen #miniCanvas{height:82px!important}html body #phone .phoneStatus{height:17px!important;line-height:15px!important}html body #phone .phoneKeys{grid-template-rows:repeat(3,31px)!important;gap:3px!important;padding-top:4px!important}html body #phone .phoneKeys .phoneApp{height:31px!important;min-height:31px!important}html body #phone .phoneTraining{height:31px!important;min-height:31px!important}} </style> </head> <body> <canvas id="game" tabindex="0" aria-label="Vancerts Build the Scene game"></canvas> <div id="hud" class="hud hidden"> <div class="top"> <div class="panel objective objectiveTop" id="objective" aria-hidden="true"><div class="trainingHeader" id="trainingHeader"><span class="trainingBadge" id="trainingBadge">TRAINING WHEELS</span><span class="trainingProgress" id="trainingProgress"></span></div><b id="objectiveTitle"></b><br><span id="objectiveText"></span><div class="trainingActions" id="trainingActions"><button id="trainingGuide" class="trainingGuide" type="button" onclick="showTrainingMissionGuide()">MISSION GUIDE</button></div></div> <div class="stats"><div class="chip">CASH $<span id="cash"></span></div><div class="chip">OWED $<span id="owed"></span></div><div class="chip">COMMUNITY ♥ <span id="rep"></span></div><div class="chip">AUSTIN <span id="clock">--:--:--</span></div><div class="chip">SHOWS <span id="shows"></span></div><div class="chip">VAN <span id="vanhp"></span>%</div></div> </div> <div class="toast" id="toast"></div> </div> <div id="rotaryRadio" class="rotaryRadio spotify512Radio hidden" aria-label="512 Jams Community Radio player"> <div class="radioCabinet"> <button id="radioCollapse" class="radioCollapse" type="button" aria-label="Open or minimize 512 Jams Community Radio without resetting the game" data-now-playing="512 JAMS COMMUNITY RADIO • PRESS PLAY">MINIMIZE</button> <div class="radioTop"> <div class="radioBrand">TAPE<br>RADIO</div> <div class="radioDisplay"><div class="radioDialScale" aria-hidden="true"><span>88</span><i></i><span>94</span><i></i><span>100</span><i></i><span>108</span></div><small id="spotifyStatus">CASSETTE RADIO</small><div class="radioTicker" aria-live="polite"><span id="nowPlayingText">512 JAMS • PRESS PLAY IN SPOTIFY</span></div></div> </div> <div class="spotifySafety">SAFE PLAYER • DRIVING PAUSES HERE • MINIMIZE TO RESUME • YOUR GAME WILL NOT RESET</div> <div id="spotifyEmbed" class="spotifyEmbed"><div class="spotifyLoading">512 JAMS COMMUNITY RADIO READY<br><small>Open the player and press Play.</small></div></div> <div class="spotify512Actions"> <button id="radioStop" class="spotifyStop" type="button" aria-label="Stop Spotify audio without changing game progress">STOP MUSIC ONLY</button> <button id="radioRestore" class="spotifyRestore" type="button" aria-label="Reload the Spotify player without changing game progress">RESTORE PLAYER</button> <button id="radioJoinPlaylist" class="spotifyJoin" type="button" aria-label="Submit music for consideration on 512 Jams Community Radio">SUBMIT MUSIC</button> </div> <div class="spotify512Foot">SUBMISSIONS REQUIRE A SPOTIFY LINK • IF ACCEPTED, ADDED WITHIN 24–48 HOURS • EMAIL OPENS WITHOUT RESETTING THE GAME</div> </div> </div> <div class="phone hidden" id="phone" aria-label="Vancerts phone"> <div class="phoneTop"><button id="phoneZoomDial" class="phoneZoomDial" type="button" aria-label="Choose map zoom"><span class="zoomIcon">1–5×</span></button><span class="phoneZoomDialLabel">ZOOM</span><div id="zoomChoices" class="zoomChoices"><button data-zoom="1">1×</button><button data-zoom="2">2×</button><button data-zoom="3">3×</button><button data-zoom="4">4×</button><button data-zoom="5">5×</button></div><div id="zoomHelp" class="zoomHelp"><b>MAP ZOOM 1×–5×</b>Tap to choose a level.<br>Scroll or swipe for in/out.</div><div class="phoneBrand">NOOKIA</div><button id="phoneCollapse" class="phoneCollapse" type="button" aria-label="Collapse phone">▾</button></div> <div class="phoneScreen"><canvas id="miniCanvas" width="340" height="190"></canvas><div class="phoneObjective" aria-live="polite"><b id="phoneObjectiveTitle">CURRENT OBJECTIVE</b><span id="phoneObjectiveText">Drive to the next marked location.</span></div><div class="phoneStatus" id="phoneStatus">NOW PLAYING • COMMUNITY RADIO READY</div></div> <div class="phoneLegacyQuick" aria-hidden="true"><button class="phoneCall" id="phoneCall" tabindex="-1">CALL</button><button class="phoneMail" id="phoneMail" tabindex="-1">EMAIL</button></div> <div class="phoneKeys" aria-label="Nookia touchscreen apps"> <button class="phoneApp" id="phoneDialerApp" type="button"><span>⌨</span>DIALER</button> <button class="phoneApp" id="phoneWallet" type="button"><span>🪪</span>WALLET</button> <button class="phoneApp" id="phoneContacts" type="button"><span>☎</span>CONTACTS<i class="appBadge" id="contactsBadge" hidden>0</i></button> <button class="phoneApp" id="phoneEmailApp" type="button"><span>✉</span>EMAIL<i class="appBadge" id="emailBadge" hidden>0</i></button> <button class="phoneApp" id="phoneRadioApp" type="button"><span class="tapeAppIcon" aria-hidden="true">▣</span>RADIO</button> <button class="phoneApp" id="phoneStaffApp" type="button"><span>👥</span>TEAM<i class="appBadge" id="teamBadge" hidden>0</i></button> <button class="phoneApp" id="phoneLedgerApp" type="button"><span>🧾</span>BUSINESS</button> <button class="phoneApp" id="phoneWaygoApp" type="button"><span>🚕</span>WAYGO<i class="appBadge" id="waygoBadge" hidden>0</i></button> <button class="phoneApp" id="phoneBankApp" type="button"><span>🏦</span>BANK</button> <button class="phoneApp" id="phoneSettingsApp" type="button"><span>💾</span>SAVE / LOAD</button> <button class="phoneApp" id="phoneHowToApp" type="button" onclick="showHow()"><span>?</span>HOW TO PLAY</button> <button class="phoneApp resetGameApp" id="phoneFullscreenApp" type="button" aria-label="Reset game"><span>×</span>RESET GAME</button> </div> <div class="phoneHint">BUILD THE SCENE</div> <button class="phoneTraining" id="phoneReset" aria-pressed="true" type="button">TRAINING ON</button> </div> <div class="controllerWake" id="controllerWake" aria-live="polite"><div class="controllerWakeBox"><div class="controllerWakeTitle">CONTROLLER DETECTED</div><div class="controllerWakeSub">PRESS ANY CONTROLLER BUTTON TO START</div><div class="controllerBadge" id="controllerWakeName">GAMEPAD READY</div><p class="small">This first press activates the controller in your browser. No settings are required.</p></div></div><div class="controllerStatus" id="controllerStatus" aria-live="polite"></div><div class="controllerPointer" id="controllerPointer" aria-hidden="true"></div> <div class="modalWrap" id="modalWrap"><div class="modal" id="modal"></div></div><div class="waygoFade" id="waygoFade" aria-hidden="true"><div>WAYGO<small id="waygoFadeText">YOUR RIDE IS ON THE WAY</small></div></div><div class="gameError" id="gameError"><b>GAME ERROR</b><br><span id="gameErrorText"></span><br><small>Close this message and reload the page. In Squarespace preview, progress may last only for the current session; on the published hosted game, progress saves normally.</small></div> <div class="mobile hidden" id="mobile"> <div class="mobileSteer" aria-label="Steering controls"><button data-key="ArrowLeft" aria-label="Turn left">◀</button><button data-key="ArrowRight" aria-label="Turn right">▶</button></div> <div class="mobileDrive" aria-label="Drive controls"><button data-key="ArrowUp" aria-label="Drive forward">▲</button><button data-key="ArrowDown" aria-label="Reverse">▼</button></div> <button class="mobileDonut" id="mobileDonut" type="button" aria-label="Fire doughnut cannon" aria-hidden="true" hidden>🍩</button> <button class="landscapeToggle" id="landscapeToggle" type="button">⛶ LANDSCAPE</button> </div> <div id="mobileTapHint" class="mobileTapHint">TAP THE MAP TO INTERACT</div> <div class="rotateHint" id="rotateHint"><div>LANDSCAPE RECOMMENDED<br><small>Use FULLSCREEN for the clearest driving view.</small></div></div> <div class="splash" id="splash"><div class="splashBox"><div class="logo">VANCERTS</div><div class="tagline">START WITH A VAN. BUILD A MUSIC SCENE.</div><p>A playable Austin story about mobile production, local businesses, artists, and turning ordinary spaces into stages.</p><div class="introPermitSetup hidden" id="introPermitSetup"><h3>CREATE YOUR VANCERTS DRIVER PERMIT</h3><div class="introPermitGrid"><div class="introPermitPreview" id="introPermitPreview">UPLOAD DRIVER PHOTO<br><small>Optional • crop and pixel-fit automatically</small></div><div class="introPermitFields"><label><b>DRIVER NAME</b><input id="introDriverName" maxlength="28" placeholder="Type your name before starting"></label><div class="introPermitId" id="introPermitId">PERMIT ID GENERATES WITH THIS SAVE</div><div class="btns"><button type="button" onclick="chooseIntroPermitPhoto()">ADD / CHANGE PHOTO</button></div><span class="small">Your permit stays inside the Wallet app on the Nookia and can be opened at any time.</span></div></div></div><div class="btns" style="justify-content:center"><button id="playGameButton" onclick="startGame()">PLAY GAME • FULLSCREEN</button><button class="green" onclick="choosePortableSave()">LOAD GAME FILE</button><button onclick="exportPortableSave()">EXPORT SAVE FILE</button><button class="secondary" onclick="showHow()">HOW TO PLAY</button></div><input id="portableSaveInput" type="file" accept=".json,.vancerts.json,application/json" hidden onchange="loadPortableSaveFile(this)"><p class="small introBuildNotes"><b>UPDATE R36B52O</b><br>STORY + GPS AUTHORITY: Training follows the active Owner, Band, Audio Engineer, or Stagehand story step exactly. Matching road arrows turn red toward the next physical destination, and the Nookia map draws a red line from the van triangle to that destination until arrival.</p></div></div> <script> const $=id=>document.getElementById(id),canvas=$('game'),ctx=canvas.getContext('2d'),miniCtx=$('miniCanvas').getContext('2d');let W,H,DPR=1,last=0,near=null,activeSetup=null;window.addEventListener('error',e=>{const message=String(e&&e.message||'').trim();const genericCrossOrigin=!e.error&&(!message||message.toLowerCase()==='script error.'||message.toLowerCase()==='script error');if(genericCrossOrigin)return;const box=$('gameError'),text=$('gameErrorText');if(box&&text){text.textContent=message||'Unknown game error';box.classList.add('show')}}); function resize(){DPR=Math.min(2,devicePixelRatio||1);W=innerWidth;H=innerHeight;canvas.width=W*DPR;canvas.height=H*DPR;ctx.setTransform(DPR,0,0,DPR,0,0);ctx.imageSmoothingEnabled=false}addEventListener('resize',resize);resize(); // R36B45F: initialize career-home data before any startup, collision, camera, or render code can access it. // R36B45F: career-home data is initialized near the top of the script before startup. const CAMERA_ZOOM_LEVELS=[1,2,3,4,5]; function cameraZoomLevel(){ const z=Math.round(Number(state.cameraZoom)||1); return CAMERA_ZOOM_LEVELS.includes(z)?z:1 } const FULL_CITY_VIEW_BOUNDS={x:-430,y:-760,w:3680,h:4120}; const BIRD_EYE_VIEW_BOUNDS={x:-2045,y:-1850,w:7060,h:6900}; function cameraScale(){ const z=cameraZoomLevel(); if(z===4)return Math.max(.075,Math.min(.5,W/FULL_CITY_VIEW_BOUNDS.w,H/FULL_CITY_VIEW_BOUNDS.h)); if(z===5)return Math.max(.04,Math.min(.25,W/BIRD_EYE_VIEW_BOUNDS.w,H/BIRD_EYE_VIEW_BOUNDS.h)); return 1/z } function cameraViewName(level=cameraZoomLevel()){ return({1:'STREET VIEW',2:'NEIGHBORHOOD VIEW',3:'DISTRICT VIEW',4:'FULL CITY VIEW',5:'BIRD’S-EYE VIEW'})[level]||'STREET VIEW' } function cameraViewShort(level=cameraZoomLevel()){ return({1:'STREET',2:'NEIGHBORHOOD',3:'DISTRICT',4:'FULL CITY',5:'BIRD EYE'})[level]||'STREET' } function updateZoomDial(){ const dial=$('phoneZoomDial'),z=cameraZoomLevel(),choices=$('zoomChoices'); if(dial){dial.setAttribute('aria-label',`Choose map zoom. Current: ${z} times, ${cameraViewName(z)}.`);dial.title=`ZOOM 1×–5× • CURRENT ${z}× ${cameraViewName(z)}`} if(choices)choices.querySelectorAll('[data-zoom]').forEach(b=>b.classList.toggle('active',Number(b.dataset.zoom)===z)) } function dismissZoomHelp(){ const help=$('zoomHelp');if(help)help.classList.remove('show'); if(!state.zoomHelpSeen){state.zoomHelpSeen=true;save()} } function showZoomHelp(){ const help=$('zoomHelp');if(!help||state.zoomHelpSeen)return; help.classList.add('show'); setTimeout(()=>{help.classList.remove('show');state.zoomHelpSeen=true;save()},6500) } function setCameraZoom(level,announce=true){ const old=cameraZoomLevel(),next=Math.max(1,Math.min(5,Math.round(Number(level)||1))); state.cameraZoom=next; updateZoomDial(); if(old!==next){ save(); if(announce)toast(`${cameraViewName(next)} • ${next}×`) } } function stepCameraZoom(direction){ const z=cameraZoomLevel(); setCameraZoom(z+(direction>0?1:-1)) } window.setCameraZoom=setCameraZoom; function installZoomDial(){ const dial=$('phoneZoomDial');if(!dial)return; let active=false,startY=0,moved=false,pointerId=null; dial.addEventListener('click',e=>{dismissZoomHelp();if(moved){moved=false;return}const c=$('zoomChoices');if(c)c.classList.toggle('show');e.preventDefault();e.stopPropagation()}); dial.addEventListener('wheel',e=>{dismissZoomHelp();stepCameraZoom(e.deltaY<0?1:-1);e.preventDefault()},{passive:false}); dial.addEventListener('pointerdown',e=>{dismissZoomHelp();active=true;moved=false;startY=e.clientY;pointerId=e.pointerId;try{dial.setPointerCapture(pointerId)}catch(_){}e.preventDefault()}); dial.addEventListener('pointermove',e=>{ if(!active||e.pointerId!==pointerId)return; const dy=e.clientY-startY; if(Math.abs(dy)>=18){moved=true;stepCameraZoom(dy<0?1:-1);startY=e.clientY} e.preventDefault() }); const finish=e=>{if(!active||e.pointerId!==pointerId)return;active=false;try{dial.releasePointerCapture(pointerId)}catch(_){}pointerId=null;e.preventDefault()}; dial.addEventListener('pointerup',finish); dial.addEventListener('pointercancel',()=>{active=false;pointerId=null}); const choices=$('zoomChoices'); if(choices){choices.querySelectorAll('[data-zoom]').forEach(b=>b.addEventListener('click',e=>{setCameraZoom(Number(b.dataset.zoom));choices.classList.remove('show');e.preventDefault();e.stopPropagation()}));document.addEventListener('pointerdown',e=>{if(!choices.contains(e.target)&&e.target!==dial)choices.classList.remove('show')})} updateZoomDial();setTimeout(showZoomHelp,700) } const world={w:3250,h:2600},roads=[ // Perimeter roads form one closed box around the current district. {x:0,y:0,w:3250,h:150,edge:true},{x:0,y:2450,w:3250,h:150,edge:true},{x:0,y:0,w:150,h:2600,edge:true},{x:3100,y:0,w:150,h:2600,edge:true},{x:0,y:1900,w:3250,h:150},{x:2550,y:0,w:150,h:2600}, // Interior two-sided streets. {x:0,y:600,w:2700,h:180},{x:0,y:1300,w:2700,h:180},{x:610,y:0,w:170,h:2600},{x:1270,y:0,w:170,h:2600},{x:1930,y:0,w:170,h:2600} ]; const CITY_POLISH={sidewalkBase:14,sidewalkUpgrade:24,curbWidth:5,buildingApron:14,propertyBuffer:18,treeRadius:24,collisionPad:16,crosswalkDepth:30,crosswalkGap:10,stopBarGap:10}; function sidewalkWidth(){return projectLevel('sidewalks')?CITY_POLISH.sidewalkUpgrade:CITY_POLISH.sidewalkBase} const SOLO={name:'SOLO ACT',bandCost:100,needs:{main:2,sub:1,mic:1,monitor:1,lights:0,backline:0}}; const BAND={name:'FULL BAND',bandCost:300,needs:{main:2,sub:2,mic:3,monitor:3,lights:0,backline:0}}; const operatorCost=300,prices={main:120,sub:150,mic:35,monitor:90,lights:300,backline:300}; function packageCost(pkg,extras={lights:false,backline:false}){let n=operatorCost+pkg.bandCost;for(const[k,v]of Object.entries(pkg.needs))n+=(prices[k]||0)*v;if(extras.lights)n+=300;if(extras.backline)n+=300;return n} const SOLO_COST=packageCost(SOLO),BAND_COST=packageCost(BAND); const places=[ {x:180,y:175,w:245,h:170,name:'REPUBLIC SQUARE',phone:'',abbr:'RSQ',short:'Republic Square',type:'gig',id:'republic',color:'#659b59',logo:['REPUBLIC SQUARE'],subtitle:'DOWNTOWN PARK',setup:{x:440,y:175,w:145,h:170},parking:{x:180,y:375,w:405,h:205,cols:4,rows:4},interact:{x:512,y:260},capacity:16}, {x:820,y:175,w:300,h:170,name:'TOP NOTCH HAMBURGERS',phone:'(512) 452-2181',abbr:'TN',short:'Top Notch',type:'gig',id:'topnotch',color:'#d65d4d',logo:['TOP NOTCH','HAMBURGERS'],setup:{x:1135,y:175,w:100,h:170},parking:{x:820,y:375,w:415,h:205,cols:4,rows:4},interact:{x:1185,y:260},capacity:16}, {x:1480,y:175,w:300,h:170,name:'BLUE OWL BREWING',phone:'(512) 593-1262',abbr:'BO',short:'Blue Owl',type:'gig',id:'blueowl',color:'#5792ad',logo:['BLUE OWL','BREWING'],setup:{x:1795,y:175,w:100,h:170},parking:{x:1480,y:375,w:415,h:205,cols:4,rows:4},interact:{x:1845,y:260},capacity:16}, {x:2140,y:175,w:300,h:170,name:'JUAN IN A MILLION',phone:'(512) 472-3872',abbr:'JM',short:'Juan',type:'gig',id:'juan',color:'#d68c40',logo:['JUAN IN','A MILLION'],setup:{x:2450,y:175,w:65,h:170},parking:{x:2140,y:375,w:375,h:205,cols:4,rows:4},interact:{x:2482,y:260},capacity:16}, {x:180,y:825,w:245,h:180,name:'FSG PRINTSHOP',phone:'(512) 666-9050',abbr:'FSG',short:'FSG',type:'gig',id:'fsg',color:'#ca493c',logo:['FSG','PRINTSHOP'],setup:{x:440,y:825,w:145,h:180},parking:{x:180,y:1030,w:405,h:240,cols:4,rows:4},interact:{x:512,y:915},capacity:16}, {x:820,y:825,w:300,h:180,name:'GIG BAG ATX',abbr:'GB',short:'Gig Bag',type:'shop',id:'shop',color:'#e0aa36',logo:['GIG BAG','ATX'],setup:{x:1135,y:825,w:100,h:180},parking:{x:820,y:1030,w:415,h:240,cols:4,rows:4},interact:{x:1185,y:915},capacity:16}, {x:1480,y:825,w:300,h:180,name:'BYOB AUSTIN',abbr:'BYOB',short:'BYOB',type:'hq',id:'hq',color:'#3c7fa1',logo:['BYOB','AUSTIN'],subtitle:'VANCERTS HQ',setup:{x:1795,y:825,w:100,h:180},parking:{x:1480,y:1030,w:415,h:240,cols:4,rows:4},interact:{x:1845,y:915},capacity:16}, {x:2140,y:825,w:300,h:180,name:'HOPE OUTDOOR GALLERY',phone:'(512) 222-6888',abbr:'HOG',short:'Hope',type:'gig',id:'hope',color:'#9766a3',logo:['HOPE OUTDOOR','GALLERY'],setup:{x:2450,y:825,w:65,h:180},parking:{x:2140,y:1030,w:375,h:240,cols:4,rows:4},interact:{x:2482,y:915},capacity:16}, {x:820,y:1515,w:300,h:115,name:'MAMA DEAREST',abbr:'MD',short:'Mama Dearest',type:'gig',id:'mama',expansion:'mama',color:'#080808',logo:['MAMA DEAREST'],setup:{x:1135,y:1510,w:100,h:320},parking:{x:820,y:1660,w:415,h:170,cols:4,rows:2},interact:{x:1185,y:1670},capacity:8}, {x:1480,y:1515,w:300,h:115,name:'WORLD LIQUOR',abbr:'WL',short:'World Liquor',type:'gig',id:'worldliquor',expansion:'eastAustin',color:'#7e2d2d',logo:['WORLD','LIQUOR'],setup:{x:1795,y:1510,w:100,h:320},parking:{x:1480,y:1660,w:415,h:170,cols:4,rows:2},interact:{x:1845,y:1670},capacity:8}, {x:2790,y:2105,w:220,h:115,name:'PORK CHOP SCREEN PRINTING',abbr:'PCS',short:'Pork Chop',type:'gig',id:'porkchop',expansionPermit:'east-porkchop',color:'#cc5d42',logo:['PORK CHOP SCREEN PRINTING'],setup:{x:2705,y:2105,w:75,h:120},parking:{x:2790,y:2240,w:220,h:165,cols:4,rows:2},interact:{x:2742,y:2165},capacity:8}, {x:2790,y:1265,w:220,h:80,name:'BADD BURGER',abbr:'BAD',short:'BADD Burger',type:'gig',id:'baddburgers',expansionPermit:'east-baddburgers',color:'#d66b32',logo:['BADD BURGER'],setup:{x:2708,y:1265,w:65,h:245},parking:{x:2790,y:1360,w:220,h:135,cols:4,rows:2},interact:{x:2740,y:1387},capacity:8}, {x:2790,y:905,w:220,h:80,name:'HIGH NOON SALOON',abbr:'HNS',short:'High Noon Saloon',type:'gig',id:'highnoon',expansionPermit:'east-highnoon',color:'#b97837',logo:['HIGH NOON SALOON'],setup:{x:2708,y:905,w:65,h:245},parking:{x:2790,y:1000,w:220,h:135,cols:4,rows:2},interact:{x:2740,y:1027},capacity:8}, {x:2790,y:545,w:220,h:80,name:'CHESS CLUB',abbr:'CHS',short:'Chess Club',type:'gig',id:'chessclub',expansionPermit:'east-chessclub',color:'#343434',logo:['CHESS CLUB'],setup:{x:2708,y:545,w:65,h:245},parking:{x:2790,y:640,w:220,h:135,cols:4,rows:2},interact:{x:2740,y:667},capacity:8}, {x:2790,y:185,w:220,h:80,name:'THE 13TH FLOOR',abbr:'13F',short:'The 13th Floor',type:'gig',id:'thirteenthfloor',expansionPermit:'east-thirteenthfloor',color:'#6a4380',logo:['THE 13TH FLOOR'],setup:{x:2708,y:185,w:65,h:245},parking:{x:2790,y:280,w:220,h:135,cols:4,rows:2},interact:{x:2740,y:307},capacity:8}, {x:170,y:2105,w:250,h:115,name:'KAZI 88.7FM',abbr:'KAZ',short:'KAZI 88.7FM',type:'gig',id:'kazi',expansionPermit:'west-kazi',color:'#090909',logo:['KAZI 88.7FM'],subtitle:'Radio',setup:{x:435,y:2070,w:100,h:330},parking:{x:170,y:2240,w:365,h:165,cols:4,rows:2},interact:{x:485,y:2190},capacity:8}, {x:820,y:2105,w:300,h:115,name:'TASCAM MODEL 24',abbr:'TAC',short:'Tascam Model 24',type:'gig',id:'tascam',expansionPermit:'west-tascam',color:'#353535',logo:['TASCAM MODEL 24'],subtitle:'Mix House',setup:{x:1135,y:2070,w:100,h:330},parking:{x:820,y:2240,w:415,h:165,cols:4,rows:2},interact:{x:1185,y:2190},capacity:8}, {x:1480,y:2105,w:300,h:115,name:'JBL PRO',abbr:'JBL',short:'JBL Pro',type:'gig',id:'jblpro',expansionPermit:'west-jblpro',color:'#d97924',logo:['JBL PRO'],subtitle:'Speak Easy',setup:{x:1795,y:2070,w:100,h:330},parking:{x:1480,y:2240,w:415,h:165,cols:4,rows:2},interact:{x:1845,y:2190},capacity:8}, {x:2140,y:2105,w:300,h:115,name:'REMOVED PROPERTY',abbr:'OLD',short:'Removed Property',type:'retired',id:'removedsouppeddler',retiredByReorg:true,color:'#77a35e',logo:['REMOVED PROPERTY'],setup:{x:-9999,y:-9999,w:1,h:1},parking:null,interact:{x:-9999,y:-9999},capacity:0}, {x:2790,y:1645,w:220,h:95,name:'LEFTWAY STUDIOS',abbr:'LWS',short:'Leftway Studios',type:'studio',id:'leftway',color:'#456f77',logo:['LEFTWAY STUDIOS'],subtitle:'Recording Studio Resort',parking:{x:2790,y:1760,w:220,h:135,cols:4,rows:2},interact:{x:2742,y:1692},capacity:8}, {x:180,y:1515,w:300,h:115,name:'VANCERTS COMMUNITY BANK',abbr:'BANK',short:'Bank',type:'bank',id:'bank',color:'#315d3b',logo:['VANCERTS','COMMUNITY BANK'],subtitle:'MICRO LOANS • REPAYMENT',setup:{x:495,y:1510,w:90,h:320},parking:{x:180,y:1660,w:405,h:170,cols:4,rows:2},interact:{x:540,y:1670},capacity:8,hideParkingLabel:true} ]; function setR36B19Place(id,patch){const p=places.find(x=>x.id===id);if(!p)return;Object.assign(p,patch)} function retireReorganizedPlace(id){const p=places.find(x=>x.id===id);if(p){p.retiredByReorg=true;p.type='retired';p.parking=null;p.setup=null;p.interact={x:-9999,y:-9999}}} function applyR36B19CityLayout(){ retireReorganizedPlace('topnotch');retireReorganizedPlace('removedsouppeddler'); // DOWNTOWN / STARTING CORE — same existing parcels, intentional identities. setR36B19Place('shop',{x:180,y:175,w:245,h:170,name:'GIG BAG ATX',abbr:'GB',short:'Gig Bag',type:'shop',color:'#e0aa36',logo:['GIG BAG','ATX'],subtitle:'',setup:{x:440,y:175,w:145,h:170},parking:{x:180,y:375,w:405,h:205,cols:4,rows:4},interact:{x:512,y:260},capacity:16}); setR36B19Place('hq',{x:820,y:175,w:300,h:170,name:'BYOB AUSTIN',abbr:'BYOB',short:'BYOB',type:'hq',color:'#3c7fa1',logo:['BYOB','AUSTIN'],subtitle:'VANCERTS HQ',setup:{x:1135,y:175,w:100,h:170},parking:{x:820,y:375,w:415,h:205,cols:4,rows:4},interact:{x:1185,y:260},capacity:16}); setR36B19Place('fsg',{x:1480,y:175,w:300,h:170,name:'FSG PRINTSHOP',abbr:'FSG',short:'FSG',type:'gig',color:'#ca493c',logo:['FSG','PRINTSHOP'],setup:{x:1795,y:175,w:100,h:170},parking:{x:1480,y:375,w:415,h:205,cols:4,rows:4},interact:{x:1845,y:260},capacity:16}); setR36B19Place('blueowl',{x:2140,y:175,w:300,h:170,name:'BLUE OWL BREWING',abbr:'BO',short:'Blue Owl',type:'gig',color:'#5792ad',logo:['BLUE OWL','BREWING'],setup:{x:2450,y:175,w:65,h:170},parking:{x:2140,y:375,w:375,h:205,cols:4,rows:4},interact:{x:2482,y:260},capacity:16}); setR36B19Place('juan',{x:180,y:825,w:245,h:180,name:'JUAN IN A MILLION',abbr:'JM',short:'Juan',type:'gig',color:'#d68c40',logo:['JUAN IN','A MILLION'],setup:{x:440,y:825,w:145,h:180},parking:{x:180,y:1030,w:405,h:240,cols:4,rows:4},interact:{x:512,y:915},capacity:16}); setR36B19Place('hope',{x:820,y:825,w:300,h:180,name:'HOPE OUTDOOR GALLERY',abbr:'HOG',short:'Hope',type:'gig',color:'#9766a3',logo:['HOPE OUTDOOR','GALLERY'],setup:{x:1135,y:825,w:100,h:180},parking:{x:820,y:1030,w:415,h:240,cols:4,rows:4},interact:{x:1185,y:915},capacity:16}); setR36B19Place('mama',{x:1480,y:825,w:300,h:180,name:'MAMA DEAREST',abbr:'MD',short:'Mama Dearest',type:'gig',expansion:'mama',color:'#080808',logo:['MAMA DEAREST'],setup:{x:1795,y:825,w:100,h:180},parking:{x:1480,y:1030,w:415,h:240,cols:4,rows:4},interact:{x:1845,y:915},capacity:16}); setR36B19Place('worldliquor',{x:2140,y:825,w:300,h:180,name:'WORLD LIQUOR',abbr:'WL',short:'World Liquor',type:'gig',expansion:'eastAustin',color:'#7e2d2d',logo:['WORLD','LIQUOR'],setup:{x:2450,y:825,w:65,h:180},parking:{x:2140,y:1030,w:375,h:240,cols:4,rows:4},interact:{x:2482,y:915},capacity:16}); setR36B19Place('porkchop',{x:180,y:1515,w:300,h:115,name:'PORK CHOP SCREEN PRINTING',abbr:'PCS',short:'Pork Chop',type:'gig',expansionPermit:'east-porkchop',color:'#cc5d42',logo:['PORK CHOP SCREEN PRINTING'],setup:{x:495,y:1510,w:90,h:320},parking:{x:180,y:1660,w:405,h:170,cols:4,rows:2},interact:{x:540,y:1670},capacity:8}); setR36B19Place('republic',{x:820,y:1515,w:300,h:115,name:'REPUBLIC SQUARE',abbr:'RSQ',short:'Republic Square',type:'gig',color:'#659b59',logo:['REPUBLIC SQUARE'],subtitle:'DOWNTOWN PARK',setup:{x:1135,y:1660,w:120,h:170},parking:{x:820,y:1660,w:311,h:170,cols:4,rows:2},interact:{x:1195,y:1745},capacity:8,openFromStart:true}); setR36B19Place('leftway',{x:1480,y:1515,w:300,h:115,name:'LEFTWAY STUDIOS',abbr:'LWS',short:'Leftway Studios',type:'studio',color:'#456f77',logo:['LEFTWAY STUDIOS'],subtitle:'Recording Studio Resort',setup:{x:1795,y:1510,w:100,h:320},parking:{x:1480,y:1660,w:415,h:170,cols:4,rows:2},interact:{x:1845,y:1670},capacity:8,openFromStart:true}); // Leftway's second connected parcel: pond, house, stage, flowers, hangout lawn. let grounds=places.find(x=>x.id==='leftwaygrounds'); if(!grounds){grounds={id:'leftwaygrounds'};places.push(grounds)} Object.assign(grounds,{x:2140,y:1515,w:375,h:315,name:'LEFTWAY GROUNDS',abbr:'LWG',short:'Leftway Grounds',type:'grounds',color:'#6e9b61',logo:['LEFTWAY GROUNDS'],subtitle:'Pond • House • Outdoor Stage',setup:null,parking:null,interact:{x:2160,y:1660},capacity:0,compoundWith:'leftway'}); // WEST LOCKED-FUTURE PARCELS. Bank is open immediately; the other three retain their permits. setR36B19Place('bank',{x:-310,y:185,w:220,h:80,name:'VANCERTS COMMUNITY BANK',abbr:'BANK',short:'Bank',type:'bank',color:'#315d3b',logo:['VANCERTS','BANK'],subtitle:'MICRO LOANS',setup:{x:-82,y:280,w:72,h:135,curbside:true,invisible:true,westContained:true,westParcelPullIn:true},parking:{x:-310,y:280,w:228,h:135,cols:4,rows:2},interactionRect:{x:-82,y:280,w:72,h:135},interact:{x:-46,y:347},capacity:8,hideParkingLabel:true,openFromStart:true}); setR36B19Place('kazi',{x:-310,y:545,w:220,h:80,name:'KAZI 88.7FM',abbr:'KAZ',short:'KAZI 88.7FM',type:'gig',expansionPermit:'west-kazi',color:'#090909',logo:['KAZI 88.7FM'],subtitle:'Radio',setup:{x:-82,y:640,w:72,h:135,curbside:true,invisible:true,westContained:true,westParcelPullIn:true},parking:{x:-310,y:640,w:228,h:135,cols:4,rows:2},interactionRect:{x:-82,y:640,w:72,h:135},interact:{x:-46,y:707},capacity:8}); setR36B19Place('tascam',{x:-310,y:905,w:220,h:80,name:'TASCAM MODEL 24',abbr:'TAC',short:'Tascam Model 24',type:'gig',expansionPermit:'west-tascam',color:'#353535',logo:['TASCAM MODEL 24'],subtitle:'Mix House',setup:{x:-82,y:1000,w:72,h:135,curbside:true,invisible:true,westContained:true,westParcelPullIn:true},parking:{x:-310,y:1000,w:228,h:135,cols:4,rows:2},interactionRect:{x:-82,y:1000,w:72,h:135},interact:{x:-46,y:1067},capacity:8}); setR36B19Place('jblpro',{x:-310,y:1265,w:220,h:80,name:'JBL PRO',abbr:'JBL',short:'JBL Pro',type:'gig',expansionPermit:'west-jblpro',color:'#d97924',logo:['JBL PRO'],subtitle:'Speak Easy',setup:{x:-82,y:1360,w:72,h:135,curbside:true,invisible:true,westContained:true,westParcelPullIn:true},parking:{x:-310,y:1360,w:228,h:135,cols:4,rows:2},interactionRect:{x:-82,y:1360,w:72,h:135},interact:{x:-46,y:1427},capacity:8}); let queueTube=places.find(x=>x.id==='queuetube'); if(!queueTube){queueTube={id:'queuetube'};places.push(queueTube)} Object.assign(queueTube,{x:-310,y:1625,w:220,h:80,name:'QUEUE TUBE',abbr:'QT',short:'Queue Tube',type:'gig',color:'#111111',logo:['QUEUE'],subtitle:'Community Playlist & Radio',setup:{x:-82,y:1720,w:72,h:135,curbside:true,invisible:true,westContained:true,westParcelPullIn:true},parking:{x:-310,y:1720,w:228,h:135,cols:4,rows:2},interactionRect:{x:-82,y:1720,w:72,h:135},interact:{x:-46,y:1787},capacity:8,openFromStart:true,vancertsOwned:true}); // EAST SIDE symmetry: AML mirrors BADD Burger and is open from the beginning. let aml=places.find(x=>x.id==='amlhouse'); if(!aml){aml={id:'amlhouse'};places.push(aml)} Object.assign(aml,{x:2790,y:1645,w:220,h:80,name:'AUSTIN MUSIC LOVE',abbr:'AML',short:'Austin Music Love',type:'gig',color:'#f2dfa0',logo:['AUSTIN MUSIC LOVE'],subtitle:'Houseshows',setup:{x:2708,y:1740,w:65,h:135},parking:{x:2790,y:1740,w:220,h:135,cols:4,rows:2},interact:{x:2740,y:1767},capacity:8,openFromStart:true,payoutModel:'HALF COMMUNITY • HALF FOR PROFIT'}); } applyR36B19CityLayout(); const BUSINESS_CANONICAL={ shop:{name:'GIG BAG ATX',short:'Gig Bag',abbr:'GBA',logo:['GIG BAG ATX'],subtitle:'GEAR • SHOP • HQ'}, hq:{name:'BYOB AUSTIN',short:'BYOB Austin',abbr:'BYOB',logo:['BYOB AUSTIN'],subtitle:'VANCERTS HQ'}, fsg:{name:'FSG PRINTSHOP',short:'FSG Printshop',abbr:'FSG',logo:['FSG PRINTSHOP'],subtitle:'PRINT • ART • MUSIC'}, blueowl:{name:'BLUE OWL BREWING',short:'Blue Owl Brewing',abbr:'BOW',logo:['BLUE OWL BREWING'],subtitle:'SOUR BEER'}, juan:{name:'JUAN IN A MILLION',short:'Juan In A Million',abbr:'JIM',logo:['JUAN IN A MILLION'],subtitle:'BREAKFAST • COMMUNITY'}, hope:{name:'HOPE OUTDOOR GALLERY',short:'Hope Outdoor Gallery',abbr:'HOG',logo:['HOPE OUTDOOR GALLERY'],subtitle:'ART • MUSIC'}, republic:{name:'REPUBLIC SQUARE',short:'Republic Square',abbr:'RSQ',logo:['REPUBLIC SQUARE'],subtitle:'DOWNTOWN PARK'}, mama:{name:'MAMA DEAREST',short:'Mama Dearest',abbr:'MD',logo:['MAMA DEAREST'],subtitle:'BAR • LATE NIGHT'}, worldliquor:{name:'WORLD LIQUOR',short:'World Liquor',abbr:'WLQ',logo:['WORLD LIQUOR'],subtitle:'EAST AUSTIN'}, porkchop:{name:'PORK CHOP SCREEN PRINTING',short:'Pork Chop Screen Printing',abbr:'PCS',logo:['PORK CHOP SCREEN PRINTING'],subtitle:'SCREEN PRINTING'}, leftway:{name:'LEFTWAY STUDIOS',short:'Leftway Studios',abbr:'LWS',logo:['LEFTWAY STUDIOS'],subtitle:'RECORDING STUDIO'}, leftwaygrounds:{name:'LEFTWAY GROUNDS',short:'Leftway Grounds',abbr:'LWG',logo:['LEFTWAY GROUNDS'],subtitle:'POND • HOUSE • STAGE'}, bank:{name:'VANCERTS COMMUNITY BANK',short:'Community Bank',abbr:'BANK',logo:['VANCERTS BANK'],subtitle:'MICRO LOANS'}, kazi:{name:'KAZI 88.7 FM',short:'KAZI 88.7 FM',abbr:'KAZ',logo:['KAZI 88.7 FM'],subtitle:'RADIO'}, tascam:{name:'TASCAM MODEL 24',short:'Tascam Model 24',abbr:'T24',logo:['TASCAM MODEL 24'],subtitle:'MIX HOUSE'}, jblpro:{name:'JBL PRO',short:'JBL Pro',abbr:'JBL',logo:['JBL PRO'],subtitle:'SPEAK EASY'}, queuetube:{name:'QUEUE TUBE',short:'Queue Tube',abbr:'QT',logo:['QUEUE'],subtitle:'Community Playlist & Radio'}, thirteenthfloor:{name:'THE 13TH FLOOR',short:'The 13th Floor',abbr:'13F',logo:['THE 13TH FLOOR'],subtitle:'PSYCH • LIVE MUSIC'}, chessclub:{name:'CHESS CLUB',short:'Chess Club',abbr:'CHS',logo:['CHESS CLUB'],subtitle:'LIVE MUSIC'}, highnoon:{name:'HIGH NOON',short:'High Noon',abbr:'HNS',logo:['HIGH NOON'],subtitle:'SALOON'}, baddburgers:{name:'BADD BURGER',short:'BADD Burger',abbr:'BADD',logo:['BADD BURGER'],subtitle:'BURGERS'}, amlhouse:{name:'AUSTIN MUSIC LOVE',short:'Austin Music Love',abbr:'AML',logo:['AUSTIN MUSIC LOVE'],subtitle:'HOUSESHOWS'} }; function applyCanonicalBusinessData(){ for(const [id,meta] of Object.entries(BUSINESS_CANONICAL)){ const p=places.find(x=>x.id===id); if(!p)continue; Object.assign(p,{ name:meta.name, short:meta.short, abbr:meta.abbr, logo:[...meta.logo], subtitle:meta.subtitle }) } } applyCanonicalBusinessData(); const lockedEdgeBusinesses=[ {id:'bank',x:-265,y:175,w:405,h:255},{id:'kazi',x:-265,y:535,w:405,h:255},{id:'tascam',x:-265,y:895,w:405,h:255},{id:'jblpro',x:-265,y:1255,w:405,h:255}, {id:'east-thirteenthfloor',x:2780,y:175,w:240,h:255},{id:'east-chessclub',x:2780,y:535,w:240,h:255},{id:'east-highnoon',x:2780,y:895,w:240,h:255},{id:'east-baddburgers',x:2780,y:1255,w:240,h:255} ]; const order=['fsg','republic','blueowl','juan','hope']; const gigMeta={fsg:{title:'THE FIRST PARKING-LOT SHOW',rep:8,impact:5},blueowl:{title:'BREWERY FRIDAY SHOW',rep:14,impact:8},topnotch:{title:'FEED AUSTIN BENEFIT',rep:20,impact:25},juan:{title:'BREAKFAST BLOCK PARTY',rep:16,impact:14},hope:{title:'ART + MUSIC ACTIVATION',rep:25,impact:20},mama:{title:'MAMA DEAREST LATE-NIGHT SHOW',rep:35,impact:30},worldliquor:{title:'WORLD LIQUOR EAST AUSTIN SHOW',rep:40,impact:35},porkchop:{title:'PORK CHOP PRINT SHOW',rep:35,impact:30},baddburgers:{title:'BADD BURGERS BLOCK PARTY',rep:38,impact:32},highnoon:{title:'HIGH NOON NIGHT SHOW',rep:40,impact:34},chessclub:{title:'CHESS CLUB PUNK NIGHT',rep:44,impact:38},thirteenthfloor:{title:'13TH FLOOR PSYCH NIGHT',rep:48,impact:42},kazi:{title:'KAZI 88.7 FM COMMUNITY BROADCAST',rep:50,impact:45},tascam:{title:'TASCAM MODEL 24 STUDIO SESSION',rep:50,impact:45},jblpro:{title:'JBL PRO SPEAKER LAND SHOW',rep:50,impact:45},queuetube:{title:'QUEUE TUBE COMMUNITY PLAYLIST SHOW',rep:45,impact:40},republic:{title:'REPUBLIC SQUARE OPEN JAM',rep:50,impact:45},amlhouse:{title:'AUSTIN MUSIC LOVE HOUSESHOW',rep:30,impact:24}}; function freshVenues(){const o={};for(const p of places.filter(p=>p.type==='gig'))o[p.id]={budget:SOLO_COST,eventCount:0,rateCars:0,sign:false,fillFlags:0,lotCycleFull:false,flagCycleArmed:false,amlPromotionActive:false};return o} function permanentCarsLegacy(eventCount,capacity=16){return !eventCount?0:Math.min(capacity,Math.pow(2,eventCount-1))} const defaults={cash:1000,rep:0,impact:0,shows:0,vanhp:100,gameTimeOffsetHours:0,cameraZoom:1,zoomHelpSeen:false,completed:[],seenIntro:false,introVersion:0,inventory:{main:2,sub:0,mic:4,lights:0,backline:0,monitor:0,xlr:0,iec:0,speakerCable50:0,snake24:0,highTom:0,lowTom:0,floorTom:0,bassDrum:0,drumHardware:0,guitarAmp:0,bassAmp:0,diBox:0},venues:freshVenues(),invoices:[],sponsor:null,activeJob:null,sponsorEmailSeen:false,sponsorOffers:[],pendingOffer:null,communityUpgrades:{sidewalks:0,stoplights:0,crosswalks:0,rainbowCrosswalks:0,foodPantry:0,busStops:0,garden:0,publicArt:0,freeConcerts:0,snakePatrol:0,snakeRelocation:0,wildlifeManagement:0},wildlifeFreezeDay:'',expansionPermits:{mama:false,eastAustin:false,'east-porkchop':false,'east-baddburgers':false,'east-highnoon':false,'east-chessclub':false,'east-thirteenthfloor':false,'west-kazi':false,'west-tascam':false,'west-jblpro':false},rentalOrder:null,passengerRide:null,passengerStats:{rides:0,earnings:0},bankLoan:null,bankLoans:[],bankLastAdvanceDay:'',bankStats:{loansTaken:0,totalBorrowed:0,totalRepaid:0,totalInterestCharged:0,totalInterestPaid:0},finance:null,compliance:{bmi:{status:'active',annualMinimum:437,minimumCovered:true,coverageYear:new Date().getFullYear(),events:[],submittedQuarters:[],additionalPaid:0,lastSubmission:''}},career:{path:'owner',teamRole:'stagehand',ownerXp:0,stagehandXp:0,audioXp:0,bandXp:0,bandName:'THE BAND'},staff:{paul:{hired:false,nextShift:false,shifts:0,wagesPaid:0,lastJobId:'',truckVisible:false}},waygoStats:{trips:0,inches:0,spent:0,emergencyTrips:0},byobCommunity:{shows:0,flags:0,savings:0},amlStats:{bookings:0,promotions:0,bookingFees:0,promotionFees:0},collectedResources:{},vanUpgrades:{armored:false,potatoGun:false}, driverPass:{name:'',photo:'',address:'517 N I-35 FRONTAGE RD, AUSTIN, TX 78702',started:'',passId:'',photoStyle:'VANCERTS VAN'}, foodCannon:{selected:'potato',defeated:{traffic:false,blackstar:false,waygo:false,elon:false},codesUnlocked:false}, training:{enabled:true,chapterSeen:[],chapterStarted:[],flags:{moved:false,phoneOpened:false,phoneClosed:false,radioOpened:false,radioClosed:false}}, specialHazardsRemoved:0,communityServicesLastDay:'',cheats:{sandbox:false,revealMap:false,invulnerable:false,forceElon:false,showSpawns:false,trafficSpeed:1,manualRoadTest:false},story:{festivalEmailSeen:false,festivalActive:false,festivalIndex:0,festivalComplete:false,eastAustinUnlocked:false,chapter3Started:false,secondFestivalActive:false,secondFestivalIndex:0,secondFestivalComplete:false,secondFestivalRoute:[],westAustinUnlocked:false,worldLiquorProgressionNormalized:false}}; const SAVE_KEY='vancerts-v8'; const TRAINING_PREF_KEY='vancerts-training-wheels-v1'; const PORTABLE_SESSION_KEY='vancerts-portable-session-v1'; function readPortableSession(){ try{ const raw=sessionStorage.getItem(PORTABLE_SESSION_KEY); if(!raw)return null; const parsed=JSON.parse(raw); return parsed&&parsed.format==='VANCERTS_SAVE'&&parsed.saveKey===SAVE_KEY&&parsed.state&&typeof parsed.state==='object'?parsed:null }catch(_){return null} } let portableSaveFile=readPortableSession(); let portableMode=!!portableSaveFile; function portablePayload(sourceState=state){ return { format:'VANCERTS_SAVE', version:1, build:'R36B41B TOUCHSCREEN NOOKIA + WALLET PERMIT', saveKey:SAVE_KEY, exportedAt:new Date().toISOString(), state:JSON.parse(JSON.stringify(sourceState)) } } function portableFilename(){ const d=new Date(),pad=n=>String(n).padStart(2,'0'); return `Vancerts_Save_${d.getFullYear()}-${pad(d.getMonth()+1)}-${pad(d.getDate())}_${pad(d.getHours())}-${pad(d.getMinutes())}.vancerts.json` } function exportPortableSave(){ const payload=portablePayload(state),blob=new Blob([JSON.stringify(payload,null,2)],{type:'application/json'}); const url=URL.createObjectURL(blob),a=document.createElement('a'); a.href=url;a.download=portableFilename();document.body.appendChild(a);a.click();a.remove(); setTimeout(()=>URL.revokeObjectURL(url),1000); toast('PORTABLE SAVE EXPORTED • COPY IT TO A USB DRIVE OR KEEP IT ON THIS COMPUTER') } window.exportPortableSave=exportPortableSave; function choosePortableSave(){ const input=$('portableSaveInput'); if(input){input.value='';input.click()} } window.choosePortableSave=choosePortableSave; async function loadPortableSaveFile(input){ const file=input&&input.files&&input.files[0];if(!file)return; try{ const parsed=JSON.parse(await file.text()); const payload=parsed&&parsed.format==='VANCERTS_SAVE'?parsed:{format:'VANCERTS_SAVE',version:1,saveKey:SAVE_KEY,state:parsed}; if(payload.saveKey!==SAVE_KEY||!payload.state||typeof payload.state!=='object')throw new Error('This is not a compatible Vancerts save file.'); sessionStorage.setItem(PORTABLE_SESSION_KEY,JSON.stringify(payload)); location.reload() }catch(err){ modal(`<h2>LOAD GAME FAILED</h2><p>${String(err&&err.message||'The selected file could not be read.')}</p><div class="btns"><button onclick="closeModal()">CLOSE</button></div>`) } } window.loadPortableSaveFile=loadPortableSaveFile; function returnToComputerSave(){ sessionStorage.removeItem(PORTABLE_SESSION_KEY);location.reload() } window.returnToComputerSave=returnToComputerSave; let storageAvailable=false; const memoryStorage={}; const WINDOW_STORE_PREFIX='VANCERTS_WINDOW_STORE:'; function readWindowStore(){try{return window.name.startsWith(WINDOW_STORE_PREFIX)?JSON.parse(decodeURIComponent(window.name.slice(WINDOW_STORE_PREFIX.length)))||{}:{}}catch(err){return {}}} function writeWindowStore(store){try{window.name=WINDOW_STORE_PREFIX+encodeURIComponent(JSON.stringify(store));return true}catch(err){return false}} Object.assign(memoryStorage,readWindowStore()); const safeStorage={ getItem(key){ try{const value=window.localStorage.getItem(key);storageAvailable=true;if(value!==null)return value}catch(err){} const named=readWindowStore();if(Object.prototype.hasOwnProperty.call(named,key))return named[key]; return Object.prototype.hasOwnProperty.call(memoryStorage,key)?memoryStorage[key]:null }, setItem(key,value){ memoryStorage[key]=String(value);writeWindowStore(memoryStorage); try{window.localStorage.setItem(key,String(value));storageAvailable=true;return true}catch(err){return false} }, removeItem(key){ delete memoryStorage[key];writeWindowStore(memoryStorage); try{window.localStorage.removeItem(key);storageAvailable=true;return true}catch(err){return false} } }; let savedState={}; try{savedState=portableSaveFile?portableSaveFile.state:(JSON.parse(safeStorage.getItem(SAVE_KEY)||'{}')||{})}catch(err){savedState={}} const savedStateHadData=Object.keys(savedState).length>0; let state=Object.assign({},defaults,savedState);state.cameraZoom=Math.max(1,Math.min(5,Math.round(Number(state.cameraZoom)||1)));state.zoomHelpSeen=!!state.zoomHelpSeen;state.inventory=Object.assign({},defaults.inventory,state.inventory||{});state.venues=Object.assign(freshVenues(),state.venues||{});state.invoices=Array.isArray(state.invoices)?state.invoices:[];state.completed=Array.isArray(state.completed)?state.completed:[];state.sponsor=state.sponsor||null;state.activeJob=state.activeJob||null;state.sponsorOffers=Array.isArray(state.sponsorOffers)?state.sponsorOffers.filter(id=>typeof id==='string'):[];if(!Number.isFinite(Number(state.vanhp)))state.vanhp=defaults.vanhp;state.vanhp=Math.max(0,Math.min(100,Number(state.vanhp)));const freshStory=Number(state.shows||0)===0&&state.completed.length===0&&!state.activeJob&&!state.pendingOffer;if(freshStory&&state.vanhp<=0)state.vanhp=defaults.vanhp;if(state.activeJob){state.activeJob.phase=state.activeJob.phase||'delivery';if(!state.activeJob.needs){const pk=state.activeJob.pkg==='band'?BAND:SOLO;state.activeJob.needs=gearNeedsFor(pk,state.activeJob.extras||{})}}if(state.activeJob){state.activeJob.posterCampaign=state.activeJob.posterCampaign&&typeof state.activeJob.posterCampaign==='object'?state.activeJob.posterCampaign:{placed:[]};state.activeJob.posterCampaign.placed=Array.isArray(state.activeJob.posterCampaign.placed)?state.activeJob.posterCampaign.placed.filter(x=>typeof x==='string'):[]}state.sponsorEmailSeen=!!state.sponsorEmailSeen;state.introVersion=Number(state.introVersion||0);state.pendingOffer=state.pendingOffer||null;if(state.pendingOffer&&state.pendingOffer.offer&&typeof state.pendingOffer.offer==='object')state.pendingOffer=state.pendingOffer.offer;if(state.pendingOffer&&!places.some(p=>p.id===state.pendingOffer.id))state.pendingOffer=null;state.communityUpgrades=Object.assign({},defaults.communityUpgrades,state.communityUpgrades||{});for(const k of Object.keys(defaults.communityUpgrades))state.communityUpgrades[k]=Math.max(0,Number(state.communityUpgrades[k])||0);state.wildlifeFreezeDay=String(state.wildlifeFreezeDay||'');state.expansionPermits=Object.assign(defaults.expansionPermits,state.expansionPermits||{});if(state.expansionPermits.eastAustin&&!state.expansionPermits['east-porkchop'])state.expansionPermits['east-porkchop']=true;state.expansionPermits.mama=!!state.expansionPermits.mama;state.expansionPermits.eastAustin=!!state.expansionPermits.eastAustin;if(state.venues.worldliquor&&(state.venues.worldliquor.sign||state.venues.worldliquor.eventCount>0||state.venues.worldliquor.rateCars>0)){state.expansionPermits.eastAustin=true;state.story=state.story||{};state.story.eastAustinUnlocked=true;state.story.festivalComplete=true;if(state.venues.worldliquor.sign){state.venues.worldliquor.eventCount=Math.max(4,Number(state.venues.worldliquor.eventCount)||0);state.venues.worldliquor.rateCars=8;state.venues.worldliquor.lotCycleFull=true;state.venues.worldliquor.flagCycleArmed=false;}}state.rentalOrder=state.rentalOrder&&typeof state.rentalOrder==='object'?state.rentalOrder:null;state.passengerRide=state.passengerRide&&typeof state.passengerRide==='object'?state.passengerRide:null;state.passengerStats=Object.assign({},defaults.passengerStats,state.passengerStats||{});state.passengerStats.rides=Math.max(0,Number(state.passengerStats.rides)||0);state.passengerStats.earnings=Math.max(0,Number(state.passengerStats.earnings)||0);state.bankLoan=state.bankLoan&&typeof state.bankLoan==='object'?state.bankLoan:null;if(state.bankLoan){state.bankLoan.principal=Math.max(0,Number(state.bankLoan.principal)||0);state.bankLoan.payoff=Math.max(state.bankLoan.principal,Number(state.bankLoan.payoff)||state.bankLoan.principal);state.bankLoan.repaid=Math.max(0,Math.min(state.bankLoan.payoff,Number(state.bankLoan.repaid)||0));if(state.bankLoan.repaid>=state.bankLoan.payoff)state.bankLoan=null}state.bankStats=Object.assign({},defaults.bankStats,state.bankStats||{});state.bankStats.loansTaken=Math.max(0,Number(state.bankStats.loansTaken)||0);state.bankStats.totalBorrowed=Math.max(0,Number(state.bankStats.totalBorrowed)||0);state.bankStats.totalRepaid=Math.max(0,Number(state.bankStats.totalRepaid)||0);state.byobCommunity=Object.assign({},defaults.byobCommunity,state.byobCommunity||{});state.byobCommunity.shows=Math.max(0,Number(state.byobCommunity.shows)||0);state.byobCommunity.flags=Math.max(0,Number(state.byobCommunity.flags)||0);state.byobCommunity.savings=Math.max(0,Number(state.byobCommunity.savings)||0);state.amlStats=Object.assign({},defaults.amlStats,state.amlStats||{});for(const k of Object.keys(defaults.amlStats))state.amlStats[k]=Math.max(0,Number(state.amlStats[k])||0);state.collectedResources=state.collectedResources&&typeof state.collectedResources==='object'?state.collectedResources:{};for(const k of Object.keys(state.collectedResources))state.collectedResources[k]=Math.max(0,Number(state.collectedResources[k])||0);state.vanUpgrades=Object.assign({},defaults.vanUpgrades,state.vanUpgrades||{});state.vanUpgrades.armored=!!state.vanUpgrades.armored;state.vanUpgrades.potatoGun=!!state.vanUpgrades.potatoGun;state.compliance=state.compliance&&typeof state.compliance==='object'?state.compliance:{};state.compliance.bmi=Object.assign({},defaults.compliance.bmi,state.compliance.bmi||{});state.compliance.bmi.events=Array.isArray(state.compliance.bmi.events)?state.compliance.bmi.events:[];state.compliance.bmi.submittedQuarters=Array.isArray(state.compliance.bmi.submittedQuarters)?state.compliance.bmi.submittedQuarters:[];state.compliance.bmi.additionalPaid=Math.max(0,Number(state.compliance.bmi.additionalPaid)||0);state.compliance.bmi.annualMinimum=437;state.compliance.bmi.minimumCovered=true;state.compliance.bmi.status='active'; state.career=Object.assign({},defaults.career,state.career||{});state.career.path=['owner','team','band'].includes(state.career.path)?state.career.path:'owner';state.career.teamRole=['stagehand','audio'].includes(state.career.teamRole)?state.career.teamRole:'stagehand';state.career.ownerXp=Math.max(0,Number(state.career.ownerXp)||0);state.career.stagehandXp=Math.max(0,Number(state.career.stagehandXp)||0);state.career.audioXp=Math.max(0,Number(state.career.audioXp)||0);state.career.bandXp=Math.max(0,Number(state.career.bandXp)||0);state.career.bandName=String(state.career.bandName||'THE BAND').slice(0,28);state.staff=Object.assign({},defaults.staff,state.staff||{});state.staff.paul=Object.assign({},defaults.staff.paul,state.staff.paul||{});state.staff.paul.hired=!!state.staff.paul.hired;state.staff.paul.nextShift=!!state.staff.paul.nextShift;state.staff.paul.shifts=Math.max(0,Number(state.staff.paul.shifts)||0);state.staff.paul.wagesPaid=Math.max(0,Number(state.staff.paul.wagesPaid)||0);state.staff.paul.lastJobId=String(state.staff.paul.lastJobId||'');state.staff.paul.truckVisible=state.staff.paul.hired||!!state.staff.paul.truckVisible;if(state.activeJob&&state.activeJob.staff&&state.activeJob.staff.paul){state.staff.paul.hired=true;state.staff.paul.truckVisible=true} state.bankLoans=Array.isArray(state.bankLoans)?state.bankLoans.map(normalizeBankLoanRecord).filter(Boolean):[]; if(state.bankLoan){const legacyLoan=normalizeBankLoanRecord({...state.bankLoan,id:`legacy-${state.bankLoan.takenAt||Date.now()}`,createdAt:state.bankLoan.takenAt||Date.now(),legacy:true});if(legacyLoan){state.bankLoans.push(legacyLoan);if(!state.bankLastAdvanceDay)state.bankLastAdvanceDay=austinDateKey(new Date(legacyLoan.createdAt))}state.bankLoan=null} state.bankLastAdvanceDay=String(state.bankLastAdvanceDay||''); state.bankStats=Object.assign({},defaults.bankStats,state.bankStats||{}); for(const k of Object.keys(defaults.bankStats))state.bankStats[k]=Math.max(0,Number(state.bankStats[k])||0); state.bankStats.totalInterestCharged=Math.max(state.bankStats.totalInterestCharged,state.bankLoans.reduce((sum,loan)=>sum+loan.interest,0)); state.bankStats.totalInterestPaid=Math.max(state.bankStats.totalInterestPaid,state.bankLoans.reduce((sum,loan)=>sum+loan.interestPaid,0)); state.waygoStats=Object.assign({},defaults.waygoStats,state.waygoStats||{});for(const k of Object.keys(defaults.waygoStats))state.waygoStats[k]=Math.max(0,Number(state.waygoStats[k])||0); state.finance=normalizeFinanceState(state.finance,savedStateHadData); const savedTraining=state.training&&typeof state.training==='object'?state.training:{}; state.training={enabled:Object.prototype.hasOwnProperty.call(savedTraining,'enabled')?savedTraining.enabled!==false:true,chapterSeen:Array.isArray(savedTraining.chapterSeen)?savedTraining.chapterSeen.filter(n=>[1,2,3,4].includes(Number(n))).map(Number):[],chapterStarted:Array.isArray(savedTraining.chapterStarted)?savedTraining.chapterStarted.filter(n=>[1,2,3,4].includes(Number(n))).map(Number):[],flags:Object.assign({},defaults.training.flags,savedTraining.flags||{})}; for(const k of Object.keys(defaults.training.flags))state.training.flags[k]=!!state.training.flags[k]; const storedTrainingPreference=safeStorage.getItem(TRAINING_PREF_KEY);if(storedTrainingPreference==='off')state.training.enabled=false;else if(storedTrainingPreference==='on')state.training.enabled=true; state.driverPass=Object.assign({},defaults.driverPass,state.driverPass||{});state.driverPass.photo=typeof state.driverPass.photo==='string'?state.driverPass.photo:''; state.driverPass.address='517 N I-35 FRONTAGE RD, AUSTIN, TX 78702'; state.driverPass.started=String(state.driverPass.started||austinDateKey()); state.driverPass.passId=String(state.driverPass.passId||('VAN-'+Math.random().toString(36).slice(2,8).toUpperCase())); state.driverPass.name=String(state.driverPass.name||'').slice(0,28); state.foodCannon=Object.assign({},defaults.foodCannon,state.foodCannon||{}); state.foodCannon.defeated=Object.assign({},defaults.foodCannon.defeated,state.foodCannon.defeated||{}); state.foodCannon.selected=['potato','donut','taco','burger','pickle'].includes(state.foodCannon.selected)?state.foodCannon.selected:'potato'; state.foodCannon.codesUnlocked=!!state.foodCannon.codesUnlocked;state.specialHazardsRemoved=Math.max(0,Number(state.specialHazardsRemoved)||0);state.communityServicesLastDay=String(state.communityServicesLastDay||'');state.cheats=Object.assign({},defaults.cheats,state.cheats||{});state.cheats.sandbox=!!state.cheats.sandbox;state.cheats.revealMap=!!state.cheats.revealMap;state.cheats.invulnerable=!!state.cheats.invulnerable;state.cheats.forceElon=!!state.cheats.forceElon;state.cheats.showSpawns=!!state.cheats.showSpawns;state.cheats.trafficSpeed=Math.max(.25,Math.min(3,Number(state.cheats.trafficSpeed)||1));state.cheats.manualRoadTest=!!state.cheats.manualRoadTest;state.story=Object.assign({},defaults.story,state.story||{});state.story.festivalEmailSeen=!!state.story.festivalEmailSeen;state.story.festivalActive=!!state.story.festivalActive;state.story.festivalIndex=Math.max(0,Number(state.story.festivalIndex)||0);state.story.festivalComplete=!!state.story.festivalComplete;state.story.eastAustinUnlocked=!!state.story.eastAustinUnlocked;state.story.chapter3Started=!!state.story.chapter3Started;state.story.secondFestivalActive=!!state.story.secondFestivalActive;state.story.secondFestivalIndex=Math.max(0,Number(state.story.secondFestivalIndex)||0);state.story.secondFestivalComplete=!!state.story.secondFestivalComplete;state.story.secondFestivalRoute=Array.isArray(state.story.secondFestivalRoute)?state.story.secondFestivalRoute:[];state.story.westAustinUnlocked=!!state.story.westAustinUnlocked;state.story.worldLiquorProgressionNormalized=!!state.story.worldLiquorProgressionNormalized;activateWorldLiquorAfterFestival();normalizeWorldLiquorAutoState();for(const p of places.filter(p=>p.type==='gig')){const v=state.venues[p.id];v.eventCount=Math.max(0,Number(v.eventCount)||0);v.budget=Math.max(0,Number(v.budget)||SOLO_COST);v.sign=!!v.sign;v.fillFlags=Math.max(0,Number(v.fillFlags)||0);v.lotCycleFull=!!v.lotCycleFull;v.flagCycleArmed=!!v.flagCycleArmed;v.amlPromotionActive=!!v.amlPromotionActive;if(typeof v.rateCars!=='number')v.rateCars=permanentCarsLegacy(v.eventCount,p.capacity);v.rateCars=Math.max(0,Number(v.rateCars)||0);if(v.sign&&permanentCarsLegacy(v.eventCount,p.capacity)>=(p.capacity||16)&&!v.lotCycleFull){v.lotCycleFull=true;v.flagCycleArmed=false}if((v.eventCount>0||v.rateCars>0||v.sign)&&!state.completed.includes(p.id))state.completed.push(p.id)}normalizeAllSponsorFlagRules(); const GIGBAG_SPAWN={x:566,y:410,angle:Math.PI/2}; const BYOB_REPAIR={x:1185,y:410,angle:Math.PI/2}; function livePullInSpawn(id,fallback){ const p=places.find(x=>x.id===id),d=drivewayFor(id)||p?.setup; if(!d)return fallback; return{x:d.x+d.w/2,y:d.y+Math.min(42,d.h/2),angle:Math.PI/2} } function initializeLiveSpawnPoints(){ Object.assign(GIGBAG_SPAWN,livePullInSpawn('shop',GIGBAG_SPAWN)); Object.assign(BYOB_REPAIR,livePullInSpawn('hq',BYOB_REPAIR)) } // BUILD R30: BYOB Austin is a protected safe ground. Dangerous objects cannot enter or damage the van here. const BYOB_SAFE_ZONE={x:790,y:145,w:485,h:520}; function inByobSafeZone(x,y,pad=0){return x>BYOB_SAFE_ZONE.x-pad&&x<BYOB_SAFE_ZONE.x+BYOB_SAFE_ZONE.w+pad&&y>BYOB_SAFE_ZONE.y-pad&&y<BYOB_SAFE_ZONE.y+BYOB_SAFE_ZONE.h+pad} function hazardBlockedByByob(x,y){return inByobSafeZone(x,y,18)} const van={x:GIGBAG_SPAWN.x,y:GIGBAG_SPAWN.y,angle:GIGBAG_SPAWN.angle,speed:0},keys={},traffic=[]; function sponsorSignCount(){return places.filter(p=>p.type==='gig'&&state.venues[p.id]&&state.venues[p.id].sign).length} function desiredBlackStarCount(){return 1+sponsorSignCount()} const COMMUNITY_PROJECTS={ sidewalks:{name:'SIDEWALK + TREE PROJECT',cost:2500,community:25,max:1,desc:'Adds sidewalks, shade trees, and safer walking paths throughout the district.'}, stoplights:{name:'TRAFFIC SIGNAL INSTALLATION',cost:5000,community:50,max:8,desc:'Signalizes one real intersection. Ordinary traffic and pedestrians wait for red lights. The Vancerts van, Black Star cars, and the road snake keep moving.'}, foodPantry:{name:'FOOD PANTRY',cost:7500,community:75,max:1,desc:'Adds a food pantry near Gig Bag ATX and makes Russel move 35% faster while collecting city resources.'}, busStops:{name:'BUS STOP PROGRAM',cost:10000,community:100,max:1,desc:'Upgrades the starter stop and adds three more pseudo-3D curbside shelters with waiting passengers.'}, garden:{name:'COMMUNITY GARDEN',cost:6250,community:125,max:1,desc:'Adds a garden and makes food and flower collectibles respawn faster.'}, publicArt:{name:'PUBLIC ART PROGRAM',cost:7500,community:150,max:1,desc:'Adds murals near businesses and increases Community earned from completed shows.'}, crosswalks:{name:'CITYWIDE CROSSWALK BUILDOUT',cost:3500,community:90,max:3,desc:'Adds marked crossings district by district: Eastside, South Side, then the complete city grid.'}, rainbowCrosswalks:{name:'RAINBOW CROSSWALK INITIATIVE',cost:5000,community:150,max:1,desc:'Repaints every major crosswalk in bright rainbow stripes. Austin keeps its color in this game world.'}, freeConcerts:{name:'FREE CONCERT SERIES',cost:10000,community:250,max:1,desc:'Adds a permanent free-concert program. Every future completed show earns bonus Community.'}, }; function projectLevel(id){return Math.max(0,Number(state.communityUpgrades[id])||0)} function snakeReduction(){return 0} function snakeMinimumLength(){return 5+sponsorSignCount()*3} function ordinaryTrafficFactor(){return state.cheats?state.cheats.trafficSpeed:1} const ROAD_ACTIVITY_BUDGET=25; const SPECIAL_ROAD_ROSTER=[ {vehicleType:'motorcycle',label:'MOTORCYCLE • LONG-HAIRED BEARDED RIDER',speed:2.35,color:'#292929',routeSeed:0,ignoreSignals:false,damage:4}, {vehicleType:'boxtruck',label:'BOX TRUCK',speed:1.02,color:'#d8d2c1',routeSeed:1,ignoreSignals:false,damage:6}, {vehicleType:'limousine',label:'LIMOUSINE',speed:1.55,color:'#171717',routeSeed:2,ignoreSignals:false,damage:5}, {vehicleType:'horse',label:'HORSEBACK RIDER',speed:.58,color:'#744b2d',routeSeed:3,ignoreSignals:false,damage:2}, {vehicleType:'testarossa',label:'RED TESTAROSSA-STYLE CAR',speed:3.35,color:'#d52326',routeSeed:4,ignoreSignals:true,damage:8}, {vehicleType:'lamborghini',label:'YELLOW SUPERCAR',speed:3.75,color:'#f2c621',routeSeed:5,ignoreSignals:true,damage:9}, {vehicleType:'ambulance',label:'AMBULANCE',speed:2.65,color:'#f3f3ed',routeSeed:6,ignoreSignals:true,damage:7}, {vehicleType:'waymo',label:'DRIVERLESS WAYMO-STYLE CAR',speed:1.28,color:'#f2f2ef',routeSeed:7,ignoreSignals:false,damage:4} ]; const ORDINARY_VEHICLE_TYPES=['sedan','hatchback','suv','pickup','deliveryvan']; const ORDINARY_COLORS=['#3f77a8','#8e3f42','#d2c8ad','#4f6c49','#6c547d','#d77a32','#565d65','#d7d7d2']; let lastTrafficBudgetSync=0; function snakeTrafficCost(){return roadSnake.active?Math.min(5,Math.max(1,Math.ceil(roadSnake.length/6))):0} function specialRoadCount(){return SPECIAL_ROAD_ROSTER.length} function desiredOrdinaryTrafficCount(){return Math.max(3,ROAD_ACTIVITY_BUDGET-specialRoadCount())} function trafficRouteForIndex(i,avoidEast=false){ // Current connected corridors. Eastside receives a controlled minority only. const core=[['x',642,75,world.w-75,-1],['x',738,75,world.w-75,1],['x',1342,75,world.w-75,-1],['x',1438,75,world.w-75,1],['x',1927,75,world.w-75,-1],['x',2023,75,world.w-75,1],['y',650,75,world.h-75,1],['y',740,75,world.h-75,-1],['y',1310,75,world.h-75,1],['y',1400,75,world.h-75,-1],['y',1970,75,world.h-75,1],['y',2060,75,world.h-75,-1]]; const east=[['y',2580,75,world.h-75,1],['y',2670,75,world.h-75,-1]]; const defs=avoidEast?core:core.concat((Math.abs(i)%6===0)?east:[]); const d=defs[Math.abs(i)%defs.length],span=d[3]-d[2]; return{axis:d[0],lane:d[1],min:d[2],max:d[3],dir:d[4],pos:d[2]+span*((Math.abs(i)*.173)%1)} } function createOrdinaryRoadVehicle(i){ const route=trafficRouteForIndex(i),vehicleType=ORDINARY_VEHICLE_TYPES[i%ORDINARY_VEHICLE_TYPES.length]; return Object.assign(route,{isSpecialRoad:false,vehicleType,label:vehicleType.toUpperCase(),speed:.78+(i%7)*.17,color:ORDINARY_COLORS[i%ORDINARY_COLORS.length],damage:3}) } function createSpecialRoadVehicle(spec,i){return Object.assign(trafficRouteForIndex(spec.routeSeed+12),{...spec,isSpecialRoad:true,nextPullOverAt:Date.now()+9000+i*1800,parkedUntil:0,pullOverUntil:0})} function initializeRoadTraffic(){traffic.length=0;SPECIAL_ROAD_ROSTER.forEach((spec,i)=>traffic.push(createSpecialRoadVehicle(spec,i)));syncRoadActivityBudget(true)} function syncRoadActivityBudget(force=false){ if(sandboxRoadTestingActive())return; const now=Date.now();if(!force&&now-lastTrafficBudgetSync<1000)return;lastTrafficBudgetSync=now; const target=desiredOrdinaryTrafficCount(),ordinary=traffic.filter(c=>!c.isSpecialRoad); while(ordinary.length<target){const car=createOrdinaryRoadVehicle(ordinary.length+specialRoadCount());traffic.push(car);ordinary.push(car)} while(ordinary.length>target){const car=ordinary.pop(),idx=traffic.indexOf(car);if(idx>=0)traffic.splice(idx,1)} } function trafficBudgetSnapshot(){return{budget:ROAD_ACTIVITY_BUDGET,ordinary:traffic.filter(c=>!c.isSpecialRoad).length,specialRoad:traffic.filter(c=>c.isSpecialRoad).length,blackStar:specialCars.length,snakeSegments:roadSnake.active?roadSnake.length:0,collectibles:collectibles.filter(c=>c.active&&!c.delivered).length}} function emergencyActive(){return(Date.now()%55000)<18000} function trafficVisualXY(c){ const q=carXY(c),angle=q.angle||0;let lateral=0; if(c.vehicleType==='waymo'&&c.parkedUntil>Date.now())lateral=31; if(c.pullOverUntil>Date.now())lateral=28;if(c.socialPullUntil>Date.now())lateral=48; if(c.vehicleType==='testarossa')lateral=Math.sin(Date.now()/420+c.routeSeed)*12; if(c.vehicleType==='lamborghini')lateral=Math.cos(Date.now()/360+c.routeSeed)*14; return{x:q.x-Math.sin(angle)*lateral,y:q.y+Math.cos(angle)*lateral,angle} } function updateEmergencyPullovers(){ const ambulance=traffic.find(c=>c.vehicleType==='ambulance');if(!ambulance||!emergencyActive())return; const aq=trafficVisualXY(ambulance),now=Date.now(); for(const c of traffic){if(c===ambulance||c.vehicleType==='horse'||c.vehicleType==='motorcycle')continue;const q=trafficVisualXY(c);if(Math.hypot(q.x-aq.x,q.y-aq.y)<310)c.pullOverUntil=now+1000} } const TRAFFIC_SIGNAL_NODES=[ {id:'congress-6th',x:695,y:690,offset:0}, {id:'cesar-6th',x:1355,y:690,offset:1500}, {id:'redriver-6th',x:2015,y:690,offset:3000}, {id:'congress-lower',x:695,y:1390,offset:4500}, {id:'cesar-lower',x:1355,y:1390,offset:6000}, {id:'redriver-lower',x:2015,y:1390,offset:7500}, {id:'congress-north',x:695,y:75,offset:9000}, {id:'redriver-south',x:2015,y:1775,offset:10500} ]; const BUS_STOPS_ENABLED=false; if(!BUS_STOPS_ENABLED)state.passengerRide=null; const BUS_STOP_SITES=[ {x:1775,y:786,w:82,h:27,label:'6TH / BYOB',side:'south'}, {x:500,y:568,w:82,h:27,label:'6TH / CONGRESS',side:'north'}, {x:1115,y:786,w:82,h:27,label:'6TH / CESAR',side:'south'}, {x:2285,y:1487,w:82,h:27,label:'LOWER / EAST',side:'south'} ]; const BUS_FARE=5; function visibleBusStops(){if(!BUS_STOPS_ENABLED)return[];return projectLevel('busStops')?BUS_STOP_SITES:BUS_STOP_SITES.slice(0,1)} function busStopPickupPoint(site){return{x:site.x+site.w/2,y:site.side==='north'?site.y-22:site.y+site.h+22}} function busDestinationChoices(){return places.filter(p=>placeVisible(p)&&['gig','shop','hq'].includes(p.type))} function chooseBusDestination(stopIndex){const choices=busDestinationChoices();if(!choices.length)return null;const stop=BUS_STOP_SITES[stopIndex],pt=busStopPickupPoint(stop);const filtered=choices.filter(p=>Math.hypot(p.interact.x-pt.x,p.interact.y-pt.y)>180);const pool=filtered.length?filtered:choices;return pool[Math.floor(Math.random()*pool.length)]} function startPassengerRide(stopIndex){if(!BUS_STOPS_ENABLED)return;if(state.passengerRide)return toast('A passenger is already in the van.');const dest=chooseBusDestination(stopIndex);if(!dest)return toast('No passenger destination is available.');state.passengerRide={stopIndex,destinationId:dest.id,startedAt:Date.now(),fare:BUS_FARE};save();hud();toast(`PASSENGER PICKED UP • ${dest.short||dest.name} • $${BUS_FARE} ON DELIVERY`)} function finishPassengerRide(){const ride=state.passengerRide;if(!ride)return;const dest=places.find(p=>p.id===ride.destinationId);if(!dest||!placeVisible(dest)){state.passengerRide=null;save();hud();return}const fare=Number(ride.fare)||BUS_FARE;creditCash(fare,'Passenger Service',`Passenger ride to ${dest.name}`);state.passengerStats.rides++;state.passengerStats.earnings+=fare;state.passengerRide=null;save();hud();toast(`PASSENGER DELIVERED • +$${fare}`)} function activePassengerDestination(){return BUS_STOPS_ENABLED&&state.passengerRide?places.find(p=>p.id===state.passengerRide.destinationId&&placeVisible(p)):null} function activeBusPickupNear(){if(state.passengerRide)return null;const stops=visibleBusStops();let best=null,bestD=74;for(let i=0;i<stops.length;i++){const pt=busStopPickupPoint(stops[i]),d=Math.hypot(van.x-pt.x,van.y-pt.y);if(d<bestD){bestD=d;best={type:'busstop',stopIndex:i,interact:pt,name:stops[i].label}}}return best} function posterCampaignJob(){const j=state.activeJob;return j&&j.amlPromotion&&j.phase==='delivery'?j:null} function posterSpotList(){ const spots=[]; const add=(id,x,y,type,label,district)=>spots.push({id,x,y,type,label,district,interact:{x,y}}); visibleBusStops().forEach((stop,i)=>{const p=busStopPickupPoint(stop);add(`bus-${i}`,p.x+48,p.y,'busstop',`${stop.label} BUS STOP`,p.x<900?'west':p.x>2050?'east':'central')}); for(const p of places){ if(p.type==='retired'||p.id==='leftwaygrounds')continue; const visible=placeVisible(p),closed=!visible||((p.type==='gig')&&!unlocked(p.id)); const q=r36b45StreetPosterPoint(p),x=Math.max(22,Math.min(world.w-22,q.x)),y=Math.max(22,Math.min(world.h-22,q.y)); add(`${closed?'closed':'business'}-${p.id}`,x,y,closed?'closed':'business',`${closed?'CLOSED / FUTURE':'STREET ACCESS'} • ${p.short||p.name}`,x<700?'west':x>2600?'east':x<1400?'north':x<2100?'central':'south'); } for(const b of lockedEdgeBusinesses){const id=b.id||`locked-${Math.round(b.x)}-${Math.round(b.y)}`;add(`closed-${id}`,b.x+b.w/2,b.y+b.h/2,'closed','CLOSED BUSINESS',b.x<700?'west':b.x>2600?'east':'outer')} return spots } function activePosterSpotNear(){ const j=posterCampaignJob();if(!j)return null; const used=new Set(j.posterCampaign?.placed||[]);let best=null,bestD=66; for(const s of posterSpotList()){if(used.has(s.id))continue;const d=Math.hypot(van.x-s.x,van.y-s.y);if(d<bestD){bestD=d;best={...s,type:'poster',interact:{x:s.x,y:s.y}}}} return best } function placePromotionPoster(spot){ const j=posterCampaignJob();if(!j||!spot)return toast('Book a promoted show before placing posters.'); j.posterCampaign=j.posterCampaign||{placed:[]};j.posterCampaign.placed=Array.isArray(j.posterCampaign.placed)?j.posterCampaign.placed:[]; if(j.posterCampaign.placed.includes(spot.id))return toast('A poster is already here.'); j.posterCampaign.placed.push(spot.id);save();hud();toast(`POSTER ${j.posterCampaign.placed.length} • ${spot.label}`) } function posterCampaignResult(job,venueId,capacity,priorCars,normalIncrease){ const placed=[...new Set(job?.posterCampaign?.placed||[])],map=new Map(posterSpotList().map(s=>[s.id,s])),spots=placed.map(id=>map.get(id)).filter(Boolean); const types=new Set(spots.map(s=>s.type)),districts=new Set(spots.map(s=>s.district)); const inventive=spots.filter(s=>s.type==='busstop'||s.type==='closed').length; const score=spots.length+types.size*2+districts.size+inventive*2; let added=0,tier='NO POSTERS'; if(spots.length){ const roll=Math.random(); if(score>=18){added=capacity-priorCars;tier='CITYWIDE BUZZ'} else if(score>=13){added=roll<.55?capacity-priorCars:Math.max(4,Math.ceil(normalIncrease*3));tier='BREAKOUT CAMPAIGN'} else if(score>=8){added=Math.max(2,Math.ceil(normalIncrease*(1.5+roll)));tier='STRONG CAMPAIGN'} else{added=2;tier='STREET-LEVEL BOOST'} } added=Math.max(0,Math.min(capacity-priorCars,added)); const payoutPct=Math.min(40,spots.length*4+types.size*3+districts.size*2+inventive*2); const halo=score>=18; return{placed:spots.length,types:types.size,districts:districts.size,inventive,score,added,payoutPct,halo,tier} } function applyPromotionHalo(sourceId){ const source=places.find(p=>p.id===sourceId),changed=[];if(!source)return changed; const sx=source.interact?.x||source.x,sy=source.interact?.y||source.y; const nearby=places.filter(p=>p.type==='gig'&&p.id!==sourceId&&placeVisible(p)&&state.venues[p.id]).sort((a,b)=>Math.hypot((a.interact?.x||a.x)-sx,(a.interact?.y||a.y)-sy)-Math.hypot((b.interact?.x||b.x)-sx,(b.interact?.y||b.y)-sy)).slice(0,4); for(const p of nearby){const v=state.venues[p.id],before=permanentCars(p.id),after=Math.min(p.capacity||16,before+2);if(after>before){v.rateCars=Math.max(Number(v.rateCars)||0,after);changed.push(p.short||p.name)}} return changed } function activePassengerDropNear(){const dest=activePassengerDestination();if(!dest)return null;const d=Math.hypot(van.x-dest.interact.x,van.y-dest.interact.y);return d<92?{type:'passengerDrop',id:dest.id,interact:dest.interact,name:dest.name}:null} const socialRide={active:false,hourKey:'',progress:0,lastHorn:0,durationMs:240000,forcedUntil:0,bikes:100,route:[{x:150,y:690},{x:2625,y:690},{x:2625,y:1390},{x:700,y:1390},{x:700,y:1975},{x:2625,y:1975},{x:2625,y:75},{x:700,y:75},{x:700,y:690}],points:[]}; function socialRideRouteData(){const segs=[],r=socialRide.route;let total=0;for(let i=0;i<r.length-1;i++){const a=r[i],b=r[i+1],len=Math.hypot(b.x-a.x,b.y-a.y);segs.push({a,b,len,start:total});total+=len}return{segs,total}} const SOCIAL_RIDE_ROUTE=socialRideRouteData(); function socialRidePoint(distance){const total=SOCIAL_RIDE_ROUTE.total;let d=((distance%total)+total)%total;for(const seg of SOCIAL_RIDE_ROUTE.segs){if(d<=seg.len){const t=seg.len?d/seg.len:0;return{x:seg.a.x+(seg.b.x-seg.a.x)*t,y:seg.a.y+(seg.b.y-seg.a.y)*t,angle:Math.atan2(seg.b.y-seg.a.y,seg.b.x-seg.a.x)}}d-=seg.len}const p=socialRide.route[0];return{x:p.x,y:p.y,angle:0}} function updateSocialRide(dt){const t=austinTimeParts(),key=`${austinDateKey()}-${t.hour}`,forced=Date.now()<Number(socialRide.forcedUntil||0),shouldRun=t.minute<4||forced;if(shouldRun&&socialRide.hourKey!==key){socialRide.hourKey=key;socialRide.progress=0;socialRide.active=true;socialRide.lastHorn=0;toast('SOCIAL BIKE RIDE! 100 riders are taking three quarters of the street. Plan another route.')}if(!shouldRun){socialRide.active=false;socialRide.points=[];return}socialRide.active=true;socialRide.progress+=dt*.105;socialRide.points=[];const columns=4,lateralSlots=[-33,-11,11,33];for(let i=0;i<socialRide.bikes;i++){const row=Math.floor(i/columns),col=i%columns;const packOffset=row*21+(row%6)*2;const variation=Math.sin((performance.now()/700)+(i*1.7))*4;const p=socialRidePoint(socialRide.progress-packOffset+variation);const lateral=lateralSlots[col]+Math.sin(i*2.1)*2;p.x+=-Math.sin(p.angle)*lateral;p.y+=Math.cos(p.angle)*lateral;socialRide.points.push({...p,index:i,entityId:`#BIKE-GROUP-${String(i+1).padStart(3,'0')}`})}if(Date.now()-socialRide.lastHorn>1800){socialRide.lastHorn=Date.now();playSocialRideHorns()}} function socialRideBlocksTrafficAt(x,y){if(!socialRide.active||!socialRide.points.length)return false;for(let i=0;i<socialRide.points.length;i+=3){const p=socialRide.points[i];if(Math.hypot(x-p.x,y-p.y)<185)return true}return false} let socialRideAudio=null;function playSocialRideHorns(){try{socialRideAudio=socialRideAudio||new (window.AudioContext||window.webkitAudioContext)();if(socialRideAudio.state==='suspended')socialRideAudio.resume();const now=socialRideAudio.currentTime;[0,.06,.13,.22].forEach((delay,i)=>{const o=socialRideAudio.createOscillator(),g=socialRideAudio.createGain();o.type=i%2?'square':'sawtooth';o.frequency.value=175+i*38;g.gain.setValueAtTime(.0001,now+delay);g.gain.exponentialRampToValueAtTime(.062,now+delay+.015);g.gain.exponentialRampToValueAtTime(.0001,now+delay+.14);o.connect(g);g.connect(socialRideAudio.destination);o.start(now+delay);o.stop(now+delay+.16)})}catch(e){}} function drawSocialBike(p){const leader=p.index===0,safety=p.index===socialRide.bikes-1;ctx.save();ctx.translate(p.x,p.y);ctx.rotate(p.angle);ctx.strokeStyle='#171514';ctx.lineWidth=2.4;ctx.beginPath();ctx.ellipse(-8,5,6,3,0,0,Math.PI*2);ctx.ellipse(8,5,6,3,0,0,Math.PI*2);ctx.moveTo(-8,5);ctx.lineTo(0,-2);ctx.lineTo(8,5);ctx.moveTo(0,-2);ctx.lineTo(3,5);ctx.stroke();ctx.fillStyle=['#2e8657','#e4b52c','#1e1e1e','#8f3f69','#3f84a5','#d45d45'][p.index%6];ctx.fillRect(-3,-12,7,11);ctx.fillStyle=['#5b3828','#7a4d32','#38261f','#9a6a49','#cf9b75'][p.index%5];ctx.beginPath();ctx.arc(0,-16,4,0,Math.PI*2);ctx.fill();if(leader||safety){ctx.fillStyle=leader?'#e4b52c':'#79c88e';ctx.beginPath();ctx.moveTo(-5,-10);ctx.lineTo(-15,-16);ctx.lineTo(-11,-3);ctx.closePath();ctx.fill();ctx.fillStyle='#111';ctx.font='1000 5px system-ui';ctx.textAlign='center';ctx.fillText(leader?'LEAD':'SAFE',0,-22)}ctx.restore()} function drawSocialRide(){if(!socialRide.active)return;for(let i=socialRide.points.length-1;i>=0;i--)drawSocialBike(socialRide.points[i])} function activeTrafficSignals(){return TRAFFIC_SIGNAL_NODES.slice(0,Math.min(projectLevel('stoplights'),TRAFFIC_SIGNAL_NODES.length))} function trafficSignalState(node,now=Date.now()){ const phase=((now+node.offset)%12000+12000)%12000; if(phase<4000)return{x:'green',y:'red'}; if(phase<5000)return{x:'yellow',y:'red'}; if(phase<6000)return{x:'red',y:'red'}; if(phase<10000)return{x:'red',y:'green'}; if(phase<11000)return{x:'red',y:'yellow'}; return{x:'red',y:'red'} } function crossedSignalLine(a,b,line,dir){return dir>0?a<=line&&b>line:a>=line&&b<line} function movementBlockedByRed(x,y,nx,ny,kind='vehicle'){ // The Vancerts van and physical hazards never stop for traffic lights. if(kind==='van'||kind==='trash'||kind==='tire'||kind==='snake'||kind==='blackstar')return false; const dx=nx-x,dy=ny-y;if(Math.abs(dx)+Math.abs(dy)<.001)return false; const axis=Math.abs(dx)>=Math.abs(dy)?'x':'y',dir=Math.sign(axis==='x'?dx:dy)||1; const lateralLimit=kind==='pedestrian'?135:kind==='trash'?115:82; for(const node of activeTrafficSignals()){ const lateral=axis==='x'?Math.abs((y+ny)/2-node.y):Math.abs((x+nx)/2-node.x); if(lateral>lateralLimit)continue; if(trafficSignalState(node)[axis]==='green')continue; const line=(axis==='x'?node.x:node.y)-dir*108; if(crossedSignalLine(axis==='x'?x:y,axis==='x'?nx:ny,line,dir))return true; } return false } function loopRouteStaysOnRoad(c,nextT){ const len=loopLength(c.inset),delta=((nextT-c.t)%len+len)%len,steps=Math.max(2,Math.ceil(delta/18)); for(let i=0;i<=steps;i++){const t=(c.t+delta*(i/steps))%len,q=loopPoint({...c,t});if(!onDesignatedRoadPoint(q.x,q.y,1)||hazardBlockedByByob(q.x,q.y))return false} return true } function advanceTrafficCar(c,f){ const factor=ordinaryTrafficFactor(),now=Date.now(); const ridePos=trafficVisualXY(c);if(socialRideBlocksTrafficAt(ridePos.x,ridePos.y)){c.socialPullUntil=now+1400;return;} if(c.hiddenUntil>now)return; if(c.entryMode){advanceTrafficEntry(c,f);return} if(c.exitMode){advanceTrafficExit(c,f);return} if(c.pullOverUntil>now)return; if(c.vehicleType==='waymo'){if(c.parkedUntil>now)return;if(now>=c.nextPullOverAt){c.parkedUntil=now+30000;c.nextPullOverAt=c.parkedUntil+10000;return}} let np=c.pos+c.dir*c.speed*f*factor; const q=carXY(c),nq=c.axis==='x'?{x:np,y:c.lane}:{x:c.lane,y:np}; if(np<c.min||np>c.max){beginTrafficExit(c);return} const roadSafe=onDesignatedRoadPoint(q.x,q.y,1)&&onDesignatedRoadPoint(nq.x,nq.y,1)&&segmentStaysOnRoad(q.x,q.y,nq.x,nq.y); if(roadSafe&&!hazardBlockedByByob(nq.x,nq.y)&&!movementBlockedByRed(q.x,q.y,nq.x,nq.y,c.ignoreSignals?'blackstar':'vehicle'))c.pos=np } function advanceSpecialCar(car,f){ let remaining=car.speed*f; while(remaining>0){ const dx=car.targetX-car.x,dy=car.targetY-car.y,d=Math.hypot(dx,dy)||1; car.angle=Math.atan2(dy,dx); if(d<=remaining+0.01){car.x=car.targetX;car.y=car.targetY;remaining-=d;chooseBlackStarTarget(car)} else{const nx=car.x+dx/d*remaining,ny=car.y+dy/d*remaining;if(onDesignatedRoadPoint(nx,ny,1)){car.x=nx;car.y=ny}else{car.x=car.targetX;car.y=car.targetY;chooseBlackStarTarget(car)}remaining=0} } } function signalLampColor(state,lamp){ if(state===lamp)return lamp==='red'?'#f0473e':lamp==='yellow'?'#ffd447':'#4fe06d'; return lamp==='red'?'#4a1917':lamp==='yellow'?'#4b421b':'#173d20' } function drawSignalHead(x,y,state,axis){ ctx.save();ctx.translate(x,y);ctx.fillStyle='#333';ctx.fillRect(-4,0,8,30);ctx.fillStyle='#171514';ctx.fillRect(-11,-18,22,25);ctx.strokeStyle='#777';ctx.lineWidth=2;ctx.strokeRect(-11,-18,22,25); const lamps=['red','yellow','green'];for(let i=0;i<3;i++){ctx.fillStyle=signalLampColor(state,lamps[i]);ctx.beginPath();ctx.arc(-6+i*6,-6,2.6,0,Math.PI*2);ctx.fill()} ctx.fillStyle='#f4e6be';ctx.font='900 6px monospace';ctx.textAlign='center';ctx.fillText(axis==='x'?'↔':'↕',0,5);ctx.restore() } function drawTrafficSignal(node){ const st=trafficSignalState(node),x=node.x,y=node.y; ctx.save();ctx.strokeStyle='#f4e6be';ctx.lineWidth=4; ctx.beginPath();ctx.moveTo(x-126,y-66);ctx.lineTo(x-126,y+66);ctx.moveTo(x+126,y-66);ctx.lineTo(x+126,y+66);ctx.moveTo(x-66,y-126);ctx.lineTo(x+66,y-126);ctx.moveTo(x-66,y+126);ctx.lineTo(x+66,y+126);ctx.stroke(); ctx.lineWidth=2;ctx.strokeStyle='rgba(255,255,255,.7)'; for(let i=-54;i<=54;i+=18){ctx.beginPath();ctx.moveTo(x+i,y-101);ctx.lineTo(x+i+10,y-88);ctx.moveTo(x+i,y+101);ctx.lineTo(x+i+10,y+88);ctx.moveTo(x-101,y+i);ctx.lineTo(x-88,y+i+10);ctx.moveTo(x+101,y+i);ctx.lineTo(x+88,y+i+10);ctx.stroke()} drawSignalHead(x-112,y-112,st.x,'x');drawSignalHead(x+112,y+112,st.x,'x');drawSignalHead(x+112,y-112,st.y,'y');drawSignalHead(x-112,y+112,st.y,'y'); ctx.restore() } function drawBusStop(site){ const{x,y,w,h,label}=site;ctx.save();ctx.fillStyle='#d5d0bc';ctx.fillRect(x-4,y+h-2,w+8,6);ctx.fillStyle='#2d566c';ctx.fillRect(x,y,w,h);ctx.strokeStyle='#17232a';ctx.lineWidth=3;ctx.strokeRect(x,y,w,h);ctx.fillStyle='rgba(200,230,240,.75)';ctx.fillRect(x+7,y+5,w-14,h-12);ctx.fillStyle='#714b2d';ctx.fillRect(x+12,y+h-7,w-24,5);ctx.fillStyle='#1d2830';ctx.fillRect(x+w+5,y-7,5,h+20);ctx.fillStyle='#f4e6be';ctx.fillRect(x+w-2,y-11,34,18);ctx.strokeStyle='#17232a';ctx.strokeRect(x+w-2,y-11,34,18);ctx.fillStyle='#17232a';ctx.font='1000 7px monospace';ctx.textAlign='center';ctx.fillText('BUS',x+w+15,y+1);ctx.font='900 6px monospace';ctx.fillStyle='#fff';ctx.fillText(label,x+w/2,y+17);ctx.restore() } function collectibleRespawnMs(){return projectLevel('garden')?90000:180000} function showCommunityShop(){const cards=Object.entries(COMMUNITY_PROJECTS).filter(([id])=>BUS_STOPS_ENABLED||id!=='busStops').map(([id,p])=>{const lvl=projectLevel(id),owned=lvl>=p.max,repeat=p.max>1;let badge=owned?'<span class="projectOwned">COMPLETE</span>':repeat?`<span class="projectLevel">LEVEL ${lvl}/${p.max}</span>`:'';let effect=id==='wildlifeManagement'&&state.wildlifeFreezeDay===austinDateKey()?'<br><span class="good">ACTIVE TODAY</span>':'';return `<div class="card"><h3>${p.name}</h3>${badge}<p>${p.desc}${effect}</p><p><b>$${p.cost.toLocaleString()}</b> • COMMUNITY +${p.community}</p><button onclick="buyCommunityUpgrade('${id}')" ${owned||state.cash<p.cost?'disabled':''}>${owned?'PURCHASED':'PURCHASE'}</button></div>`}).join('');modal(`<h2>BYOB COMMUNITY PROJECTS</h2><div class="communityLegend"><b>BUILD THE BUSINESS. BUILD THE CITY.</b><br>Community projects permanently change Austin. After all active founding sponsors sign, purchase the Mama Dearest expansion permit at BYOB for $12,500. They never reduce the number of Black Star cars; they improve the streets, volunteers, public spaces, and your ability to manage the snake.</div><div class="grid communityShop">${cards}</div><div class="btns"><button class="secondary" onclick="hqModal()">BACK TO BYOB</button></div>`)} window.showCommunityShop=showCommunityShop; window.buyCommunityUpgrade=id=>{const p=COMMUNITY_PROJECTS[id];if(!p)return;const lvl=projectLevel(id);if(lvl>=p.max||!debitCash(p.cost,'Community Projects',p.name))return;state.communityUpgrades[id]=lvl+1;state.rep+=p.community;if(id==='foodPantry')cartCollector.speed=.070;save();hud();toast(`${p.name} PURCHASED • COMMUNITY +${p.community}`);showCommunityShop()}; const specialCars=[]; function specialCarActive(){return true} function daytimePedestriansActive(){const t=austinTimeParts(),mins=t.hour*60+t.minute;return !!state.sponsor&&mins>=480&&mins<1080} function pointInRect(x,y,r,pad=0){return x>=r.x-pad&&x<=r.x+r.w+pad&&y>=r.y-pad&&y<=r.y+r.h+pad} function rectsOverlap(a,b,pad=0){return a.x-pad<b.x+b.w&&a.x+a.w+pad>b.x&&a.y-pad<b.y+b.h&&a.y+a.h+pad>b.y} function auditR36B26ARenderFunctions(){ const required=['drawSpecialCar','drawRoadSnake','drawDonutProjectiles','drawVan','drawRoadVehicle','drawPseudoVehicle','drawCartCollector','drawPedestrians']; const missing=[]; for(const name of required){ try{if(typeof eval(name)!=='function')missing.push(name)} catch(_){missing.push(name)} } return{ok:missing.length===0,missing} } window.auditR36B26ARenderFunctions=auditR36B26ARenderFunctions; function auditR36B26Systems(){ const issues=[]; for(const p of places.filter(p=>p.parking&&!p.retiredByReorg)){ if(!p.setup?.parcelContained)issues.push(`${p.id}: pull-in not parcel-contained`); if(p.setup&&roads.some(r=>rectsOverlap(p.setup,r,0)))issues.push(`${p.id}: pull-in overlaps traffic`); } if(typeof driverPassModal!=='function')issues.push('Driver Permit missing'); if(typeof foodCannonModal!=='function')issues.push('Food Cannon menu missing'); if(!state.driverPass?.started)issues.push('Driver Permit start date missing'); if(!state.foodCannon?.defeated)issues.push('Hazard recipe state missing'); const west=['bank','kazi','tascam','jblpro'].map(id=>places.find(p=>p.id===id)); if(west.some(p=>!p||!placeVisible(p)))issues.push('west businesses are not permanently visible'); return{ok:issues.length===0,issues,chapter:currentChapter(),food:state.foodCannon.selected} } window.auditR36B26Systems=auditR36B26Systems; function auditR36B25Layout(){ const issues=[]; const genericLocks=lockedEdgeBusinesses.filter(b=>!b.id); if(genericLocks.length)issues.push(`south lock overlays remain: ${genericLocks.length}`); for(const id of ['bank','kazi','tascam','jblpro']){ const p=places.find(x=>x.id===id); if(!p){issues.push(`${id}: missing`);continue} if(p.w!==300||p.parking?.w!==300)issues.push(`${id}: still visually undersized`); if(p.setup?.x!==75||p.setup?.w!==55)issues.push(`${id}: contained pull-in incorrect`); if(p.setup&&p.setup.x+p.setup.w>140)issues.push(`${id}: pull-in enters traffic`); } const grounds=places.find(p=>p.id==='leftwaygrounds'); if(!grounds||grounds.x!==2140||grounds.w!==375)issues.push('Leftway Grounds parcel mismatch'); if(DRIVEWAYS.some(d=>d.id==='leftwaygrounds'))issues.push('stale Leftway Grounds driveway remains'); return{ok:issues.length===0,issues} } window.auditR36B25Layout=auditR36B25Layout; function auditR36B24Layout(){ const issues=[]; const grounds=places.find(p=>p.id==='leftwaygrounds'); if(!grounds||grounds.x!==2140||grounds.w!==375)issues.push('Leftway Grounds not filling neighboring parcel'); for(const id of ['bank','kazi','tascam','jblpro']){ const p=places.find(x=>x.id===id); if(!p)issues.push(`${id}: missing`); else{ const parcel=WEST_VISUAL_PARCELS.find(q=>q.id===id); if(!parcel)issues.push(`${id}: missing grass parcel`); if(!p.setup||p.setup.x+p.setup.w>140)issues.push(`${id}: pull-in exceeds property edge`); if(p.setup&&p.parking&&p.setup.x<p.parking.x+p.parking.w)issues.push(`${id}: pull-in overlaps parking`); } } const generic=lockedEdgeBusinesses.filter(b=>!b.id); if(generic.length!==5)issues.push(`expected 5 southern future markers, found ${generic.length}`); const xs=new Set(generic.map(b=>b.x)); if(xs.size!==generic.length)issues.push('future markers share a parcel'); return{ok:issues.length===0,issues} } window.auditR36B24Layout=auditR36B24Layout; function auditR36B23Fixes(){ const issues=[]; for(const fn of ['autoPlace','placeSlot','clearSetup'])if(typeof window[fn]!=='function')issues.push(`${fn} missing`); const grounds=places.find(p=>p.id==='leftwaygrounds'); if(!grounds||grounds.w!==315||grounds.h!==315)issues.push('Leftway Grounds parcel dimensions'); if(grounds&&grounds.setup)issues.push('Leftway Grounds still uses oversized setup rectangle'); for(const id of ['bank','kazi','tascam','jblpro']){ const p=places.find(x=>x.id===id); if(!p||p.w!==220||p.parking?.w!==220)issues.push(`${id}: west scale mismatch`) } if(lockedEdgeBusinesses.some(b=>!b.id&&b.y<0))issues.push('future locked businesses remain north'); return{ok:issues.length===0,issues} } window.auditR36B23Fixes=auditR36B23Fixes; function auditR36B22MapAndAccess(){ const issues=[]; const rep=places.find(p=>p.id==='republic'&&!p.retiredByReorg); if(!rep||rep.x!==820||rep.y!==1515)issues.push('Republic Square is not in the center parcel'); if(places.some(p=>p.id==='souppeddler'&&placeVisible(p)))issues.push('Soup Peddler still visible'); for(const p of places){ if(!placeVisible(p)||p.retiredByReorg||!p.parking||p.id==='leftwaygrounds')continue; if(!p.setup?.unifiedPullIn)issues.push(`${p.id}: unified pull-in missing`); if(!p.interactionRect)issues.push(`${p.id}: full-lane interaction missing`); if(!roads.some(r=>rectsOverlap(p.setup,r,0)))issues.push(`${p.id}: pull-in does not touch street`); } return{ok:issues.length===0,issues} } window.auditR36B22MapAndAccess=auditR36B22MapAndAccess; function auditR36B21CityConsistency(){ const issues=[]; for(const [id,meta] of Object.entries(BUSINESS_CANONICAL)){ const p=places.find(x=>x.id===id); if(!p){issues.push(`${id}: missing business`);continue} if(p.name!==meta.name)issues.push(`${id}: name mismatch`); if(p.short!==meta.short)issues.push(`${id}: short name mismatch`); if((p.logo?.[0]||'')!==meta.logo[0])issues.push(`${id}: sign mismatch`); if((p.subtitle||'')!==meta.subtitle)issues.push(`${id}: subtitle mismatch`); if(p.type==='gig'&&!p.parking)issues.push(`${id}: missing parking`); if(p.type==='gig'&&!p.setup)issues.push(`${id}: missing pull-in/stage area`); if(p.type==='gig'&&!p.interact)issues.push(`${id}: missing interaction point`); } if(typeof DRIVEWAYS==='undefined'||!Array.isArray(DRIVEWAYS))issues.push('driveways not initialized'); if(!onRoad(GIGBAG_SPAWN.x,GIGBAG_SPAWN.y))issues.push('Gig Bag spawn not drivable'); if(!FESTIVAL_ROUTE.includes('republic'))issues.push('Republic Square missing from active route'); if(!FESTIVAL_ROUTE.includes('republic'))issues.push('Soup Peddler missing from active route'); if((places.find(p=>p.id==='mama')?.logo?.[0]||'')!=='MAMA DEAREST')issues.push('Mama sign is not full name'); if(places.some(p=>p.id==='souppeddler'&&placeVisible(p)))issues.push('Soup Peddler still visible'); if(BUSINESS_CANONICAL.souppeddler)issues.push('Soup Peddler still canonical'); if(FESTIVAL_ROUTE.includes('souppeddler'))issues.push('Soup Peddler still in festival route'); return{ok:issues.length===0,issues,build:'R36B38B HUD + 100 RIDER SOCIAL RIDE'} } window.auditR36B21CityConsistency=auditR36B21CityConsistency; function auditR36B20DSystems(viewportWidth=393,viewportHeight=852){ const issues=[]; const shop=places.find(p=>p.id==='shop'); if(!shop||!onRoad(GIGBAG_SPAWN.x,GIGBAG_SPAWN.y))issues.push('Gig Bag spawn is not drivable'); const visualDepth=PSEUDO_BUILDING_DEPTH; for(const p of places.filter(p=>placeVisible(p)&&!p.retiredByReorg)){ const slabLeft=p.x-visualDepth-CITY_POLISH.buildingApron; const slabRight=p.x+p.w+CITY_POLISH.buildingApron; const footprintLeft=p.x-visualDepth,footprintRight=p.x+p.w; if(Math.abs((footprintLeft+footprintRight)/2-(slabLeft+slabRight)/2)>.51)issues.push(`${p.id}: pseudo building not slab centered`) } const scale4=Math.min(.5,viewportWidth/FULL_CITY_VIEW_BOUNDS.w,viewportHeight/FULL_CITY_VIEW_BOUNDS.h); const scale5=Math.min(.25,viewportWidth/BIRD_EYE_VIEW_BOUNDS.w,viewportHeight/BIRD_EYE_VIEW_BOUNDS.h); if(scale5>scale4/1.9)issues.push('5x is not approximately double-distance from 4x'); if(FESTIVAL_ROUTE.includes('republic'))issues.push('Republic remains in festival route'); if(!FESTIVAL_ROUTE.includes('republic'))issues.push('Soup Peddler missing from festival route'); return{ok:issues.length===0,issues,spawn:GIGBAG_SPAWN,scale4,scale5} } window.auditR36B20DSystems=auditR36B20DSystems; function auditR36B20CVisualAlignment(){ const issues=[]; for(const id of ['bank','kazi','tascam','jblpro']){ const p=places.find(x=>x.id===id),d=drivewayFor(id); if(!p||!d||!d.westParcelPullIn)issues.push(`${id}: west pull-in missing`); if(d&&p?.parking&&(d.x<p.parking.x+p.parking.w||d.x+d.w>p.x+p.w+1))issues.push(`${id}: pull-in outside west parcel`); } for(const p of places.filter(p=>placeVisible(p)&&!p.retiredByReorg)){ if(Math.round(p.x)!==p.x||Math.round(p.y)!==p.y)issues.push(`${p.id}: building not pixel aligned`); const s=sponsorSignSite(p); if(p.type==='gig'&&p.parking&&s.x+s.w>p.parking.x+p.parking.w+1)issues.push(`${p.id}: sponsor sign outside lot edge`); } return{ok:issues.length===0,issues,cameraCentered1to4:true} } window.auditR36B20CVisualAlignment=auditR36B20CVisualAlignment; function auditR36B20BPhoneAndPullIns(viewportWidth=393){ const issues=[]; for(const p of places){ if(p.retiredByReorg||!p.parking||p.id==='bank'||p.id==='leftwaygrounds')continue; const d=drivewayFor(p.id); if(!d||!d.eastPullIn)issues.push(`${p.id}: missing east pull-in`); if(d&&d.x<p.parking.x+p.parking.w)issues.push(`${p.id}: lane overlaps parking`); if(d&&!roads.some(r=>rectsOverlap(d,r,2)))issues.push(`${p.id}: lane does not reach street`); } const scale=Math.max(.075,Math.min(.5,viewportWidth/FULL_CITY_VIEW_BOUNDS.w)); const visibleWidth=viewportWidth/scale; if(visibleWidth<FULL_CITY_VIEW_BOUNDS.w-1)issues.push('4x does not include full city width'); return{ok:issues.length===0,issues,visibleWidth,requiredWidth:FULL_CITY_VIEW_BOUNDS.w} } window.auditR36B20BPhoneAndPullIns=auditR36B20BPhoneAndPullIns; function auditR36B20MapAlignment(){ const byId=id=>places.find(p=>p.id===id),issues=[]; const shop=byId('shop'),hq=byId('hq'),aml=byId('amlhouse'),pork=byId('porkchop'),grounds=byId('leftwaygrounds'); if(!shop||shop.x!==180||shop.y!==175)issues.push('Gig Bag coordinates'); if(GIGBAG_SPAWN.x!==512||GIGBAG_SPAWN.y!==275)issues.push('Gig Bag return spawn'); if(!hq||hq.x!==820||hq.y!==175)issues.push('BYOB coordinates'); if(BYOB_REPAIR.x!==1185||BYOB_REPAIR.y!==275)issues.push('BYOB repair point'); if(!aml||aml.color!=='#f2dfa0'||!PULL_IN_BUSINESS_IDS.has('amlhouse'))issues.push('AML styling/pull-in'); if(!pork||pork.logo[0]!=='PORK CHOP SCREEN PRINTING')issues.push('Pork Chop full sign'); if(!grounds||typeof drawLeftwayCompoundBridge!=='function')issues.push('Leftway overhead bridge'); for(const id of ['bank','kazi','tascam','jblpro']){const p=byId(id);if(!p||p.x!==-235)issues.push(`${id} west future parcel`)} if(placeVisible(byId('republic'))||placeVisible(byId('topnotch')))issues.push('retired duplicate businesses'); return{ok:issues.length===0,issues} } window.auditR36B20MapAlignment=auditR36B20MapAlignment; function activePlaceRects(includeHidden=false){const rects=[];for(const p of places){if(!includeHidden&&!placeVisible(p))continue;rects.push(p);if(p.setup)rects.push(p.setup);if(p.parking)rects.push(p.parking)}return rects} function propertyBounds(p){const rects=[p,p.setup,p.parking].filter(Boolean),x1=Math.min(...rects.map(r=>r.x)),y1=Math.min(...rects.map(r=>r.y)),x2=Math.max(...rects.map(r=>r.x+r.w)),y2=Math.max(...rects.map(r=>r.y+r.h));return{x:x1,y:y1,w:x2-x1,h:y2-y1}} const EAST_PULL_IN_EXEMPT_IDS=new Set(['bank','kazi','tascam','jblpro','queuetube','leftwaygrounds']); function nearestEastRoadEdge(x){ const candidates=roads.filter(r=>r.h>r.w&&r.x>=x-2).map(r=>r.x).sort((a,b)=>a-b); return candidates.length?candidates[0]:x+110 } function normalizeEastSidePullIns(){ for(const p of places){ if(p.retiredByReorg||!p.parking||EAST_PULL_IN_EXEMPT_IDS.has(p.id))continue; const originalRight=p.parking.x+p.parking.w; const laneStart=Math.max(p.parking.x+72,originalRight-72); const roadEdge=nearestEastRoadEdge(originalRight); p.parking.w=Math.max(68,laneStart-p.parking.x-8); p.setup={x:laneStart,y:p.parking.y,w:Math.max(62,roadEdge-laneStart),h:p.parking.h,curbside:true,invisible:true,eastPullIn:true}; p.interact={x:p.setup.x+p.setup.w/2,y:p.setup.y+Math.min(34,p.setup.h/2)} } } const WEST_PARCEL_IDS=new Set(['bank','kazi','tascam','jblpro','queuetube']); function normalizeWestParcelPullIns(){ // R36B25: intentionally disabled. West geometry is final in applyR36B19CityLayout(). return } function alignBuildingsToConcreteSlabs(){ for(const p of places){ if(p.retiredByReorg)continue; // All primary buildings align exactly with the left edge of their concrete building slab. p.x=Math.round(p.x); p.y=Math.round(p.y); if(p.parking){ p.parking.x=Math.round(p.parking.x); p.parking.y=Math.round(p.parking.y) } } } normalizeWestParcelPullIns(); alignBuildingsToConcreteSlabs(); function finalizeWestPropertyGeometry(){return} finalizeWestPropertyGeometry(); applyCanonicalBusinessData(); function normalizeAllBusinessAccess(){ for(const p of places){ if(p.retiredByReorg||!p.parking||p.id==='leftwaygrounds')continue; const verticalRoads=roads.filter(r=>r.h>r.w&&r.x>=p.parking.x+p.parking.w-80).sort((a,b)=>a.x-b.x); const road=verticalRoads[0]; if(!road)continue; const propertyRight=Math.round(road.x-10); const laneW=Math.max(55,Math.min(100,Math.round((propertyRight-p.parking.x)*.24))); const laneX=propertyRight-laneW; // R36B31: overlap the parking lot and pull-in lane so there is never a hidden no-drive gap. // The parking surface continues beneath the pull-in by 8px; both rectangles remain drivable. const parkingRight=laneX+8; p.parking.w=Math.max(110,parkingRight-p.parking.x); p.setup={ x:laneX,y:Math.round(p.parking.y),w:laneW,h:Math.round(p.parking.h), curbside:true,invisible:true,unifiedPullIn:true,parcelContained:true }; p.interactionRect={x:p.setup.x,y:p.setup.y,w:p.setup.w,h:p.setup.h}; p.interact={x:p.setup.x+p.setup.w/2,y:p.setup.y+p.setup.h/2} } } function businessInteractionNear(p,pad=22){ if(!p||!p.interact)return false; if(p.interactionRect&&pointInRect(van.x,van.y,p.interactionRect,pad))return true; if(p.setup&&pointInRect(van.x,van.y,p.setup,pad))return true; return Math.hypot(van.x-p.interact.x,van.y-p.interact.y)<92 } const DRIVEWAYS=[ {id:'shop',x:355,y:345,w:220,h:255},{id:'hq',x:1135,y:345,w:100,h:255,curbside:true,invisible:true},{id:'fsg',x:1795,y:345,w:100,h:255},{id:'blueowl',x:2450,y:345,w:65,h:255}, {id:'juan',x:355,y:1005,w:220,h:295},{id:'hope',x:1135,y:1005,w:100,h:295},{id:'mama',x:1795,y:1005,w:100,h:295},{id:'worldliquor',x:2450,y:1005,w:65,h:295}, {id:'porkchop',x:495,y:1480,w:90,h:350,curbside:true,invisible:true},{id:'republic',x:1135,y:1480,w:100,h:350},{id:'leftway',x:1795,y:1480,w:100,h:350}, {id:'bank',x:-82,y:280,w:84,h:135,curbside:true,invisible:false,westContained:true,westParcelPullIn:true,openCurbCut:true},{id:'kazi',x:-82,y:640,w:84,h:135,curbside:true,invisible:false,westContained:true,westParcelPullIn:true,openCurbCut:true},{id:'tascam',x:-82,y:1000,w:84,h:135,curbside:true,invisible:false,westContained:true,westParcelPullIn:true,openCurbCut:true},{id:'jblpro',x:-82,y:1360,w:84,h:135,curbside:true,invisible:false,westContained:true,westParcelPullIn:true,openCurbCut:true}, {id:'queuetube',x:-82,y:1720,w:84,h:135,curbside:true,invisible:false,westContained:true,westParcelPullIn:true,openCurbCut:true}, {id:'thirteenthfloor',x:2700,y:185,w:78,h:245,curbside:true,invisible:true},{id:'chessclub',x:2700,y:545,w:78,h:245,curbside:true,invisible:true},{id:'highnoon',x:2700,y:905,w:78,h:245,curbside:true,invisible:true},{id:'baddburgers',x:2700,y:1265,w:78,h:245,curbside:true,invisible:true},{id:'amlhouse',x:2700,y:1645,w:78,h:245,curbside:true,invisible:true} ]; normalizeEastSidePullIns(); normalizeAllBusinessAccess(); // R36B31: continuous street → curb cut → pull-in lane → parking lot access at every business. // The driveway collision surface touches the road by 2px, but its visible gray asphalt is clipped at the road edge. // Parking and pull-in surfaces overlap so no curb, sidewalk, or hidden gap can trap the van. function rebuildAllBusinessDriveways(){ const mouthDepth=2,sideOverlap=18,minMouth=72; for(const p of places){ if(p.retiredByReorg)continue; const access=p.setup||p.parking; if(!access)continue; const candidates=[]; for(const r of roads){ const horizontal=r.w>=r.h; if(horizontal){ const x1=Math.max(access.x,r.x),x2=Math.min(access.x+access.w,r.x+r.w),overlap=x2-x1; if(overlap<Math.min(minMouth,access.w*.55))continue; const w=Math.max(48,Math.min(access.w-8,Math.max(minMouth,overlap-4))); const cx=(x1+x2)/2; if(access.y+access.h<=r.y){ const gap=r.y-(access.y+access.h); candidates.push({gap,rect:{x:Math.round(cx-w/2),y:Math.round(access.y+access.h-sideOverlap),w:Math.round(w),h:Math.round(gap+sideOverlap+mouthDepth)}}) }else if(r.y+r.h<=access.y){ const gap=access.y-(r.y+r.h); candidates.push({gap,rect:{x:Math.round(cx-w/2),y:Math.round(r.y+r.h-mouthDepth),w:Math.round(w),h:Math.round(gap+sideOverlap+mouthDepth)}}) } }else{ const y1=Math.max(access.y,r.y),y2=Math.min(access.y+access.h,r.y+r.h),overlap=y2-y1; if(overlap<Math.min(minMouth,access.h*.55))continue; const h=Math.max(48,Math.min(access.h-8,Math.max(minMouth,overlap-4))); const cy=(y1+y2)/2; if(access.x+access.w<=r.x){ const gap=r.x-(access.x+access.w); candidates.push({gap,rect:{x:Math.round(access.x+access.w-sideOverlap),y:Math.round(cy-h/2),w:Math.round(gap+sideOverlap+mouthDepth),h:Math.round(h)}}) }else if(r.x+r.w<=access.x){ const gap=access.x-(r.x+r.w); candidates.push({gap,rect:{x:Math.round(r.x+r.w-mouthDepth),y:Math.round(cy-h/2),w:Math.round(gap+sideOverlap+mouthDepth),h:Math.round(h)}}) } } } candidates.sort((u,v)=>u.gap-v.gap); if(!candidates.length)continue; const existing=DRIVEWAYS.find(d=>d.id===p.id); const rebuilt={id:p.id,...candidates[0].rect,curbside:true,invisible:false,openCurbCut:true,pullInMouth:true}; if(existing)Object.assign(existing,rebuilt);else DRIVEWAYS.push(rebuilt) } } rebuildAllBusinessDriveways(); for(const id of ['bank','kazi','tascam','jblpro','queuetube']){ const p=places.find(x=>x.id===id);if(!p)continue; p.interactionRect={x:p.setup.x,y:p.setup.y,w:p.setup.w,h:p.setup.h} } for(const p of places){ if(!(p.setup?.eastPullIn||p.setup?.unifiedPullIn))continue; // Keep the R36B30 road-bridging mouth. Only create a setup surface when a business has no driveway record. if(!DRIVEWAYS.find(x=>x.id===p.id))DRIVEWAYS.push({id:p.id,...p.setup,curbside:true,invisible:false,unifiedPullIn:true,openCurbCut:true}) } function drivewayFor(id){return DRIVEWAYS.find(d=>d.id===id)||null} initializeLiveSpawnPoints(); van.x=GIGBAG_SPAWN.x;van.y=GIGBAG_SPAWN.y;van.angle=GIGBAG_SPAWN.angle; function activeDriveways(){return DRIVEWAYS.filter(d=>{const p=places.find(x=>x.id===d.id);return p&&placeVisible(p)})} function onDesignatedRoadPoint(x,y,margin=2){return roads.some(r=>x>=r.x+margin&&x<=r.x+r.w-margin&&y>=r.y+margin&&y<=r.y+r.h-margin)} function segmentStaysOnRoad(x1,y1,x2,y2){if(x1!==x2&&y1!==y2)return false;const steps=Math.max(2,Math.ceil(Math.hypot(x2-x1,y2-y1)/40));for(let i=0;i<=steps;i++){const t=i/steps;if(!onDesignatedRoadPoint(x1+(x2-x1)*t,y1+(y2-y1)*t,1))return false}return true} function validGrassArea(x,y,radius=CITY_POLISH.treeRadius){ const maxWalk=CITY_POLISH.sidewalkUpgrade+CITY_POLISH.curbWidth; if(x<=150+maxWalk+radius||x>=world.w-150-maxWalk-radius||y<=150+maxWalk+radius||y>=world.h-150-maxWalk-radius)return false; for(const r of roads)if(pointInRect(x,y,r,maxWalk+radius))return false; for(const p of places){const bounds=propertyBounds(p);if(pointInRect(x,y,bounds,CITY_POLISH.propertyBuffer+radius))return false} for(const r of DRIVEWAYS)if(pointInRect(x,y,r,CITY_POLISH.curbWidth+radius))return false; for(const r of BUS_STOP_SITES)if(pointInRect(x,y,r,18+radius))return false; return true } function treeSiteAllowed(x,y){return validGrassArea(x,y,CITY_POLISH.treeRadius)} const TREE_SITES=[]; for(let y=205;y<=1645;y+=70){for(let x=205;x<=2495;x+=82){const seed=Math.abs(tHash(`tree-r36-${x}-${y}`));if(seed%3!==0)continue;const tx=x+(seed%17)-8,ty=y+((seed>>3)%15)-7;if(treeSiteAllowed(tx,ty))TREE_SITES.push({x:tx,y:ty,scale:.82+(seed%5)*.045})}} function drawTreeTrunk(x,y,scale=1){ctx.save();ctx.translate(x,y);ctx.scale(scale,scale);ctx.fillStyle='rgba(0,0,0,.25)';ctx.beginPath();ctx.ellipse(9,15,20,8,0,0,Math.PI*2);ctx.fill();ctx.fillStyle='#4a2f20';ctx.fillRect(-5,-3,10,25);ctx.fillStyle='#795137';ctx.fillRect(-2,-3,4,22);ctx.restore()} function drawTreeCanopy(x,y,scale=1){ctx.save();ctx.translate(x,y);ctx.scale(scale,scale);ctx.fillStyle='rgba(0,0,0,.15)';ctx.beginPath();ctx.ellipse(7,-5,25,12,0,0,Math.PI*2);ctx.fill();const crowns=[[-12,-18,14,'#2b6538'],[8,-18,15,'#347840'],[-2,-30,16,'#438d4d'],[-17,-30,11,'#397d45'],[15,-31,11,'#4b9954']];for(const [cx,cy,r,c] of crowns){ctx.fillStyle=c;ctx.beginPath();ctx.arc(cx,cy,r,0,Math.PI*2);ctx.fill()}ctx.fillStyle='rgba(255,255,255,.13)';ctx.beginPath();ctx.arc(-7,-33,7,0,Math.PI*2);ctx.fill();ctx.restore()} function drawTree(x,y,scale=1){drawTreeTrunk(x,y,scale);drawTreeCanopy(x,y,scale)} function drawTreeBases(){for(const t of TREE_SITES)drawTreeTrunk(t.x,t.y,t.scale)} function drawForegroundTrees(){for(const t of TREE_SITES)drawTreeCanopy(t.x,t.y,t.scale)} // R36B40N: the van is guaranteed to outrun every Black Star car by exactly 25% at forward top speed. const BLACK_STAR_BASE_SPEED=4.55,BLACK_STAR_SPEED_STEP=.42,BLACK_STAR_SPEED_VARIANTS=4,VANCERTS_VAN_SPEED_RATIO=1.25; const FASTEST_BLACK_STAR_SPEED=BLACK_STAR_BASE_SPEED+(BLACK_STAR_SPEED_VARIANTS-1)*BLACK_STAR_SPEED_STEP; const VANCERTS_VAN_TOP_SPEED=FASTEST_BLACK_STAR_SPEED*VANCERTS_VAN_SPEED_RATIO,VANCERTS_VAN_REVERSE_SPEED=3.1; function blackStarSpeedForIndex(i){return BLACK_STAR_BASE_SPEED+(Math.abs(i)%BLACK_STAR_SPEED_VARIANTS)*BLACK_STAR_SPEED_STEP} const BLACKSTAR_GRAPH_XS=[75,695,1355,2015,2625,3175],BLACKSTAR_GRAPH_YS=[75,690,1390,1975,2525]; function blackStarNeighbors(x,y){const xi=BLACKSTAR_GRAPH_XS.indexOf(x),yi=BLACKSTAR_GRAPH_YS.indexOf(y),n=[];if(xi>0)n.push([BLACKSTAR_GRAPH_XS[xi-1],y]);if(xi<BLACKSTAR_GRAPH_XS.length-1)n.push([BLACKSTAR_GRAPH_XS[xi+1],y]);if(yi>0)n.push([x,BLACKSTAR_GRAPH_YS[yi-1]]);if(yi<BLACKSTAR_GRAPH_YS.length-1)n.push([x,BLACKSTAR_GRAPH_YS[yi+1]]);return n.filter(([nx,ny])=>segmentStaysOnRoad(x,y,nx,ny))} function chooseBlackStarTarget(car){let options=blackStarNeighbors(car.x,car.y);const forward=options.filter(([nx,ny])=>nx!==car.prevX||ny!==car.prevY);if(forward.length)options=forward;const pick=options[Math.floor(Math.random()*options.length)]||options[0]||[75,75];car.prevX=car.x;car.prevY=car.y;car.targetX=pick[0];car.targetY=pick[1]} function createBlackStar(i){const nodes=[];for(const x of BLACKSTAR_GRAPH_XS)for(const y of BLACKSTAR_GRAPH_YS)if(onDesignatedRoadPoint(x,y,1))nodes.push([x,y]);const start=nodes[(i*7+3)%nodes.length];const car={x:start[0],y:start[1],targetX:start[0],targetY:start[1],prevX:null,prevY:null,speed:blackStarSpeedForIndex(i),color:'#050505',special:true,angle:0};chooseBlackStarTarget(car);return car} function syncSpecialCars(){if(sandboxRoadTestingActive())return;const wanted=desiredBlackStarCount();while(specialCars.length<wanted)specialCars.push(createBlackStar(specialCars.length))} syncSpecialCars(); const pedestrians=[];let specialCrashCooldown=0,snakeCrashCooldown=0; const collectibleDefs=[ {type:'guitarcase',label:'GUITAR CASE',hp:0,rep:2,x:1115,y:1215}, {type:'foodcrate',label:'FOOD DONATION CRATE',hp:8,rep:1,x:900,y:735}, {type:'sapling',label:'SAPLING',hp:3,rep:3,x:430,y:1215}, {type:'paint',label:'PAINT SUPPLIES',hp:0,rep:2,x:2260,y:1215}, {type:'gas',label:'GAS CAN',hp:30,rep:1,x:1325,y:690}, {type:'cassette',label:'LOCAL MUSIC TAPE',hp:0,rep:1,x:690,y:1540}, {type:'microphone',label:'MICROPHONE',hp:1,rep:2,x:820,y:1540}, {type:'snare',label:'SNARE DRUM',hp:2,rep:3,x:1470,y:1540}, {type:'keyboard',label:'KEYBOARD',hp:1,rep:3,x:2130,y:1540}, {type:'sax',label:'SAXOPHONE',hp:0,rep:3,x:520,y:900}, {type:'trumpet',label:'TRUMPET',hp:0,rep:3,x:1180,y:820}, {type:'cable',label:'XLR CABLE',hp:1,rep:2,x:1840,y:1510}, {type:'speaker',label:'PA SPEAKER',hp:3,rep:4,x:2320,y:820}, {type:'mixer',label:'MIXER',hp:2,rep:4,x:2800,y:1530}, {type:'ticket',label:'SHOW TICKET',hp:0,rep:2,x:3000,y:690}, {type:'tambourine',label:'TAMBOURINE',hp:1,rep:2,x:2450,y:1880}, {type:'bass',itemKey:'bass',label:'BASS GUITAR',hp:0,rep:3,x:1710,y:690}, {type:'micstand',itemKey:'micstand',label:'MIC STAND',hp:1,rep:2,x:2015,y:1080}, {type:'donation',itemKey:'donation',label:'DONATION ENVELOPE',hp:0,rep:3,x:2625,y:1760}, {type:'flyer',itemKey:'flyer',label:'SHOW FLYER',hp:0,rep:2,x:695,y:2190}, {type:'poster',itemKey:'poster',label:'EVENT POSTER',hp:0,rep:3,x:1355,y:2370}, {type:'coupon',itemKey:'coupon',label:'SPONSOR COUPON',hp:0,rep:2,x:3175,y:1160} ]; const collectibles=collectibleDefs.map((d,i)=>({...d,homeX:d.x,homeY:d.y,active:true,delivered:false,respawnAt:0,bob:i*.8})); const LIVING_CITY_VERSION='R36B17'; const COLLECTIBLE_MIN_SPACING=78; const COLLECTIBLE_SAFE_SPAWNS=[ [320,690],[460,690],[860,690],[1030,690],[1510,690],[1680,690],[2170,690],[2380,690],[2790,690],[2990,690], [695,300],[695,470],[695,930],[695,1110],[695,1570],[695,1740],[695,2190],[695,2380], [1355,270],[1355,460],[1355,900],[1355,1080],[1355,1580],[1355,1760],[1355,2170],[1355,2370], [2015,270],[2015,450],[2015,900],[2015,1100],[2015,1580],[2015,1760],[2015,2170],[2015,2370], [2625,250],[2625,455],[2625,900],[2625,1090],[2625,1580],[2625,1760],[2625,2170],[2625,2360], [3175,300],[3175,500],[3175,930],[3175,1160],[3175,1600],[3175,1800],[3175,2180],[3175,2360], [350,1390],[520,1390],[900,1390],[1080,1390],[1530,1390],[1740,1390],[2210,1390],[2400,1390],[2780,1390],[3000,1390], [330,1975],[520,1975],[900,1975],[1090,1975],[1530,1975],[1740,1975],[2200,1975],[2400,1975],[2790,1975],[3000,1975] ]; function collectibleInventoryKey(c){return String(c.itemKey||c.type||'resource')} function collectibleEmoji(c){ return({guitarcase:'🎸',bass:'🎸',foodcrate:'🥫',sapling:'🌱',paint:'🎨',gas:'⛽',cassette:'📼', microphone:'🎤',micstand:'🎙️',snare:'🥁',keyboard:'🎹',sax:'🎷',trumpet:'🎺', cable:'🔌',speaker:'🔊',mixer:'🎚️',ticket:'🎟️',tambourine:'🪘', donation:'💌',flyer:'📄',poster:'🪧',coupon:'🏷️',donut:'🍩',egg:'🥚'})[c.type]||'📦' } function collectiblePointReachable(x,y){ return onRoad(x,y)&&!buildingBlocked(x,y,34)&&!places.some(p=>pointInRect(x,y,{x:p.x,y:p.y,w:p.w,h:p.h},18)) } function nearestSafeCollectibleSpawn(c,index,occupied=[]){ const original=[Number(c.homeX)||Number(c.x)||75,Number(c.homeY)||Number(c.y)||75]; const candidates=COLLECTIBLE_SAFE_SPAWNS.map((p,i)=>({x:p[0],y:p[1],score:Math.hypot(p[0]-original[0],p[1]-original[1])+((i+index)%7)*2})) .filter(p=>collectiblePointReachable(p.x,p.y)) .filter(p=>occupied.every(o=>Math.hypot(o.x-p.x,o.y-p.y)>=COLLECTIBLE_MIN_SPACING)) .sort((a,b)=>a.score-b.score); return candidates[0]||{x:1355,y:690} } function auditCollectibleSpawns(){ const occupied=[]; collectibles.forEach((c,i)=>{ const currentOkay=collectiblePointReachable(c.homeX,c.homeY)&&occupied.every(o=>Math.hypot(o.x-c.homeX,o.y-c.homeY)>=COLLECTIBLE_MIN_SPACING); const p=currentOkay?{x:c.homeX,y:c.homeY}:nearestSafeCollectibleSpawn(c,i,occupied); c.homeX=p.x;c.homeY=p.y; if(!c.delivered){c.x=p.x;c.y=p.y} occupied.push(p) }) } function gigBagDeliverySlot(index){ const cols=6,spacingX=55,spacingY=44; return{x:220+(index%cols)*spacingX,y:420+Math.floor(index/cols)*spacingY} } function normalizeGigBagDeliverySlots(){ const delivered=collectibles.filter(c=>c.delivered).sort((a,b)=>String(a.label).localeCompare(String(b.label))||a.bob-b.bob); delivered.forEach((c,i)=>{const p=gigBagDeliverySlot(i);c.x=p.x;c.y=p.y}) } function renderCollectedResources(){ const counts=state.collectedResources||{},defs={}; for(const c of collectibles)defs[collectibleInventoryKey(c)]=c; const rows=Object.entries(counts).filter(([,n])=>Number(n)>0).sort((a,b)=>{ const aa=(defs[a[0]]&&defs[a[0]].label)||a[0],bb=(defs[b[0]]&&defs[b[0]].label)||b[0]; return aa.localeCompare(bb) }); if(!rows.length)return '<div class="card"><h3>STREET COLLECTIBLES</h3><p>No collected street resources yet.</p></div>'; const reserveTotal=Object.values(state.collectibleRepairReserve||{}).reduce((a,b)=>a+(Number(b)||0),0);return `<div class="card"><h3>STREET COLLECTIBLES</h3><p>Collected items repair the van immediately. Overflow is held for later.</p>${reserveTotal?`<p class="good"><b>VAN REPAIR RESERVE: +${reserveTotal}%</b></p>`:''}<div class="gigBagCollectibleGrid">${rows.map(([key,n])=>{const c=defs[key]||{type:key,label:key.replace(/_/g,' ').toUpperCase()};return `<div class="gigBagCollectibleSlot">${collectibleEmoji(c)}<b>${c.label}</b><span>× ${Number(n)||0}</span></div>`}).join('')}</div></div>` } function trafficRespawnRoute(c,avoidEast=false){ const seed=Math.floor(Math.random()*5000)+traffic.indexOf(c)*17; beginTrafficEntry(c,trafficRouteForIndex(seed,avoidEast)) } function trafficMovementAudit(c,now=Date.now()){ if(c.hiddenUntil>now||c.entryMode||c.exitMode||c.pullOverUntil>now||c.parkedUntil>now)return; const q=trafficVisualXY(c); if(!Number.isFinite(q.x)||!Number.isFinite(q.y)||!onDesignatedRoadPoint(q.x,q.y,1)){beginTrafficExit(c);return} if(!Number.isFinite(c.lastRoadX)){c.lastRoadX=q.x;c.lastRoadY=q.y;c.lastMoveAt=now;return} if(Math.hypot(q.x-c.lastRoadX,q.y-c.lastRoadY)>6){c.lastRoadX=q.x;c.lastRoadY=q.y;c.lastMoveAt=now;c.stuckSince=0;return} if(!c.stuckSince)c.stuckSince=now; if(now-c.stuckSince>3500)beginTrafficExit(c) } function livingCityAudit(){ auditCollectibleSpawns(); normalizeGigBagDeliverySlots(); for(const c of traffic)trafficMovementAudit(c); return{ civilian:traffic.filter(c=>!c.isSpecialRoad).length, specials:traffic.filter(c=>c.isSpecialRoad).length, unreachableCollectibles:collectibles.filter(c=>!c.delivered&&!collectiblePointReachable(c.homeX,c.homeY)).length, spacingErrors:collectibles.filter((c,i)=>collectibles.some((d,j)=>j<i&&!c.delivered&&!d.delivered&&Math.hypot(c.homeX-d.homeX,c.homeY-d.homeY)<COLLECTIBLE_MIN_SPACING)).length } } window.livingCityAudit=livingCityAudit; function beginTrafficExit(c){ if(c.exitMode)return; const q=trafficVisualXY(c); c.exitMode=true; c.exitAxis=c.axis||((Math.abs(q.x-world.w/2)>Math.abs(q.y-world.h/2))?'x':'y'); if(c.exitAxis==='x')c.exitDir=q.x<world.w/2?-1:1; else c.exitDir=q.y<world.h/2?-1:1; c.exitX=q.x;c.exitY=q.y; c.hiddenUntil=0 } function finishTrafficExit(c){ const seed=Math.floor(Math.random()*9000)+traffic.indexOf(c)*31; const fresh=trafficRouteForIndex(seed,Math.random()<.65); beginTrafficEntry(c,fresh) } function advanceTrafficExit(c,f){ const speed=Math.max(4.5,Number(c.speed)||2.5)*f; if(c.exitAxis==='x')c.exitX+=c.exitDir*speed; else c.exitY+=c.exitDir*speed; if(c.exitX<-220||c.exitX>world.w+220||c.exitY<-220||c.exitY>world.h+220)finishTrafficExit(c) } function trafficVisible(c){return !c.hiddenUntil||Date.now()>=c.hiddenUntil} function routeEntryGeometry(route){ if(route.axis==='x'){ const fromLeft=route.dir>0; return{ startX:fromLeft?-150:world.w+150,startY:route.lane, targetX:fromLeft?route.min:route.max,targetY:route.lane, angle:fromLeft?0:Math.PI } } const fromTop=route.dir>0; return{ startX:route.lane,startY:fromTop?-150:world.h+150, targetX:route.lane,targetY:fromTop?route.min:route.max, angle:fromTop?Math.PI/2:-Math.PI/2 } } function beginTrafficEntry(c,route){ for(const key of ['route','inset','t','dir','axis','lane','min','max','pos','exitMode','exitAxis','exitDir','exitX','exitY','entryMode','entryX','entryY','entryTargetX','entryTargetY'])delete c[key]; Object.assign(c,route); const g=routeEntryGeometry(route); c.entryMode=true; c.entryX=g.startX;c.entryY=g.startY; c.entryTargetX=g.targetX;c.entryTargetY=g.targetY; c.entryAngle=g.angle; c.pos=route.dir>0?route.min:route.max; c.hiddenUntil=0; c.stuckSince=0;c.lastMoveAt=Date.now();c.lastRoadX=NaN;c.lastRoadY=NaN } function advanceTrafficEntry(c,f){ const dx=c.entryTargetX-c.entryX,dy=c.entryTargetY-c.entryY,dist=Math.hypot(dx,dy); const step=Math.max(4.6,Number(c.speed)||2.5)*f; if(dist<=step+2){ c.entryX=c.entryTargetX;c.entryY=c.entryTargetY;c.entryMode=false; c.lastRoadX=NaN;c.lastRoadY=NaN;c.stuckSince=0; return } c.entryX+=dx/dist*step;c.entryY+=dy/dist*step } function trafficDrawPoint(c){ if(c.entryMode)return{x:c.entryX,y:c.entryY,angle:c.entryAngle}; if(c.exitMode)return{x:c.exitX,y:c.exitY,angle:c.exitAxis==='x'?(c.exitDir>0?0:Math.PI):(c.exitDir>0?Math.PI/2:-Math.PI/2)}; return trafficVisualXY(c) } const ARMORED_VAN_COST=20000; const CONSUMABLE_TYPES=new Set(['foodcrate','gas','donut','egg']); const donutProjectiles=[]; let lastDonutShotAt=0; function isConsumableType(type){return CONSUMABLE_TYPES.has(String(type||''))} function consumableCount(type){return Math.max(0,Number(state.collectedResources[type])||0)} function consumeResource(type){ if(!isConsumableType(type)||consumableCount(type)<1)return toast('No '+String(type).toUpperCase()+' consumable available.'); if(state.vanhp>=100)return toast('VAN ALREADY AT 100%'); state.collectedResources[type]--; const before=state.vanhp; state.vanhp=Math.min(100,state.vanhp+25); save();hud();hqModal(); toast(`${type==='donut'?'DOUGHNUT':type==='egg'?'ELON EGG':type==='gas'?'GAS CAN':'FOOD CRATE'} CONSUMED • VAN ${Math.round(before)}% → ${Math.round(state.vanhp)}%`) } window.consumeResource=consumeResource; function consumablesHtml(){ const rows=[ ['foodcrate','FOOD DONATION CRATE','🥫'], ['gas','GAS CAN','⛽'], ['donut','HAZARD DOUGHNUT','🍩'], ['egg','ELON EGG','🥚'] ]; return `<div class="card"><h3>CONSUMABLES</h3><p>Each item is consumed separately and restores <b>25%</b> van condition, capped at 100%.</p>${rows.map(([key,label,icon])=>`<div class="btns" style="justify-content:space-between;margin:5px 0"><b>${icon} ${label} × ${consumableCount(key)}</b><button onclick="consumeResource('${key}')" ${consumableCount(key)<1||state.vanhp>=100?'disabled':''}>CONSUME +25%</button></div>`).join('')}</div>` } const FOOD_AMMO={ potato:{label:'POTATO',icon:'🥔',fill:'#b88b4a',accent:'#8b6331'}, donut:{label:'DOUGHNUT',icon:'🍩',fill:'#d69b59',accent:'#f2a8bd'}, taco:{label:'TACO',icon:'🌮',fill:'#e4b14b',accent:'#55a052'}, burger:{label:'BURGER',icon:'🍔',fill:'#b36b3f',accent:'#e5c14d'}, pickle:{label:'PICKLE',icon:'🥒',fill:'#4e9e4f',accent:'#b6d76a'} }; const HAZARD_CODES={traffic:'#51231',blackstar:'#51232',waygo:'#51233',elon:'#51209'}; function currentChapter(){return state.story.chapter3Started?3:state.story.festivalComplete?2:1} function foodAmmo(){return FOOD_AMMO[state.foodCannon.selected]||FOOD_AMMO.potato} function chooseFoodAmmo(id){ if(!FOOD_AMMO[id])return; state.foodCannon.selected=id;save();toast(`${FOOD_AMMO[id].label} AMMO LOADED`);foodCannonModal() } function markHazardDefeated(id){ if(state.foodCannon.defeated[id])return; state.foodCannon.defeated[id]=true; const all=Object.values(state.foodCannon.defeated).every(Boolean); if(all&&!state.foodCannon.codesUnlocked){ state.foodCannon.codesUnlocked=true; toast('ALL HAZARD RECIPES FOUND • CODES ADDED TO DRIVER PERMIT') } save() } function foodCannonModal(){ const selected=state.foodCannon.selected; modal(`<h2>POTATO CANNON FOOD LOCKER</h2><p>Choose the food the roof cannon fires. A direct hit converts a traffic hazard into that food collectible.</p><div class="grid">${Object.entries(FOOD_AMMO).map(([id,f])=>`<div class="card" style="border-color:${id===selected?'#f1b83e':'#111'}"><div style="font-size:34px">${f.icon}</div><b>${f.label}</b><br><button onclick="chooseFoodAmmo('${id}')">${id===selected?'LOADED':'LOAD'}</button></div>`).join('')}</div><div class="btns"><button class="secondary" onclick="hqModal()">BACK TO BYOB</button></div>`) } window.chooseFoodAmmo=chooseFoodAmmo; window.foodCannonModal=foodCannonModal; function escapeHtml(value){return String(value??'').replace(/[&<>\"']/g,ch=>'&'+'#'+ch.charCodeAt(0)+';')} const DEFAULT_DRIVER_PERMIT_PHOTO='data:image/jpeg;base64,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'; let permitGateActive=false; let permitGatePhotoPending=''; function driverPermitPlaceholderArt(){ return `<div style="aspect-ratio:4/3;display:flex;align-items:center;justify-content:center;background:#d8c88f;border:4px solid #171514;font-weight:1000;text-align:center;padding:12px">UPLOAD YOUR PHOTO<br><span style="font-size:12px">It will be converted into pixel-game style.</span></div>` } function driverPermitPortraitHtml(){ const photo=(state.driverPass&&state.driverPass.photo)||DEFAULT_DRIVER_PERMIT_PHOTO; return `<img src="${photo}" alt="Driver permit portrait" style="display:block;width:100%;aspect-ratio:4/3;object-fit:cover;object-position:center;border:4px solid #171514;image-rendering:auto;background:#d8c88f">` } function chooseDriverPermitPhoto(){ const picker=document.createElement('input');picker.type='file';picker.accept='image/*';picker.hidden=true; picker.addEventListener('change',()=>{const file=picker.files&&picker.files[0];if(!file)return;const reader=new FileReader();reader.onload=()=>{const img=new Image();img.onload=()=>{ const small=document.createElement('canvas');small.width=96;small.height=72;const sx=small.getContext('2d',{willReadFrequently:true}); sx.imageSmoothingEnabled=false;const scale=Math.max(96/img.width,72/img.height),w=img.width*scale,h=img.height*scale;sx.drawImage(img,(96-w)/2,(72-h)/2,w,h); const data=sx.getImageData(0,0,96,72);for(let i=0;i<data.data.length;i+=4){for(let c=0;c<3;c++)data.data[i+c]=Math.round(data.data[i+c]/51)*51}sx.putImageData(data,0,0); const out=document.createElement('canvas');out.width=384;out.height=288;const ox=out.getContext('2d');ox.imageSmoothingEnabled=false;ox.drawImage(small,0,0,out.width,out.height); state.driverPass.photo=out.toDataURL('image/jpeg',.82);save();driverPassModal();toast('DRIVER PERMIT PHOTO UPDATED'); };img.onerror=()=>toast('COULD NOT READ THAT PHOTO');img.src=String(reader.result)};reader.readAsDataURL(file)}); document.body.appendChild(picker);picker.click();setTimeout(()=>picker.remove(),60000) } function saveDriverPassName(){ const input=document.getElementById('driverPassName'); const name=String(input?.value||'').trim().slice(0,28); if(!name)return toast('ENTER A NAME FOR THE DRIVER PERMIT'); state.driverPass.name=name;save();driverPassModal() } function editDriverPermitName(){ const current=escapeHtml(state.driverPass?.name||''); modal(`<h2>EDIT DRIVER NAME</h2><div class="card"><label><b>DRIVER NAME</b><input id="driverPassName" maxlength="28" value="${current}" style="width:100%;padding:12px;margin-top:8px"></label></div><div class="btns"><button onclick="saveDriverPassName()">SAVE NAME</button><button class="secondary" onclick="driverPassModal()">CANCEL</button></div>`); const input=document.getElementById('driverPassName');if(input){input.focus();input.select()} } function driverPassModal(){ if(!state.driverPass.name){ modal(`<h2>CREATE VANCERTS DRIVER PERMIT</h2><p>This permit is issued only at BYOB Austin and stays with this save.</p><div class="card"><label><b>DRIVER NAME</b><input id="driverPassName" maxlength="28" placeholder="Choose your driver name" style="width:100%;padding:12px;margin-top:8px"></label></div><div class="btns"><button onclick="saveDriverPassName()">ISSUE DRIVER PERMIT</button><button class="secondary" onclick="closeModal()">CLOSE WALLET</button></div>`); const input=document.getElementById('driverPassName');if(input)input.focus();return } const chapter=currentChapter(); const codes=state.foodCannon.codesUnlocked?Object.entries(HAZARD_CODES).map(([k,v])=>`<b>${k.toUpperCase()}</b> ${v}`).join(' • '):'Convert TRAFFIC, BLACK STAR, WAYGO and ELON with the food cannon to reveal the hazard codes.'; modal(`<h2>PLAYER WALLET</h2><div style="max-width:720px;margin:auto;background:#efe5bb;border:6px solid #171514;border-radius:18px;padding:16px;color:#171514;box-shadow:8px 8px 0 rgba(0,0,0,.35)"><div style="display:flex;justify-content:space-between;align-items:center;border-bottom:4px solid #171514;padding-bottom:8px"><b style="font-size:24px">VANCERTS DRIVER PERMIT</b><b>CHAPTER ${chapter}</b></div><div style="display:grid;grid-template-columns:minmax(180px,40%) 1fr;gap:16px;margin-top:14px"><div>${driverPermitPortraitHtml()}</div><div style="text-align:left"><b>DRIVER</b><div style="font-size:24px">${escapeHtml(state.driverPass.name)}</div><br><b>HOME BASE</b><div>${escapeHtml(state.driverPass.address)}</div><br><b>STARTED PLAYING</b><div>${escapeHtml(state.driverPass.started)}</div><br><b>PERMIT ID</b><div>${escapeHtml(state.driverPass.passId)}</div></div></div><div style="margin-top:14px;padding:10px;border:3px dashed #171514"><b>HAZARD CODES</b><br>${codes}</div></div><div class="btns"><button onclick="chooseDriverPermitPhoto()">${state.driverPass.photo?'CHANGE PHOTO':'UPLOAD PHOTO'}</button><button onclick="foodCannonModal()">FOOD CANNON</button><button onclick="editDriverPermitName()">EDIT NAME</button><button class="secondary" onclick="closeModal()">CLOSE WALLET</button></div>`) } window.chooseDriverPermitPhoto=chooseDriverPermitPhoto; let introPermitPhotoPending=''; function refreshIntroPermitPreview(){ const preview=$('introPermitPreview'),name=$('introDriverName'),id=$('introPermitId');if(!preview)return; const photo=introPermitPhotoPending||state.driverPass?.photo||''; preview.innerHTML=photo?`<img src="${photo}" alt="Driver permit preview">`:'UPLOAD DRIVER PHOTO<br><small>Optional • crop and pixel-fit automatically</small>'; if(name&&!name.value&&state.driverPass?.name)name.value=state.driverPass.name; if(id)id.textContent=`PERMIT ID • ${state.driverPass?.passId||'GENERATES WITH THIS SAVE'}` } function chooseIntroPermitPhoto(){ const picker=document.createElement('input');picker.type='file';picker.accept='image/*';picker.hidden=true; picker.addEventListener('change',()=>{const file=picker.files&&picker.files[0];if(!file)return;const reader=new FileReader();reader.onload=()=>{const img=new Image();img.onload=()=>{const small=document.createElement('canvas');small.width=96;small.height=72;const sx=small.getContext('2d',{willReadFrequently:true});sx.imageSmoothingEnabled=false;const scale=Math.max(96/img.width,72/img.height),w=img.width*scale,h=img.height*scale;sx.drawImage(img,(96-w)/2,(72-h)/2,w,h);const data=sx.getImageData(0,0,96,72);for(let i=0;i<data.data.length;i+=4){for(let c=0;c<3;c++)data.data[i+c]=Math.round(data.data[i+c]/51)*51}sx.putImageData(data,0,0);const out=document.createElement('canvas');out.width=384;out.height=288;const ox=out.getContext('2d');ox.imageSmoothingEnabled=false;ox.drawImage(small,0,0,out.width,out.height);introPermitPhotoPending=out.toDataURL('image/jpeg',.82);refreshIntroPermitPreview();toast('PERMIT PHOTO READY')};img.onerror=()=>toast('COULD NOT READ THAT PHOTO');img.src=String(reader.result)};reader.readAsDataURL(file)}); document.body.appendChild(picker);picker.click();setTimeout(()=>picker.remove(),60000) } function commitIntroPermit(){ const input=$('introDriverName');const name=String(input?.value||state.driverPass?.name||'').trim().slice(0,28); if(!name){toast('ENTER YOUR DRIVER NAME BEFORE STARTING');input?.focus();return false} state.driverPass.name=name;if(introPermitPhotoPending)state.driverPass.photo=introPermitPhotoPending;save();return true } function renderPermitGatePhoto(){ const el=$('permitGatePhoto');if(!el)return; const src=permitGatePhotoPending||state.driverPass?.photo||DEFAULT_DRIVER_PERMIT_PHOTO; const isFallback=src===DEFAULT_DRIVER_PERMIT_PHOTO;el.classList.toggle('permitGatePhotoFallback',isFallback);el.innerHTML=`<img src="${src}" alt="VANCERTS driver permit photo">`; } let permitPhotoEditImage=null; let permitPhotoEditState={zoom:1,x:0,y:0}; function ensurePermitPhotoEditor(){ let editor=$('permitPhotoEditor');if(editor)return editor; editor=document.createElement('div');editor.id='permitPhotoEditor';editor.className='permitPhotoEditor hidden'; editor.innerHTML=`<div class="permitPhotoEditorPanel" role="dialog" aria-modal="true" aria-labelledby="permitPhotoEditorTitle"><h3 id="permitPhotoEditorTitle">EDIT YOUR PERMIT PHOTO</h3><p class="permitPhotoEditorHelp">The picture is shown inside the actual permit frame. Adjust it until this preview looks right; this exact crop will be saved.</p><div class="permitPhotoEditorLayout"><div class="permitPhotoCard" aria-label="Live VANCERTS driver permit preview"><div class="permitPhotoCardHead"><strong>VANCERTS<br>DRIVER PERMIT</strong><span>REQUIRED TO DRIVE</span></div><div class="permitPhotoCardBody"><div class="permitPhotoCanvasWrap"><canvas id="permitPhotoCanvas" width="300" height="400" aria-label="Permit photo crop preview"></canvas></div><div class="permitPhotoCardInfo"><div class="permitPhotoCardLabel">DRIVER NAME</div><div class="permitPhotoCardValue" id="permitPhotoPreviewName">DRIVER</div><div class="permitPhotoCardMeta">PERMIT ID • VAN-Q400E3<br>HOME BASE • SELECTED CAREER HOME<br>CLASS • LIVE MUSIC OPERATIONS</div></div></div><div class="permitPhotoCardFoot">CITY CONTROLS LOCKED UNTIL PERMIT ISSUED</div></div><div class="permitPhotoControls"><label>ZOOM <input id="permitPhotoZoom" type="range" min="1" max="3" step="0.01" value="1"></label><label>MOVE LEFT / RIGHT <input id="permitPhotoX" type="range" min="-1" max="1" step="0.01" value="0"></label><label>MOVE UP / DOWN <input id="permitPhotoY" type="range" min="-1" max="1" step="0.01" value="0"></label><div class="permitPhotoEditorButtons"><button type="button" class="save" id="permitPhotoSave">USE THIS PHOTO</button><button type="button" class="cancel" id="permitPhotoCancel">CANCEL</button></div></div></div></div>`; document.body.appendChild(editor); ['permitPhotoZoom','permitPhotoX','permitPhotoY'].forEach(id=>$(id).addEventListener('input',()=>{permitPhotoEditState.zoom=Number($('permitPhotoZoom').value)||1;permitPhotoEditState.x=Number($('permitPhotoX').value)||0;permitPhotoEditState.y=Number($('permitPhotoY').value)||0;drawPermitPhotoEditor()})); $('permitPhotoSave').addEventListener('click',savePermitPhotoCrop);$('permitPhotoCancel').addEventListener('click',closePermitPhotoEditor); return editor } function drawPermitPhotoEditor(){ const canvas=$('permitPhotoCanvas');if(!canvas||!permitPhotoEditImage)return;const c=canvas.getContext('2d');const img=permitPhotoEditImage,cw=canvas.width,ch=canvas.height; c.clearRect(0,0,cw,ch);c.fillStyle='#222';c.fillRect(0,0,cw,ch); const base=Math.max(cw/img.width,ch/img.height),scale=base*permitPhotoEditState.zoom,dw=img.width*scale,dh=img.height*scale; const roomX=Math.max(0,(dw-cw)/2),roomY=Math.max(0,(dh-ch)/2);const dx=(cw-dw)/2-permitPhotoEditState.x*roomX,dy=(ch-dh)/2-permitPhotoEditState.y*roomY; c.imageSmoothingEnabled=true;c.imageSmoothingQuality='high';c.drawImage(img,dx,dy,dw,dh); c.strokeStyle='rgba(244,230,190,.9)';c.lineWidth=3;c.strokeRect(1.5,1.5,cw-3,ch-3); c.strokeStyle='rgba(255,255,255,.26)';c.lineWidth=1;c.beginPath();c.moveTo(cw/3,0);c.lineTo(cw/3,ch);c.moveTo(cw*2/3,0);c.lineTo(cw*2/3,ch);c.moveTo(0,ch/3);c.lineTo(cw,ch/3);c.moveTo(0,ch*2/3);c.lineTo(cw,ch*2/3);c.stroke() } function openPermitPhotoEditor(src){ const editor=ensurePermitPhotoEditor(),img=new Image();img.onload=()=>{permitPhotoEditImage=img;permitPhotoEditState={zoom:1,x:0,y:0};$('permitPhotoZoom').value='1';$('permitPhotoX').value='0';$('permitPhotoY').value='0';const previewName=$('permitPhotoPreviewName'),nameField=$('permitGateName');if(previewName)previewName.textContent=String(nameField?.value||state.driverPass?.name||'DRIVER').trim().toUpperCase()||'DRIVER';editor.classList.remove('hidden');editor.scrollTop=0;drawPermitPhotoEditor()};img.onerror=()=>toast('COULD NOT OPEN THAT PHOTO');img.src=src } function closePermitPhotoEditor(){const editor=$('permitPhotoEditor');if(editor)editor.classList.add('hidden');permitPhotoEditImage=null} function savePermitPhotoCrop(){const canvas=$('permitPhotoCanvas');if(!canvas||!permitPhotoEditImage)return;permitGatePhotoPending=canvas.toDataURL('image/jpeg',.9);renderPermitGatePhoto();closePermitPhotoEditor();toast('DRIVER PHOTO CENTERED AND READY')} function handlePermitPhotoFile(file){if(!file)return;const reader=new FileReader();reader.onload=()=>openPermitPhotoEditor(String(reader.result||''));reader.onerror=()=>toast('COULD NOT READ THAT PHOTO');reader.readAsDataURL(file)} function choosePermitGatePhoto(){ const picker=document.createElement('input');picker.type='file';picker.accept='image/*';picker.hidden=true; picker.addEventListener('change',()=>handlePermitPhotoFile(picker.files&&picker.files[0]));document.body.appendChild(picker);picker.click();setTimeout(()=>picker.remove(),60000) } let permitCameraStream=null; function stopPermitCamera(){if(permitCameraStream){for(const track of permitCameraStream.getTracks())track.stop();permitCameraStream=null}} function closePermitCamera(){stopPermitCamera();const modal=$('permitCameraModal');if(modal)modal.classList.add('hidden')} function ensurePermitCameraModal(){ let modal=$('permitCameraModal');if(modal)return modal; modal=document.createElement('div');modal.id='permitCameraModal';modal.className='permitCameraModal hidden'; modal.innerHTML=`<div class="permitCameraPanel" role="dialog" aria-modal="true" aria-labelledby="permitCameraTitle"><h3 id="permitCameraTitle">TAKE YOUR PERMIT PHOTO</h3><p class="permitCameraHelp">Allow camera access, center yourself in the frame, then capture. You can zoom and reposition the photo before saving it to the permit.</p><div class="permitCameraStage"><video id="permitCameraVideo" autoplay muted playsinline></video><div class="permitCameraGuide" aria-hidden="true"></div></div><div class="permitCameraStatus" id="permitCameraStatus" aria-live="polite">REQUESTING CAMERA…</div><div class="permitCameraButtons"><button type="button" class="permitCameraCapture" id="permitCameraCapture" disabled>📷 CAPTURE PHOTO</button><button type="button" class="permitCameraCancel" id="permitCameraCancel">CANCEL</button></div></div>`; document.body.appendChild(modal); $('permitCameraCapture').addEventListener('click',capturePermitCameraFrame);$('permitCameraCancel').addEventListener('click',closePermitCamera); return modal } function capturePermitCameraFrame(){ const video=$('permitCameraVideo');if(!video||!video.videoWidth||!video.videoHeight){toast('CAMERA IS NOT READY YET');return} const canvas=document.createElement('canvas');canvas.width=video.videoWidth;canvas.height=video.videoHeight;const c=canvas.getContext('2d'); c.translate(canvas.width,0);c.scale(-1,1);c.drawImage(video,0,0,canvas.width,canvas.height); const src=canvas.toDataURL('image/jpeg',.92);closePermitCamera();openPermitPhotoEditor(src) } async function openPermitLiveCamera(){ const modal=ensurePermitCameraModal(),video=$('permitCameraVideo'),status=$('permitCameraStatus'),capture=$('permitCameraCapture'); modal.classList.remove('hidden');status.textContent='REQUESTING CAMERA…';capture.disabled=true;stopPermitCamera(); if(!window.isSecureContext||!navigator.mediaDevices?.getUserMedia){status.textContent='LIVE CAMERA REQUIRES HTTPS. USE UPLOAD PHOTO INSTEAD.';toast('CAMERA UNAVAILABLE • USE UPLOAD PHOTO');return} try{ permitCameraStream=await navigator.mediaDevices.getUserMedia({audio:false,video:{facingMode:'user',width:{ideal:1280},height:{ideal:960}}}); video.srcObject=permitCameraStream;await video.play();status.textContent='CAMERA READY • CENTER YOUR FACE AND CAPTURE';capture.disabled=false }catch(err){ stopPermitCamera();status.textContent='CAMERA ACCESS WAS BLOCKED. ALLOW CAMERA ACCESS IN YOUR BROWSER, THEN TRY AGAIN.';toast('CAMERA BLOCKED • CHECK BROWSER PERMISSION') } } function takePermitGatePhoto(){ const coarse=window.matchMedia?.('(pointer:coarse)')?.matches; if(coarse&&window.innerWidth<900){const picker=document.createElement('input');picker.type='file';picker.accept='image/*';picker.capture='user';picker.hidden=true;picker.addEventListener('change',()=>handlePermitPhotoFile(picker.files&&picker.files[0]));document.body.appendChild(picker);picker.click();setTimeout(()=>picker.remove(),60000);return} openPermitLiveCamera() } function usePermitBackupPhoto(){permitGatePhotoPending=DEFAULT_DRIVER_PERMIT_PHOTO;renderPermitGatePhoto();toast('VANCERTS VAN BACKUP PHOTO SELECTED')} function showDriverPermitGate(){ if(state.driverPass?.name)return; permitGateActive=true;permitGatePhotoPending=state.driverPass?.photo||DEFAULT_DRIVER_PERMIT_PHOTO; const id=escapeHtml(state.driverPass?.passId||'GENERATING…'); modal(`<div class="permitGateShell"><div class="permitGateTitle"><h2>VANCERTS<br>DRIVER PERMIT</h2><b>REQUIRED TO DRIVE</b></div><div class="permitGateGrid"><div class="permitGatePhoto" id="permitGatePhoto"></div><div class="permitGateFields"><label>DRIVER NAME<input id="permitGateName" maxlength="28" autocomplete="name" placeholder="Enter your name"><button type="button" class="permitLetterLaunch" onclick="openPermitLetterBox('permitGateName')">🎮 CONTROLLER LETTER BOX</button></label><div class="permitLetterBox hidden" id="permitLetterBox"><div class="permitLetterDisplay" id="permitLetterDisplay">SELECT LETTERS WITH THE CONTROLLER</div><div class="permitKeyboard" id="permitKeyboard"></div><span class="controllerScrollHint">LEFT JOYSTICK SCROLLS • D-PAD SELECTS • CROSS / A CONFIRMS</span></div><div class="permitGateId">PERMIT ID • ${id}<br>HOME BASE • SELECTED CAREER HOME<br>CLASS • LIVE MUSIC OPERATIONS</div><div class="permitGateNote"><b>CHOOSE YOUR CHARACTER DURING PERMIT CREATION.</b><br>Your home, starting vehicle, responsibilities, and career progression follow this selection.</div><div class="permitCareerGrid"><label class="permitCareerChoice"><input type="radio" name="permitCareer" value="owner" checked onchange="permitCareerChanged()">🚐 OWNER<br><small>Old house • wood stage • white flame van</small></label><label class="permitCareerChoice"><input type="radio" name="permitCareer" value="stagehand" onchange="permitCareerChanged()">🚚 PAUL / STAGEHAND<br><small>Gear warehouse • plain white VANCERTS van</small></label><label class="permitCareerChoice"><input type="radio" name="permitCareer" value="audio" onchange="permitCareerChanged()">🔊 SOUND ENGINEER<br><small>Mixers • speakers • production van</small></label><label class="permitCareerChoice"><input type="radio" name="permitCareer" value="band" onchange="permitCareerChanged()">🔥 BAND<br><small>Small house • backyard stage • flame van</small></label></div><label class="permitBandName" id="permitBandNameWrap">BAND NAME<input id="permitBandName" maxlength="28" placeholder="Name your band"><button type="button" class="permitLetterLaunch" onclick="openPermitLetterBox('permitBandName')">🎮 CONTROLLER LETTER BOX</button></label></div></div><div class="permitGateActions permitGateActionsWide"><button onclick="choosePermitGatePhoto()">UPLOAD PHOTO</button><button class="secondary" onclick="usePermitBackupPhoto()">USE VAN PHOTO</button><button class="green permitGateCamera" onclick="takePermitGatePhoto()">📷 TAKE PICTURE • OPEN CAMERA</button><button class="permitGateIssue" onclick="issueDriverPermitFromGate()">ISSUE PERMIT • START DRIVING</button></div><div class="permitGateLock">🔒 CITY CONTROLS LOCKED UNTIL PERMIT ISSUED</div></div>`); requestAnimationFrame(()=>{renderPermitGatePhoto();const n=$('permitGateName');if(n){n.value=state.driverPass?.name||'';n.focus()}}) } function permitCareerChanged(){const picked=document.querySelector('input[name="permitCareer"]:checked')?.value||'owner';const wrap=$('permitBandNameWrap');if(wrap)wrap.classList.toggle('show',picked==='band')} let permitLetterTarget='permitGateName'; function permitLetterValue(){const input=$(permitLetterTarget);return input?String(input.value||'').slice(0,28):''} function refreshPermitLetterDisplay(){const d=$('permitLetterDisplay');if(d)d.textContent=permitLetterValue()||'SELECT LETTERS WITH THE CONTROLLER'} function permitLetterKey(value){const input=$(permitLetterTarget);if(!input)return;if(value==='BACK')input.value=String(input.value||'').slice(0,-1);else if(value==='CLEAR')input.value='';else if(value==='SPACE'){if(input.value.length<28)input.value+=' '}else if(value==='DONE'){closePermitLetterBox();return}else if(input.value.length<28)input.value+=value;input.dispatchEvent(new Event('input',{bubbles:true}));refreshPermitLetterDisplay()} function openPermitLetterBox(targetId){permitLetterTarget=targetId||'permitGateName';const box=$('permitLetterBox'),grid=$('permitKeyboard');if(!box||!grid)return;box.classList.remove('hidden');if(!grid.dataset.ready){const letters='ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('').map(ch=>`<button type="button" data-permit-key="${ch}" onclick="permitLetterKey('${ch}')">${ch}</button>`).join('');grid.innerHTML=letters+`<button type="button" class="wide" onclick="permitLetterKey('SPACE')">SPACE</button><button type="button" class="back" onclick="permitLetterKey('BACK')">⌫ BACK</button><button type="button" class="clear" onclick="permitLetterKey('CLEAR')">CLEAR</button><button type="button" class="done" onclick="permitLetterKey('DONE')">DONE</button>`;grid.dataset.ready='1'}refreshPermitLetterDisplay();setTimeout(()=>{const first=grid.querySelector('button');if(first){first.focus({preventScroll:true});first.classList.add('controllerFocus');first.scrollIntoView({block:'nearest'})}},0)} function closePermitLetterBox(){const box=$('permitLetterBox');if(box)box.classList.add('hidden');const input=$(permitLetterTarget);if(input)input.focus({preventScroll:true})} window.openPermitLetterBox=openPermitLetterBox;window.permitLetterKey=permitLetterKey;window.closePermitLetterBox=closePermitLetterBox; function issueDriverPermitFromGate(){ const input=$('permitGateName'),name=String(input?.value||'').trim().slice(0,28); if(!name){toast('ENTER YOUR DRIVER NAME');input?.focus();return} state.driverPass.name=name;state.driverPass.photo=permitGatePhotoPending||DEFAULT_DRIVER_PERMIT_PHOTO;state.driverPass.started=state.driverPass.started||austinDateKey();const picked=document.querySelector('input[name="permitCareer"]:checked')?.value||'owner';if(picked==='band'){state.career.path='band';state.career.bandName=String($('permitBandName')?.value||state.career.bandName||'THE BAND').trim().slice(0,28)||'THE BAND'}else if(picked==='audio'){state.career.path='team';state.career.teamRole='audio'}else if(picked==='stagehand'){state.career.path='team';state.career.teamRole='stagehand'}else state.career.path='owner';state.__careerSpawnVersion=1;spawnCareerAtHome(state.career.path,state.career.teamRole);save();permitGateActive=false;$('modalWrap').classList.remove('show');for(const k of Object.keys(keys))keys[k]=false;canvas.focus({preventScroll:true});hud();toast(`PERMIT ISSUED • WELCOME, ${name.toUpperCase()}`);setTimeout(maybeShowTrainingChapter,280) } window.permitCareerChanged=permitCareerChanged;window.takePermitGatePhoto=takePermitGatePhoto;window.choosePermitGatePhoto=choosePermitGatePhoto;window.usePermitBackupPhoto=usePermitBackupPhoto;window.issueDriverPermitFromGate=issueDriverPermitFromGate; let radioPhoneAppMode=false; function openRadioApp(){ const radio=$('rotaryRadio'),phone=$('phone');if(!radio)return; radioPhoneAppMode=true; if(phone)phone.classList.remove('radioAppOpen','deviceSuppressed'); radio.classList.remove('hidden','collapsed','inPhoneApp','deviceSuppressed','deviceFreePosition'); radio.classList.add('radioOverlayOpen'); radio.style.left='50%';radio.style.top='50%';radio.style.right='auto';radio.style.bottom='auto';radio.style.transform='translate(-50%,-50%)'; const close=$('radioCollapse');if(close){close.textContent='CLOSE';close.setAttribute('aria-label','Close Community Radio and return to the Nookia phone')} if(!spotifyPlayerLoaded)load512Jams(true);state.training.flags.radioOpened=true;save();toast('COMMUNITY RADIO OPEN • CLOSE RETURNS TO PHONE') } function closeRadioApp(){ const radio=$('rotaryRadio'),phone=$('phone');if(!radio)return; radioPhoneAppMode=false; radio.classList.remove('radioOverlayOpen','inPhoneApp','collapsed'); radio.classList.add('hidden'); radio.style.left='';radio.style.top='';radio.style.right='';radio.style.bottom='';radio.style.transform=''; const close=$('radioCollapse');if(close){close.textContent='MINIMIZE';close.setAttribute('aria-label','Open or minimize 512 Jams Community Radio without resetting the game')} if(phone){phone.classList.remove('radioAppOpen','deviceSuppressed');requestAnimationFrame(()=>{fitDeviceToViewport(phone);positionExpanded(phone,true)})} toast('COMMUNITY RADIO CLOSED • NOW PLAYING STAYS ON PHONE') } window.chooseIntroPermitPhoto=chooseIntroPermitPhoto;window.openRadioApp=openRadioApp;window.closeRadioApp=closeRadioApp; requestAnimationFrame(refreshIntroPermitPreview); window.editDriverPermitName=editDriverPermitName; window.saveDriverPassName=saveDriverPassName; window.driverPassModal=driverPassModal; function buyArmoredVan(){ if(state.vanUpgrades.armored)return toast('ARMORED VANCERTS VAN ALREADY OWNED'); if(state.cash<ARMORED_VAN_COST)return toast('Need $20,000 for the armored van upgrade.'); debitCash(ARMORED_VAN_COST,'Van Upgrades','Armored Vancerts Van'); state.vanUpgrades.armored=true; state.vanUpgrades.potatoGun=true; updateMobileDonutButton();save();hud();hqModal(); toast('ARMORED VANCERTS VAN PURCHASED • POTATO GUN ONLINE') } window.buyArmoredVan=buyArmoredVan; function armoredVanCard(){ return `<div class="card"><h3>ARMORED VANCERTS VAN</h3>${state.vanUpgrades.armored?'<b class="good">OWNED</b><p>Full vehicle armor and a roof-mounted potato cannon.<br>Regular traffic and environmental hazards cause no damage. Road Snake and Black Star damage is reduced by 25%.</p>':`<p><b>$20,000</b><br>Adds full-body protective armor, a front safety cage and a roof-mounted potato cannon to the existing VANCERTS van.</p><p><b>Protection:</b> regular hazards cause no damage; Road Snake and Black Star damage is reduced by 25%.</p><button onclick="buyArmoredVan()" ${state.cash<ARMORED_VAN_COST?'disabled':''}>BUY ARMOR + CANNON</button>`}</div>` } function fireDonut(){ if(!state.vanUpgrades.potatoGun)return false; const now=Date.now(); if(now-lastDonutShotAt<340)return true; lastDonutShotAt=now; donutProjectiles.push({ x:van.x+Math.cos(van.angle)*42, y:van.y+Math.sin(van.angle)*42, angle:van.angle, speed:12.5, born:now, food:state.foodCannon.selected }); toast(`FOOD CANNON • ${foodAmmo().label} FIRED`); return true } function spawnProjectileCollectible(type,x,y,label){const c={type,itemKey:type,label,hp:0,rep:1,x,y,homeX:x,homeY:y,active:true,delivered:false,respawnAt:0,bob:Math.random()*6,temporary:true};collectibles.push(c);return c} function spawnFoodCollectible(food,x,y,label){ const f=FOOD_AMMO[food]||FOOD_AMMO.potato; return spawnProjectileCollectible(food,x,y,label||`${f.label} PICKUP`) } function spawnDonutCollectible(x,y,label='HAZARD DOUGHNUT'){return spawnFoodCollectible('donut',x,y,label)} function spawnEggCollectible(x,y,label='ELON EGG'){return spawnProjectileCollectible('egg',x,y,label)} function replaceDefeatedSpecial(index,x,y){ const count=Math.max(0,Number(state.specialHazardsRemoved)||0)+1; state.specialHazardsRemoved=count; const replacement=count%2===0?createBlackStar(index):createSpecialWaygo(index); specialCars[index]=replacement; specialCars[index].hiddenUntil=Date.now()+800+Math.random()*1400 } function createSpecialWaygo(i){ const car=createBlackStar(i); car.vehicleType='specialwaygo'; car.color='#f2f2ef'; car.speed=2.45+(i%3)*.18; return car } function projectilePointHits(px,py,x,y,r=30){return Math.hypot(px-x,py-y)<=r} function updateDonutProjectiles(f){ const now=Date.now(); for(let i=donutProjectiles.length-1;i>=0;i--){ const d=donutProjectiles[i]; d.x+=Math.cos(d.angle)*d.speed*f; d.y+=Math.sin(d.angle)*d.speed*f; let hit=false; for(const c of traffic){ if(c.hiddenUntil>now)continue; const q=trafficVisualXY(c); if(projectilePointHits(d.x,d.y,q.x,q.y,c.vehicleType==='boxtruck'?42:30)){ spawnFoodCollectible(d.food,q.x,q.y,`${foodAmmo().label} FROM ${String(c.vehicleType||'TRAFFIC').toUpperCase()}`);markHazardDefeated('traffic'); beginTrafficExit(c); hit=true;break } } if(!hit&&specialCarActive()){ for(let s=0;s<specialCars.length;s++){ const car=specialCars[s]; if(car.hiddenUntil>now)continue; if(projectilePointHits(d.x,d.y,car.x,car.y,33)){ spawnFoodCollectible(d.food,car.x,car.y,`${foodAmmo().label} FROM ${car.vehicleType==='specialwaygo'?'WAYGO':'BLACK STAR'}`); markHazardDefeated(car.vehicleType==='specialwaygo'?'waygo':'blackstar'); specialCars.splice(s,1); hit=true;break } } } if(!hit&&roadSnake.active){ for(let seg=0;seg<roadSnake.length;seg++){ const q=snakeSegmentPoint(seg); if(projectilePointHits(d.x,d.y,q.x,q.y,25)){ roadSnake.length=Math.max(0,roadSnake.length-1); spawnFoodCollectible(d.food,q.x,q.y,`${foodAmmo().label} FROM ELON`); if(roadSnake.length===0){roadSnake.active=false;markHazardDefeated('elon');toast('ELON FULLY CONVERTED • HAZARD REMOVED')} else toast(`ELON CONVERTED • ${roadSnake.length} CARS REMAIN`); hit=true;break } } } if(hit||now-d.born>2600||d.x<-250||d.y<-250||d.x>world.w+250||d.y>world.h+250)donutProjectiles.splice(i,1) } } function drawDonutProjectiles(){ for(const d of donutProjectiles){ const f=FOOD_AMMO[d.food]||FOOD_AMMO.potato; ctx.save();ctx.translate(d.x,d.y);ctx.rotate(d.angle); ctx.fillStyle=f.fill;ctx.beginPath();ctx.arc(0,0,8,0,Math.PI*2);ctx.fill(); ctx.strokeStyle=f.accent;ctx.lineWidth=3;ctx.stroke(); ctx.fillStyle='#171514';ctx.font='900 8px system-ui';ctx.textAlign='center';ctx.fillText(f.icon,0,3); ctx.restore() } } function combatOrInteract(forceInteract=false){ if(!forceInteract&&state.vanUpgrades.potatoGun&&(Math.abs(van.speed)>.35||!near))return fireDonut(); interact(); return true } function updateMobileDonutButton(){ const button=$('mobileDonut'); if(!button)return; const unlocked=!!(state.vanUpgrades&&state.vanUpgrades.armored&&state.vanUpgrades.potatoGun); button.classList.toggle('ready',unlocked); button.hidden=!unlocked; button.disabled=!unlocked; button.setAttribute('aria-hidden',unlocked?'false':'true'); button.title=unlocked?'FIRE DOUGHNUT CANNON':'BUY ARMORED VAN TO UNLOCK' } function mobileFireDonut(e){ if(e){e.preventDefault();e.stopPropagation()} if(!(state.vanUpgrades&&state.vanUpgrades.potatoGun)){ toast('BUY THE ARMORED VAN TO UNLOCK THE DOUGHNUT CANNON'); return } const button=$('mobileDonut'); if(button){ button.classList.add('firing'); setTimeout(()=>button.classList.remove('firing'),180) } fireDonut() } window.mobileFireDonut=mobileFireDonut; const mobileDonutButton=$('mobileDonut'); if(mobileDonutButton){ mobileDonutButton.addEventListener('pointerdown',mobileFireDonut); mobileDonutButton.addEventListener('click',e=>{e.preventDefault();e.stopPropagation()}); } auditCollectibleSpawns(); const cartCollector={name:'RUSSEL',active:true,x:512,y:330,target:null,carried:[],speed:.052,lastDay:''}; function cartCollectorActive(){return true} function cartDepot(){return{x:512,y:330}} function depositCartItems(){if(!cartCollector.carried.length)return;const deliveredCount=cartCollector.carried.length,start=collectibles.filter(c=>c.delivered).length;cartCollector.carried.forEach((c,i)=>{const p=gigBagDeliverySlot(start+i);c.x=p.x;c.y=p.y;c.active=true;c.delivered=true;c.respawnAt=0});normalizeGigBagDeliverySlots();state.rep+=1;cartCollector.carried=[];save();hud();toast(`RUSSEL DELIVERY! ${deliveredCount} resources returned to the new Gig Bag location • COMMUNITY +1`)} function chooseCartTarget(){if(cartCollector.carried.length>=3){cartCollector.target={kind:'depot',...cartDepot()};return}const candidates=collectibles.filter(c=>c.active&&!c.delivered);if(!candidates.length){cartCollector.target=cartCollector.carried.length?{kind:'depot',...cartDepot()}:null;return}candidates.sort((a,b)=>Math.hypot(a.x-cartCollector.x,a.y-cartCollector.y)-Math.hypot(b.x-cartCollector.x,b.y-cartCollector.y));const c=candidates[0];cartCollector.target={kind:'item',item:c,x:c.x,y:c.y}} function updateCartCollector(dt){if(sandboxRoadTestingActive())return;cartCollector.active=true;if(!cartCollector.target)chooseCartTarget();const t=cartCollector.target;if(!t)return;const dx=t.x-cartCollector.x,dy=t.y-cartCollector.y,d=Math.hypot(dx,dy)||1,collectorSpeed=.052*(projectLevel('foodPantry')?1.35:1)*(state.rep>=500?1.15:1),step=collectorSpeed*dt;if(d<=step+4){cartCollector.x=t.x;cartCollector.y=t.y;if(t.kind==='item'&&t.item&&t.item.active){t.item.active=false;cartCollector.carried.push(t.item);toast(`RUSSEL PICKED UP: ${t.item.label}`)}else if(t.kind==='depot')depositCartItems();cartCollector.target=null;chooseCartTarget()}else{const nx=cartCollector.x+dx/d*step,ny=cartCollector.y+dy/d*step;if(!movementBlockedByRed(cartCollector.x,cartCollector.y,nx,ny,'pedestrian')){cartCollector.x=nx;cartCollector.y=ny}else{cartCollector.target=null;chooseCartTarget()}}} function drawCartCollector(){if(!cartCollector.active)return;ctx.save();ctx.translate(cartCollector.x,cartCollector.y);const walking=Math.sin(performance.now()/125)*2; // Cape: black outer shape with green center and yellow trim. ctx.fillStyle='#111';ctx.beginPath();ctx.moveTo(-13,-8);ctx.lineTo(-29,8+walking);ctx.lineTo(-20,24);ctx.lineTo(-7,15);ctx.closePath();ctx.fill(); ctx.fillStyle='#2f7d45';ctx.beginPath();ctx.moveTo(-12,-5);ctx.lineTo(-25,9+walking);ctx.lineTo(-18,19);ctx.lineTo(-8,13);ctx.closePath();ctx.fill(); ctx.strokeStyle='#e4b52c';ctx.lineWidth=2;ctx.stroke(); // Dark-skinned face, hair, and bright mask. ctx.fillStyle='#3f2418';ctx.beginPath();ctx.arc(-8,-19,8,0,Math.PI*2);ctx.fill();ctx.fillStyle='#111';ctx.beginPath();ctx.arc(-8,-22,8,Math.PI,Math.PI*2);ctx.fill();ctx.fillStyle='#e4b52c';ctx.fillRect(-14,-20,12,4);ctx.fillStyle='#fff';ctx.fillRect(-12,-19,3,2);ctx.fillRect(-6,-19,3,2); // Green, black, and yellow superhero suit. ctx.fillStyle='#1b1b1b';ctx.fillRect(-16,-11,17,25);ctx.fillStyle='#2f7d45';ctx.fillRect(-14,-9,13,20);ctx.fillStyle='#e4b52c';ctx.fillRect(-14,7,13,4); ctx.fillStyle='#e4b52c';ctx.beginPath();ctx.arc(-7,-1,6,0,Math.PI*2);ctx.fill();ctx.fillStyle='#111';ctx.font='1000 8px system-ui';ctx.textAlign='center';ctx.textBaseline='middle';ctx.fillText('R',-7,-1); // Arms and legs. ctx.strokeStyle='#3f2418';ctx.lineWidth=4;ctx.beginPath();ctx.moveTo(-14,-6);ctx.lineTo(-21,4);ctx.moveTo(-1,-6);ctx.lineTo(5,0);ctx.stroke();ctx.strokeStyle='#111';ctx.lineWidth=5;ctx.beginPath();ctx.moveTo(-12,14);ctx.lineTo(-17,25+walking);ctx.moveTo(-3,14);ctx.lineTo(2,25-walking);ctx.stroke();ctx.strokeStyle='#e4b52c';ctx.lineWidth=2;ctx.stroke(); // Grocery basket with handle, wheels, and visible collected items. ctx.strokeStyle='#111';ctx.lineWidth=5;ctx.strokeRect(7,-3,30,20);ctx.strokeStyle='#e4b52c';ctx.lineWidth=2;ctx.strokeRect(7,-3,30,20);ctx.beginPath();ctx.moveTo(3,-7);ctx.lineTo(12,-7);ctx.lineTo(15,-2);ctx.stroke();ctx.strokeStyle='#111';ctx.lineWidth=2;for(let x=12;x<36;x+=6){ctx.beginPath();ctx.moveTo(x,-1);ctx.lineTo(x,15);ctx.stroke()}for(let y=3;y<15;y+=6){ctx.beginPath();ctx.moveTo(9,y);ctx.lineTo(36,y);ctx.stroke()}ctx.fillStyle='#111';ctx.beginPath();ctx.arc(13,21,4,0,Math.PI*2);ctx.arc(33,21,4,0,Math.PI*2);ctx.fill(); const itemColors=['#e4b52c','#2f7d45','#e64a38','#3f84a5'];for(let i=0;i<cartCollector.carried.length;i++){ctx.fillStyle=itemColors[i%itemColors.length];ctx.fillRect(11+i*7,0-(i%2)*5,7,8)} // Name plate makes Russel identifiable at game scale. ctx.restore()} const snakeGraphXs=[75,695,1355,2015,2625,3175],snakeGraphYs=[75,690,1390,1975,2525]; const roadSnake={x:75,y:75,targetX:695,targetY:75,prevX:null,prevY:null,speed:2.45,length:5,eventKey:'',active:false,spacing:34,trail:[],dayKey:''}; function snakeNeighbors(x,y){const xi=snakeGraphXs.indexOf(x),yi=snakeGraphYs.indexOf(y),n=[];if(xi>0)n.push([snakeGraphXs[xi-1],y]);if(xi<snakeGraphXs.length-1)n.push([snakeGraphXs[xi+1],y]);if(yi>0)n.push([x,snakeGraphYs[yi-1]]);if(yi<snakeGraphYs.length-1)n.push([x,snakeGraphYs[yi+1]]);return n.filter(([nx,ny])=>segmentStaysOnRoad(x,y,nx,ny))} function tHash(value){let h=2166136261;const text=String(value||'');for(let i=0;i<text.length;i++){h^=text.charCodeAt(i);h=Math.imul(h,16777619)}return h>>>0} function initRoadSnake(dayKey){roadSnake.dayKey=dayKey;roadSnake.length=snakeMinimumLength();const edge=[];for(const x of snakeGraphXs){edge.push([x,75],[x,2525])}for(const y of snakeGraphYs.slice(1,-1)){edge.push([75,y],[3175,y])}const start=edge[tHash(dayKey)%edge.length];roadSnake.x=start[0];roadSnake.y=start[1];roadSnake.prevX=null;roadSnake.prevY=null;roadSnake.trail=[{x:roadSnake.x,y:roadSnake.y,angle:0}];chooseSnakeTarget()} function chooseSnakeTarget(){let n=snakeNeighbors(roadSnake.x,roadSnake.y);const filtered=n.filter(p=>p[0]!==roadSnake.prevX||p[1]!==roadSnake.prevY);if(filtered.length)n=filtered;const pick=n[Math.floor(Math.random()*n.length)]||n[0];roadSnake.prevX=roadSnake.x;roadSnake.prevY=roadSnake.y;roadSnake.targetX=pick[0];roadSnake.targetY=pick[1]} function updateSnakeWindow(){if(sandboxRoadTestingActive()&&!state.cheats.forceElon){roadSnake.active=false;roadSnake.trail=[];return}const t=austinTimeParts(),mins=t.hour*60+t.minute,key=austinDateKey(),active=(mins>=720&&mins<1440)||!!state.cheats.forceElon;if(active&&roadSnake.dayKey!==key){initRoadSnake(key);toast('ROAD SNAKE! It will roam every street until midnight.')}roadSnake.active=active;if(active)roadSnake.length=Math.max(roadSnake.length,5+sponsorSignCount()*3);if(!active){roadSnake.length=snakeMinimumLength();roadSnake.trail=[]}} function updateRoadSnake(f){if(!roadSnake.active)return;let remaining=roadSnake.speed*f;while(remaining>0){const dx=roadSnake.targetX-roadSnake.x,dy=roadSnake.targetY-roadSnake.y,d=Math.hypot(dx,dy)||1;if(d<=remaining+0.01){roadSnake.x=roadSnake.targetX;roadSnake.y=roadSnake.targetY;remaining-=d;chooseSnakeTarget()}else{const sx=roadSnake.x+dx/d*remaining,sy=roadSnake.y+dy/d*remaining;if(onDesignatedRoadPoint(sx,sy,1)){roadSnake.x=sx;roadSnake.y=sy}else{roadSnake.x=roadSnake.targetX;roadSnake.y=roadSnake.targetY;chooseSnakeTarget()}remaining=0}}const last=roadSnake.trail[0];if(!last||Math.hypot(last.x-roadSnake.x,last.y-roadSnake.y)>=3){const angle=Math.atan2(roadSnake.targetY-roadSnake.y,roadSnake.targetX-roadSnake.x);roadSnake.trail.unshift({x:roadSnake.x,y:roadSnake.y,angle});let total=0,cut=roadSnake.trail.length;for(let i=1;i<roadSnake.trail.length;i++){total+=Math.hypot(roadSnake.trail[i-1].x-roadSnake.trail[i].x,roadSnake.trail[i-1].y-roadSnake.trail[i].y);if(total>roadSnake.length*roadSnake.spacing+120){cut=i+1;break}}roadSnake.trail.length=Math.min(roadSnake.trail.length,cut)}} function snakeSegmentPoint(i){const target=i*roadSnake.spacing;if(!roadSnake.trail.length)return{x:roadSnake.x,y:roadSnake.y,angle:0};let dist=0;for(let j=1;j<roadSnake.trail.length;j++){const a=roadSnake.trail[j-1],b=roadSnake.trail[j],seg=Math.hypot(a.x-b.x,a.y-b.y);if(dist+seg>=target){const t=(target-dist)/(seg||1);return{x:a.x+(b.x-a.x)*t,y:a.y+(b.y-a.y)*t,angle:Math.atan2(a.y-b.y,a.x-b.x)}}dist+=seg}return roadSnake.trail[roadSnake.trail.length-1]} function snakeHit(){if(inByobSafeZone(van.x,van.y,8))return false;for(let i=0;i<roadSnake.length;i++){const q=snakeSegmentPoint(i);if(Math.hypot(van.x-q.x,van.y-q.y)<31)return true}return false} function ensurePedestrians(){if(sandboxRoadTestingActive())return;if(pedestrians.length)return;const paths=[{x1:585,y1:545,x2:585,y2:835},{x1:1245,y1:545,x2:1245,y2:835},{x1:1905,y1:545,x2:1905,y2:835},{x1:585,y1:1245,x2:585,y2:1535}];const extra=BUS_STOPS_ENABLED&&projectLevel('busStops')?4:0;for(let i=0;i<8+extra;i++){const path=paths[i%paths.length];pedestrians.push({...path,t:(i%4)/4,dir:i%2?1:-1,speed:.00022+Math.random()*.00018,entityId:`#NPC-${String(i+1).padStart(3,'0')}`})}} function austinGameDate(date=new Date()){return new Date(date.getTime()+Number(state?.gameTimeOffsetHours||0)*3600000)} function austinTimeParts(){const parts=new Intl.DateTimeFormat('en-US',{timeZone:'America/Chicago',hour:'2-digit',minute:'2-digit',second:'2-digit',hour12:false,timeZoneName:'short'}).formatToParts(austinGameDate()),o={};for(const part of parts)o[part.type]=part.value;let hour=Number(o.hour||0);if(hour===24)hour=0;return{hour,minute:Number(o.minute||0),second:Number(o.second||0),zone:o.timeZoneName||'CT',label:`${String(hour%12||12).padStart(2,'0')}:${String(o.minute||'00').padStart(2,'0')}:${String(o.second||'00').padStart(2,'0')} ${o.timeZoneName||'CT'}`}} function austinDateKey(date=new Date()){const parts=new Intl.DateTimeFormat('en-US',{timeZone:'America/Chicago',year:'numeric',month:'2-digit',day:'2-digit'}).formatToParts(austinGameDate(date)),o={};for(const part of parts)o[part.type]=part.value;return `${o.year||'0000'}-${o.month||'00'}-${o.day||'00'}`} function updateClock(){const el=$('clock');if(el)el.textContent=austinTimeParts().label} function ensureTrashBalls(){} updateClock();setInterval(updateClock,1000); const carColors=ORDINARY_COLORS; function loopLength(inset){return 2*((world.w-inset*2)+(world.h-inset*2))} initializeRoadTraffic(); const store=[['Main speaker',650,'main'],['Subwoofer',750,'sub'],['Microphone',110,'mic'],['Stage monitor',425,'monitor'],['Lighting package',300,'lights'],['Backline package',900,'backline'],['XLR cable',25,'xlr'],['IEC power cable',25,'iec'],['50FT speaker cable',75,'speakerCable50'],['50FT 24-channel snake',650,'snake24'],['High tom',275,'highTom'],['Low tom',300,'lowTom'],['Floor tom',350,'floorTom'],['Bass drum',500,'bassDrum'],['Drum hardware pack',450,'drumHardware'],['Guitar amp',650,'guitarAmp'],['Bass amp',750,'bassAmp'],['DI box',120,'diBox']]; const FINANCE_LEDGER_LIMIT=400; const SHOW_GAS_PRICE_PER_GALLON=3.855; const SHOW_TANK_GALLONS=20; const SHOW_FUEL_COST=Math.round(SHOW_GAS_PRICE_PER_GALLON*SHOW_TANK_GALLONS*100)/100; const SHOW_MEAL_PER_PERSON=20; const SHOW_VEHICLE_WEAR_ESTIMATE=15; const SHOW_EQUIPMENT_WEAR_ESTIMATE=10; const PAUL_SHIFT_RATE=150; function financeAmount(value){const n=Number(value);return Number.isFinite(n)?Math.max(0,Math.round(n*100)/100):0} function cleanFinanceBreakdown(value){const out={};if(!value||typeof value!=='object')return out;for(const [key,amount] of Object.entries(value)){const n=financeAmount(amount);if(n>0)out[String(key).slice(0,50)]=n}return out} function normalizeBankLoanRecord(loan,index=0){ if(!loan||typeof loan!=='object')return null; const principal=financeAmount(loan.principal),payoff=Math.max(principal,financeAmount(loan.payoff)||principal),interest=financeAmount(Object.prototype.hasOwnProperty.call(loan,'interest')?loan.interest:payoff-principal); if(principal<=0||payoff<=0)return null; const paid=Math.min(payoff,financeAmount(Object.prototype.hasOwnProperty.call(loan,'paid')?loan.paid:loan.repaid)); const interestPaid=Math.min(interest,financeAmount(Object.prototype.hasOwnProperty.call(loan,'interestPaid')?loan.interestPaid:Math.min(paid,interest))); const principalPaid=Math.min(principal,financeAmount(Object.prototype.hasOwnProperty.call(loan,'principalPaid')?loan.principalPaid:Math.max(0,paid-interestPaid))); const createdAt=Number(loan.createdAt||loan.takenAt)||Date.now(); return{id:String(loan.id||`loan-${createdAt}-${index}`),day:String(loan.day||austinDateKey(new Date(createdAt))),principal,interest,payoff,paid:Math.min(payoff,interestPaid+principalPaid),interestPaid,principalPaid,createdAt,legacy:!!loan.legacy} } function deductionPercent(value){if(value===null||value==='review'||value==='REVIEW'||value===undefined)return null;const n=Number(value);return Number.isFinite(n)?Math.max(0,Math.min(100,Math.round(n))):null} function receiptDefaults(type,category,label,options={}){ const c=String(category||'Other'),income=type==='income',loan=type==='loan',repayment=type==='repayment',estimate=type==='estimate'; let vendor=String(options.vendor||label||'VANCERTS').slice(0,80),purpose=String(options.businessPurpose||'Business transaction recorded in the Vancerts ledger.').slice(0,220),pct=deductionPercent(options.deductiblePct),taxTreatment=String(options.taxTreatment||'').slice(0,260),status='REVIEW'; if(income){pct=0;status='INCOME';taxTreatment=taxTreatment||'BUSINESS INCOME • Include deposits and final client payments in gross business receipts.'} else if(loan){pct=0;status='NONDEDUCTIBLE';taxTreatment=taxTreatment||'LOAN PROCEEDS • Loan principal is tracked separately from business income. Repaying principal is not a business expense deduction.'} else if(repayment){pct=0;status='NONDEDUCTIBLE';taxTreatment=taxTreatment||'DEBT PAYMENT • Principal repayment is not a deduction. Business interest may require separate tax treatment.'} else if(estimate){pct=0;status='ESTIMATE';taxTreatment=taxTreatment||'NON-CASH PLANNING ESTIMATE • Track the expected cost, but do not claim a deduction until an actual qualifying expense is paid or incurred.'} else if(c==='Fuel'){pct=100;status='DEDUCTIBLE';taxTreatment=taxTreatment||'BUSINESS VEHICLE ACTUAL EXPENSE • Track business use and do not double-count the same use under both actual expenses and the standard mileage method.'} else if(c==='Meals'){pct=50;status='PARTIAL';taxTreatment=taxTreatment||'BUSINESS MEAL • Educational estimate uses 50% when the meal is ordinary, necessary, properly documented, and not lavish or extravagant.'} else if(c==='Payroll'){pct=100;status='DEDUCTIBLE';taxTreatment=taxTreatment||'EMPLOYEE OR CONTRACT LABOR • Educational estimate assumes reasonable payment for actual business services and proper worker classification/reporting.'} else if(['Repairs','Towing','Rentals','Waygo','Permits','Community Projects','Community Giving'].includes(c)){pct=100;status='DEDUCTIBLE';taxTreatment=taxTreatment||'BUSINESS OPERATING EXPENSE • Educational estimate assumes the cost is ordinary, necessary, and entirely business related.'} else if(c==='Equipment'){pct=null;status='REVIEW';taxTreatment=taxTreatment||'EQUIPMENT PURCHASE • Business-use equipment may be expensed, depreciated, or capitalized depending on the item, cost, and tax election.'} else if(c==='Debt Repayment'){pct=0;status='NONDEDUCTIBLE';taxTreatment=taxTreatment||'DEBT PAYMENT • Principal repayment is not treated as a current business expense deduction.'} else if(type==='expense'&&pct!==null){status=pct===100?'DEDUCTIBLE':pct>0?'PARTIAL':'NONDEDUCTIBLE'} else if(type==='expense'){status='REVIEW';taxTreatment=taxTreatment||'REVIEW WITH A TAX PROFESSIONAL • Deductibility depends on business purpose, records, business-use percentage, timing, and capitalization rules.'} return{vendor,purpose,pct,taxTreatment,status,paymentMethod:String(options.paymentMethod||((income||loan)?'CLIENT / BANK PAYMENT':'VANCERTS BUSINESS FUNDS')).slice(0,60),jobId:String(options.jobId||'').slice(0,60),employee:String(options.employee||'').slice(0,60),gallons:financeAmount(options.gallons),unitPrice:financeAmount(options.unitPrice),crewCount:Math.max(0,Math.round(Number(options.crewCount)||0))} } function normalizeFinanceTransaction(tx,index,now){ const type=String(tx.type||'adjustment'),category=String(tx.category||'Other').slice(0,50),label=String(tx.label||'Transaction').slice(0,100),meta=receiptDefaults(type,category,label,{vendor:tx.vendor,businessPurpose:tx.businessPurpose||tx.purpose,deductiblePct:Object.prototype.hasOwnProperty.call(tx,'deductiblePct')?tx.deductiblePct:undefined,taxTreatment:tx.taxTreatment,paymentMethod:tx.paymentMethod,jobId:tx.jobId,employee:tx.employee,gallons:tx.gallons,unitPrice:tx.unitPrice,crewCount:tx.crewCount}); return{id:String(tx.id||`tx-import-${index}`),at:String(tx.at||now),day:String(tx.day||austinDateKey()),type,category,label,amount:financeAmount(tx.amount),balance:financeAmount(tx.balance),interest:financeAmount(tx.interest),receiptNo:String(tx.receiptNo||`VC-IMPORT-${String(index+1).padStart(4,'0')}`),vendor:meta.vendor,businessPurpose:meta.purpose,deductiblePct:meta.pct,taxTreatment:meta.taxTreatment,deductionStatus:String(tx.deductionStatus||meta.status),paymentMethod:meta.paymentMethod,jobId:meta.jobId,employee:meta.employee,gallons:meta.gallons,unitPrice:meta.unitPrice,crewCount:meta.crewCount} } function normalizeFinanceState(raw,legacySave){ const source=raw&&typeof raw==='object'?raw:null,now=new Date().toISOString(); const transactions=Array.isArray(source?.transactions)?source.transactions.filter(tx=>tx&&typeof tx==='object').slice(-400).map((tx,index)=>normalizeFinanceTransaction(tx,index,now)):[]; const derivedDeductible=transactions.filter(tx=>tx.type==='expense'&&Number.isFinite(Number(tx.deductiblePct))).reduce((sum,tx)=>sum+tx.amount*(Number(tx.deductiblePct)||0)/100,0),derivedReview=transactions.filter(tx=>tx.type==='expense'&&tx.deductiblePct===null).reduce((sum,tx)=>sum+tx.amount,0),derivedEstimate=transactions.filter(tx=>tx.type==='estimate').reduce((sum,tx)=>sum+tx.amount,0); return{version:2,openingCash:financeAmount(source?.openingCash??state.cash),trackingStartedAt:String(source?.trackingStartedAt||now),trackingStartedDay:String(source?.trackingStartedDay||austinDateKey()),legacyOpening:source?!!source.legacyOpening:!!legacySave,totalEarned:financeAmount(source?.totalEarned),totalSpent:financeAmount(source?.totalSpent),totalBorrowed:Math.max(financeAmount(source?.totalBorrowed),financeAmount(state.bankStats.totalBorrowed)),totalDebtPaid:Math.max(financeAmount(source?.totalDebtPaid),financeAmount(state.bankStats.totalRepaid)),totalInterestCharged:Math.max(financeAmount(source?.totalInterestCharged),financeAmount(state.bankStats.totalInterestCharged)),totalInterestPaid:Math.max(financeAmount(source?.totalInterestPaid),financeAmount(state.bankStats.totalInterestPaid)),totalAdjustments:Number(source?.totalAdjustments)||0,totalPotentialDeductions:Math.max(financeAmount(source?.totalPotentialDeductions),financeAmount(derivedDeductible)),totalReviewExpenses:Math.max(financeAmount(source?.totalReviewExpenses),financeAmount(derivedReview)),totalEstimatedCosts:Math.max(financeAmount(source?.totalEstimatedCosts),financeAmount(derivedEstimate)),receiptSequence:Math.max(Number(source?.receiptSequence)||0,transactions.length),incomeByCategory:cleanFinanceBreakdown(source?.incomeByCategory),expenseByCategory:cleanFinanceBreakdown(source?.expenseByCategory),deductionsByCategory:cleanFinanceBreakdown(source?.deductionsByCategory),estimateByCategory:cleanFinanceBreakdown(source?.estimateByCategory),transactions} } function nextReceiptNumber(){state.finance.receiptSequence=Math.max(0,Number(state.finance.receiptSequence)||0)+1;return `VC-${austinDateKey().replaceAll('-','')}-${String(state.finance.receiptSequence).padStart(5,'0')}`} function pushFinanceTransaction(type,amount,category,label,options={}){ const value=financeAmount(amount);if(value<=0)return null; const meta=receiptDefaults(type,category,label,options),tx={id:`tx-${Date.now()}-${Math.random().toString(36).slice(2,7)}`,at:new Date().toISOString(),day:austinDateKey(),type:String(type||'adjustment'),category:String(category||'Other').slice(0,50),label:String(label||'Transaction').slice(0,100),amount:value,balance:financeAmount(state.cash),interest:financeAmount(options.interest),receiptNo:nextReceiptNumber(),vendor:meta.vendor,businessPurpose:meta.purpose,deductiblePct:meta.pct,taxTreatment:meta.taxTreatment,deductionStatus:meta.status,paymentMethod:meta.paymentMethod,jobId:meta.jobId,employee:meta.employee,gallons:meta.gallons,unitPrice:meta.unitPrice,crewCount:meta.crewCount}; state.finance.transactions.push(tx);if(state.finance.transactions.length>FINANCE_LEDGER_LIMIT)state.finance.transactions.splice(0,state.finance.transactions.length-FINANCE_LEDGER_LIMIT); if(type==='income'){state.finance.totalEarned=financeAmount(state.finance.totalEarned+value);state.finance.incomeByCategory[tx.category]=financeAmount((state.finance.incomeByCategory[tx.category]||0)+value)} else if(type==='expense'){state.finance.totalSpent=financeAmount(state.finance.totalSpent+value);state.finance.expenseByCategory[tx.category]=financeAmount((state.finance.expenseByCategory[tx.category]||0)+value);if(tx.deductiblePct===null)state.finance.totalReviewExpenses=financeAmount(state.finance.totalReviewExpenses+value);else{const deduction=financeAmount(value*tx.deductiblePct/100);state.finance.totalPotentialDeductions=financeAmount(state.finance.totalPotentialDeductions+deduction);state.finance.deductionsByCategory[tx.category]=financeAmount((state.finance.deductionsByCategory[tx.category]||0)+deduction)}} else if(type==='estimate'){state.finance.totalEstimatedCosts=financeAmount(state.finance.totalEstimatedCosts+value);state.finance.estimateByCategory[tx.category]=financeAmount((state.finance.estimateByCategory[tx.category]||0)+value)} else if(type==='loan')state.finance.totalBorrowed=financeAmount(state.finance.totalBorrowed+value); else if(type==='repayment'){state.finance.totalDebtPaid=financeAmount(state.finance.totalDebtPaid+value);state.finance.totalInterestPaid=financeAmount(state.finance.totalInterestPaid+tx.interest)} else if(type==='adjustment')state.finance.totalAdjustments=Math.round((Number(state.finance.totalAdjustments)||0)+(options.direction==='debit'?-value:value)); return tx } function creditCash(amount,category,label,options={}){const value=financeAmount(amount);if(value<=0)return false;state.cash=financeAmount(Number(state.cash||0)+value);pushFinanceTransaction(options.type||'income',value,category,label,options);return true} function debitCash(amount,category,label,options={}){const value=financeAmount(amount);if(value<=0||Number(state.cash||0)<value)return false;state.cash=financeAmount(Number(state.cash||0)-value);pushFinanceTransaction(options.type||'expense',value,category,label,{...options,direction:'debit'});return true} function recordCostEstimate(amount,category,label,options={}){return pushFinanceTransaction('estimate',amount,category,label,{...options,deductiblePct:0})} function persistCommittedFinanceState(){ if(state.cheats&&state.cheats.sandbox)return false; if(portableMode){portableSaveFile=portablePayload(state);sessionStorage.setItem(PORTABLE_SESSION_KEY,JSON.stringify(portableSaveFile));return true} safeStorage.setItem(SAVE_KEY,JSON.stringify(state));safeStorage.removeItem(LEGACY_CHECKPOINT_KEY);return true } function financeDateLabel(value){try{return new Intl.DateTimeFormat('en-US',{timeZone:'America/Chicago',month:'short',day:'numeric',hour:'numeric',minute:'2-digit'}).format(new Date(value))}catch(_){return String(value||'')}} function safeFinanceText(value){return String(value??'').replace(/[&<>"']/g,ch=>({'&':'&','<':'<','>':'>','"':'"',"'":'''}[ch]))} function financeCategoryList(data,emptyText){const rows=Object.entries(data||{}).sort((a,b)=>b[1]-a[1]);return rows.length?`<ul class="financeList">${rows.map(([name,amount])=>`<li><b>${safeFinanceText(name)}</b> — $${rentalMoney(amount)}</li>`).join('')}</ul>`:`<p class="small">${emptyText}</p>`} function deductionBadgeHtml(tx){const status=String(tx.deductionStatus||'REVIEW'),cls=status==='PARTIAL'?'partial':status==='REVIEW'||status==='ESTIMATE'||status==='NONDEDUCTIBLE'?'review':status==='INCOME'?'income':'';const label=status==='DEDUCTIBLE'?`${tx.deductiblePct}% EDUCATIONAL DEDUCTION`:status==='PARTIAL'?`${tx.deductiblePct}% EDUCATIONAL DEDUCTION`:status==='INCOME'?'BUSINESS INCOME':status==='ESTIMATE'?'NON-CASH COST ESTIMATE':status==='NONDEDUCTIBLE'?'NOT A CURRENT EXPENSE DEDUCTION':'TAX REVIEW NEEDED';return `<span class="deductionBadge ${cls}">${safeFinanceText(label)}</span>`} function receiptCardHtml(tx,detail=false){const sign=tx.type==='income'||tx.type==='loan'?'+':tx.type==='expense'||tx.type==='repayment'?'-':'~',fuel=tx.gallons?`<div class="receiptLine"><span>Fuel calculation</span><b>${rentalMoney(tx.gallons)} gal × $${rentalMoney(tx.unitPrice)}</b></div>`:'',crew=tx.crewCount?`<div class="receiptLine"><span>Crew covered</span><b>${tx.crewCount}</b></div>`:'',employee=tx.employee?`<div class="receiptLine"><span>Worker</span><b>${safeFinanceText(tx.employee)}</b></div>`:'';return `<div class="receiptCard ${tx.type==='estimate'?'estimate':''}"><div class="receiptHead"><div><b>${safeFinanceText(tx.vendor)}</b><br><small>${safeFinanceText(financeDateLabel(tx.at))}</small></div><div class="receiptNo">${safeFinanceText(tx.receiptNo)}</div></div><div class="receiptLine"><span>${tx.type==='estimate'?'Estimated cost':'Amount'}</span><b>${sign}$${rentalMoney(tx.amount)}</b></div><div class="receiptLine"><span>Category</span><b>${safeFinanceText(tx.category)}</b></div><div class="receiptLine"><span>Description</span><b>${safeFinanceText(tx.label)}</b></div><div class="receiptLine"><span>Payment</span><b>${safeFinanceText(tx.paymentMethod)}</b></div>${employee}${fuel}${crew}<div class="receiptPurpose"><b>BUSINESS PURPOSE</b><br>${safeFinanceText(tx.businessPurpose)}</div>${deductionBadgeHtml(tx)}${detail?`<p class="receiptNote"><b>WHY:</b> ${safeFinanceText(tx.taxTreatment)}</p><p class="receiptNote">Balance after transaction: $${rentalMoney(tx.balance)}${tx.jobId?` • Job ${safeFinanceText(tx.jobId)}`:''}</p>`:`<button class="receiptMini" onclick="showReceipt('${safeFinanceText(tx.id)}')">${tx.type==='estimate'?'OPEN COST CARD':'VIEW RECEIPT'}</button>`}</div>`} function financeReceiptArchiveHtml(limit=18){const rows=(state.finance.transactions||[]).slice(-limit).reverse();return rows.length?`<div class="receiptGrid">${rows.map(tx=>receiptCardHtml(tx,false)).join('')}</div>`:'<div class="card">No receipts yet. Confirm a show, buy equipment, receive a payment, or hire staff to start the archive.</div>'} function financeLedgerHtml(limit=20){const rows=(state.finance.transactions||[]).slice(-limit).reverse();if(!rows.length)return '<div class="ledger"><div class="ledgerEmpty">No transactions yet. Your first income or purchase will appear here.</div></div>';return `<div class="ledger">${rows.map(tx=>{const sign=tx.type==='income'||tx.type==='loan'?'+':tx.type==='expense'||tx.type==='repayment'?'-':'~';return `<div class="ledgerRow ${safeFinanceText(tx.type)}"><span>${safeFinanceText(financeDateLabel(tx.at))}</span><span><b>${safeFinanceText(tx.label)}</b><br><small>${safeFinanceText(tx.category)} • Balance $${rentalMoney(tx.balance)}</small><br><button class="receiptMini" onclick="showReceipt('${safeFinanceText(tx.id)}')">${tx.type==='estimate'?'COST CARD':'RECEIPT'}</button></span><span class="ledgerAmount">${sign}$${rentalMoney(tx.amount)}</span></div>`}).join('')}</div>`} function financeStatementHtml(){ const f=state.finance,operatingNet=Number(f.totalEarned||0)-Number(f.totalSpent||0),estimatedTrueNet=operatingNet-Number(f.totalEstimatedCosts||0),debt=bankLoanBalance(),invoiceTotal=(state.invoices||[]).reduce((sum,invoice)=>sum+financeAmount(invoice.amount),0),invoiceCollected=(state.invoices||[]).filter(invoice=>invoice.paid).reduce((sum,invoice)=>sum+financeAmount(invoice.amount),0),receivable=Math.max(0,invoiceTotal-invoiceCollected); return `<div class="financeHero"><div class="financeMetric"><span>CURRENT CASH</span><b>$${rentalMoney(state.cash)}</b></div><div class="financeMetric earned"><span>TOTAL EARNED / RECEIVED</span><b>$${rentalMoney(f.totalEarned)}</b></div><div class="financeMetric spent"><span>ACTUAL BUSINESS SPENDING</span><b>$${rentalMoney(f.totalSpent)}</b></div><div class="financeMetric deduction"><span>POTENTIAL DEDUCTIONS</span><b>$${rentalMoney(f.totalPotentialDeductions)}</b></div><div class="financeMetric ${debt?'debt':''}"><span>CASH OPERATING NET</span><b>${operatingNet<0?'-':''}$${rentalMoney(Math.abs(operatingNet))}</b></div><div class="financeMetric estimate"><span>NON-CASH WEAR ESTIMATES</span><b>$${rentalMoney(f.totalEstimatedCosts)}</b></div><div class="financeMetric"><span>NET AFTER WEAR ESTIMATES</span><b>${estimatedTrueNet<0?'-':''}$${rentalMoney(Math.abs(estimatedTrueNet))}</b></div><div class="financeMetric"><span>EXPENSES NEEDING REVIEW</span><b>$${rentalMoney(f.totalReviewExpenses)}</b></div></div><div class="financeSplit"><div class="card"><h3>INCOME BY CATEGORY</h3>${financeCategoryList(f.incomeByCategory,'No tracked income yet.')}</div><div class="card"><h3>ACTUAL SPENDING BY CATEGORY</h3>${financeCategoryList(f.expenseByCategory,'No tracked expenses yet.')}</div><div class="card"><h3>EDUCATIONAL DEDUCTIONS BY CATEGORY</h3>${financeCategoryList(f.deductionsByCategory,'No fixed-percentage deduction estimates yet.')}</div><div class="card"><h3>WEAR & TEAR ESTIMATES</h3>${financeCategoryList(f.estimateByCategory,'No operating-cost estimates yet.')}</div><div class="card"><h3>DEBT HISTORY</h3>Borrowed <b>$${rentalMoney(f.totalBorrowed)}</b><br>Interest charged <b>$${rentalMoney(f.totalInterestCharged)}</b><br>Debt repaid <b>$${rentalMoney(f.totalDebtPaid)}</b><br>Interest paid <b>$${rentalMoney(f.totalInterestPaid)}</b><br>Current bank debt <b>$${rentalMoney(debt)}</b></div><div class="card"><h3>ACCOUNTS RECEIVABLE</h3>Invoices issued <b>$${rentalMoney(invoiceTotal)}</b><br>Invoice payments collected <b>$${rentalMoney(invoiceCollected)}</b><br>Still owed by clients <b>$${rentalMoney(receivable)}</b><br><span class="small">Deposits and final payments each produce their own payment receipt.</span></div><div class="card"><h3>SHOW COST STANDARD</h3>Fuel budget <b>${SHOW_TANK_GALLONS} gal × $${rentalMoney(SHOW_GAS_PRICE_PER_GALLON)} = $${rentalMoney(SHOW_FUEL_COST)}</b><br>Crew food <b>$${SHOW_MEAL_PER_PERSON} per person</b><br>Vehicle wear estimate <b>$${SHOW_VEHICLE_WEAR_ESTIMATE}</b><br>Equipment wear estimate <b>$${SHOW_EQUIPMENT_WEAR_ESTIMATE}</b></div><div class="card"><h3>TRACKING DETAILS</h3>Opening cash <b>$${rentalMoney(f.openingCash)}</b><br>Tracking date <b>${safeFinanceText(f.trackingStartedDay)}</b><br>Stored records <b>${(f.transactions||[]).length}/${FINANCE_LEDGER_LIMIT}</b><br><span class="small">Lifetime totals continue even when the oldest individual cards roll out of the archive.</span></div></div>${f.legacyOpening?'<p class="small"><b>LEGACY SAVE NOTE:</b> Existing cash, debt, story, inventory, and progress were preserved. Detailed receipt metadata begins with this build because older versions did not store vendor, purpose, or deduction fields.</p>':'<p class="small">Loans are tracked separately from income. Non-cash wear estimates help price jobs but are not presented as paid tax deductions.</p>'}<h3>RECENT TRANSACTIONS</h3>${financeLedgerHtml()}` } function showReceipt(id){const tx=(state.finance.transactions||[]).find(item=>item.id===id);if(!tx)return toast('RECEIPT NOT FOUND');modal(`<h2>${tx.type==='estimate'?'OPERATING COST CARD':'VANCERTS RECEIPT'}</h2>${receiptCardHtml(tx,true)}<div class="btns"><button class="secondary" onclick="openExpenseTracker()">BACK TO EXPENSE TRACKER</button></div>`)} function taxSchoolHtml(){return `<div class="taxSchool"><h3>VANCERTS TAX SCHOOL • HOW THE TRACKER WORKS</h3><p><b>1. KEEP THE RECEIPT.</b> The game stores date, vendor, amount, category, business purpose, payment method, and related job.</p><p><b>2. SEPARATE ACTUAL CASH FROM ESTIMATES.</b> Fuel, meals, payroll, repairs, and purchases reduce cash. Vehicle and equipment wear cards are planning estimates only.</p><p><b>3. APPLY THE BUSINESS-USE RULE.</b> The tracker uses 100% only when the example is entirely business related. Mixed personal/business use must be split.</p><p><b>4. KNOW THE COMMON DIFFERENCES.</b> The game estimates fuel at 100% under the actual-expense method, qualifying business meals at 50%, and reasonable worker pay at 100%. Equipment stays marked REVIEW because it may need expensing, depreciation, or capitalization.</p><p><b>5. NEVER DOUBLE COUNT.</b> Do not claim the same vehicle use under both actual gas/repair expenses and the standard mileage method.</p><p class="small"><b>EDUCATIONAL SIMULATION:</b> This is bookkeeping practice, not tax preparation or legal advice. Real treatment depends on entity type, worker classification, business-use percentage, records, elections, and current law.</p></div>`} const BMI_ANNUAL_MINIMUM=437; const BMI_PAID_ADMISSION_RATE=.005; const BMI_FREE_EVENT_RATE=.015; const BMI_REPORT_DATES=['JAN 20','APR 20','JUL 20','OCT 20']; function bmiState(){state.compliance=state.compliance&&typeof state.compliance==='object'?state.compliance:{};state.compliance.bmi=Object.assign({},defaults.compliance.bmi,state.compliance.bmi||{});state.compliance.bmi.events=Array.isArray(state.compliance.bmi.events)?state.compliance.bmi.events:[];state.compliance.bmi.submittedQuarters=Array.isArray(state.compliance.bmi.submittedQuarters)?state.compliance.bmi.submittedQuarters:[];return state.compliance.bmi} function bmiQuarterForDate(value){const d=value?new Date(value):new Date(),m=d.getMonth()+1;return m<=3?'Q1':m<=6?'Q2':m<=9?'Q3':'Q4'} function bmiQuarterDue(q){return({Q1:'APR 20',Q2:'JUL 20',Q3:'OCT 20',Q4:'JAN 20'})[q]||'APR 20'} function bmiEventCharge(e){return financeAmount(e.admissionType==='paid'?Number(e.grossAdmissionRevenue||0)*BMI_PAID_ADMISSION_RATE:Number(e.entertainmentExpenses||0)*BMI_FREE_EVENT_RATE)} function recordBmiShow(job,place,finalInvoice){const bmi=bmiState(),id=showJobId(job);if(bmi.events.some(e=>e.jobId===id))return;const admissionType=job.paidAdmission?'paid':'free',grossAdmissionRevenue=admissionType==='paid'?Math.max(0,Number(job.grossAdmissionRevenue)||0):0,entertainmentExpenses=admissionType==='free'?Math.max(0,Number(job.total)||0):0,occurredAt=new Date().toISOString();const event={jobId:id,occurredAt,day:austinDateKey(),quarter:bmiQuarterForDate(occurredAt),venueId:place.id,venue:place.name,admissionType,grossAdmissionRevenue:financeAmount(grossAdmissionRevenue),entertainmentExpenses:financeAmount(entertainmentExpenses),clientRevenue:financeAmount((Number(job.deposit)||0)+(Number(finalInvoice)||0)),reported:false};event.calculatedCharge=bmiEventCharge(event);bmi.events.push(event)} function bmiTotals(){const bmi=bmiState(),calculated=financeAmount(bmi.events.reduce((sum,e)=>sum+bmiEventCharge(e),0)),annualDue=Math.max(BMI_ANNUAL_MINIMUM,calculated),additionalDue=Math.max(0,financeAmount(annualDue-BMI_ANNUAL_MINIMUM-(Number(bmi.additionalPaid)||0)));return{calculated,annualDue,additionalDue,events:bmi.events.length}} function bmiEventRows(){const events=bmiState().events.slice().reverse();if(!events.length)return '<div class="card"><b>NO COVERED SHOWS LOGGED YET</b><p class="small">Completed gigs will appear here automatically.</p></div>';return events.map(e=>`<div class="ledgerRow"><span>${safeFinanceText(e.day)}</span><b>${safeFinanceText(e.venue)}</b><span>${e.admissionType==='paid'?'PAID':'FREE'}</span><span>$${rentalMoney(bmiEventCharge(e))}</span></div>`).join('')} function submitBmiQuarter(q){const bmi=bmiState();if(bmi.submittedQuarters.includes(q))return toast(`${q} BMI REPORT ALREADY SUBMITTED`);const rows=bmi.events.filter(e=>e.quarter===q&&!e.reported);rows.forEach(e=>e.reported=true);bmi.submittedQuarters.push(q);bmi.lastSubmission=austinDateKey();const totals=bmiTotals();let paid=0;if(totals.additionalDue>0&&state.cash>=totals.additionalDue){paid=totals.additionalDue;debitCash(paid,'Licenses & Permits',`BMI ${q} additional license payment`,{vendor:'BMI',businessPurpose:`Additional public-performance licensing amount above the Vancerts annual minimum after ${q} reporting.`,deductiblePct:100,paymentMethod:'VANCERTS BUSINESS FUNDS'});bmi.additionalPaid=financeAmount((Number(bmi.additionalPaid)||0)+paid)}save();hud();toast(paid?`${q} BMI REPORT SUBMITTED • $${rentalMoney(paid)} ADDITIONAL PAID`:`${q} BMI REPORT SUBMITTED • ANNUAL MINIMUM STILL COVERS ESTIMATE`);openComplianceApp()} function openComplianceLearning(){modal(`<h2>HOW THE VANCERTS BMI EXPENSE WORKS</h2><div class="grid"><div class="card"><h3>ACTIVE COVERAGE</h3>VANCERTS enters the game with its basic BMI license active and the <b>$437 annual minimum already covered</b>. That opening policy cost is documented here but is not removed from the player's $1,000 operating cash.</div><div class="card"><h3>FREE EVENTS</h3>The game estimates <b>1.5% of covered entertainment expenses</b> for free-to-attend events under the VANCERTS agreement used for this simulation.</div><div class="card"><h3>PAID ADMISSION</h3>For a ticketed event, the game estimates <b>0.5% of applicable gross admission revenue</b>. A future ticketing system can populate that amount directly.</div><div class="card"><h3>REPORTING</h3>Events are organized into quarterly reports due around <b>January 20, April 20, July 20, and October 20</b>. The player reviews what the game prepared, submits it, and retains the report and payment record.</div><div class="card"><h3>YEAR END</h3>The annual obligation is the greater of the <b>$437 minimum</b> or the calculated event amount. Only the amount above the minimum creates an additional payment in this game.</div><div class="card"><h3>IMPORTANT LIMIT</h3>BMI covers music represented by BMI under the applicable agreement. It is not presented as universal permission for every song, every rights organization, or every type of music use.</div></div><p class="small">Educational simulation: actual licensing depends on the signed agreement, music use, venue responsibilities, and current rules. Keep the real contract and reports as the final authority.</p><div class="btns"><button onclick="openComplianceApp()">BACK TO COMPLIANCE</button><button class="secondary" onclick="closeModal()">CLOSE</button></div>`)} function openComplianceApp(){const bmi=bmiState(),totals=bmiTotals(),currentQ=bmiQuarterForDate(),quarterCards=['Q1','Q2','Q3','Q4'].map(q=>{const events=bmi.events.filter(e=>e.quarter===q),charge=financeAmount(events.reduce((n,e)=>n+bmiEventCharge(e),0)),done=bmi.submittedQuarters.includes(q);return `<div class="card"><h3>${q} REPORT</h3>Due: <b>${bmiQuarterDue(q)}</b><br>Shows: <b>${events.length}</b><br>Calculated: <b>$${rentalMoney(charge)}</b><br>Status: <b class="${done?'good':''}">${done?'SUBMITTED':q===currentQ?'CURRENT • REVIEW':'NOT SUBMITTED'}</b><div class="btns"><button onclick="submitBmiQuarter('${q}')" ${done?'disabled':''}>${done?'SUBMITTED':'REVIEW & SUBMIT'}</button></div></div>`}).join('');modal(`<h2>BUSINESS COMPLIANCE • BMI</h2><div class="financeHero"><div class="metricCard"><span>LICENSE</span><b class="good">ACTIVE</b><small>VANCERTS coverage</small></div><div class="metricCard"><span>ANNUAL MINIMUM</span><b>$${BMI_ANNUAL_MINIMUM}</b><small>Already covered</small></div><div class="metricCard"><span>CALCULATED</span><b>$${rentalMoney(totals.calculated)}</b><small>${totals.events} logged show${totals.events===1?'':'s'}</small></div><div class="metricCard"><span>ADDITIONAL DUE</span><b>$${rentalMoney(totals.additionalDue)}</b><small>Above minimum</small></div></div><div class="card"><h3>VANCERTS BMI LICENSE</h3>Status: <b class="good">ACTIVE</b><br>Coverage year: <b>${safeFinanceText(bmi.coverageYear)}</b><br>Annual minimum: <b>$${BMI_ANNUAL_MINIMUM} COVERED</b><br>Estimated annual obligation: <b>$${rentalMoney(totals.annualDue)}</b><br>Additional payments made: <b>$${rentalMoney(bmi.additionalPaid||0)}</b><p class="small">The annual minimum is treated as an opening business-license expense that VANCERTS already carried before playable operating cash begins.</p></div><h3>QUARTERLY REPORTS</h3><div class="grid">${quarterCards}</div><h3>AUTOMATIC COVERED-SHOW LOG</h3><div class="financeLedger">${bmiEventRows()}</div><div class="btns"><button onclick="openComplianceLearning()">WHY THIS EXPENSE WORKS THIS WAY</button><button onclick="openExpenseTracker()">OPEN FULL LEDGER</button><button class="secondary" onclick="closeModal()">CLOSE COMPLIANCE</button></div>`)} window.openComplianceApp=openComplianceApp;window.openComplianceLearning=openComplianceLearning;window.submitBmiQuarter=submitBmiQuarter; function openExpenseTracker(){modal(`<h2>EXPENSE TRACKER & RECEIPT ARCHIVE</h2><div class="expenseActions"><button class="green" onclick="openComplianceApp()">BUSINESS COMPLIANCE • BMI</button><button onclick="openStaffManager()">STAFF & PAYROLL</button><button onclick="bankModal()">COMMUNITY BANK STATEMENT</button></div>${taxSchoolHtml()}${financeStatementHtml()}<h3>RECEIPT & COST-CARD ARCHIVE</h3>${financeReceiptArchiveHtml(24)}<div class="btns"><button class="secondary" onclick="closeModal()">CLOSE TRACKER</button></div>`)} function paulState(){state.staff=state.staff||{};state.staff.paul=Object.assign({},defaults.staff.paul,state.staff.paul||{});return state.staff.paul} function hirePaul(){const paul=paulState();if(paul.hired)return openStaffManager();paul.hired=true;paul.truckVisible=true;save();hud();toast('PAUL ADDED TO THE VANCERTS TEAM ROSTER');openStaffManager()} function assignPaulToJob(job,place){const paul=paulState();if(!paul.hired||!job||job.staff?.paul)return false;if(!debitCash(PAUL_SHIFT_RATE,'Payroll',`Paul helper shift • ${place.name}`,{vendor:'VANCERTS PAYROLL',employee:'Paul',businessPurpose:`Stagehand, loading, hauling, and show support for the ${place.name} Vancerts job.`,deductiblePct:100,jobId:String(job.created||job.id||Date.now()),paymentMethod:'VANCERTS BUSINESS PAYROLL'}))return false;job.staff=Object.assign({},job.staff||{},{paul:true});paul.nextShift=false;paul.shifts+=1;paul.wagesPaid=financeAmount(paul.wagesPaid+PAUL_SHIFT_RATE);paul.lastJobId=String(job.created||job.id||Date.now());paul.truckVisible=true;return true} function schedulePaul(){const paul=paulState();if(!paul.hired)return hirePaul();if(state.activeJob){if(state.activeJob.phase!=='pickup')return toast('PAUL MUST BE ASSIGNED BEFORE THE VAN LEAVES GIG BAG');const place=places.find(p=>p.id===state.activeJob.id);if(state.activeJob.staff?.paul)return toast('PAUL IS ALREADY ON THIS SHOW');if(!assignPaulToJob(state.activeJob,place))return toast(`PAUL'S SHIFT COSTS $${PAUL_SHIFT_RATE}`);recordPaulMealAdjustment(state.activeJob,place);save();hud();toast('PAUL ASSIGNED • WHITE TRUCK HEADING TO GIG BAG');return openStaffManager()}paul.nextShift=true;save();hud();toast('PAUL SCHEDULED FOR THE NEXT CONFIRMED SHOW');openStaffManager()} function cancelPaulSchedule(){const paul=paulState();if(state.activeJob?.staff?.paul)return toast('PAUL IS ALREADY PAID AND ASSIGNED TO THE ACTIVE SHOW');paul.nextShift=false;save();hud();toast('PAUL REMOVED FROM THE NEXT-SHOW SCHEDULE');openStaffManager()} function allocatePaulTruckLoad(owned){const protectedLoad={},limits={main:4,sub:2,monitor:4,mic:6,xlr:12,iec:12,speakerCable50:8,snake24:1,lights:1,backline:1,highTom:1,lowTom:1,floorTom:1,bassDrum:1,drumHardware:1,guitarAmp:1,bassAmp:1,diBox:4};for(const [key,limit] of Object.entries(limits)){const count=Math.min(Math.max(0,Number(owned?.[key])||0),limit);if(count>0)protectedLoad[key]=count}return protectedLoad} function showJobId(job){return String(job?.created||job?.id||Date.now())} function recordPaulMealAdjustment(job,place){if(!job||job.paulMealAdded)return;const amount=SHOW_MEAL_PER_PERSON;if(debitCash(amount,'Meals',`Paul crew meal • ${place.name}`,{vendor:'VANCERTS CREW MEAL',businessPurpose:`Additional meal for Paul while working the ${place.name} show.`,deductiblePct:50,jobId:showJobId(job),crewCount:1,paymentMethod:'VANCERTS BUSINESS FUNDS'})){job.paulMealAdded=true;job.operatingCosts=financeAmount((job.operatingCosts||0)+amount)}} function recordGigOperatingCosts(job,place){if(!job||job.operatingCostsRecorded)return;const jobId=showJobId(job),crewCount=1+(job.staff?.paul?1:0);let actual=0;if(debitCash(SHOW_FUEL_COST,'Fuel',`Show fuel • ${place.name}`,{vendor:'AUSTIN FUEL STOP',businessPurpose:`One standardized ${SHOW_TANK_GALLONS}-gallon business fuel fill-up for travel, load-in, show operation, and return from ${place.name}.`,deductiblePct:100,jobId,gallons:SHOW_TANK_GALLONS,unitPrice:SHOW_GAS_PRICE_PER_GALLON,paymentMethod:'VANCERTS BUSINESS FUNDS'}))actual+=SHOW_FUEL_COST;const mealCost=SHOW_MEAL_PER_PERSON*crewCount;if(debitCash(mealCost,'Meals',`Crew food • ${place.name}`,{vendor:'VANCERTS CREW MEAL',businessPurpose:`Food for ${crewCount} working crew member${crewCount===1?'':'s'} during the ${place.name} show day.`,deductiblePct:50,jobId,crewCount,paymentMethod:'VANCERTS BUSINESS FUNDS'}))actual+=mealCost;recordCostEstimate(SHOW_VEHICLE_WEAR_ESTIMATE,'Vehicle Wear',`Vehicle wear estimate • ${place.name}`,{vendor:'VANCERTS COST ESTIMATE',businessPurpose:`Planning allowance for tires, fluids, depreciation, and accumulated vehicle wear caused by the ${place.name} job.`,jobId});recordCostEstimate(SHOW_EQUIPMENT_WEAR_ESTIMATE,'Equipment Wear',`Equipment wear estimate • ${place.name}`,{vendor:'VANCERTS COST ESTIMATE',businessPurpose:`Planning allowance for cables, connectors, speaker components, cases, hardware, and other equipment wear caused by the ${place.name} job.`,jobId});job.operatingCostsRecorded=true;job.operatingCosts=financeAmount(actual);job.wearEstimate=financeAmount(SHOW_VEHICLE_WEAR_ESTIMATE+SHOW_EQUIPMENT_WEAR_ESTIMATE)} function careerLevel(xp){xp=Math.max(0,Number(xp)||0);if(xp>=30)return'LEAD';if(xp>=15)return'EXPERIENCED';if(xp>=6)return'GROWING';return'ROOKIE'} function chooseCareerPath(path,role){if(!['owner','team','band'].includes(path))return;if(path==='team'&&['stagehand','audio'].includes(role))state.career.teamRole=role;state.career.path=path;spawnCareerAtHome(path,role||state.career.teamRole);save();hud();openStaffManager();toast(path==='owner'?'OWNER STORY ACTIVE • HOME SPAWN':path==='band'?'BAND STORY ACTIVE • FLAME VAN READY':`${state.career.teamRole==='audio'?'AUDIO ENGINEER':'STAGEHAND'} STORY ACTIVE • WORK TRUCK READY`)} function renameBandCareer(){const current=String(state.career?.bandName||'THE BAND').replace(/&/g,'&').replace(/\"/g,'"').replace(/</g,'<').replace(/>/g,'>');modal(`<h2>NAME YOUR BAND</h2><div class="card"><label><b>BAND NAME</b><input id="bandCareerNameInput" maxlength="40" value="${current}" style="width:100%;padding:10px;margin-top:8px;font:inherit"></label></div><div class="btns"><button class="green" onclick="saveBandCareerName()">SAVE BAND NAME</button><button class="secondary" onclick="openStaffManager()">BACK</button></div>`)} function saveBandCareerName(){const el=document.getElementById('bandCareerNameInput'),name=String(el?.value||'').trim().replace(/\s+/g,' ').slice(0,40);if(!name)return toast('ENTER A BAND NAME');state.career.bandName=name;save();hud();openStaffManager();toast('BAND NAME SAVED')} window.saveBandCareerName=saveBandCareerName; function openStaffManager(){const paul=paulState(),active=state.activeJob,activePlace=active?places.find(p=>p.id===active.id):null,assigned=!!active?.staff?.paul,status=!paul.hired?'AVAILABLE TO JOIN TEAM':assigned?`ON ACTIVE SHOW • ${activePlace?.name||'CLIENT'}`:paul.nextShift?'SCHEDULED FOR NEXT SHOW':'ON TEAM • AT BYOB';const c=state.career||defaults.career;const activeName=c.path==='owner'?'VANCERTS OWNER':c.path==='band'?c.bandName:(c.teamRole==='audio'?'AUDIO ENGINEER':'STAGEHAND');modal(`<h2>VANCERTS TEAM & CAREER PATHS</h2><div class="card" style="border-color:#315d3b"><h3>ACTIVE PLAYER • ${safeFinanceText(activeName)}</h3><p>Choose the live-music path you want to experience. The Austin world, venues, expenses, equipment, and business lessons stay connected.</p><div class="grid"><div class="card"><h3>🚐 VANCERTS OWNER</h3><b>ORIGINAL STORY • ${careerLevel(c.ownerXp)}</b><p>Run the company, drive the van, book clients, manage money, collect deposits and final payments, grow sponsors, and lead the team.</p><button class="green" onclick="chooseCareerPath('owner')" ${c.path==='owner'?'disabled':''}>${c.path==='owner'?'ACTIVE OWNER STORY':'PLAY OWNER STORY'}</button></div><div class="card"><h3>🔊 VANCERTS TEAM MEMBER</h3><b>${c.teamRole==='audio'?'AUDIO ENGINEER':'STAGEHAND'} • ${careerLevel(c.teamRole==='audio'?c.audioXp:c.stagehandXp)}</b><p>Work shows for wages and learn the real three-person VANCERTS stage flow: the owner/main character, one stagehand, and one audio engineer who also runs the van.</p><div class="btns"><button onclick="chooseCareerPath('team','stagehand')" ${c.path==='team'&&c.teamRole==='stagehand'?'disabled':''}>STAGEHAND</button><button onclick="chooseCareerPath('team','audio')" ${c.path==='team'&&c.teamRole==='audio'?'disabled':''}>AUDIO ENGINEER / VAN</button></div></div><div class="card"><h3>🎸 BAND</h3><b>${safeFinanceText(c.bandName)} • ${careerLevel(c.bandXp)}</b><p>Learn booking, guarantees, deposits, stage plots, input lists, merch, promotion, show expenses, and when hiring VANCERTS is smarter than owning production.</p><div class="btns"><button class="green" onclick="chooseCareerPath('band')" ${c.path==='band'?'disabled':''}>${c.path==='band'?'ACTIVE BAND STORY':'PLAY BAND STORY'}</button><button onclick="renameBandCareer()">NAME BAND</button></div></div></div></div><div class="card"><h3>THE VANCERTS STAGE CREW</h3><p><b>1 owner / stage manager</b> runs the business and main character. <b>1 stagehand</b> handles load-in, setup, cable work, strike, and gear care. <b>1 audio engineer</b> runs the van, PA, soundcheck, front-of-house mix, and teardown support.</p><p>No certification collection is used. Progress comes from completed shows, practical experience, reliability, reputation, and learning the work.</p></div><div class="staffRoster"><div class="staffPortrait"><div class="staffTruckPreview" aria-label="Paul's plain white pickup truck with a removable Vancerts magnet"></div></div><div class="card"><h3>PAUL • STAGEHAND / TEAM MEMBER</h3><span class="staffStatus ${paul.hired?'hired':''} ${paul.nextShift||assigned?'scheduled':''}">${safeFinanceText(status)}</span><p>Paul drives his own <b>plain white pickup</b> with one removable VANCERTS logo magnet. He helps load, build, strike, wrap cable, and protect part of the gear haul.</p><p><b>$${PAUL_SHIFT_RATE} per show</b> • payroll receipt included • $${SHOW_MEAL_PER_PERSON} crew meal tracked separately.</p><p>Completed shifts: <b>${paul.shifts}</b><br>Total wages paid: <b>$${rentalMoney(paul.wagesPaid)}</b><br>Stagehand progression: <b>${careerLevel(paul.shifts)}</b></p>${!paul.hired?'<button class="green" onclick="hirePaul()">ADD PAUL TO THE TEAM</button>':assigned?'<button disabled>ASSIGNED TO ACTIVE SHOW</button>':paul.nextShift?'<button class="red" onclick="cancelPaulSchedule()">CANCEL NEXT-SHOW SCHEDULE</button>':`<button class="green" onclick="schedulePaul()">${active?'ASSIGN TO ACTIVE SHOW':'SCHEDULE NEXT SHOW'} • $${PAUL_SHIFT_RATE}</button>`}</div></div><div class="card"><h3>TEAM ACCOUNTING</h3>Scheduling a paid team member creates a payroll receipt tied to the show. Crew food is tracked separately so the expense tracker teaches the meal rule instead of mixing food into wages.</div><div class="btns"><button onclick="openExpenseTracker()">OPEN EXPENSE TRACKER</button><button class="secondary" onclick="closeModal()">CLOSE TEAM</button></div>`)} window.chooseCareerPath=chooseCareerPath;window.renameBandCareer=renameBandCareer; window.showReceipt=showReceipt;window.openExpenseTracker=openExpenseTracker;window.openStaffManager=openStaffManager;window.hirePaul=hirePaul;window.schedulePaul=schedulePaul;window.cancelPaulSchedule=cancelPaulSchedule; const LEGACY_CHECKPOINT_KEY=SAVE_KEY+'-30min-checkpoints'; // Gameplay changes stay in memory until the player presses SAVE. function save(){return true} function manualSave(){if(state.cheats&&state.cheats.sandbox)return toast('SANDBOX MODE • HARD SAVING DISABLED • RELOAD TO RESTORE YOUR SAVE');if(portableMode){portableSaveFile=portablePayload(state);sessionStorage.setItem(PORTABLE_SESSION_KEY,JSON.stringify(portableSaveFile));toast('PORTABLE GAME SAVED IN THIS SESSION • EXPORT THE FILE TO KEEP IT')}else{safeStorage.setItem(SAVE_KEY,JSON.stringify(state));safeStorage.removeItem(LEGACY_CHECKPOINT_KEY);toast('COMPUTER HARD SAVE UPDATED')}}window.manualSave=manualSave; function openSaveLoadApp(){const mode=portableMode?'PORTABLE FILE SESSION':'THIS DEVICE';const saved=portableMode?'Use Save Game, then Export Save File to keep the updated portable game.':'Progress also autosaves during normal play. Save Game creates a deliberate manual checkpoint on this device.';modal(`<h2>NOOKIA SAVE CENTER</h2><div class="card"><h3>${mode}</h3><p>${saved}</p></div><div class="grid"><div class="card"><h3>CONTINUE</h3><p>Return to the current game without changing progress.</p><button class="green" onclick="closeModal()">CONTINUE GAME</button></div><div class="card"><h3>SAVE GAME</h3><p>Update the current manual save checkpoint.</p><button onclick="manualSave();closeModal()">SAVE NOW</button></div><div class="card"><h3>LOAD / IMPORT</h3><p>Choose a Vancerts save file from this device.</p><button onclick="choosePortableSave()">CHOOSE SAVE FILE</button></div><div class="card"><h3>EXPORT</h3><p>Download a portable copy of the current progress.</p><button onclick="exportPortableSave()">EXPORT SAVE FILE</button></div><div class="card"><h3>RESET STORY</h3><p>Erase the current story save and begin again. This cannot be undone.</p><button class="red" onclick="openResetPrompt()">RESET STORY</button></div></div><div class="btns"><button class="secondary" onclick="closeModal()">CLOSE SAVE CENTER</button></div>`)}window.openSaveLoadApp=openSaveLoadApp; function toast(t){$('toast').textContent=t;$('toast').classList.add('show');setTimeout(()=>$('toast').classList.remove('show'),1900)}function modal(h){$('modal').innerHTML=h;$('modalWrap').classList.add('show')}function closeModal(){if(permitGateActive)return;$('modalWrap').classList.remove('show')}window.closeModal=closeModal; function clearSandboxRoads(showToast=true){ traffic.length=0; specialCars.length=0; pedestrians.length=0; donutProjectiles.length=0; roadSnake.active=false; roadSnake.trail=[]; roadSnake.length=5; state.cheats.forceElon=false; for(const c of collectibles){ c.active=false; c.delivered=false; c.respawnAt=0 } cartCollector.carried.length=0; cartCollector.target=null; if(showToast)toast('SANDBOX ROAD RESET • CITY STREETS EMPTY') } function sandboxRoadTestingActive(){ return !!(state.cheats&&state.cheats.sandbox&&state.cheats.manualRoadTest) } function addSandboxTrafficVehicle(type){ if(!sandboxRoadTestingActive())return toast('ACTIVATE SANDBOX #4986 FIRST'); let car; const special=SPECIAL_ROAD_ROSTER.find(v=>v.vehicleType===type); if(special){ car=createSpecialRoadVehicle({...special},traffic.length+1) }else if(ORDINARY_VEHICLE_TYPES.includes(type)){ const index=Math.max(0,ORDINARY_VEHICLE_TYPES.indexOf(type)); car=createOrdinaryRoadVehicle(index+traffic.length*3); car.vehicleType=type; car.label=type.toUpperCase(); car.isSpecialRoad=false }else return toast('UNKNOWN ROAD TEST VEHICLE'); beginTrafficEntry(car,trafficRouteForIndex(traffic.length+31,false)); traffic.push(car); toast(`SANDBOX ROAD TEST • ${String(car.label||type).toUpperCase()} ADDED`) } function addSandboxBlackStar(){ if(!sandboxRoadTestingActive())return toast('ACTIVATE SANDBOX #4986 FIRST'); specialCars.push(createBlackStar(specialCars.length)); toast('SANDBOX ROAD TEST • BLACK STAR ADDED') } function addSandboxSpecialWaygo(){ if(!sandboxRoadTestingActive())return toast('ACTIVATE SANDBOX #4986 FIRST'); specialCars.push(createSpecialWaygo(specialCars.length)); toast('SANDBOX ROAD TEST • SPECIAL WAYGO ADDED') } function addSandboxElon(){ if(!sandboxRoadTestingActive())return toast('ACTIVATE SANDBOX #4986 FIRST'); state.cheats.forceElon=true; initRoadSnake(`sandbox-${Date.now()}`); roadSnake.length=5; roadSnake.active=true; toast('SANDBOX ROAD TEST • ELON ADDED AT 5 CARS') } function addSandboxPedestrian(){ if(!sandboxRoadTestingActive())return toast('ACTIVATE SANDBOX #4986 FIRST'); const paths=[{x1:585,y1:545,x2:585,y2:835},{x1:1245,y1:545,x2:1245,y2:835},{x1:1905,y1:545,x2:1905,y2:835},{x1:585,y1:1245,x2:585,y2:1535}]; const path=paths[pedestrians.length%paths.length]; pedestrians.push({...path,t:.15,dir:1,speed:.00032,entityId:`#NPC-${String(pedestrians.length+1).padStart(3,'0')}`}); toast('SANDBOX ROAD TEST • PEDESTRIAN ADDED') } function addSandboxCollectible(type='guitar'){ if(!sandboxRoadTestingActive())return toast('ACTIVATE SANDBOX #4986 FIRST'); let c=collectibles.find(x=>x.type===type&&!x.active); if(!c)c=collectibles.find(x=>!x.active); if(!c)return toast('NO UNUSED COLLECTIBLE SLOT AVAILABLE'); c.active=true;c.delivered=false;c.respawnAt=0; const safe=nearestSafeCollectibleSpawn(c,collectibles.indexOf(c),collectibles.filter(x=>x.active&&!x.delivered&&x!==c).map(x=>({x:x.x,y:x.y}))); c.x=c.homeX=safe.x;c.y=c.homeY=safe.y; toast(`SANDBOX ROAD TEST • ${String(c.label||c.type).toUpperCase()} ADDED`) } function prepareSandboxFlagTest(){ const testIds=['worldliquor','mama','fsg','republic','juan','blueowl','hope']; for(const p of places.filter(p=>p.type==='gig')){ const v=state.venues[p.id]; v.sign=true; v.fillFlags=0; v.eventCount=0; v.rateCars=p.capacity||16; v.lotCycleFull=true; v.flagCycleArmed=false; v.amlPromotionActive=false; if(!state.completed.includes(p.id))state.completed.push(p.id) } normalizeAllSponsorFlagRules(); toast(`SANDBOX FLAG TEST READY • ${testIds.length} PRIORITY BUSINESSES + ALL OTHERS AT FULL SPONSORED LOTS • ACCEPT NEXT JOB TO BANK FLAG 1/3`) } window.clearSandboxRoads=clearSandboxRoads; window.prepareSandboxFlagTest=prepareSandboxFlagTest; function openProductionStageTest(chapter){ if(!(state.cheats&&state.cheats.sandbox))return toast('ACTIVATE SANDBOX #4986 FIRST'); const venue=places.find(p=>p.id==='fsg'&&placeVisible(p))||places.find(p=>p.type==='gig'&&placeVisible(p)); if(!venue)return toast('NO TEST VENUE AVAILABLE'); state.story.festivalComplete=true; state.story.chapter3Started=chapter>=3; const cableKeys=['xlr','iec','speakerCable50','snake24']; for(const k of cableKeys)state.inventory[k]=99; if(chapter>=3){ for(const k of ['highTom','lowTom','floorTom','bassDrum','drumHardware','guitarAmp','bassAmp','diBox'])state.inventory[k]=99 } const needs={main:2,sub:2,mic:3,monitor:3,backline:chapter>=3?1:0,lights:0}; activeSetup={ id:venue.id, pkg:'band', extras:{backline:chapter>=3}, needs, placed:{}, deposit:0, total:1000, amlBooking:false, amlPromotion:false, developmentTest:true, cablesLoaded:false, backlineDetailedLoaded:false }; closeModal(); renderSetup(); toast(`DEVELOPMENT TEST • CHAPTER ${chapter} STAGE PLOT OPEN`) } window.openProductionStageTest=openProductionStageTest; let developerSoloBike={active:false,x:165,y:1510,angle:0,progress:0,entityId:'#BIKE-SOLO-001'}; function activateDeveloperNpcGroup(){spawnCommunityCrowd();ensurePedestrians();toast(`ALL NPCS ACTIVE • ${pedestrians.length} CODED CHARACTERS`) } function activateDeveloperBikeGroup(){socialRide.active=true;socialRide.forcedUntil=Date.now()+240000;socialRide.hourKey=`DEVELOPER-RIDE-${Date.now()}`;socialRide.progress=0;socialRide.points=[];toast('BIKE RIDER GROUP ACTIVE • 100 CODED RIDERS • 4 MINUTES')} function toggleDeveloperSoloBike(){developerSoloBike.active=!developerSoloBike.active;developerSoloBike.progress=0;toast(`SOLO BIKE ${developerSoloBike.active?'ACTIVE • #BIKE-SOLO-001':'OFF'}`)} function updateDeveloperSoloBike(dt){if(!developerSoloBike.active)return;developerSoloBike.progress+=dt*.10;const p=socialRidePoint(developerSoloBike.progress);developerSoloBike.x=p.x;developerSoloBike.y=p.y;developerSoloBike.angle=p.angle} function drawDeveloperSoloBike(){if(!developerSoloBike.active)return;drawSocialBike({x:developerSoloBike.x,y:developerSoloBike.y,angle:developerSoloBike.angle,index:7,entityId:developerSoloBike.entityId})} const PHONE_CODES={ '#51200':{name:'CODE DIRECTORY',action:()=>showCheatDirectory()}, '#51201':{name:'ROADTRIP',action:()=>{state.cheats.revealMap=true;toast('ROADTRIP • ENTIRE CITY REVEALED • PERMITS NOT PURCHASED')}}, '#51202':{name:'SOUNDCHECK',action:()=>{state.cheats.invulnerable=!state.cheats.invulnerable;toast(`SOUNDCHECK • DAMAGE ${state.cheats.invulnerable?'OFF':'ON'}`)}}, '#51203':{name:'BOOKED SOLID',action:()=>fillVisibleLots()}, '#51204':{name:'HEADLINER',action:()=>{creditCash(100000,'Developer Codes','Headliner cheat',{type:'adjustment'});state.rep+=1000;hud();toast('HEADLINER • $100,000 • COMMUNITY +1000')}}, '#51205':{name:'SPONSOR ME',action:()=>sponsorAllVisible(1)}, '#51206':{name:'FESTIVAL',action:()=>unlockFestivalTesting()}, '#51207':{name:'ARMOR UP',action:()=>unlockArmoredTesting()}, '#51208':{name:'DONUT SHOP',action:()=>{state.collectedResources.donut=(Number(state.collectedResources.donut)||0)+25;hud();toast('DONUT SHOP • 25 DOUGHNUT CONSUMABLES')}}, '#51209':{name:'ELON',action:()=>addSandboxElon()}, '#51210':{name:'STAR CAR',action:()=>addSandboxBlackStar()}, '#51211':{name:'SPECIAL WAYGO',action:()=>addSandboxSpecialWaygo()}, '#51212':{name:'SHOW FLAGS',action:()=>showFlagDebug()}, '#51213':{name:'SHOW STORY',action:()=>showStoryDebug()}, '#51214':{name:'SHOW HAZARDS',action:()=>showHazardDebug()}, '#51215':{name:'SHOW SPAWNS',action:()=>{state.cheats.showSpawns=!state.cheats.showSpawns;toast(`SPAWN OVERLAY ${state.cheats.showSpawns?'ON':'OFF'}`)}}, '#51216':{name:'FREE BIRD',action:()=>{state.cheats.trafficSpeed=2;toast('FREE BIRD • TRAFFIC 2× SPEED')}}, '#51217':{name:'SLOW RIDE',action:()=>{state.cheats.trafficSpeed=.5;toast('SLOW RIDE • TRAFFIC 50% SPEED')}}, '#51218':{name:'PARTY TIME',action:()=>fillVisibleLots()}, '#51219':{name:'COMMUNITY',action:()=>spawnCommunityCrowd()}, '#51220':{name:'VANCERTS',action:()=>maxCitySponsors()}, '#51230':{name:'CLEAR ROAD LAB',action:()=>clearSandboxRoads()}, '#51231':{name:'SEDAN',action:()=>addSandboxTrafficVehicle('sedan')}, '#51232':{name:'HATCHBACK',action:()=>addSandboxTrafficVehicle('hatchback')}, '#51233':{name:'SUV',action:()=>addSandboxTrafficVehicle('suv')}, '#51234':{name:'PICKUP',action:()=>addSandboxTrafficVehicle('pickup')}, '#51235':{name:'DELIVERY VAN',action:()=>addSandboxTrafficVehicle('deliveryvan')}, '#51236':{name:'MOTORCYCLE',action:()=>addSandboxTrafficVehicle('motorcycle')}, '#51237':{name:'BOX TRUCK',action:()=>addSandboxTrafficVehicle('boxtruck')}, '#51238':{name:'LIMOUSINE',action:()=>addSandboxTrafficVehicle('limousine')}, '#51239':{name:'HORSEBACK RIDER',action:()=>addSandboxTrafficVehicle('horse')}, '#51240':{name:'TESTAROSSA',action:()=>addSandboxTrafficVehicle('testarossa')}, '#51241':{name:'LAMBORGHINI',action:()=>addSandboxTrafficVehicle('lamborghini')}, '#51242':{name:'AMBULANCE',action:()=>addSandboxTrafficVehicle('ambulance')}, '#51243':{name:'WAYGO TRAFFIC',action:()=>addSandboxTrafficVehicle('waymo')}, '#51244':{name:'BLACK STAR',action:()=>addSandboxBlackStar()}, '#51245':{name:'ELON 5-CAR SNAKE',action:()=>addSandboxElon()}, '#51246':{name:'PEDESTRIAN',action:()=>addSandboxPedestrian()}, '#51247':{name:'COLLECTIBLE',action:()=>addSandboxCollectible()}, '#51248':{name:'FLAG CYCLE TEST',action:()=>prepareSandboxFlagTest()}, '#51249':{name:'CHAPTER 2 STAGE TEST',action:()=>openProductionStageTest(2)}, '#51250':{name:'CHAPTER 3 STAGE TEST',action:()=>openProductionStageTest(3)}, '#51251':{name:'ALL NPCS',action:()=>activateDeveloperNpcGroup()}, '#51252':{name:'BIKE RIDER GROUP',action:()=>activateDeveloperBikeGroup()}, '#51253':{name:'SOLO BIKE',action:()=>toggleDeveloperSoloBike()} }; let phoneDialBuffer=''; function phoneDialDisplay(){ const el=$('phoneStatus'); if(!el)return; if(phoneDialBuffer)el.textContent=`DIAL: ${phoneDialBuffer}`; else hud() } function clearPhoneDial(message='DIAL CLEARED'){ phoneDialBuffer=''; phoneDialDisplay(); if(message)toast(message) } function appendPhoneDigit(value){ if(phoneDialBuffer.length>=8)return toast('PHONE CODE MAXIMUM REACHED'); phoneDialBuffer+=String(value); phoneDialDisplay() } function executePhoneCode(){ const code=phoneDialBuffer; phoneDialBuffer=''; if(!code)return openPhone(); if(code==='#211')return useCommunityServices(); if(code==='#4986')return activateSandbox(); const entry=PHONE_CODES[code]; if(!entry){phoneDialDisplay();return toast('NOOKIA • INVALID CODE')} entry.action(); phoneDialDisplay(); hud() } function openDialer(){ const value=phoneDialBuffer||'ENTER NUMBER OR CODE'; modal(`<h2>NOOKIA DIALER</h2><p>Manual dialing remains available for phone numbers, community services, developer codes, and game cheats.</p><div class="dialerDisplay" id="dialerDisplay">${value}</div><div class="dialerPad">${['1','2','3','4','5','6','7','8','9','*','0','#'].map(n=>`<button type="button" data-modal-dial="${n}">${n}</button>`).join('')}</div><div class="dialerActions"><button class="green" id="dialerCall" type="button">CALL / ENTER CODE</button><button id="dialerBackspace" type="button">BACKSPACE</button><button class="secondary" id="dialerClear" type="button">CLEAR</button><button class="secondary" onclick="closeModal()">CLOSE</button></div><p class="small">Known service codes include #211. Developer access and test codes continue to work exactly as before.</p>`); const display=$('dialerDisplay'); const refresh=()=>{if(display)display.textContent=phoneDialBuffer||'ENTER NUMBER OR CODE'}; document.querySelectorAll('[data-modal-dial]').forEach(b=>b.addEventListener('click',()=>{appendPhoneDigit(b.dataset.modalDial);refresh()})); $('dialerBackspace').onclick=()=>{phoneDialBuffer=phoneDialBuffer.slice(0,-1);phoneDialDisplay();refresh()}; $('dialerClear').onclick=()=>{phoneDialBuffer='';phoneDialDisplay();refresh()}; $('dialerCall').onclick=()=>{const had=!!phoneDialBuffer;executePhoneCode();if(had&&!$('modalWrap').classList.contains('show'))return;refresh()}; } window.openDialer=openDialer; function showCheatDirectory(){ const cards=Object.entries(PHONE_CODES).filter(([code])=>code!=='#51200').map(([code,e])=>`<div class="card"><b>${code}</b><br>${e.name}</div>`).join(''); modal(`<h2>NOOKIA TEST CODE DIRECTORY</h2><p><b>#4986</b> SANDBOX • <b>#211</b> COMMUNITY SERVICES</p><div class="grid">${cards}</div><div class="btns"><button onclick="closeModal()">CLOSE</button></div>`) } function activateSandbox(){ if(state.cheats.sandbox)return toast('SANDBOX ALREADY ACTIVE • USE #51230 TO CLEAR THE ROAD AGAIN'); state.cheats.sandbox=true; state.cheats.manualRoadTest=true; state.cheats.invulnerable=true; state.cheats.revealMap=true; state.cheats.trafficSpeed=1; creditCash(Math.max(0,1000000-state.cash),'Developer Codes','Sandbox cash adjustment',{type:'adjustment'}); state.rep=Math.max(state.rep,1000000); state.vanhp=100; for(const k of Object.keys(state.inventory))state.inventory[k]=Math.max(99,Number(state.inventory[k])||0); for(const k of Object.keys(state.expansionPermits))state.expansionPermits[k]=true; state.story.festivalComplete=true; state.story.eastAustinUnlocked=true; state.story.chapter3Started=true; state.story.secondFestivalComplete=true; state.story.westAustinUnlocked=true; state.vanUpgrades.armored=true; state.vanUpgrades.potatoGun=true; clearSandboxRoads(false); prepareSandboxFlagTest(); hud(); toast('SANDBOX #4986 ACTIVE • EMPTY ROAD LAB • SAVING DISABLED • USE #51230–#51247 TO ADD ROAD ACTORS ONE AT A TIME') } function fillVisibleLots(){ for(const p of places.filter(p=>p.type==='gig'&&placeVisible(p))){ const v=state.venues[p.id];v.rateCars=p.capacity||16;v.lotCycleFull=!!v.sign;v.flagCycleArmed=false } hud();toast('BOOKED SOLID • EVERY VISIBLE PARKING LOT FILLED') } function sponsorAllVisible(amount=1){ for(const p of places.filter(p=>p.type==='gig'&&placeVisible(p))){ const v=state.venues[p.id];v.sign=true;v.fillFlags=Math.min(3,(Number(v.fillFlags)||0)+amount) } hud();toast('SPONSOR ME • VISIBLE BUSINESSES SPONSORED • FLAGS +1') } function unlockFestivalTesting(){ for(const id of order){state.venues[id].sign=true;state.venues[id].rateCars=places.find(p=>p.id===id).capacity||16;if(!state.completed.includes(id))state.completed.push(id)} state.expansionPermits.mama=true;state.story.festivalComplete=true;state.story.eastAustinUnlocked=true;state.story.chapter3Started=true;activateWorldLiquorAfterFestival();hud();toast('FESTIVAL • CHAPTER 2 COMPLETE • MAMA + WORLD LIQUOR OPEN') } function unlockArmoredTesting(){ state.vanUpgrades.armored=true;state.vanUpgrades.potatoGun=true;updateMobileDonutButton();hud();toast('ARMOR UP • ARMORED VAN + POTATO GUN') } function showFlagDebug(){ const rows=auditAllBusinessFlags().filter(r=>r.visible).map(r=>{const p=places.find(x=>x.id===r.id);return `<div class="card"><b>${p.short||p.name}</b><br>Sponsored: ${r.sponsored?'YES':'NO'}<br>Flags: ${r.flags}/3<br>Draw sites: ${r.sites}</div>`}).join(''); modal(`<h2>FLAG DEBUG</h2><div class="grid">${rows}</div><div class="btns"><button onclick="closeModal()">CLOSE</button></div>`) } function showStoryDebug(){ modal(`<h2>STORY DEBUG</h2><div class="grid"><div class="card">Chapter 3: <b>${state.story.chapter3Started?'YES':'NO'}</b><br>Van Fest I: <b>${state.story.festivalComplete?'COMPLETE':'OPEN'}</b><br>Van Fest II: <b>${state.story.secondFestivalComplete?'COMPLETE':'OPEN'}</b><br>East Austin: <b>${state.story.eastAustinUnlocked?'OPEN':'LOCKED'}</b><br>South Side: <b>${state.story.westAustinUnlocked?'OPEN':'LOCKED'}</b></div><div class="card">Completed businesses: <b>${state.completed.length}</b><br>Shows: <b>${state.shows}</b><br>Community: <b>${Math.round(state.rep)}</b><br>Cash: <b>$${rentalMoney(state.cash)}</b></div></div><div class="btns"><button onclick="closeModal()">CLOSE</button></div>`) } function showHazardDebug(){ modal(`<h2>HAZARD DEBUG</h2><div class="grid"><div class="card">Elon active: <b>${roadSnake.active?'YES':'NO'}</b><br>Elon length: <b>${roadSnake.length}</b><br>Force Elon: <b>${state.cheats.forceElon?'ON':'OFF'}</b></div><div class="card">Black/Special cars: <b>${specialCars.length}</b><br>Ordinary traffic: <b>${traffic.filter(c=>!c.isSpecialRoad).length}</b><br>Special road traffic: <b>${traffic.filter(c=>c.isSpecialRoad).length}</b></div><div class="card">Collectibles active: <b>${collectibles.filter(c=>c.active).length}</b><br>Spawn overlay: <b>${state.cheats.showSpawns?'ON':'OFF'}</b></div></div><div class="btns"><button onclick="closeModal()">CLOSE</button></div>`) } function spawnCommunityCrowd(){ ensurePedestrians(); const base=pedestrians[0]||{x1:585,y1:545,x2:585,y2:835}; for(let i=0;i<16;i++)pedestrians.push({...base,t:Math.random(),dir:i%2?1:-1,speed:.0002+Math.random()*.00025,entityId:`#NPC-${String(pedestrians.length+1).padStart(3,'0')}`}); toast('COMMUNITY • EXTRA WALKERS ADDED') } function maxCitySponsors(){ for(const p of places.filter(p=>p.type==='gig')){ const v=state.venues[p.id];v.sign=true;v.fillFlags=3;v.rateCars=p.capacity||16;v.lotCycleFull=true; if(!state.completed.includes(p.id))state.completed.push(p.id) } state.byobCommunity.flags=Math.max(3,Number(state.byobCommunity.flags)||0);state.rep+=512;hud();toast('VANCERTS • FULLY SPONSORED CITY MODE') } function useCommunityServices(){ const day=austinDateKey(); if(state.communityServicesLastDay===day)return toast('#211 ALREADY USED TODAY'); state.communityServicesLastDay=day;state.vanhp=100;creditCash(500,'Community Support','#211 emergency support');hud();toast('#211 COMMUNITY SERVICES • VAN 100% • $500 EMERGENCY SUPPORT') } const WAYGO_PIXELS_PER_INCH=96; function waygoDestinationOpen(place){if(!place||place.retiredByReorg||!place.interact)return false;if(['shop','hq','bank','studio','grounds'].includes(place.type))return true;if(place.type==='gig')return unlocked(place.id);return false} function waygoDestinations(){const priority={hq:0,shop:1,bank:2,leftway:3,leftwaygrounds:4};return places.filter(waygoDestinationOpen).sort((a,b)=>(priority[a.id]??20)-(priority[b.id]??20)||a.name.localeCompare(b.name))} function waygoArrival(place){const drive=drivewayFor(place.id);if(drive)return{x:drive.x+drive.w/2,y:drive.y+drive.h/2,angle:drive.h>=drive.w?Math.PI/2:0};return{x:place.interact.x,y:place.interact.y,angle:van.angle}} function waygoQuote(place){const arrival=waygoArrival(place),worldDistance=Math.abs(van.x-arrival.x)+Math.abs(van.y-arrival.y),inches=worldDistance/WAYGO_PIXELS_PER_INCH,fare=worldDistance<8?0:Math.max(1,Math.ceil(inches));return{arrival,inches,fare}} function performWaygoArrival(place,quote,after){for(const key of Object.keys(keys))keys[key]=false;van.speed=0;closeModal();const fade=$('waygoFade'),label=$('waygoFadeText'),finish=()=>{if(fade){fade.classList.remove('show');fade.setAttribute('aria-hidden','true')}canvas.focus({preventScroll:true});if(typeof after==='function')after()};if(label)label.textContent=`TO ${place.short||place.name} • ${quote.fare?'$'+rentalMoney(quote.fare):'EMERGENCY RIDE'}`;if(fade){fade.classList.add('show');fade.setAttribute('aria-hidden','false')}setTimeout(()=>{van.x=quote.arrival.x;van.y=quote.arrival.y;van.angle=quote.arrival.angle;van.speed=0;near=null;setTimeout(finish,260);hud()},240);setTimeout(()=>{if(fade&&fade.classList.contains('show'))finish()},900)} function openWaygo(){const destinations=waygoDestinations(),cards=destinations.map(place=>{const q=waygoQuote(place),here=q.fare===0,canPay=state.cash>=q.fare;return `<div class="card waygoCard"><span class="waygoFare">${here?'HERE':'$'+rentalMoney(q.fare)}</span><h3>${safeFinanceText(place.name)}</h3><p>${q.inches.toFixed(1)} map inches away<br><span class="small">$1 per map inch • fare rounds up to the next dollar</span></p><button onclick="bookWaygo('${safeFinanceText(place.id)}')" ${here||!canPay?'disabled':''}>${here?'CURRENT LOCATION':canPay?'BOOK WAYGO':'NOT ENOUGH CASH'}</button></div>`}).join('');modal(`<h2>WAYGO • ALWAYS ON YOUR NOOKIA</h2><div class="waygoIntro"><b>$1 PER MAP INCH OF TRAVEL.</b><br>Choose any currently open business. Waygo calculates the route from the van’s current position, shows the fare first, and delivers the van to that property’s loading entrance. Your active mission, phone, radio, and game progress stay intact.</div><div class="grid waygoGrid">${cards}</div><div class="btns"><button class="secondary" onclick="closeModal()">CLOSE WAYGO</button></div>`)} function bookWaygo(id){const place=waygoDestinations().find(item=>item.id===id);if(!place)return toast('THAT WAYGO DESTINATION IS NOT OPEN');const quote=waygoQuote(place);if(quote.fare<=0)return toast('YOU ARE ALREADY AT THAT DESTINATION');if(!debitCash(quote.fare,'Waygo',`Waygo to ${place.name}`,{vendor:'WAYGO',businessPurpose:`Business transportation to ${place.name}.`,deductiblePct:100,paymentMethod:'VANCERTS BUSINESS FUNDS'}))return toast(`WAYGO FARE IS $${rentalMoney(quote.fare)}`);state.waygoStats.trips+=1;state.waygoStats.inches=financeAmount(state.waygoStats.inches+quote.inches);state.waygoStats.spent=financeAmount(state.waygoStats.spent+quote.fare);save();performWaygoArrival(place,quote,()=>toast(`WAYGO ARRIVED • ${place.name} • $${rentalMoney(quote.fare)}`))} function emergencyWaygoAvailable(){return state.vanhp<=0&&state.cash<299} function callEmergencyWaygo(){ if(!emergencyWaygoAvailable())return toast('EMERGENCY WAYGO IS ONLY AVAILABLE WHEN DISABLED AND UNABLE TO AFFORD TOWING'); const bank=places.find(p=>p.id==='bank'); const quote=waygoQuote(bank);quote.fare=0;state.waygoStats.emergencyTrips+=1;performWaygoArrival(bank,quote,()=>{toast('EMERGENCY WAYGO ARRIVED • TRANSPORTED TO VANCERTS BANK');setTimeout(bankModal,220)}) } function drawDevSpawnOverlay(){ if(!state.cheats.showSpawns)return; ctx.save();ctx.lineWidth=3;ctx.font='900 10px monospace';ctx.textAlign='center'; ctx.strokeStyle='#ff3a3a';ctx.fillStyle='#ff3a3a'; for(const x of snakeGraphXs)for(const y of snakeGraphYs){ctx.beginPath();ctx.arc(x,y,8,0,Math.PI*2);ctx.stroke()} ctx.strokeStyle='#35d7ff';ctx.fillStyle='#35d7ff'; for(const c of collectibles.filter(c=>c.active)){ctx.strokeRect(c.x-10,c.y-10,20,20)} ctx.fillText('RED = ROAD NODES • BLUE = COLLECTIBLES',van.x,van.y-90); ctx.restore() } window.showCheatDirectory=showCheatDirectory;window.openWaygo=openWaygo;window.bookWaygo=bookWaygo; window.callEmergencyWaygo=callEmergencyWaygo; function workedBusinessIds(){return new Set(state.completed)} function workedBusinesses(){const done=workedBusinessIds();return places.filter(p=>p.type==='gig'&&done.has(p.id))} function unpaidTotal(){const done=workedBusinessIds();return state.invoices.filter(i=>!i.paid&&done.has(i.venueId||places.find(p=>p.name===i.venue)?.id)).reduce((a,i)=>a+i.amount,0)} function bankLoanBalance(){return financeAmount((state.bankLoans||[]).reduce((sum,loan)=>sum+Math.max(0,Number(loan.payoff||0)-Number(loan.paid||0)),0))} function totalOwed(){return unpaidTotal()+bankLoanBalance()} function firstCycleComplete(){return order.every(id=>state.completed.includes(id))} function originalSponsorsComplete(){return order.every(id=>state.venues[id]&&state.venues[id].sign)} const FESTIVAL_ROUTE=['fsg','republic','blueowl','juan','hope','mama','hq']; function flagEraActive(){return !!state.story.festivalComplete} function byobFlagCount(){return Math.max(0,Number(state.byobCommunity.flags)||0)} function byobThreeFlags(){return byobFlagCount()>=3} function startChapter3FromResetJob(){ if(!flagEraActive()||state.story.chapter3Started)return; state.story.chapter3Started=true; state.story.eastAustinUnlocked=true; toast('CHAPTER 3 STARTED • FLAGS ACTIVE • EAST AUSTIN PERMITS AVAILABLE') } function hostFreeCommunityShow(amount){ amount=Math.max(0,Math.round(Number(amount)||0)); if(!flagEraActive())return toast('Complete It’s A Van Fest I before BYOB can earn Community Flags.'); if(amount<100)return toast('Choose at least $100 for the Community Savings Fund.'); if(state.cash<amount)return toast('Not enough company cash for that community contribution.'); debitCash(amount,'Community Giving','Free BYOB community show'); state.byobCommunity.savings+=amount; state.byobCommunity.shows++; state.byobCommunity.flags++; state.shows++; state.rep+=50; state.impact+=40; save();hud(); modal(`<h2>FREE BYOB COMMUNITY SHOW COMPLETE</h2><div class="grid"><div class="card"><h3>Community Flag</h3><b>+1 BYOB FLAG</b><br>Total: <b>${state.byobCommunity.flags}</b></div><div class="card"><h3>Charity Savings</h3>Contribution: <b>$${amount.toLocaleString()}</b><br>Fund balance: <b>$${state.byobCommunity.savings.toLocaleString()}</b></div><div class="card"><h3>Community Impact</h3>Community <b>+50</b><br>Impact <b>+40</b></div></div><p class="small">The Charity Savings Fund is reserved for a future help-people system. It cannot currently be withdrawn or spent.</p><div class="btns"><button onclick="hqModal()">BACK TO BYOB</button></div>`) } window.hostFreeCommunityShow=hostFreeCommunityShow; function communityShowModal(){ if(!flagEraActive())return modal(`<h2>FREE COMMUNITY SHOWS</h2><p>Complete It’s A Van Fest I first. After World Liquor opens, BYOB can begin earning Community Flags.</p><div class="btns"><button onclick="hqModal()">BACK</button></div>`); modal(`<h2>HOST A FREE BYOB COMMUNITY SHOW</h2><p>Every free company show earns <b>1 BYOB Community Flag</b>. Choose how much company cash to transfer into the separate Charity Savings Fund.</p><div class="grid"><div class="card"><h3>BYOB Progress</h3>Community shows <b>${state.byobCommunity.shows}</b><br>Flags <b>${state.byobCommunity.flags}</b><br>Charity Savings <b>$${state.byobCommunity.savings.toLocaleString()}</b></div><div class="card"><h3>Fund Rule</h3>This money is held separately for a future help-people system.<br><span class="small">No withdrawals or spending yet.</span></div></div><div class="btns"><button onclick="hostFreeCommunityShow(100)" ${state.cash<100?'disabled':''}>SHOW + SAVE $100</button><button onclick="hostFreeCommunityShow(250)" ${state.cash<250?'disabled':''}>SHOW + SAVE $250</button><button onclick="hostFreeCommunityShow(500)" ${state.cash<500?'disabled':''}>SHOW + SAVE $500</button><button onclick="hostFreeCommunityShow(1000)" ${state.cash<1000?'disabled':''}>SHOW + SAVE $1,000</button><button class="secondary" onclick="hqModal()">BACK</button></div>`) } window.communityShowModal=communityShowModal; const EAST_EXPANSION_ORDER=['porkchop','baddburgers','highnoon','chessclub','thirteenthfloor','amlhouse']; const WEST_EXPANSION_ORDER=['kazi','tascam','jblpro']; const EXPANSION_PERMIT_COST=12500; function sponsoredBusinessThreeFlags(id){ const v=state.venues[id]; return !!(v&&v.sign&&(Number(v.fillFlags)||0)>=3) } function openBusinessesRequiredBeforePermit(id){ const i=EAST_EXPANSION_ORDER.indexOf(id); if(i<=0)return []; return places.filter(p=>p.type==='gig'&&placeVisible(p)&&p.id!==id&&!EAST_EXPANSION_ORDER.slice(i).includes(p.id)) } function eastPermitMissingRequirements(id){ if(id==='porkchop')return []; return openBusinessesRequiredBeforePermit(id).filter(p=>!sponsoredBusinessThreeFlags(p.id)) } function eastPermitProgressText(id){ if(id==='porkchop')return state.story.chapter3Started?'FIRST EASTSIDE PERMIT':'START CHAPTER 3 FIRST'; const missing=eastPermitMissingRequirements(id); if(!missing.length)return 'ALL CURRENT BUSINESSES COMPLETE'; return `NEED 3 FLAGS: ${missing.map(p=>p.short||p.name).join(', ')}` } function normalizeAllSponsorFlagRules(){ for(const p of places.filter(p=>p.type==='gig')){ const v=state.venues[p.id]; if(!v)continue; v.fillFlags=Math.max(0,Math.min(3,Number(v.fillFlags)||0)); if(!v.sign){ v.fillFlags=0; v.flagCycleArmed=false; continue } const full=permanentCars(p.id)>=(p.capacity||16); v.lotCycleFull=!!full; v.flagCycleArmed=!full&&v.fillFlags<3 } } function eastCorridorTrafficAudit(){ const east=[]; for(const c of traffic){ const q=trafficVisualXY(c); if(q.x>2520)east.push(c) } // Keep a little life on Eastside, but never allow another wall of vehicles. east.sort((a,b)=>(a.isSpecialRoad?1:0)-(b.isSpecialRoad?1:0)); for(let i=4;i<east.length;i++)beginTrafficExit(east[i]) } function eastCorridorPeopleAudit(){ for(const p of pedestrians){ const x=Number.isFinite(p.x)?p.x:p.x1+(p.x2-p.x1)*p.t; if(x>2520){ p.t=Math.random()*.75; p.dir=Math.random()<.5?-1:1; p.x=undefined;p.y=undefined } } } function permitKeyForBusiness(id){return 'east-'+id.replace('thirteenthfloor','thirteenthfloor').replace('baddburgers','baddburgers')} function westPermitKeyForBusiness(id){return 'west-'+id} function businessPermitOwned(id){ const p=places.find(x=>x.id===id); return !p||!p.expansionPermit?true:!!state.expansionPermits[p.expansionPermit] } function previousExpansionSponsored(id,orderList){ const i=orderList.indexOf(id); if(i<=0)return true; const prev=orderList[i-1]; return !!(state.venues[prev]&&state.venues[prev].sign) } function eastPermitAvailableFor(id){ if(!state.story.chapter3Started||!state.story.eastAustinUnlocked)return false; const i=EAST_EXPANSION_ORDER.indexOf(id); if(i<0)return false; if(i===0)return true; if(!EAST_EXPANSION_ORDER.slice(0,i).every(prev=>businessPermitOwned(prev)))return false; return eastPermitMissingRequirements(id).length===0 } function westPermitAvailableFor(id){ if(!state.story.westAustinUnlocked)return false; return previousExpansionSponsored(id,WEST_EXPANSION_ORDER) } function allEastPermitsOwned(){return EAST_EXPANSION_ORDER.every(id=>businessPermitOwned(id))} function allVisibleBusinessesFiveFlags(){ const open=places.filter(p=>p.type==='gig'&&placeVisible(p)); return open.length>0&&byobThreeFlags()&&open.every(p=>state.venues[p.id]?.sign&&(Number(state.venues[p.id].fillFlags)||0)>=3) } function eastAustinConquered(){return allEastPermitsOwned()&&allVisibleBusinessesFiveFlags()} function dynamicFestivalRoute(){return places.filter(p=>p.type==='gig'&&placeVisible(p)&&state.venues[p.id]?.sign).map(p=>p.id).concat('hq')} function secondFestivalReady(){return eastAustinConquered()&&!state.story.secondFestivalComplete&&!state.story.secondFestivalActive} function secondFestivalEmailCard(){ if(state.story.secondFestivalComplete)return''; const ready=secondFestivalReady(),open=places.filter(p=>p.type==='gig'&&placeVisible(p)),three=open.filter(p=>(state.venues[p.id]?.fillFlags||0)>=3).length; return `<div class="card" style="border-color:#f1b83e;box-shadow:4px 4px 0 #111"><h3>EAST AUSTIN CITYWIDE FESTIVAL</h3><p><b>IT'S A VAN FEST II</b> — Every currently open business joins one citywide route.</p><p>${allEastPermitsOwned()?'✅':'⬜'} All five East Austin permits<br>${three===open.length?'✅':'⬜'} Three flags at every open sponsored business (${three}/${open.length})<br>${byobThreeFlags()?'✅':'⬜'} BYOB Community Flags (${Math.min(byobFlagCount(),3)}/3)</p><button class="red" onclick="startSecondFestival()" ${ready?'':'disabled'}>${state.story.secondFestivalActive?'FESTIVAL IN PROGRESS':ready?'START VAN FEST II':'REQUIREMENTS NOT MET'}</button></div>` } window.startSecondFestival=()=>{ if(!secondFestivalReady())return; const route=dynamicFestivalRoute(); state.story.secondFestivalActive=true;state.story.secondFestivalIndex=0;state.story.secondFestivalRoute=route; state.pendingOffer=buildOffer(route[0]);save();hud();openEmail() } function advanceSecondFestivalAfterShow(id){ if(!state.story.secondFestivalActive)return; const route=state.story.secondFestivalRoute||dynamicFestivalRoute(),expected=route[state.story.secondFestivalIndex]; if(id!==expected)return; state.story.secondFestivalIndex++; if(state.story.secondFestivalIndex<route.length-1){ const next=route[state.story.secondFestivalIndex];state.pendingOffer=buildOffer(next);toast(`VAN FEST II STOP COMPLETE • NEXT: ${places.find(p=>p.id===next).name}`) }else toast('VAN FEST II FINALE READY • RETURN TO BYOB') } window.completeSecondFestivalFinale=()=>{ const route=state.story.secondFestivalRoute||[]; if(!state.story.secondFestivalActive||route[state.story.secondFestivalIndex]!=='hq')return toast('Complete every open-business stop first.'); state.story.secondFestivalActive=false;state.story.secondFestivalComplete=true;state.story.westAustinUnlocked=true; creditCash(15000,'Festival Rewards',"It's A Van Fest II reward");state.rep+=750;save();hud(); modal(`<h2>IT'S A VAN FEST II COMPLETE</h2><p class="good"><b>CHAPTER 4 UNLOCKED — SOUTH SIDE — RESERVED FOR FUTURE EXPANSION</b></p><div class="grid"><div class="card"><b>KAZI 88.7 FM</b><br>Radio</div><div class="card"><b>TASCAM</b><br>Model 24 Studio</div><div class="card"><b>JBL PRO</b><br>Speaker Land</div><div class="card"><b>SOUP PEDDLER</b><br>Soup Shop</div></div><div class="btns"><button onclick="showExpansionPermits()">VIEW SOUTH SIDE PERMITS</button></div>`) } function worldLiquorShouldBeOpen(){ return !!(state.story&&state.story.festivalComplete) } function activateWorldLiquorAfterFestival(){ if(!worldLiquorShouldBeOpen())return; state.venues.worldliquor||(state.venues.worldliquor={budget:SOLO_COST,eventCount:0,rateCars:0,sign:false,fillFlags:0,lotCycleFull:false,flagCycleArmed:false}); state.story.eastAustinUnlocked=true; state.expansionPermits.eastAustin=true; // legacy compatibility only; no purchase is required. state.venues.worldliquor.budget=Math.max(Number(state.venues.worldliquor.budget)||0,2400) } function normalizeWorldLiquorAutoState(){ if(!worldLiquorShouldBeOpen()||state.story.worldLiquorProgressionNormalized)return; const v=state.venues.worldliquor; if(v&&v.sign&&(Number(v.fillFlags)||0)===0&&(Number(v.rateCars)||0)===8&&(Number(v.eventCount)||0)>=4&&!v.flagCycleArmed){ v.sign=false;v.eventCount=0;v.rateCars=0;v.lotCycleFull=false;v.flagCycleArmed=false; state.completed=state.completed.filter(id=>id!=='worldliquor') } state.story.worldLiquorProgressionNormalized=true } const FUTURE_EAST_AUSTIN=['PORK CHOP SCREEN PRINTING','BADD BURGERS — TACOS, HOTDOGS & HAMBURGERS','HIGH NOON AUSTIN — BAR','CHESS CLUB — PUNK ROCK CLUB','THE 13TH FLOOR — PSYCH ROCK']; function allSponsorsComplete(){return [...order,'mama'].every(id=>state.venues[id]&&state.venues[id].sign)} function allSponsoredLotsFull(){return [...order,'mama'].every(id=>{const p=places.find(x=>x.id===id),v=state.venues[id];return !!(p&&v&&v.sign&&permanentCars(id)>=(p.capacity||16))})} function festivalRequirements(){return{allSponsors:allSponsorsComplete(),lotsFull:allSponsoredLotsFull(),community:state.rep>=500,van:state.vanhp>=75,cash:state.cash>=25000}} function festivalReady(){const r=festivalRequirements();return Object.values(r).every(Boolean)&&!state.story.festivalComplete} function festivalEmailCard(){if(state.story.festivalComplete)return'';const r=festivalRequirements(),ready=festivalReady();return `<div class="card" style="border-color:#e64a38;box-shadow:4px 4px 0 #111"><h3>CITYWIDE FESTIVAL OPPORTUNITY</h3><p><b>IT'S A VAN FEST</b> — Every current sponsor wants a show on the same Austin day, ending with a BYOB Austin finale.</p><p>${r.allSponsors?'✅':'⬜'} All seven sponsors<br>${r.lotsFull?'✅':'⬜'} Every sponsored parking lot refilled<br>${r.community?'✅':'⬜'} Community 500+<br>${r.van?'✅':'⬜'} Van Health 75%+<br>${r.cash?'✅':'⬜'} $25,000 Cash</p><button class="red" onclick="startFestivalBoss()" ${ready&&!state.story.festivalActive?'':'disabled'}>${state.story.festivalActive?'FESTIVAL IN PROGRESS':ready?'START BOSS EVENT':'REQUIREMENTS NOT MET'}</button></div>`} window.startFestivalBoss=()=>{if(!festivalReady()||state.story.festivalActive)return;state.story.festivalActive=true;state.story.festivalIndex=0;state.story.festivalEmailSeen=true;const first=FESTIVAL_ROUTE[0];state.pendingOffer=buildOffer(first);save();hud();toast("IT'S A VAN FEST STARTED");openEmail()} function advanceFestivalAfterShow(id){if(!state.story.festivalActive)return;const expected=FESTIVAL_ROUTE[state.story.festivalIndex];if(id!==expected)return;state.story.festivalIndex++;if(state.story.festivalIndex<FESTIVAL_ROUTE.length-1){const next=FESTIVAL_ROUTE[state.story.festivalIndex];state.pendingOffer=buildOffer(next);toast(`FESTIVAL STOP COMPLETE • NEXT: ${places.find(p=>p.id===next).name}`)}else{toast('FINAL STOP READY • RETURN TO BYOB AUSTIN')}} window.completeFestivalFinale=()=>{if(!state.story.festivalActive||FESTIVAL_ROUTE[state.story.festivalIndex]!=='hq')return toast('Complete every festival stop first.');state.story.festivalActive=false;state.story.festivalComplete=true;state.story.eastAustinUnlocked=true;state.story.festivalIndex=FESTIVAL_ROUTE.length;activateWorldLiquorAfterFestival();creditCash(10000,'Festival Rewards',"It's A Van Fest reward");state.rep+=500;save();hud();modal(`<h2>IT'S A VAN FEST COMPLETE</h2><p class="good"><b>CHAPTER 2 COMPLETE — BUILD THE COMMUNITY</b></p><p>Every sponsor banner surrounds the BYOB Austin finale. The parking lot is full, the city is celebrating, and the scene you built now has the strength to expand east.</p><div class="grid"><div class="card"><b>REWARD</b><br>$10,000<br>Community +500</div><div class="card"><b>EAST AUSTIN DISTRICT</b><br>NOW OPEN</div><div class="card"><b>WORLD LIQUOR</b><br>NOW OPEN • BOOK THE FIRST SHOW</div></div><div class="btns"><button onclick="closeModal()">SEE WORLD LIQUOR ON THE MAP</button></div>`)} function mamaPermitUnlocked(){return !!(state.expansionPermits&&state.expansionPermits.mama)} function eastAustinPermitAvailable(){return !!(state.story&&state.story.festivalComplete&&state.story.eastAustinUnlocked)} function eastAustinPermitUnlocked(){return !!(state.expansionPermits&&state.expansionPermits.eastAustin)} function placeVisible(p){ if(p&&p.retiredByReorg)return false; // R36B26: city geometry is permanent. Future businesses remain visible as closed buildings. return !!p } function unlocked(id){if(state.cheats&&state.cheats.sandbox)return true;const p=places.find(x=>x.id===id);if(p&&p.openFromStart)return true;if(p&&p.expansionPermit)return businessPermitOwned(id);if(id==='mama')return mamaPermitUnlocked();if(id==='worldliquor')return worldLiquorShouldBeOpen();return firstCycleComplete()||order.indexOf(id)<=state.completed.length} function permanentCars(id){const v=state.venues[id],p=places.find(x=>x.id===id);if(!v||!p)return 0;const organic=v.eventCount<=0?0:Math.pow(2,v.eventCount-1);return Math.min(p.capacity,Math.max(organic,Number(v.rateCars)||0))} function nextShowCars(id){const v=state.venues[id],p=places.find(x=>x.id===id);return Math.min(p.capacity,Math.max(Math.pow(2,v.eventCount),Number(v.rateCars)||0))} function expectedCars(id){return permanentCars(id)} function venueHasShowHistory(id){const v=state.venues[id];return !!v&&(state.completed.includes(id)||v.eventCount>0||v.rateCars>0||v.sign)} function refreshSponsorOffers(){const valid=places.filter(p=>p.type==='gig'&&venueHasShowHistory(p.id)&&permanentCars(p.id)>=(p.capacity||16)&&!state.venues[p.id].sign).map(p=>p.id);const queued=Array.isArray(state.sponsorOffers)?state.sponsorOffers:[];state.sponsorOffers=[...new Set([...queued.filter(id=>valid.includes(id)),...valid])];return state.sponsorOffers} function eligibleSponsorBusinesses(){const ids=refreshSponsorOffers();return ids.map(id=>places.find(p=>p.id===id)).filter(Boolean)} function sponsorEligible(){return eligibleSponsorBusinesses().length>0} function sponsorMultiplier(id){if(!state.sponsor)return 1;return state.sponsor===id?0.8:1.2} function crowdMultiplier(id){return 1+((state.venues[id]?.rateCars||0)*0.10)} // R36B40A: parked cars grow the client's future budget; they never inflate gear, performer or operator prices. function priceMultiplier(id){return sponsorMultiplier(id)} function isAustinNight(){const t=austinTimeParts();return t.hour>=19||t.hour<6} function clientPrice(id,base){const night=id==='mama'&&isAustinNight()?1.15:1;return Math.round(base*priceMultiplier(id)*night)} function gearNeedsFor(pkg,extras){const n=Object.assign({},pkg.needs);if(extras.backline)n.backline=1;if(extras.lights)n.lights=1;return n} function gearPurchaseCost(k){const m={main:650,sub:750,mic:110,monitor:425,lights:300,backline:900,xlr:25,iec:25,speakerCable50:75,snake24:650,highTom:275,lowTom:300,floorTom:350,bassDrum:500,drumHardware:450,guitarAmp:650,bassAmp:750,diBox:120};return m[k]||0} const CABLE_ITEM_LABELS={xlr:'XLR CABLE',iec:'IEC POWER CABLE',speakerCable50:'50FT SPEAKER CABLE',snake24:'50FT 24-CHANNEL SNAKE'}; const BACKLINE_ITEM_LABELS={highTom:'HIGH TOM',lowTom:'LOW TOM',floorTom:'FLOOR TOM',bassDrum:'BASS DRUM',drumHardware:'DRUM HARDWARE',guitarAmp:'GUITAR AMP',bassAmp:'BASS AMP',diBox:'DI BOX'}; function chapterTwoProductionActive(){return !!state.story.festivalComplete} function chapterThreeProductionActive(){return !!state.story.chapter3Started} function productionCableRequirements(setup=activeSetup){const n=setup?.needs||{},fullBand=setup?.pkg==='band',poweredSpeakers=(+n.main||0)+(+n.sub||0)+(+n.monitor||0),amps=(setup?.extras?.backline||n.backline)?3:0;return{xlr:poweredSpeakers+(+n.mic||0)+(fullBand?5:0)+amps+1,iec:poweredSpeakers+amps+1,speakerCable50:2,snake24:1}} const EQUIPMENT_MANIFEST_LABELS={main:'MAIN SPEAKER',sub:'SUBWOOFER',mic:'MICROPHONE',monitor:'STAGE MONITOR',lights:'LIGHTING PACKAGE',backline:'BACKLINE PACKAGE',xlr:'XLR CABLE',iec:'IEC POWER CABLE',speakerCable50:'50FT SPEAKER CABLE',snake24:'50FT 24-CHANNEL SNAKE',highTom:'HIGH TOM',lowTom:'LOW TOM',floorTom:'FLOOR TOM',bassDrum:'BASS DRUM',drumHardware:'DRUM HARDWARE',guitarAmp:'GUITAR AMP',bassAmp:'BASS AMP',diBox:'DI BOX'}; function buildEquipmentManifest(job){ if(!job)return{}; const manifest={}; for(const[k,n0]of Object.entries(job.needs||{})){const n=Math.max(0,Number(n0)||0);if(n)manifest[k]=n} if(chapterTwoProductionActive())for(const[k,n]of Object.entries(productionCableRequirements(job)))manifest[k]=Math.max(manifest[k]||0,n); if(chapterThreeProductionActive()&&(job.extras?.backline||job.needs?.backline))for(const[k,n]of Object.entries(productionBacklineRequirements()))manifest[k]=Math.max(manifest[k]||0,n); return manifest } function ensureEquipmentManifest(job=state.activeJob){ if(!job)return{}; const expected=buildEquipmentManifest(job),saved=job.manifest&&typeof job.manifest==='object'?job.manifest:{}; job.manifest=Object.assign({},saved,expected); return job.manifest } function equipmentManifestHtml(job=state.activeJob){ const manifest=ensureEquipmentManifest(job); return Object.entries(manifest).filter(([,n])=>Number(n)>0).map(([k,n])=>`<div class="manifestLine"><b>${EQUIPMENT_MANIFEST_LABELS[k]||String(k).replace(/([A-Z])/g,' $1').toUpperCase()}</b><span>× ${n}</span></div>`).join('') } window.ensureEquipmentManifest=ensureEquipmentManifest; function productionBacklineRequirements(){return{highTom:1,lowTom:1,floorTom:1,bassDrum:1,drumHardware:1,guitarAmp:2,bassAmp:1,diBox:2}} function inventoryShortages(r){const m={};for(const[k,n]of Object.entries(r)){const h=Math.max(0,+state.inventory[k]||0);if(h<n)m[k]=n-h}return m} function requirementSummary(r,l){return Object.entries(r).map(([k,n])=>{const h=Math.max(0,+state.inventory[k]||0);return`<div class="${h>=n?'good':'bad'}"><b>${l[k]||k}</b> — need ${n} • have ${h}</div>`}).join('')} function productionCableComplete(s=activeSetup){return!!s?.cablesLoaded&&!Object.keys(inventoryShortages(productionCableRequirements(s))).length} function productionBacklineComplete(s=activeSetup){return!!s?.backlineDetailedLoaded&&!Object.keys(inventoryShortages(productionBacklineRequirements())).length} function loadCablePackage(){if(!activeSetup)return;const m=inventoryShortages(productionCableRequirements(activeSetup));if(Object.keys(m).length)return toast('CABLE PACKAGE INCOMPLETE • '+Object.entries(m).map(([k,n])=>`${CABLE_ITEM_LABELS[k]} −${n}`).join(' • '));activeSetup.cablesLoaded=true;toast('CABLE PACKAGE LOADED • 80% AVAILABLE');renderSetup()} function loadDetailedBackline(){if(!activeSetup)return;const m=inventoryShortages(productionBacklineRequirements());if(Object.keys(m).length)return toast('BACKLINE INCOMPLETE • '+Object.entries(m).map(([k,n])=>`${BACKLINE_ITEM_LABELS[k]} −${n}`).join(' • '));activeSetup.backlineDetailedLoaded=true;toast('COMPLETE BACKLINE LOADED • 100% AVAILABLE');renderSetup()} function amlHouseModal(){modal(`<h2>AUSTIN MUSIC LOVE</h2><div class="card"><h3>HOUSESHOWS</h3><p>Open from the start. Vancerts can run community and for-profit houseshows here with a future 50/50 impact-and-income model.</p><p><b>Full AML Houseshow planning opens in the next pass.</b></p></div><div class="btns"><button onclick="closeModal()">BACK</button></div>`)}window.amlHouseModal=amlHouseModal; const LEFTWAY_SERVICES=[ {id:'demo',group:'RECORDING',name:'DEMO RECORDING',cost:150,need:0,asset:'Demo Recording',quality:4,fans:8,followers:4,sponsor:0,desc:'A fast first recording that helps the band approach venues with something real.'}, {id:'single',group:'RECORDING',name:'SINGLE',cost:400,need:2,asset:'Recorded Single',quality:9,fans:18,followers:12,sponsor:2,desc:'One polished song for radio, booking pitches, and online release.'}, {id:'ep',group:'RECORDING',name:'EP',cost:1000,need:7,asset:'Recorded EP',quality:18,fans:42,followers:30,sponsor:6,desc:'A multi-song release that gives the band a stronger local identity.'}, {id:'album',group:'RECORDING',name:'ALBUM',cost:2500,need:14,asset:'Full Album',quality:35,fans:90,followers:70,sponsor:14,desc:'The highest recording tier, opening larger touring, festival, and sponsorship opportunities.'}, {id:'liveAudio',group:'RECORDING',name:'LIVE SESSION',cost:600,need:4,asset:'Live Session Recording',quality:12,fans:30,followers:22,sponsor:4,desc:'A professional live recording that proves how the band sounds onstage.'}, {id:'liveVideo',group:'VIDEO',name:'LIVE SESSION VIDEO',cost:750,need:4,asset:'Live Session Video',quality:5,fans:34,followers:40,sponsor:6,desc:'A filmed performance that improves booking confidence and fan trust.'}, {id:'musicVideo',group:'VIDEO',name:'MUSIC VIDEO',cost:1800,need:14,asset:'Music Video',quality:8,fans:70,followers:100,sponsor:16,desc:'A major visual release with the strongest online and sponsor impact.'}, {id:'socialClips',group:'VIDEO',name:'SOCIAL CLIPS',cost:200,need:0,asset:'Social Clip Pack',quality:1,fans:12,followers:24,sponsor:1,desc:'Short promotional clips that steadily grow engagement between shows.'}, {id:'behindVideo',group:'VIDEO',name:'BEHIND-THE-SCENES VIDEO',cost:450,need:4,asset:'Behind-the-Scenes Video',quality:2,fans:16,followers:28,sponsor:4,desc:'Studio and road footage that strengthens fan loyalty and band personality.'}, {id:'artistInterview',group:'PODCAST / INTERVIEWS',name:'ARTIST INTERVIEW',cost:250,need:2,asset:'Artist Interview',quality:1,fans:18,followers:18,sponsor:2,desc:'A focused conversation about the music, the band story, and upcoming shows.'}, {id:'behindStory',group:'PODCAST / INTERVIEWS',name:'BEHIND-THE-SCENES STORY',cost:350,need:7,asset:'Behind-the-Scenes Story',quality:1,fans:24,followers:24,sponsor:4,desc:'A deeper story about recording, touring, challenges, and band dynamics.'}, {id:'creatorFeature',group:'PODCAST / INTERVIEWS',name:'LOCAL CREATOR FEATURE',cost:500,need:10,asset:'Local Creator Feature',quality:1,fans:34,followers:34,sponsor:7,desc:'A collaborative Austin feature that builds community reputation and cross-promotion.'} ]; function leftwayState(){ state.leftwayMedia=state.leftwayMedia&&typeof state.leftwayMedia==='object'?state.leftwayMedia:{}; state.leftwayMedia.projects=Array.isArray(state.leftwayMedia.projects)?state.leftwayMedia.projects:[]; state.career.bandFans=Math.max(0,Number(state.career.bandFans)||0); state.career.onlineFollowers=Math.max(0,Number(state.career.onlineFollowers)||0); state.career.songQuality=Math.max(0,Number(state.career.songQuality)||0); state.career.sponsorInterest=Math.max(0,Number(state.career.sponsorInterest)||0); return state.leftwayMedia; } function leftwayServiceById(id){return LEFTWAY_SERVICES.find(s=>s.id===id)} function leftwayProjectCard(p){ const playable=/recording|single|ep|album|interview|story/i.test(p.asset||''); return `<div class="card"><h3>${safeFinanceText(p.asset)}</h3><p><b>${safeFinanceText(p.bandName)}</b><br><span class="small">Created at Leftway Studios • ${safeFinanceText(p.dateLabel)}</span></p><p>Song quality +${p.quality} • Fans +${p.fans} • Followers +${p.followers} • Sponsor interest +${p.sponsor}</p>${playable?`<button onclick="playLeftwayProject('${p.id}')">PLAY ON COMMUNITY RADIO</button>`:''}</div>` } function leftwayModal(){ const media=leftwayState(),band=state.career.path==='band',xp=Math.max(0,Number(state.career.bandXp)||0),projects=media.projects.slice().reverse(); if(!band){modal(`<h2>LEFTWAY STUDIOS</h2><div class="card"><h3>BAND MEDIA HOME BASE</h3><p>Leftway is open as a major Band-story destination for recording, video, podcasts, and interviews.</p><p>Switch to the Band career to produce media here. Other careers can still visit the property in the shared Austin world.</p></div><div class="btns"><button onclick="openStaffManager()">CHOOSE BAND CAREER</button><button class="secondary" onclick="closeModal()">BACK TO AUSTIN</button></div>`);return} const groups=['RECORDING','VIDEO','PODCAST / INTERVIEWS']; const groupHtml=groups.map(group=>`<div class="card"><h3>${group}</h3>${LEFTWAY_SERVICES.filter(s=>s.group===group).map(s=>{const unlocked=xp>=s.need,afford=Number(state.cash||0)>=s.cost;return `<div class="card" style="margin:8px 0;opacity:${unlocked?1:.55}"><b>${s.name}</b> • $${s.cost}<br><span class="small">${s.desc}</span><br><span class="${unlocked?'good':'bad'}">${unlocked?`UNLOCKED • Band experience ${xp}`:`LOCKED • Complete ${s.need} Band shows (${xp}/${s.need})`}</span><div class="btns"><button class="green" onclick="produceLeftwayService('${s.id}')" ${!unlocked||!afford?'disabled':''}>${!unlocked?'LOCKED':!afford?'NOT ENOUGH CASH':'CREATE PROJECT'}</button></div></div>`}).join('')}</div>`).join(''); modal(`<h2>LEFTWAY STUDIOS • BAND MEDIA</h2><div class="card"><h3>${safeFinanceText(state.career.bandName)}</h3><p>Band experience: <b>${xp}</b> • Song quality: <b>${state.career.songQuality}</b> • Fans: <b>${state.career.bandFans}</b> • Online followers: <b>${state.career.onlineFollowers}</b> • Sponsor interest: <b>${state.career.sponsorInterest}</b></p><p class="small">Projects created here become permanent Band-story media assets. Audio and interview projects can be played through Community Radio.</p></div><div class="grid">${groupHtml}</div><h2 style="margin-top:18px">LEFTWAY MEDIA LIBRARY</h2>${projects.length?`<div class="grid">${projects.map(leftwayProjectCard).join('')}</div>`:'<div class="card"><p>No projects yet. Start with a demo recording or social clips.</p></div>'}<div class="btns"><button class="secondary" onclick="closeModal()">BACK TO AUSTIN</button></div>`) } function produceLeftwayService(id){ const s=leftwayServiceById(id),media=leftwayState(),xp=Math.max(0,Number(state.career.bandXp)||0);if(!s)return; if(state.career.path!=='band')return toast('LEFTWAY BAND SERVICES REQUIRE BAND CAREER'); if(xp<s.need)return toast(`LOCKED • COMPLETE ${s.need} BAND SHOWS`); if(Number(state.cash||0)<s.cost)return toast('NOT ENOUGH CASH'); const paid=typeof debitCash==='function'?debitCash(s.cost,'Media Production',`Leftway Studios • ${s.name}`,{vendor:'Leftway Studios',purpose:'Create professional band media for booking, promotion, fan growth, and sponsorship development.',deductiblePct:100,taxTreatment:'Ordinary band media and promotional production may generally be a business expense when directly connected to the music activity.'}):(state.cash-=s.cost,true); if(!paid)return toast('PAYMENT FAILED'); const project={id:`leftway-${Date.now()}-${Math.random().toString(36).slice(2,6)}`,serviceId:s.id,asset:s.asset,bandName:String(state.career.bandName||'THE BAND'),at:new Date().toISOString(),dateLabel:new Date().toLocaleDateString('en-US',{month:'short',day:'numeric',year:'numeric'}),quality:s.quality,fans:s.fans,followers:s.followers,sponsor:s.sponsor}; media.projects.push(project);if(media.projects.length>60)media.projects.splice(0,media.projects.length-60); state.career.songQuality+=s.quality;state.career.bandFans+=s.fans;state.career.onlineFollowers+=s.followers;state.career.sponsorInterest+=s.sponsor;state.rep+=Math.max(1,Math.round(s.fans/10)); if(typeof persistCommittedFinanceState==='function')persistCommittedFinanceState();else save();hud(); toast(`${s.asset.toUpperCase()} CREATED AT LEFTWAY`);leftwayModal() } function playLeftwayProject(id){ const p=leftwayState().projects.find(x=>x.id===id);if(!p)return toast('MEDIA PROJECT NOT FOUND'); const title=`${p.bandName} • ${p.asset} • LEFTWAY STUDIOS`; phoneNowPlaying=title;const np=document.getElementById('nowPlayingText'),ps=document.getElementById('phoneStatus'),rc=document.getElementById('radioCollapse');if(np)np.textContent=title;if(ps)ps.textContent=`NOW PLAYING • ${title}`;if(rc)rc.dataset.nowPlaying=title; if(typeof setPhoneStatusText==='function')setPhoneStatusText(`NOW PLAYING • ${title}`); toast('LEFTWAY PROJECT SENT TO COMMUNITY RADIO');closeModal() } window.produceLeftwayService=produceLeftwayService;window.playLeftwayProject=playLeftwayProject; window.loadCablePackage=loadCablePackage;window.loadDetailedBackline=loadDetailedBackline;window.leftwayModal=leftwayModal; const TRAINING_CHAPTER_INFO={ 1:{title:'BUILD THE SCENE',summary:'Learn the controls by completing the real first FSG parking-lot show.',points:['Drive and interact','Open and close the Nookia','Open and minimize 512 Jams','Review email and collect the deposit','Load at Gig Bag','Build the stage','Call for final payment']}, 2:{title:'BUILD THE COMMUNITY',summary:'Turn repeat shows into sponsors, community strength, and the first citywide Van Fest.',points:['Book repeat clients with CALL','Fill parking lots','Accept sponsor emails','Buy community projects','Meet the Van Fest checklist','Finish at BYOB']}, 3:{title:'EXPAND EAST',summary:'Add production depth, open East Austin in order, earn flags, and complete Van Fest II.',points:['Book World Liquor','Load the cable package','Buy East Austin permits in order','Earn three flags at every open sponsor','Complete Van Fest II','Unlock the South Side']}, 4:{title:'BUILD THE SOUTH SIDE',summary:'Open the west-edge businesses and turn the complete city into a long-running music economy.',points:['Buy South Side permits in order','Book KAZI, Tascam, and JBL Pro','Load complete backline','Keep sponsor lots cycling','Grow Community projects','Build your own long-term route']} }; let trainingGameStarted=false,lastTrainingPoll=0; function trainingStoryChapter(){if(state.story.westAustinUnlocked||state.story.secondFestivalComplete)return 4;if(state.story.festivalComplete||state.story.eastAustinUnlocked||state.story.chapter3Started)return 3;if(firstCycleComplete()||state.story.festivalActive||originalSponsorsComplete())return 2;return 1} function trainingChapterStarted(chapter=trainingStoryChapter()){return state.training.chapterStarted.includes(chapter)} function trainingMissionData(chapter,index,total,title,text,focus='objective',actionLabel='',action=''){return{chapter,index,total,title,text,focus,actionLabel,action,key:`${chapter}-${index}-${title}`}} function trainingCommonBookingMission(chapter,total=6){ if(state.pendingOffer){const p=places.find(x=>x.id===state.pendingOffer.id);return trainingMissionData(chapter,2,total,'REVIEW THE EQUIPMENT EMAIL',`Open EMAIL on the Nookia. Review ${p?.name||'the client'}'s fixed-price gear list, then collect the 50% deposit to confirm the date.`,'email','OPEN EMAIL','openEmail()')} if(state.activeJob){const p=places.find(x=>x.id===state.activeJob.id);if(state.activeJob.phase==='pickup')return trainingMissionData(chapter,3,total,'PICK UP THE EXACT GEAR',`Drive back to Gig Bag ATX, enter its loading area, and interact. Load the approved list for ${p?.name||'the show'}; call Rock N Roll Rentals from the Nookia if anything is missing.`,'drive');return trainingMissionData(chapter,4,total,state.activeJob.amlPromotion?'PROMOTE, THEN LOAD IN':'DRIVE TO THE CLIENT',state.activeJob.amlPromotion?`Place promotion posters around town, then enter ${p?.name||'the venue'}'s loading zone and interact.`:`Drive to ${p?.name||'the venue'}, enter the marked loading zone, interact, place the requested stage equipment, and open the show.`,'drive')} if(unpaidTotal()>0)return trainingMissionData(chapter,5,total,'CALL FOR THE FINAL PAYMENT',`The show is finished and $${Math.round(unpaidTotal())} is owed. Open the Nookia, press CALL with no number entered, choose the client, and collect the balance.`,'call','OPEN NOOKIA CONTACTS','openPhone()'); return null } function trainingChapterOneMission(){ const f=state.training.flags,first=places.find(p=>p.id==='fsg'),total=8; if(!f.moved)return trainingMissionData(1,1,total,'MOVE THE VAN','Use W or ↑ to drive forward, A or ← to turn left, S or → to turn right, and Z or ↓ to reverse. On touch screens use the corner driving controls.','drive'); if(!f.phoneClosed){const ph=$('phone'),open=ph&&!ph.classList.contains('collapsed');return trainingMissionData(1,2,total,'OPEN, THEN CLOSE THE NOOKIA',open?'The Nookia is open. Press the small ▾ button at its top-right corner to minimize it. This never resets the game.':'Tap the ☎ Nookia icon to open it, then press the small ▾ button to minimize it.','phoneClose','SHOW THE NOOKIA','trainingRevealPhone()')} if(!f.radioClosed){const rr=$('rotaryRadio'),open=rr&&!rr.classList.contains('collapsed');return trainingMissionData(1,3,total,'OPEN, THEN MINIMIZE 512 JAMS',open?'The player is open and driving is paused. Press MINIMIZE to return to the game while Spotify keeps playing.':'Tap the yellow ♫ 512 button to open the player, then press MINIMIZE. Closing it does not reload or reset the game.','radioClose','SHOW 512 JAMS','trainingRevealRadio()')} const common=trainingCommonBookingMission(1,total);if(common){if(state.pendingOffer)common.index=5;else if(state.activeJob?.phase==='pickup')common.index=6;else if(state.activeJob)common.index=7;else common.index=8;return common} if(!state.completed.includes('fsg'))return trainingMissionData(1,4,total,'FIRST REAL MISSION: FSG',`Drive to ${first?.name||'FSG'}, enter the loading zone, and press Space or Enter. On touch screens, tap the map when the interaction prompt appears. This creates the real first client request.`,'drive'); const next=order.find(id=>!state.completed.includes(id));if(next){const p=places.find(x=>x.id===next);return trainingMissionData(1,8,total,'FIRST MISSION COMPLETE',`You completed the full booking loop. Training Wheels stays on: continue to ${p?.name||'the next client'}, complete each founding show, and watch the objective box for the next action.`,'objective')} return trainingMissionData(1,8,total,'CHAPTER 1 COMPLETE','Every founding show is complete. The next chapter teaches repeat bookings, parking-lot growth, sponsorships, and citywide progression.','objective') } function trainingChapterTwoMission(){ const total=6,common=trainingCommonBookingMission(2,total);if(common)return common; if(state.sponsorOffers.length){const names=state.sponsorOffers.map(id=>places.find(p=>p.id===id)?.short||id).join(', ');return trainingMissionData(2,3,total,'ACCEPT A SPONSOR EMAIL',`${names} reached a full parking lot. Open EMAIL, accept the offer, install the banner, and notice that its visible lot resets while earned growth is preserved.`,'email','OPEN EMAIL','openEmail()')} if(!allSponsorsComplete())return trainingMissionData(2,1,total,'BOOK REPEAT SHOWS WITH CALL','Open the Nookia and press CALL with no number entered. Choose a completed client, book another show, and keep repeating the real show loop until its lot fills and a sponsor email arrives.','call','OPEN NOOKIA CONTACTS','openPhone()'); const req=festivalRequirements();if(!festivalReady()&&!state.story.festivalActive){const missing=[];if(!req.allSponsors)missing.push('all seven sponsors');if(!req.lotsFull)missing.push('every sponsored lot refilled');if(!req.community)missing.push('Community 500+');if(!req.van)missing.push('Van Health 75%+');if(!req.cash)missing.push('$25,000 cash');return trainingMissionData(2,4,total,'PREPARE THE CITYWIDE FESTIVAL',`Keep booking shows and building Community projects. Still needed: ${missing.join(' • ')||'open the festival email'}. Parking lots grow future client budgets; gear prices stay fixed.`,'objective')} if(state.story.festivalActive){const id=FESTIVAL_ROUTE[state.story.festivalIndex];const p=places.find(x=>x.id===id);return id==='hq'?trainingMissionData(2,6,total,"FINISH IT'S A VAN FEST",'Return to BYOB Austin, interact, and complete the citywide finale. This opens the East Austin chapter.','drive'):trainingMissionData(2,5,total,'FOLLOW THE VAN FEST ROUTE',`Complete the active festival booking for ${p?.name||'the next stop'}. Each finished show automatically advances the route.`,'drive')} return trainingMissionData(2,5,total,"START IT'S A VAN FEST",'The checklist is complete. Open EMAIL on the Nookia and start the citywide festival route.','email','OPEN EMAIL','openEmail()') } function trainingChapterThreeMission(){ const total=6,common=trainingCommonBookingMission(3,total);if(common)return common; if(!state.completed.includes('worldliquor'))return trainingMissionData(3,1,total,'BOOK WORLD LIQUOR','East Austin is open. Drive to World Liquor and complete its first show. From this chapter forward, purchase and load the calculated cable package for stronger band happiness.','drive'); const nextPermit=EAST_EXPANSION_ORDER.find(id=>!businessPermitOwned(id));if(nextPermit){const p=places.find(x=>x.id===nextPermit);return trainingMissionData(3,2,total,'BUY THE NEXT EAST AUSTIN PERMIT',`Visit BYOB Austin → EXPANSION PERMITS. The next property is ${p?.name||nextPermit}. Permits open in order and may require sponsor flags from the businesses already operating.`,'permit','OPEN EXPANSION PERMITS','showExpansionPermits()')} if(!eastAustinConquered())return trainingMissionData(3,3,total,'EARN THREE FLAGS ACROSS EAST AUSTIN','Sponsor every open business, fill each sponsored lot, then book its next show to bank a flag and reset the visible lot. Repeat until every required location and BYOB have three flags.','call','OPEN NOOKIA CONTACTS','openPhone()'); if(state.story.secondFestivalActive){const route=state.story.secondFestivalRoute||[],id=route[state.story.secondFestivalIndex];const p=places.find(x=>x.id===id);return id==='hq'?trainingMissionData(3,6,total,'FINISH VAN FEST II','Return to BYOB Austin and complete the finale to unlock the South Side.','drive'):trainingMissionData(3,5,total,'FOLLOW THE VAN FEST II ROUTE',`Complete ${p?.name||'the current East Austin stop'}. The route advances automatically after each show.`,'drive')} if(secondFestivalReady())return trainingMissionData(3,4,total,'START VAN FEST II','Every East Austin requirement is ready. Open EMAIL and launch the second citywide festival.','email','OPEN EMAIL','openEmail()'); return trainingMissionData(3,4,total,'BUILD EAST AUSTIN','Keep expanding permits, signing sponsors, and banking three flags at every required location.','objective') } function trainingChapterFourMission(){ const total=5,common=trainingCommonBookingMission(4,total);if(common)return common; const nextPermit=WEST_EXPANSION_ORDER.find(id=>!businessPermitOwned(id));if(nextPermit){const p=places.find(x=>x.id===nextPermit);return trainingMissionData(4,1,total,'BUY THE NEXT SOUTH SIDE PERMIT',`Visit BYOB Austin → EXPANSION PERMITS and open ${p?.name||nextPermit}. South Side properties unlock in order after the previous expansion business is established.`,'permit','OPEN EXPANSION PERMITS','showExpansionPermits()')} const nextBusiness=WEST_EXPANSION_ORDER.find(id=>!state.completed.includes(id));if(nextBusiness){const p=places.find(x=>x.id===nextBusiness);return trainingMissionData(4,2,total,'BUILD THE SOUTH SIDE ROUTE',`Drive to ${p?.name||nextBusiness}, complete its first show, then use repeat bookings to grow its audience and sponsor cycle.`,'drive')} return trainingMissionData(4,5,total,'TRAINING WHEELS: OPEN CITY','You now know the full loop. Keep rotating bookings, filling sponsor lots, banking flags, buying Community projects, promoting shows, collecting resources, and building the city route you want. Turn Training Wheels off whenever you want the normal story objective box.','objective') } function currentTrainingMission(){const chapter=trainingStoryChapter(),info=TRAINING_CHAPTER_INFO[chapter];if(!trainingChapterStarted(chapter))return trainingMissionData(chapter,0,info.points.length,`CHAPTER ${chapter} TRAINING READY`,`${info.summary} Open MISSION GUIDE to see the chapter flow and start Training Wheels.`,'objective');if(chapter===1)return trainingChapterOneMission();if(chapter===2)return trainingChapterTwoMission();if(chapter===3)return trainingChapterThreeMission();return trainingChapterFourMission()} function clearTrainingHighlights(){document.querySelectorAll('.trainingPulse').forEach(el=>el.classList.remove('trainingPulse'))} function applyTrainingHighlight(focus){clearTrainingHighlights();if(!state.training.enabled)return;const selectors={drive:['.driveDirections','.mobileDrive','.mobileSteer'],phoneClose:['#phoneCollapse'],radioClose:['#radioCollapse'],email:['#phoneMail'],call:['#phoneCall'],permit:['#objective'],objective:['#objective']}[focus]||['#objective'];requestAnimationFrame(()=>selectors.forEach(sel=>document.querySelectorAll(sel).forEach(el=>el.classList.add('trainingPulse'))))} function applyTrainingWheelsHud(){ const enabled=!!state.training.enabled,header=$('trainingHeader'),actions=$('trainingActions'),toggle=$('phoneReset');document.body.classList.toggle('trainingWheelsActive',enabled);header?.classList.toggle('show',enabled);actions?.classList.toggle('off',!enabled);if(toggle){toggle.textContent=enabled?'TRAINING ON':'TRAINING OFF';toggle.classList.toggle('off',!enabled);toggle.setAttribute('aria-pressed',enabled?'true':'false')} if(!enabled){clearTrainingHighlights();return} const mission=currentTrainingMission();$('trainingBadge').textContent=`TRAINING WHEELS • CHAPTER ${mission.chapter}`;$('trainingProgress').textContent=mission.index?`MISSION ${mission.index}/${mission.total}`:'CHAPTER START';$('objectiveTitle').textContent=`TRAINING • ${mission.title}`;$('objectiveText').textContent=mission.text;applyTrainingHighlight(mission.focus) } function trainingActionHtml(mission){return mission.action?`<button class="green" onclick="${mission.action}">${mission.actionLabel||'DO THIS NOW'}</button>`:''} function showTrainingChapterIntro(chapter=trainingStoryChapter(),replay=false){const info=TRAINING_CHAPTER_INFO[chapter];if(!info)return;if(!state.training.chapterSeen.includes(chapter))state.training.chapterSeen.push(chapter);modal(`<h2>TRAINING WHEELS • CHAPTER ${chapter}</h2><div class="card"><h3>${info.title}</h3><p>${info.summary}</p><ol>${info.points.map(point=>`<li>${point}</li>`).join('')}</ol></div><p><b>Training Wheels uses the real story missions.</b> It never creates fake progress, changes rewards, or resets your save. The gold objective box always shows the next training action.</p><div class="btns"><button class="green" onclick="startChapterTraining(${chapter})">${trainingChapterStarted(chapter)?'CONTINUE CHAPTER TRAINING':'START CHAPTER TRAINING'}</button><button onclick="disableTrainingWheels()">TURN OFF TRAINING WHEELS</button>${replay?'<button class="secondary" onclick="closeModal()">BACK</button>':''}</div>`)} function startChapterTraining(chapter=trainingStoryChapter()){if(!state.training.chapterStarted.includes(chapter))state.training.chapterStarted.push(chapter);closeModal();hud();toast(`TRAINING WHEELS • CHAPTER ${chapter} ACTIVE`)} function showTrainingMissionGuide(){if(!state.training.enabled)return trainingWheelsMenu();const chapter=trainingStoryChapter();if(!trainingChapterStarted(chapter))return showTrainingChapterIntro(chapter);const mission=currentTrainingMission(),info=TRAINING_CHAPTER_INFO[chapter];modal(`<h2>TRAINING MISSION • CHAPTER ${chapter}</h2><div class="card"><h3>${mission.title}</h3><p>${mission.text}</p><p class="small">Progress: ${mission.index||0}/${mission.total} • ${info.title}</p></div><div class="btns">${trainingActionHtml(mission)}<button class="green" onclick="closeModal()">RETURN TO MISSION</button><button onclick="showTrainingChapterIntro(${chapter},true)">CHAPTER OVERVIEW</button><button class="secondary" onclick="trainingWheelsMenu()">TRAINING SETTINGS</button></div>`)} function setTrainingPreference(enabled){state.training.enabled=!!enabled;safeStorage.setItem(TRAINING_PREF_KEY,enabled?'on':'off')} function toggleTrainingWheels(){const enabled=!state.training.enabled;setTrainingPreference(enabled);if(!enabled)clearTrainingHighlights();hud();toast(enabled?'TRAINING ON • GUIDED MISSIONS ACTIVE':'TRAINING OFF • STORY PROGRESS UNCHANGED');if(enabled)setTimeout(maybeShowTrainingChapter,120)} function disableTrainingWheels(){setTrainingPreference(false);clearTrainingHighlights();closeModal();hud();toast('TRAINING WHEELS OFF • STORY PROGRESS UNCHANGED')} function enableTrainingWheels(){setTrainingPreference(true);closeModal();hud();const chapter=trainingStoryChapter();setTimeout(()=>showTrainingChapterIntro(chapter,true),80);toast('TRAINING WHEELS ON')} function trainingWheelsMenu(){if(state.training.enabled)modal(`<h2>TRAINING WHEELS</h2><p>Turn off the guided mission overlay? The story, saves, rewards, and current job stay exactly where they are. You can turn training back on from the Vancerts Build the Scene box.</p><div class="btns"><button class="red" onclick="disableTrainingWheels()">YES • TURN OFF TRAINING WHEELS</button><button class="green" onclick="closeModal()">KEEP TRAINING ON</button></div>`);else modal(`<h2>TRAINING WHEELS ARE OFF</h2><p>Turn them back on from the Vancerts Build the Scene box to receive the current chapter mission, device reminders, and story-flow guidance. Nothing will reset.</p><div class="btns"><button class="green" onclick="enableTrainingWheels()">TURN TRAINING WHEELS ON</button><button class="secondary" onclick="closeModal()">RETURN TO GAME</button></div>`)} function trainingRevealPhone(){closeModal();const ph=$('phone');if(ph&&ph.classList.contains('collapsed'))expandReliable(ph,$('phoneCollapse'),$('rotaryRadio'),$('radioCollapse'));state.training.flags.phoneOpened=true;hud();toast('NOOKIA OPEN • USE ▾ TO MINIMIZE')} function trainingRevealRadio(){closeModal();state.training.flags.radioOpened=true;open512Jams();hud();toast('512 JAMS OPEN • USE MINIMIZE TO RESUME DRIVING')} function maybeShowTrainingChapter(){if(!trainingGameStarted||!state.training.enabled||state.cheats?.sandbox||$('modalWrap')?.classList.contains('show'))return;const chapter=trainingStoryChapter();if(!state.training.chapterSeen.includes(chapter))showTrainingChapterIntro(chapter)} function updateTrainingWheelProgress(){const now=performance.now();if(now-lastTrainingPoll<120)return;lastTrainingPoll=now;maybeShowTrainingChapter();if(!trainingGameStarted||!state.training.enabled||trainingStoryChapter()!==1||!trainingChapterStarted(1))return;const f=state.training.flags;let changed=false;if(!f.moved&&Math.abs(van.speed)>.35){f.moved=true;changed=true}const ph=$('phone');if(!f.phoneClosed&&ph){if(!ph.classList.contains('collapsed')&&!f.phoneOpened){f.phoneOpened=true;changed=true}else if(ph.classList.contains('collapsed')&&f.phoneOpened){f.phoneClosed=true;changed=true}}const rr=$('rotaryRadio');if(!f.radioClosed&&rr){if(!rr.classList.contains('collapsed')&&!f.radioOpened){f.radioOpened=true;changed=true}else if(rr.classList.contains('collapsed')&&f.radioOpened){f.radioClosed=true;changed=true}}if(changed)hud()} window.showTrainingMissionGuide=showTrainingMissionGuide;window.showTrainingChapterIntro=showTrainingChapterIntro;window.startChapterTraining=startChapterTraining;window.trainingWheelsMenu=trainingWheelsMenu;window.toggleTrainingWheels=toggleTrainingWheels;window.disableTrainingWheels=disableTrainingWheels;window.enableTrainingWheels=enableTrainingWheels;window.trainingRevealPhone=trainingRevealPhone;window.trainingRevealRadio=trainingRevealRadio; setInterval(updateTrainingWheelProgress,120); function hud(){updateMobileDonutButton();$('cash').textContent=rentalMoney(state.cash);$('owed').textContent=Math.round(totalOwed());$('rep').textContent=state.rep;updateClock();$('shows').textContent=state.shows;$('vanhp').textContent=Math.round(state.vanhp);const sponsorOffers=eligibleSponsorBusinesses(),festivalMail=festivalReady()&&!state.story.festivalActive,next=order.find(id=>!state.completed.includes(id))||(mamaPermitUnlocked()&&!state.completed.includes('mama')?'mama':null),permitReady=originalSponsorsComplete()&&!mamaPermitUnlocked();const passengerDest=activePassengerDestination();if(state.passengerRide&&!state.activeJob&&passengerDest){$('objectiveTitle').textContent='PASSENGER DELIVERY';$('objectiveText').textContent=`Drive to ${passengerDest.name} and interact near its loading area. Fare: $${Number(state.passengerRide.fare)||BUS_FARE}.`}else if(state.story.festivalActive&&!state.activeJob&&!state.pendingOffer&&FESTIVAL_ROUTE[state.story.festivalIndex]==='hq'){$('objectiveTitle').textContent="IT'S A VAN FEST FINALE";$('objectiveText').textContent='Return to BYOB Austin and interact to complete the citywide festival.'}else if(state.activeJob){const p=places.find(x=>x.id===state.activeJob.id);if(state.activeJob.phase==='pickup'){$('objectiveTitle').textContent='PICK UP EQUIPMENT';$('objectiveText').textContent=`Drive to the Gig Bag ATX loading area and interact to load the emailed gear list for ${p.name}.`}else{$('objectiveTitle').textContent=state.activeJob.amlPromotion?'PROMOTE, THEN LOAD IN':'GEAR LOADED';$('objectiveText').textContent=state.activeJob.amlPromotion?`Place posters around town before arriving at ${p.name}. Closed businesses, multiple districts, and varied locations improve turnout and payout. Posters placed: ${(state.activeJob.posterCampaign?.placed||[]).length}.`:`Drive carefully to ${p.name}. Park in its loading zone and interact to set up.`}}else if(festivalMail){$('objectiveTitle').textContent='CITYWIDE FESTIVAL EMAIL';$('objectiveText').textContent="Open EMAIL on the Nookia to launch IT'S A VAN FEST."}else if(sponsorOffers.length){const names=sponsorOffers.map(p=>p.short||p.name).join(', ');$('objectiveTitle').textContent='NEW SPONSOR EMAIL';$('objectiveText').textContent=`${names} reached full parking capacity. Open EMAIL on the Nookia to accept the sponsor and install its banner.`}else if(state.pendingOffer){const p=places.find(x=>x.id===state.pendingOffer.id);$('objectiveTitle').textContent='NEW EQUIPMENT EMAIL';$('objectiveText').textContent=`Open EMAIL on the Nookia. Review ${p.name}'s gear list and collect the 50% deposit to confirm the date.`}else{$('objectiveTitle').textContent=unpaidTotal()>0?'PAYMENT READY':next?'CURRENT OBJECTIVE':permitReady?'CHAPTER 2 READY':'CALL TO BOOK';$('objectiveText').textContent=unpaidTotal()>0?`Use the Nookia phone to call and collect $${Math.round(unpaidTotal())} in final payments.`:next?`Drive to ${places.find(p=>p.id===next).name}, park in the loading zone, and press Space or Enter.`:permitReady?'All active founding sponsors are signed. Visit BYOB and purchase the Mama Dearest expansion permit.':'Use CALL on the Nookia to book the next show with a previous client.'}const mail=(state.pendingOffer?' • GEAR EMAIL':'')+(festivalMail?' • FESTIVAL EMAIL':'')+(sponsorOffers.length?` • ${sponsorOffers.length} SPONSOR EMAIL${sponsorOffers.length===1?'':'S'}`:'');{const alerts=(unpaidTotal()>0?` • ${state.invoices.filter(i=>!i.paid).length} INVOICE $${Math.round(unpaidTotal())}`:'')+mail+(state.passengerRide?' • PASSENGER':'');$('phoneStatus').textContent=phoneNowPlayingStatus(alerts)};const mailButton=$('phoneMail');if(mailButton){mailButton.classList.toggle('alert',!!state.pendingOffer||sponsorOffers.length>0||festivalMail);mailButton.textContent=sponsorOffers.length?`EMAIL ${sponsorOffers.length}`:'EMAIL'}const emailApp=$('phoneEmailApp');if(emailApp)emailApp.classList.toggle('alert',!!state.pendingOffer||sponsorOffers.length>0||festivalMail);applyTrainingWheelsHud()} const OFFER_LIMITS={main:2,sub:2,mic:3,monitor:3,backline:1,lights:1}; const OFFER_MINIMUM={main:2,sub:0,mic:0,monitor:0,backline:0,lights:0}; function minimumOfferTotal(id,pkgType='solo'){const pkg=pkgType==='band'?BAND:SOLO;return clientPrice(id,operatorCost+pkg.bandCost+(OFFER_MINIMUM.main*prices.main))} function choosePackage(v,id){return minimumOfferTotal(id,'band')<=v.budget?BAND:SOLO} function bookingBreakdown(pkg,extras){const items=[];for(const[k,n]of Object.entries(pkg.needs))if(n)items.push(`${n} ${k}`);if(extras.backline)items.push('backline');if(extras.lights)items.push('lights');return items.join(', ')} function recalcOffer(o){const pkg=o.pkg==='band'?BAND:SOLO,needs=o.needs||gearNeedsFor(pkg,o.extras||{});o.needs={main:Math.max(2,Number(needs.main||0)),sub:Number(needs.sub||0),mic:Number(needs.mic||0),monitor:Number(needs.monitor||0),backline:Number(needs.backline||0),lights:Number(needs.lights||0)};o.extras={backline:o.needs.backline>0,lights:o.needs.lights>0};o.raw=operatorCost+pkg.bandCost+Object.entries(o.needs).reduce((sum,[k,n])=>sum+(prices[k]||0)*n,0);o.total=clientPrice(o.id,o.raw);o.deposit=Math.floor(o.total/2);o.final=o.total-o.deposit;return o} function offerStrength(test){ const target=test.pkg==='band'?BAND.needs:SOLO.needs;let score=test.pkg==='band'?500:0; for(const k of ['sub','mic','monitor']){const n=test.needs[k]||0,t=target[k]||0;score+=Math.min(n,t)*100+Math.max(0,n-t)*3} score+=(test.needs.backline||0)*18+(test.needs.lights||0)*12; return score } function bestAffordableOffer(o,pkgType){ const v=state.venues[o.id],candidates=[]; for(let sub=0;sub<=OFFER_LIMITS.sub;sub++)for(let mic=0;mic<=OFFER_LIMITS.mic;mic++)for(let monitor=0;monitor<=OFFER_LIMITS.monitor;monitor++)for(let backline=0;backline<=1;backline++)for(let lights=0;lights<=1;lights++){ const test={...o,pkg:pkgType,needs:{main:2,sub,mic,monitor,backline,lights}};recalcOffer(test); if(test.total<=v.budget)candidates.push(test) } candidates.sort((a,b)=>offerStrength(b)-offerStrength(a)||b.total-a.total); return candidates[0]||null } function fitOfferToBudget(o){ const v=state.venues[o.id],before=JSON.stringify({pkg:o.pkg,needs:o.needs}); // Preserve the player's performer choice whenever its performer + operator + two-main PA minimum is affordable. let best=bestAffordableOffer(o,o.pkg); if(!best&&o.pkg==='band')best=bestAffordableOffer(o,'solo'); if(best){o.pkg=best.pkg;o.needs={...best.needs};recalcOffer(o)}else{ o.pkg='solo';o.needs={...OFFER_MINIMUM};recalcOffer(o) } const changed=before!==JSON.stringify({pkg:o.pkg,needs:o.needs}),minimum=minimumOfferTotal(o.id,'solo'); o.autoFitMessage=o.total<=v.budget?(changed?`Auto-Fit used fixed prices and selected the strongest valid stage within the $${Math.round(v.budget)} budget.`:`This is already the strongest valid stage within the $${Math.round(v.budget)} budget.`):`This client needs at least $${minimum} for one solo performer, the van operator and a two-main PA system.`; o.changed=changed;return o } function buildOffer(id){const v=state.venues[id],pkg=choosePackage(v,id);let o={id,pkg:pkg===BAND?'band':'solo',extras:{backline:false,lights:false},needs:{...pkg.needs,backline:0,lights:0},created:Date.now(),amlPromotion:!!v.amlPromotionActive};recalcOffer(o);return fitOfferToBudget(o)} function createOffer(id,source='visit'){if(state.activeJob||state.pendingOffer)return toast('Finish the current booking first.');if(!unlocked(id))return toast('Complete the earlier businesses first.');if(firstCycleComplete()&&source!=='call'&&state.completed.includes(id))return toast('After the first cycle, use the Nookia CALL button to book this business.');state.pendingOffer=buildOffer(id);save();hud();const p=places.find(x=>x.id===id);modal(`<h2>${source==='call'?'PHONE BOOKING REQUEST':'NEW CLIENT REQUEST'}</h2><p><b>${p.name}</b> has sent its equipment list to your Nookia email.</p><p>The date is not confirmed until you review the list and collect the 50% deposit.</p><div class="btns"><button onclick="openEmail()">OPEN EMAIL</button><button class="secondary" onclick="closeModal()">CLOSE</button></div>`)} function gigModal(id){if(state.activeJob){if(state.activeJob.id===id&&state.activeJob.phase==='delivery'){activeSetup={...state.activeJob,placed:{}};return renderSetup()}return toast(state.activeJob.phase==='pickup'?'Load the show gear at Gig Bag ATX first.':'Finish the loaded job before starting another show.')}createOffer(id,'visit')} window.installSign=id=>window.acceptSponsor?window.acceptSponsor(id):toast('Open the sponsor email on the Nookia.') ; window.confirmOffer=()=>{ const o=state.pendingOffer;if(!o)return;fitOfferToBudget(o);const v=state.venues[o.id],p=places.find(p=>p.id===o.id),fullBeforeReset=v.lotCycleFull||permanentCars(o.id)>=(p?.capacity||16); if(v.budget<o.total)return toast(`This client needs at least $${minimumOfferTotal(o.id,'solo')} for one performer and the minimum PA.`); if(flagEraActive()&&v.sign&&fullBeforeReset){bankCompletedSponsoredLot(o.id,true);v.eventCount=0;v.rateCars=0;v.lotCycleFull=false;v.flagCycleArmed=(Number(v.fillFlags)||0)<3;v.amlPromotionActive=false;startChapter3FromResetJob();toast('NEW SHOW BOOKED • PARKING LOT RESET TO 0 CARS • EARNED FLAGS PRESERVED')} creditCash(o.deposit,'Show Deposits',`${p.name} show deposit`,{vendor:p.name,businessPurpose:`50% client deposit confirming the ${p.name} Vancerts show date.`,jobId:String(o.created||o.id||Date.now()),paymentMethod:'CLIENT PAYMENT'}); state.activeJob={...o,phase:'pickup',loadedOwned:{},loadedPaul:{},rentals:{},wrecked:false,posterCampaign:{placed:[]},staff:{}};state.activeJob.manifest=buildEquipmentManifest(state.activeJob); const paul=paulState(),paulAssigned=paul.hired&&paul.nextShift?assignPaulToJob(state.activeJob,p):false; recordGigOperatingCosts(state.activeJob,p);state.pendingOffer=null;save();hud();closeModal();toast(`DEPOSIT RECEIVED • RECEIPTS FILED${paulAssigned?' • PAUL ASSIGNED':''} • PICK UP GEAR AT GIG BAG`) }; window.acceptGig=id=>{if(!state.pendingOffer||state.pendingOffer.id!==id)return;window.confirmOffer()}; const slotDefs=[['mainL','MAIN L',4,10,15,22,'main'],['mainR','MAIN R',81,10,15,22,'main'],['subL','SUB L',8,36,13,14,'sub'],['subR','SUB R',79,36,13,14,'sub'],['mic1','MIC 1',34,18,9,13,'mic'],['mic2','MIC 2',46,18,9,13,'mic'],['mic3','MIC 3',58,18,9,13,'mic'],['backline','BACKLINE',33,40,35,18,'backline'],['lightL','LIGHT L',21,7,9,11,'lights'],['lightR','LIGHT R',70,7,9,11,'lights'],['mon1','MONITOR 1',30,64,13,10,'monitor'],['mon2','MONITOR 2',45,64,13,10,'monitor'],['mon3','MONITOR 3',60,64,13,10,'monitor'],['sign','VANCERTS SIGN',71,55,23,12,'sign']]; function placedCount(type){ return Object.values(activeSetup?.placed||{}).filter(v=>v===type).length } function placeSlot(slotId,type){ if(!activeSetup)return; if(activeSetup.placed[slotId]){ delete activeSetup.placed[slotId]; return renderSetup() } const need=setupNeeds()[type]||0; const available=type==='sign'?1:availableStageSlots(activeSetup,type); if(type!=='sign'&&placedCount(type)>=available)return toast(`NO MORE ${type.toUpperCase()} AVAILABLE`); if(need>0&&placedCount(type)>=need&&type!=='monitor'&&type!=='lights')return toast(`${type.toUpperCase()} REQUIREMENT ALREADY FILLED`); activeSetup.placed[slotId]=type; renderSetup() } function autoPlace(type){ if(!activeSetup)return; const need=setupNeeds()[type]||0; const available=type==='sign'?1:availableStageSlots(activeSetup,type); const target=Math.min(need,available); if(target<=0)return toast(`NO ${type.toUpperCase()} REQUIRED`); for(const s of slotDefs){ if(s[6]!==type||activeSetup.placed[s[0]])continue; if(placedCount(type)>=target)break; activeSetup.placed[s[0]]=type } renderSetup() } function clearSetup(){ if(!activeSetup)return; activeSetup.placed={}; activeSetup.cablesLoaded=false; activeSetup.backlineDetailedLoaded=false; renderSetup() } window.placeSlot=placeSlot; window.autoPlace=autoPlace; window.clearSetup=clearSetup; function setupNeeds(){const n=Object.assign({main:0,sub:0,mic:0,monitor:0,backline:0,lights:0},activeSetup.needs||{});if(state.venues[activeSetup.id].sign)n.sign=1;return n} function renderSetup(){const p=places.find(x=>x.id===activeSetup.id),needs=setupNeeds(),counts={};Object.values(activeSetup.placed).forEach(t=>counts[t]=(counts[t]||0)+1);let slots=slotDefs.map(s=>`<div class="slot ${activeSetup.placed[s[0]]?'filled good':''}" style="left:${s[2]}%;top:${s[3]}%;width:${s[4]}%;height:${s[5]}%" onclick="placeSlot('${s[0]}','${s[6]}')">${activeSetup.placed[s[0]]?s[1]:`+ ${s[1]}`}</div>`).join('');let eq=Object.keys(needs).filter(k=>needs[k]>0).map(k=>{const placed=counts[k]||0,required=Math.min(needs[k],k==='sign'?1:availableStageSlots(activeSetup,k)),cls=placed>=required?'gearEnough':placed>0?'gearPartial':'';return `<button class="${cls}" onclick="autoPlace('${k}')">${k.toUpperCase()} — ${placed}/${required} selected • available ${k==='sign'?1:availableStageSlots(activeSetup,k)}${placed>=required?' • READY':''}</button>`}).join('');const monitorBonus=Math.min(20,(counts.monitor||0)*5),cableReq=productionCableRequirements(activeSetup),cablesComplete=productionCableComplete(activeSetup),backlineReq=productionBacklineRequirements(),backlineComplete=productionBacklineComplete(activeSetup);let happiness=Math.min(70,50+monitorBonus);if(chapterTwoProductionActive()&&cablesComplete)happiness=80;if(chapterThreeProductionActive()&&cablesComplete&&backlineComplete)happiness=100;const cablePanel=chapterTwoProductionActive()?`<div class="card"><h3>CHAPTER 2 • CABLE COUNT</h3>${requirementSummary(cableReq,CABLE_ITEM_LABELS)}<button class="${cablesComplete?'green':''}" onclick="loadCablePackage()">${cablesComplete?'CABLE PACKAGE LOADED':'LOAD COMPLETE CABLE PACKAGE'}</button><p class="small">Every main speaker, subwoofer and stage monitor requires exactly 1 XLR cable and 1 IEC power cable. Backline amps also require 1 XLR + 1 IEC each; microphones use 1 XLR each; a full band adds five drum XLRs; the mixer adds 1 XLR + 1 IEC; plus 2 × 50FT speaker cables and 1 × 50FT 24-channel snake.</p></div>`:'';const backlinePanel=chapterThreeProductionActive()?`<div class="card"><h3>CHAPTER 3 • COMPLETE BACKLINE</h3>${requirementSummary(backlineReq,BACKLINE_ITEM_LABELS)}<button class="${backlineComplete?'green':''}" onclick="loadDetailedBackline()">${backlineComplete?'BACKLINE LOADED':'LOAD COMPLETE BACKLINE'}</button><p class="small">Drum shells/hardware, 2 guitar amps, bass amp and 2 DI boxes. Artists supply kick pedal, snare, throne and cymbals.</p></div>`:'';modal(`<h2>SET UP: ${p.name}</h2><p>The client paid a 50% deposit. Build the stage correctly before opening the show.</p><div class="stageWrap"><div class="stage">${slots}</div><div class="equipment"><h3>SHOW PACKAGE</h3>${eq}<button class="secondary" onclick="clearSetup()">CLEAR STAGE</button><div class="scorebox"><b>Band happiness</b><br>${happiness}%<br><span class="small">Monitors establish the base. Chapter 2 cables unlock 80%. Chapter 3 complete backline unlocks 100%.</span></div>${cablePanel}${backlinePanel}</div></div><div class="btns"><button class="green" onclick="finishSetup()">OPEN THE SHOW</button><button class="secondary" onclick="closeModal()">BACK</button></div>`)} function finishSetup(){if(activeSetup?.developmentTest){const chapter=state.story.chapter3Started?3:2;const cableOk=productionCableComplete(activeSetup),backlineOk=chapter>=3?productionBacklineComplete(activeSetup):true;const happiness=chapter>=3&&cableOk&&backlineOk?100:cableOk?80:Math.min(70,50);return modal(`<h2>DEVELOPMENT STAGE TEST</h2><div class="card"><b>Chapter ${chapter}</b><br>Cable package: <b>${cableOk?'PASS':'INCOMPLETE'}</b><br>${chapter>=3?`Detailed backline: <b>${backlineOk?'PASS':'INCOMPLETE'}</b><br>`:''}Band happiness result: <b>${happiness}%</b></div><div class="btns"><button onclick="activeSetup=null;closeModal()">END TEST</button><button onclick="renderSetup()">RETURN TO STAGE PLOT</button></div>`)}const id=activeSetup.id,p=places.find(x=>x.id===id),v=state.venues[id],paulAssigned=!!activeSetup.staff?.paul,needs=setupNeeds(),counts={};Object.values(activeSetup.placed).forEach(t=>counts[t]=(counts[t]||0)+1);let missing=0;for(const[k,n]of Object.entries(needs)){if(k==='sign'){missing+=Math.max(0,n-(counts[k]||0));continue}const available=availableStageSlots(activeSetup,k);missing+=Math.max(0,n-Math.min(counts[k]||0,available))}const correct=activeSetup.placed.mainL==='main'&&activeSetup.placed.mainR==='main';const monitors=Math.min(counts.monitor||0,availableStageSlots(activeSetup,'monitor')),lightingBonus=id==='mama'?(counts.lights||0)*12:0;const cableMissing=chapterTwoProductionActive()?inventoryShortages(productionCableRequirements(activeSetup)):{};const backlineMissing=chapterThreeProductionActive()?inventoryShortages(productionBacklineRequirements()):{};const cablesComplete=!chapterTwoProductionActive()||productionCableComplete(activeSetup),backlineComplete=!chapterThreeProductionActive()||productionBacklineComplete(activeSetup);missing+=Object.values(cableMissing).reduce((a,b)=>a+b,0)+Object.values(backlineMissing).reduce((a,b)=>a+b,0);let bandHappiness=Math.min(70,50+monitors*5+lightingBonus);if(chapterTwoProductionActive()&&cablesComplete)bandHappiness=80;if(chapterThreeProductionActive()&&cablesComplete&&backlineComplete)bandHappiness=100;const amlBooking=!!activeSetup.amlBooking,amlPromotion=!!activeSetup.amlPromotion,deposit=activeSetup.deposit,total=activeSetup.total,amlFees=amlFeeFor(activeSetup),amlTotal=amlFees.booking+amlFees.promotion;const finalPayment=total-deposit;const invoice=Math.max(0,finalPayment-missing*25-amlTotal);state.amlStats.bookingFees+=amlFees.booking;state.amlStats.promotionFees+=amlFees.promotion;state.invoices.push({id:Date.now(),venueId:id,venue:p.name,amount:invoice,paid:false,amlFee:amlTotal});const priorCars=permanentCars(id),normalTarget=nextShowCars(id),normalIncrease=Math.max(0,normalTarget-priorCars),promoResult=amlPromotion?posterCampaignResult(activeSetup,id,p.capacity||16,priorCars,normalIncrease):{placed:0,types:0,districts:0,inventive:0,score:0,added:normalIncrease,payoutPct:0,halo:false,tier:'NO PROMOTION'},parkingIncrease=amlPromotion?Math.max(normalIncrease,promoResult.added):normalIncrease,cars=Math.min(p.capacity||16,priorCars+parkingIncrease),newCars=Math.max(0,cars-priorCars),amlBonusCars=Math.max(0,newCars-normalIncrease),promotionPayoutBonus=amlPromotion?Math.round(invoice*(promoResult.payoutPct/100)):0,businessRevenue=cars*100+(v.sign?150:0);if(promotionPayoutBonus>0){state.invoices[state.invoices.length-1].amount+=promotionPayoutBonus}const haloBusinesses=amlPromotion&&promoResult.halo?applyPromotionHalo(id):[];v.budget=Math.min(15000,v.budget+businessRevenue);v.rateCars=cars;v.eventCount++;const earnedFullLot=flagEraActive()&&v.sign&&cars>=(p.capacity||16)&&!v.lotCycleFull;if(cars>=(p.capacity||16))v.amlPromotionActive=false;if(earnedFullLot){v.lotCycleFull=true;v.flagCycleArmed=false;toast(`FULL SPONSORED LOT AT ${p.short||p.name} • BOOK THE NEXT JOB TO BANK FLAG ${(Number(v.fillFlags)||0)+1}/3`)}else if(v.sign&&cars>=(p.capacity||16)){v.lotCycleFull=true}const mamaNight=id==='mama'&&isAustinNight();state.rep+=Math.round((gigMeta[id].rep+(correct?3:0))*(mamaNight?1.15:1))+(amlBooking?5:0)+(amlPromotion?10:0);state.impact+=gigMeta[id].impact;state.shows++;startWorldCelebration(p.interact.x,p.interact.y,cars);if(state.career.path==='owner')state.career.ownerXp++;else if(state.career.path==='band')state.career.bandXp++;else if(state.career.teamRole==='audio')state.career.audioXp++;else state.career.stagehandXp++;recordBmiShow(activeSetup,p,invoice+promotionPayoutBonus);if(!state.completed.includes(id))state.completed.push(id);const justUnlockedSponsor=permanentCars(id)>=(p.capacity||16)&&!v.sign;if(justUnlockedSponsor&&!state.sponsorOffers.includes(id))state.sponsorOffers.push(id);state.vanhp=Math.max(0,state.vanhp-(paulAssigned?1:2));state.activeJob=null;activeSetup=null;advanceFestivalAfterShow(id);advanceSecondFestivalAfterShow(id);if(justUnlockedSponsor)state.sponsorEmailSeen=true;save();hud();modal(`<h2>SHOW COMPLETE</h2><div class="grid"><div class="card"><h3>Stage result</h3>${correct?'<span class="good">Mains correctly placed</span>':'<span class="bad">Mains need left/right placement</span>'}<br>Missing or unavailable items: <b>${missing}</b><br>Band happiness: <b>${bandHappiness}%</b><br>${paulAssigned?'<span class="good">Paul assisted with load-in and protected part of the gear haul.</span>':'<span class="small">No helper assigned.</span>'}</div><div class="card"><h3>Business growth</h3>${cars} parked car${cars===1?'':'s'}<br>Venue revenue: <b>+$${businessRevenue}</b><br>Next budget: <b>$${Math.round(v.budget)}</b></div><div class="card"><h3>Payment status</h3>Deposit received: <b>$${deposit}</b><br>${amlTotal?`AML service fees: <b>−$${amlTotal}</b><br>`:''}Final amount owed: <b>$${invoice+promotionPayoutBonus}</b><br><span class="small">Use the Nookia phone to call the client.</span></div>${amlPromotion?`<div class="card"><h3>Poster promotion</h3>Campaign: <b>${promoResult.tier}</b><br>Posters placed: <b>${promoResult.placed}</b><br>Placement variety: <b>${promoResult.types} types • ${promoResult.districts} areas</b><br>Inventive placements: <b>${promoResult.inventive}</b><br>Normal parking increase: <b>+${normalIncrease}</b><br>Promotion bonus cars: <b>+${amlBonusCars}</b><br>Total added this show: <b>+${newCars}</b><br>Payout bonus: <b>+$${promotionPayoutBonus}</b><br>${haloBusinesses.length?`Neighborhood spillover: <b>+2 cars at ${haloBusinesses.join(', ')}</b><br>`:''}${cars>=(p.capacity||16)?'Lot full • campaign reached maximum turnout':'More varied poster placement improves the next result'}<br>Community: <b>+10</b></div>`:''}</div>${justUnlockedSponsor?`<p class="good">NEW SPONSOR EMAIL: ${p.name} reached ${p.capacity||16} cars. Open EMAIL on the Nookia to accept the sponsorship and install its banner.</p>`:''}<div class="btns"><button onclick="closeModal()">BACK TO AUSTIN</button><button class="green" onclick="openPhone()">CALL FOR PAYMENT</button></div>`)}window.finishSetup=finishSetup; const AML_BOOKING_RATE=.10,AML_PROMOTION_RATE=.05; function amlFeeFor(job){ const total=Math.max(0,Number(job&&job.total)||0); return{booking:job&&job.amlBooking?Math.round(total*AML_BOOKING_RATE):0,promotion:job&&job.amlPromotion?Math.round(total*AML_PROMOTION_RATE):0} } function amlEligibleBusinesses(){return workedBusinesses().filter(p=>unlocked(p.id))} function amlServiceSummary(job){ const f=amlFeeFor(job),parts=[]; if(job&&job.amlBooking)parts.push(`Booking 10%: $${f.booking}`); if(job&&job.amlPromotion)parts.push(`Promotion 5%: $${f.promotion}<br>Double parking growth active until this lot fills`); return parts.length?parts.join('<br>'):'No AML service attached.' } function openAustinMusicLove(){ const current=state.pendingOffer||state.activeJob; if(current){ const p=places.find(x=>x.id===current.id),canPromote=!current.amlPromotion; return modal(`<h2>AUSTIN MUSIC LOVE</h2><p><b>BOOKING • PROMOTION • EVENT SUPPORT</b></p><div class="card"><h3>${p?p.name:'CURRENT SHOW'}</h3>${amlServiceSummary(current)}<p>Promotion stays active for this business’s current parking cycle. Each promoted show doubles the normal car increase from the lot’s current total until the lot becomes full. The 5% fee applies to each promoted show.</p><button class="green" onclick="hireAMLPromotion()" ${canPromote?'':'disabled'}>${canPromote?'ADD PROMOTION • 5%':'PROMOTION ALREADY HIRED'}</button></div><div class="btns"><button class="secondary" onclick="openPhone()">BACK TO CONTACTS</button></div>`) } if(!firstCycleComplete())return modal(`<h2>AUSTIN MUSIC LOVE</h2><p>AML booking services unlock after the active Austin founding businesses are complete.</p><div class="btns"><button class="secondary" onclick="openPhone()">BACK</button></div>`); const clients=amlEligibleBusinesses(); const cards=clients.map(p=>`<div class="card"><h3>${p.name}</h3><p>AML can handle the booking, or book and promote the full event.</p><div class="btns"><button onclick="hireAMLBooking('${p.id}',false)">BOOKING • 10%</button><button class="green" onclick="hireAMLBooking('${p.id}',true)">BOOK + PROMOTE • 15%</button></div></div>`).join(''); modal(`<h2>AUSTIN MUSIC LOVE</h2><p>Hire AML to reduce booking and promotion pressure. Booking and promotion remain separate. Promotion doubles normal parking growth until the current lot fills. Fees are deducted from each show’s final payment.</p><div class="grid">${cards||'<div class="card">Complete a business show to add it to AML’s client options.</div>'}</div><div class="btns"><button class="secondary" onclick="openPhone()">BACK TO CONTACTS</button></div>`) } window.openAustinMusicLove=openAustinMusicLove; window.hireAMLBooking=(id,promote=false)=>{ if(state.activeJob||state.pendingOffer)return toast('Finish the current booking first.'); if(!firstCycleComplete())return toast('Complete the Austin founding cycle first.'); if(!amlEligibleBusinesses().some(p=>p.id===id))return toast('That client is not available to AML.'); const offer=buildOffer(id);if(!offer||offer.id!==id)return toast('AML could not create this booking. Reload and try again.');offer.amlBooking=true;offer.amlPromotion=!!promote||!!state.venues[id].amlPromotionActive;if(promote)state.venues[id].amlPromotionActive=true;state.pendingOffer=offer; state.amlStats.bookings++;if(promote)state.amlStats.promotions++; save();hud();closeModal();toast(promote?'AML BOOKED + PROMOTED THE SHOW':'AML BOOKED THE SHOW');openEmail() }; window.hireAMLPromotion=()=>{ const job=state.pendingOffer||state.activeJob;if(!job)return toast('No current show is available for promotion.'); if(job.amlPromotion)return toast('AML promotion is already attached.'); job.amlPromotion=true;job.posterCampaign=job.posterCampaign||{placed:[]};state.venues[job.id].amlPromotionActive=true;state.amlStats.promotions++;save();hud();toast('AML PROMOTION ACTIVE • PLACE POSTERS AROUND TOWN BEFORE LOAD-IN');openAustinMusicLove() }; function rentalMissingItems(job=state.activeJob){ const out={};if(!job)return out; for(const [k,n0] of Object.entries(ensureEquipmentManifest(job))){ const n=Number(n0)||0;if(!n)continue; const have=(state.inventory[k]||0)+((job.rentals&&job.rentals[k])||0); if(have<n)out[k]=n-have; } return out } function rentalPurchaseValue(items){let total=0;for(const[k,n0]of Object.entries(items||{})){const n=Math.max(0,Number(n0)||0);total+=gearPurchaseCost(k)*n}return total} function rentalQuote(items){return Number((rentalPurchaseValue(items)*0.25).toFixed(2))} function rentalMoney(n){const value=Number(n)||0;return value.toLocaleString(undefined,{minimumFractionDigits:Number.isInteger(value)?0:2,maximumFractionDigits:2})} function availableGearUnits(job,k){return (state.inventory[k]||0)+((job&&job.rentals&&job.rentals[k])||0)} function availableStageSlots(job,k){return availableGearUnits(job,k)} window.callRockNRollRentals=()=>{ const j=state.activeJob;if(!j)return toast('No confirmed show currently needs equipment.'); const missing=rentalMissingItems(j);if(!Object.keys(missing).length)return toast('You already have all equipment required for this show.'); if(state.rentalOrder)return toast(state.rentalOrder.status==='delivered'?'Your rental order is waiting at Gig Bag ATX.':'A rental order is already active.'); const cost=rentalQuote(missing);if(state.cash<cost)return toast(`Rock N Roll Rentals requires $${rentalMoney(cost)}.`); debitCash(cost,'Rentals','Rock N Roll Rentals order',{vendor:'ROCK N ROLL RENTALS',businessPurpose:'Required rental equipment delivered for the active Vancerts show.',deductiblePct:100,jobId:showJobId(j)});state.rentalOrder={items:missing,cost,status:'delivered',jobId:j.created||j.id,created:Date.now()};save();hud();openPhone();toast('Rock N Roll Rentals delivered the order to Gig Bag ATX.') }; window.pickupRentalOrder=()=>{ const j=state.activeJob,o=state.rentalOrder;if(!j||!o||o.status!=='delivered')return toast('No rental order is waiting.'); j.rentals=Object.assign({},j.rentals||{},o.items||{});j.wrecked=false;state.rentalOrder=null;save();hud();shopModal();toast('Rental equipment picked up at Gig Bag ATX.') }; window.callTowService=()=>{ if(state.vanhp>0)return toast('Tow service is only needed when the van is disabled.'); if(state.cash<299)return toast('Austin Tow Service costs $299.'); debitCash(299,'Towing','Austin Tow Service',{vendor:'AUSTIN TOW SERVICE',businessPurpose:'Business vehicle towing after the Vancerts van became disabled.',deductiblePct:100,paymentMethod:'VANCERTS BUSINESS FUNDS'});van.x=BYOB_REPAIR.x;van.y=BYOB_REPAIR.y;van.angle=BYOB_REPAIR.angle;van.speed=0;save();hud();closeModal();hqModal();toast('Austin Tow Service brought the van to BYOB Austin. Repair it in the garage.') }; function openPhone(){ const contacts=workedBusinesses(),done=workedBusinessIds(),unpaid=state.invoices.filter(i=>!i.paid&&done.has(i.venueId||places.find(p=>p.name===i.venue)?.id)); const j=state.activeJob,missing=rentalMissingItems(j),missingText=Object.entries(missing).map(([k,n])=>`${n} ${k}`).join(', '),quote=rentalQuote(missing); const emergencyWaygo=emergencyWaygoAvailable()?`<div class="card" style="border-color:#3f84a5"><h3>EMERGENCY WAYGO</h3><b>COMMUNITY LAST-RIDE SERVICE</b><p>Your van is disabled and you cannot afford the tow. A free Waygo can take you to Vancerts Bank.</p><button class="green" onclick="callEmergencyWaygo()">CALL FREE WAYGO TO BANK</button></div>`:''; const waygoService=`<div class="card" style="border-color:#f1b83e"><h3>WAYGO</h3><b>ALWAYS AVAILABLE • $1 PER MAP INCH</b><p>Choose an open business, see the fare before booking, and travel without resetting your mission, radio, phone, or progress.</p><button onclick="openWaygo()">OPEN WAYGO</button></div>`; const staffService=`<div class="card" style="border-color:#315d3b"><h3>VANCERTS TEAM</h3><b>CAREER PATHS • CREW • PAYROLL</b><p>Choose Owner, Team Member, or Band mode; manage the real three-person VANCERTS crew; and track payroll and crew-meal receipts. His plain white pickup carries only a removable VANCERTS logo magnet.</p><button class="green" onclick="openStaffManager()">OPEN TEAM</button></div>`; const expenseService=`<div class="card" style="border-color:#b78415"><h3>EXPENSE TRACKER</h3><b>RECEIPTS • DEDUCTIONS • COST ESTIMATES</b><p>See gas, food, payroll, equipment, deposits, final payments, business purpose, and the educational tax treatment for each record.</p><button onclick="openExpenseTracker()">OPEN RECEIPTS</button></div>`; const services=`${waygoService}${emergencyWaygo}${staffService}${expenseService}<div class="card"><h3>AUSTIN MUSIC LOVE</h3><b>BOOKING • PROMOTION</b><p>Booking is 10% and secures the client. Promotion is 5% per promoted show. Drive around town and place posters before load-in. More posters, more districts, and closed-business placements create stronger turnout, payout bonuses, and rare neighborhood spillover.</p><button class="green" onclick="openAustinMusicLove()">OPEN AML SERVICES</button></div><div class="card"><h3>AUSTIN TOW SERVICE</h3><b>ALWAYS AVAILABLE</b><p>Disabled van pickup to BYOB Austin: <b>$299</b>.</p><button onclick="callTowService()" ${state.vanhp>0||state.cash<299?'disabled':''}>CALL TOW TRUCK • $299</button></div><div class="card"><h3>ROCK N ROLL RENTALS</h3><b>ALWAYS AVAILABLE</b><p>${state.rentalOrder?'Order delivered to Gig Bag ATX. Go there to pick it up.':missingText?`Missing for current show: <b>${missingText}</b><br>Delivery quote: <b>$${rentalMoney(quote)}</b> — exactly 25% of the purchase value of the missing required equipment.`:'No missing equipment for the current show.'}</p><button onclick="callRockNRollRentals()" ${!missingText||!!state.rentalOrder||state.cash<quote?'disabled':''}>CALL & DELIVER TO GIG BAG${missingText?` • $${rentalMoney(quote)}`:''}</button></div>`; const businesses=contacts.length?contacts.map(p=>{const bills=unpaid.filter(i=>(i.venueId||places.find(x=>x.name===i.venue)?.id)===p.id);return `<div class="card"><h3>${p.name}</h3><b>${p.phone||'PUBLIC NUMBER UNAVAILABLE'}</b><p>${bills.length?bills.map(i=>`<b>$${i.amount} owed</b><div class="btns"><button class="green" onclick="collectInvoice(${i.id})">CALL & COLLECT</button></div>`).join(''):'<span class="small">No payment currently due.</span>'}</p>${firstCycleComplete()?`<button onclick="callToBook('${p.id}')" ${state.activeJob||state.pendingOffer?'disabled':''}>CALL TO BOOK NEXT SHOW</button>`:''}</div>`}).join(''):'<div class="card"><h3>NO BUSINESS CONTACTS YET</h3>Complete your first business gig to add its number.</div>'; modal(`<h2>NOOKIA CONTACTS</h2><p>Waygo, team, receipts, AML, tow, and rental services are always available from the Nookia. Business contacts unlock after completed shows.</p><div class="grid">${services}${businesses}</div><div class="btns"><button class="secondary" onclick="closeModal()">CLOSE PHONE</button></div>`) } window.openPhone=openPhone; window.callToBook=id=>{if(!firstCycleComplete())return toast('Complete all active first-cycle businesses before phone booking unlocks.');if(!workedBusinessIds().has(id))return toast('That contact is not unlocked.');closeModal();createOffer(id,'call')}; window.collectInvoice=id=>{const i=state.invoices.find(x=>x.id===id);if(!i||i.paid)return;const venueId=i.venueId||places.find(p=>p.name===i.venue)?.id;if(!workedBusinessIds().has(venueId))return toast('That business is not in your contacts yet.');i.paid=true;creditCash(i.amount,'Show Payments',`${i.venue||'Client'} final payment`,{vendor:i.venue||'CLIENT',businessPurpose:`Final client payment collected after the ${i.venue||'Vancerts'} show.`,jobId:String(i.id),paymentMethod:'CLIENT PAYMENT'});save();hud();toast(`$${i.amount} payment received • receipt filed.`);openPhone()}; document.querySelectorAll('.phoneKeys [data-dial]').forEach(button=>button.addEventListener('click',e=>{appendPhoneDigit(button.dataset.dial);e.preventDefault();e.stopPropagation()})); $('phoneCall').onclick=executePhoneCode; $('phoneWaygo')?.addEventListener('click',openWaygo); function openResetPrompt(){if(phoneDialBuffer)return clearPhoneDial();if(portableMode)return modal(`<h2>RETURN TO COMPUTER SAVE?</h2><p>The loaded portable game will close. This computer's hard save will reopen unchanged.</p><div class="btns"><button class="red" onclick="resetGame()">RETURN TO COMPUTER SAVE</button><button class="secondary" onclick="closeModal()">CANCEL</button></div>`);modal(`<h2>RESET STORY?</h2><p>This will erase this computer's hard save and restart the story.</p><div class="btns"><button class="red" onclick="resetGame()">YES, RESET</button><button class="secondary" onclick="closeModal()">CANCEL</button></div>`)} $('phoneReset').onclick=toggleTrainingWheels; $('phoneDialerApp').onclick=openDialer; $('phoneWallet').onclick=driverPassModal; $('phoneContacts').onclick=openPhone; $('phoneEmailApp').onclick=openEmail; $('phoneRadioApp').onclick=openRadioApp; $('phoneStaffApp').onclick=openStaffManager; $('phoneLedgerApp').onclick=openExpenseTracker; $('phoneWaygoApp').onclick=openWaygo; $('phoneBankApp').onclick=bankModal; $('phoneSettingsApp').onclick=openSaveLoadApp; const phoneResetApp=$('phoneResetApp');if(phoneResetApp)phoneResetApp.onclick=openResetPrompt; const DEVICE_LAYOUT_KEY='vancerts-device-layout-session-v8'; const PREVIOUS_DEVICE_LAYOUT_KEY='vancerts-device-layout-session-v7'; function deviceOrientation(){return innerWidth>=innerHeight?'landscape':'portrait'} let parentViewportClip=null; function visibleViewportRect(){ const v=window.visualViewport,doc=document.documentElement; let left=Math.round(v?v.offsetLeft:0),top=Math.round(v?v.offsetTop:0),right=left+Math.round(v?v.width:innerWidth),bottom=top+Math.round(v?v.height:innerHeight); right=Math.min(right,Math.max(1,doc.clientWidth||innerWidth));bottom=Math.min(bottom,Math.max(1,doc.clientHeight||innerHeight)); if(parentViewportClip){const baseW=Math.max(1,innerWidth),baseH=Math.max(1,innerHeight);left=Math.max(left,parentViewportClip.left*baseW);top=Math.max(top,parentViewportClip.top*baseH);right=Math.min(right,parentViewportClip.right*baseW);bottom=Math.min(bottom,parentViewportClip.bottom*baseH)} if(right<=left||bottom<=top)return{left:0,top:0,width:Math.max(1,doc.clientWidth||innerWidth),height:Math.max(1,doc.clientHeight||innerHeight)}; return{left:Math.round(left),top:Math.round(top),width:Math.max(1,Math.round(right-left)),height:Math.max(1,Math.round(bottom-top))} } function readDeviceLayouts(){try{const existing=sessionStorage.getItem(DEVICE_LAYOUT_KEY);if(existing){const x=JSON.parse(existing);return x&&typeof x==='object'?x:{}}const previous=JSON.parse(sessionStorage.getItem(PREVIOUS_DEVICE_LAYOUT_KEY)||'{}'),migrated={};for(const orientation of ['portrait','landscape'])if(previous?.[orientation]?.phone)migrated[orientation]={phone:previous[orientation].phone};sessionStorage.setItem(DEVICE_LAYOUT_KEY,JSON.stringify(migrated));return migrated}catch(_){return{}}} function writeDeviceLayouts(){try{sessionStorage.setItem(DEVICE_LAYOUT_KEY,JSON.stringify(deviceLayouts))}catch(_){}} const deviceLayouts=readDeviceLayouts(); function deviceState(el){return el.classList.contains('collapsed')?'collapsed':'expanded'} function setDeviceXY(el,x,y){el.classList.add('deviceReliable');el.style.setProperty('left',Math.round(x)+'px','important');el.style.setProperty('top',Math.round(y)+'px','important');el.style.setProperty('right','auto','important');el.style.setProperty('bottom','auto','important');el.style.setProperty('transform','scale(var(--device-fit-scale,1))','important');el.style.setProperty('transform-origin','top left','important')} function fitDeviceToViewport(el){ if(!el)return 1;el.style.setProperty('--device-fit-scale','1');el.style.setProperty('transform','scale(1)','important');el.style.setProperty('transform-origin','top left','important'); if(el.classList.contains('collapsed'))return 1; const v=visibleViewportRect(),r=el.getBoundingClientRect(),m=7,availableW=Math.max(44,v.width-m*2),availableH=Math.max(40,v.height-m*2),scale=Math.max(.52,Math.min(1,availableW/Math.max(44,r.width),availableH/Math.max(40,r.height))); el.style.setProperty('--device-fit-scale',String(scale));el.style.setProperty('transform','scale(var(--device-fit-scale,1))','important');return scale } function clampDevice(el,x,y){const v=visibleViewportRect(),r=el.getBoundingClientRect(),m=7,w=Math.max(44,r.width),h=Math.max(40,r.height);return{x:Math.max(v.left+m,Math.min(v.left+v.width-w-m,x)),y:Math.max(v.top+m,Math.min(v.top+v.height-h-m,y))}} function rectAt(el,p){const r=el.getBoundingClientRect(),w=Math.max(44,r.width),h=Math.max(40,r.height);return{left:p.x,top:p.y,right:p.x+w,bottom:p.y+h,width:w,height:h}} function overlaps(a,b,pad=7){return a.left<b.right+pad&&a.right>b.left-pad&&a.top<b.bottom+pad&&a.bottom>b.top-pad} function shownRect(node){if(!node||getComputedStyle(node).display==='none'||getComputedStyle(node).visibility==='hidden')return null;return node.getBoundingClientRect()} function deviceObstacleRects(el){ const nodes=[document.querySelector('.mobileDrive'),document.querySelector('.mobileSteer'),$('objective'),document.querySelector('.controlBar'),document.querySelector('.stats'),$('mobileDonut')].filter(Boolean); const other=el.id==='phone'?$('rotaryRadio'):$('phone');if(other&&!other.classList.contains('deviceSuppressed'))nodes.push(other); return nodes.map(shownRect).filter(Boolean) } function devicePositionSafe(el,p,pad=7){const r=rectAt(el,p),v=visibleViewportRect();if(r.left<v.left||r.top<v.top||r.right>v.left+v.width||r.bottom>v.top+v.height)return false;return !deviceObstacleRects(el).some(o=>overlaps(r,o,pad))} function nearestSafePosition(el,p){ const start=clampDevice(el,p.x,p.y);if(devicePositionSafe(el,start))return start; const v=visibleViewportRect(),r=el.getBoundingClientRect(),w=Math.max(44,r.width),h=Math.max(40,r.height),step=18; for(let radius=step;radius<Math.max(v.width,v.height);radius+=step){ const candidates=[ {x:start.x-radius,y:start.y},{x:start.x+radius,y:start.y},{x:start.x,y:start.y-radius},{x:start.x,y:start.y+radius}, {x:start.x-radius,y:start.y-radius},{x:start.x+radius,y:start.y-radius},{x:start.x-radius,y:start.y+radius},{x:start.x+radius,y:start.y+radius} ]; for(const c of candidates){const q=clampDevice(el,c.x,c.y);if(devicePositionSafe(el,q))return q} } return start } function saveDevicePosition(el){const o=deviceOrientation(),s=deviceState(el),r=el.getBoundingClientRect();deviceLayouts[o]??={};deviceLayouts[o][el.id]??={};deviceLayouts[o][el.id][s]={x:Math.round(r.left),y:Math.round(r.top)};writeDeviceLayouts()} function storedDevicePosition(el,s){const p=deviceLayouts[deviceOrientation()]?.[el.id]?.[s];if(!p||!Number.isFinite(p.x)||!Number.isFinite(p.y))return null;const q=clampDevice(el,p.x,p.y);return devicePositionSafe(el,q)?q:null} function topClearance(){const v=visibleViewportRect(),stats=shownRect(document.querySelector('.stats')),bar=shownRect(document.querySelector('.controlBar'));return Math.max(v.top+8,stats?.bottom||0,bar?.bottom||0)+8} function dockCandidates(el){ const v=visibleViewportRect(),r=el.getBoundingClientRect(),w=Math.max(44,r.width),h=Math.max(40,r.height),m=9,top=topClearance(); const drive=shownRect(document.querySelector('.mobileDrive')),steer=shownRect(document.querySelector('.mobileSteer')),objective=shownRect($('objective')); const right=v.left+v.width-w-m,left=v.left+m,center=v.left+(v.width-w)/2,bottom=v.top+v.height-h-m; const aboveDrive=(drive?.top||v.top+v.height)-h-12,aboveSteer=(steer?.top||v.top+v.height)-h-12; const lower=Math.min(aboveDrive,aboveSteer,(objective?.top||v.top+v.height)-h-12); const second=top+h+10; const preferred=el.id==='phone'? [{x:right,y:top},{x:right,y:second},{x:left,y:top},{x:right,y:lower},{x:left,y:lower}]: [{x:center,y:bottom},{x:center+24,y:bottom},{x:center,y:lower},{x:right,y:lower},{x:left,y:lower},{x:right,y:second},{x:left,y:top}]; return preferred.map(p=>clampDevice(el,p.x,p.y)) } function safeDockPosition(el){for(const p of dockCandidates(el))if(devicePositionSafe(el,p))return p;return nearestSafePosition(el,dockCandidates(el)[0])} function defaultExpanded(el){const v=visibleViewportRect(),r=el.getBoundingClientRect(),w=Math.max(44,r.width),h=Math.max(40,r.height),top=topClearance();if(el.id==='phone')return{x:v.left+v.width-w-9,y:top};return{x:v.left+Math.max(8,(v.width-w)/2),y:Math.max(top,v.top+v.height-h-12)}} function containDeviceInViewport(el){if(!el||el.classList.contains('vcQueueTube')||el.classList.contains('hidden')||getComputedStyle(el).display==='none')return;fitDeviceToViewport(el);const r=el.getBoundingClientRect(),q=clampDevice(el,r.left,r.top);if(Math.abs(q.x-r.left)>.5||Math.abs(q.y-r.top)>.5)setDeviceXY(el,q.x,q.y)} function scheduleDeviceContainment(el){for(const delay of [0,40,120,320,760,1400])setTimeout(()=>containDeviceInViewport(el),delay)} function positionCollapsed(el,useSaved=true){el.style.setProperty('--device-fit-scale','1');requestAnimationFrame(()=>{const p=(useSaved&&storedDevicePosition(el,'collapsed'))||safeDockPosition(el);const q=nearestSafePosition(el,p);setDeviceXY(el,q.x,q.y);scheduleDeviceContainment(el)})} function positionExpanded(el,useSaved=true){ const p=(useSaved&&storedDevicePosition(el,'expanded'))||defaultExpanded(el); requestAnimationFrame(()=>requestAnimationFrame(()=>{fitDeviceToViewport(el);let q=clampDevice(el,p.x,p.y);q=nearestSafePosition(el,q);setDeviceXY(el,q.x,q.y);scheduleDeviceContainment(el);setTimeout(()=>{if(el.classList.contains('collapsed'))return;fitDeviceToViewport(el);const r=el.getBoundingClientRect(),z=nearestSafePosition(el,{x:r.left,y:r.top});setDeviceXY(el,z.x,z.y);scheduleDeviceContainment(el)},120)})) } function collapseReliable(el,button,useSaved=true){saveDevicePosition(el);el.classList.add('collapsed');button.textContent='▴';button.setAttribute('aria-expanded','false');const other=el.id==='phone'?$('rotaryRadio'):$('phone');if(other)other.classList.remove('deviceSuppressed');positionCollapsed(el,useSaved);scheduleDeviceContainment(el)} function expandReliable(el,button,other,otherButton){saveDevicePosition(el);if(matchMedia('(pointer:coarse)').matches&&other){if(!other.classList.contains('collapsed'))collapseReliable(other,otherButton,true);other.classList.add('deviceSuppressed')}el.classList.remove('collapsed');button.textContent='▾';button.setAttribute('aria-expanded','true');fitDeviceToViewport(el);positionExpanded(el,true);scheduleDeviceContainment(el)} function toggleReliable(el,button,other,otherButton){if(el.id==='rotaryRadio'&&radioPhoneAppMode){closeRadioApp();return}if(el.classList.contains('collapsed'))expandReliable(el,button,other,otherButton);else collapseReliable(el,button,true)} function finishDeviceDrag(el){const r=el.getBoundingClientRect(),p=nearestSafePosition(el,{x:r.left,y:r.top});setDeviceXY(el,p.x,p.y);saveDevicePosition(el)} function installReliableDevice(elId,buttonId,handleSelector,otherId,otherButtonId){ const el=$(elId),button=$(buttonId),handle=el?.querySelector(handleSelector),other=$(otherId),otherButton=$(otherButtonId);if(!el||!button||!handle)return; el.classList.add('deviceReliable');let drag=null,suppressClick=false; const begin=(e,source)=>{if(e.button!=null&&e.button!==0)return;const r=el.getBoundingClientRect();drag={id:e.pointerId,startX:e.clientX,startY:e.clientY,left:r.left,top:r.top,moved:false,source};try{source.setPointerCapture(e.pointerId)}catch(_){}e.preventDefault();e.stopPropagation()}; const move=e=>{if(!drag||e.pointerId!==drag.id)return;const dx=e.clientX-drag.startX,dy=e.clientY-drag.startY;if(!drag.moved&&Math.hypot(dx,dy)<9)return;drag.moved=true;suppressClick=true;const p=clampDevice(el,drag.left+dx,drag.top+dy);setDeviceXY(el,p.x,p.y);e.preventDefault();e.stopPropagation()}; const end=e=>{if(!drag||e.pointerId!==drag.id)return;const moved=drag.moved;drag=null;if(moved)finishDeviceDrag(el);e.preventDefault();e.stopPropagation();if(moved)setTimeout(()=>suppressClick=false,80)}; handle.addEventListener('pointerdown',e=>{if(e.target.closest('button'))return;begin(e,handle)});handle.addEventListener('pointermove',move);handle.addEventListener('pointerup',end);handle.addEventListener('pointercancel',()=>{drag=null}); // When collapsed, the visible icon button is both tap-to-open and drag-to-move. button.addEventListener('pointerdown',e=>{if(el.classList.contains('collapsed'))begin(e,button);else e.stopPropagation()}); button.addEventListener('pointermove',move);button.addEventListener('pointerup',e=>{if(drag&&e.pointerId===drag.id){const moved=drag.moved;end(e);if(!moved)toggleReliable(el,button,other,otherButton)}else{e.preventDefault();e.stopPropagation();toggleReliable(el,button,other,otherButton)}});button.addEventListener('pointercancel',()=>{drag=null}); button.addEventListener('click',e=>{e.preventDefault();e.stopPropagation();if(suppressClick){suppressClick=false;return}if(e.detail===0)toggleReliable(el,button,other,otherButton)}); } function loadDevicePositions(){for(const el of [$('phone'),$('rotaryRadio')].filter(el=>el&&!el.classList.contains('vcQueueTube'))){el.classList.add('deviceReliable');if(el.classList.contains('hidden')||getComputedStyle(el).display==='none')continue;fitDeviceToViewport(el);if(el.classList.contains('collapsed'))positionCollapsed(el,true);else positionExpanded(el,true);scheduleDeviceContainment(el)}} function resetDeviceLayout(){for(const k of Object.keys(deviceLayouts))delete deviceLayouts[k];writeDeviceLayouts();for(const el of [$('phone'),$('rotaryRadio')].filter(Boolean)){if(el.classList.contains('collapsed'))positionCollapsed(el,false);else positionExpanded(el,false)}toast('PHONE & 512 JAMS POSITIONS RESET')} window.resetDeviceLayout=resetDeviceLayout; installReliableDevice('phone','phoneCollapse','.phoneTop','rotaryRadio','radioCollapse'); installReliableDevice('rotaryRadio','radioCollapse','.radioTop','phone','phoneCollapse'); installZoomDial(); let deviceRelayoutTimer=0; function refreshDeviceLayout(){clearTimeout(deviceRelayoutTimer);deviceRelayoutTimer=setTimeout(loadDevicePositions,90)} function scheduleLandscapeReset(force=false){clearTimeout(deviceRelayoutTimer);deviceRelayoutTimer=setTimeout(loadDevicePositions,force?30:120)} window.addEventListener('resize',refreshDeviceLayout,{passive:true}); window.addEventListener('orientationchange',()=>setTimeout(refreshDeviceLayout,180),{passive:true}); if(window.visualViewport){visualViewport.addEventListener('resize',refreshDeviceLayout,{passive:true});visualViewport.addEventListener('scroll',refreshDeviceLayout,{passive:true})} window.addEventListener('message',e=>{const d=e.data;if(!d||d.type!=='vancerts-visible-frame')return;const values=[d.left,d.top,d.right,d.bottom].map(Number);if(values.every(Number.isFinite)&&values[2]>values[0]&&values[3]>values[1]){parentViewportClip={left:Math.max(0,Math.min(1,values[0])),top:Math.max(0,Math.min(1,values[1])),right:Math.max(0,Math.min(1,values[2])),bottom:Math.max(0,Math.min(1,values[3]))};refreshDeviceLayout()}}); if(typeof ResizeObserver!=='undefined'){const deviceBoundsObserver=new ResizeObserver(entries=>entries.forEach(entry=>scheduleDeviceContainment(entry.target)));for(const el of [$('phone'),$('rotaryRadio')].filter(Boolean))deviceBoundsObserver.observe(el)} // R36B52A: retired the recurring device snap-back loop. let canvasTouchStart=null;canvas.addEventListener('pointerdown',e=>{if(e.pointerType==='touch'||matchMedia('(pointer:coarse)').matches)canvasTouchStart={x:e.clientX,y:e.clientY,t:performance.now()}},{passive:true});canvas.addEventListener('pointerup',e=>{if(!canvasTouchStart)return;const d=Math.hypot(e.clientX-canvasTouchStart.x,e.clientY-canvasTouchStart.y),elapsed=performance.now()-canvasTouchStart.t;canvasTouchStart=null;if(d<18&&elapsed<550&&near&&Math.abs(van.speed)<.7)interact()},{passive:true}); let gameFullscreenActive=false,fullscreenLaunchPending=false,gameLaunchComplete=false,fullscreenLaunchTimer=0; function syncVisibleViewport(){const vv=window.visualViewport,w=Math.round(vv?vv.width:innerWidth),h=Math.round(vv?vv.height:innerHeight);document.documentElement.style.setProperty('--app-vw',w+'px');document.documentElement.style.setProperty('--app-vh',h+'px');if(gameFullscreenActive){const c=$('game');if(c){c.style.width=w+'px';c.style.height=h+'px'}}setTimeout(resize,30)} function setFullscreenUi(active){gameFullscreenActive=!!active;document.documentElement.classList.toggle('mobileFullscreen',gameFullscreenActive);document.body.classList.toggle('mobileFullscreen',gameFullscreenActive);const a=$('fullscreenToggle'),p=$('phoneFullscreenApp'),b=$('landscapeToggle');if(a){a.classList.toggle('active',gameFullscreenActive);a.textContent=gameFullscreenActive?'EXIT FULLSCREEN':'FULLSCREEN'}if(p){p.classList.remove('active');p.classList.add('resetGameApp');p.innerHTML='<span>×</span>RESET GAME';p.setAttribute('aria-label','Reset game')}if(b){b.classList.toggle('active',gameFullscreenActive);b.textContent=gameFullscreenActive?'× EXIT':'⛶ FULLSCREEN'}if(gameFullscreenActive&&matchMedia('(pointer:coarse)').matches){requestAnimationFrame(()=>{const ph=$('phone');if(ph){ph.classList.remove('deviceSuppressed');containDeviceInViewport(ph)}})}syncVisibleViewport();setTimeout(()=>{resize();loadDevicePositions()},120)} function notifyParentFullscreen(action){try{window.parent.postMessage({type:'vancerts-fullscreen',action},'*')}catch(e){}} async function enterLandscape(){const wantsExit=gameFullscreenActive||document.fullscreenElement||document.webkitFullscreenElement;if(wantsExit){try{if(document.exitFullscreen)await document.exitFullscreen();else if(document.webkitExitFullscreen)document.webkitExitFullscreen()}catch(e){}notifyParentFullscreen('exit');setFullscreenUi(false);return}setFullscreenUi(true);notifyParentFullscreen('enter');try{const el=document.documentElement,fn=el.requestFullscreen||el.webkitRequestFullscreen;if(fn&&!document.fullscreenElement&&!document.webkitFullscreenElement)await fn.call(el)}catch(e){}try{if(screen.orientation&&screen.orientation.lock)await screen.orientation.lock('landscape')}catch(e){}$('rotateHint')?.classList.add('hiddenByUser');setTimeout(resize,220)} const landscapeToggle=$('landscapeToggle');if(landscapeToggle)landscapeToggle.onclick=enterLandscape; window.addEventListener('message',e=>{if(e.data&&e.data.type==='vancerts-fullscreen-state'){const active=!!e.data.active;setFullscreenUi(active);if(active&&fullscreenLaunchPending)completeFullscreenLaunch()}}); window.addEventListener('resize',syncVisibleViewport,{passive:true});if(window.visualViewport){visualViewport.addEventListener('resize',syncVisibleViewport,{passive:true});visualViewport.addEventListener('scroll',syncVisibleViewport,{passive:true})} ['fullscreenchange','webkitfullscreenchange'].forEach(evt=>document.addEventListener(evt,()=>{const active=!!(document.fullscreenElement||document.webkitFullscreenElement);if(active){setFullscreenUi(true);if(fullscreenLaunchPending)completeFullscreenLaunch()}})); addEventListener('orientationchange',()=>setTimeout(resize,220)); function offerEmailCard(){if(!state.pendingOffer)return'';const o=state.pendingOffer,p=places.find(x=>x.id===o.id),v=state.venues[o.id];if(!p||!v){state.pendingOffer=null;save();return `<div class="card"><h3>BOOKING RECOVERED</h3><p class="bad">An incomplete saved booking was removed safely. Return to CONTACTS and book the client again.</p></div>`}recalcOffer(o);const pkg=o.pkg==='band'?BAND:SOLO,gear=Object.entries(o.needs).filter(([,n])=>n).map(([k,n])=>`${n} ${k}`).join(', ')||'No production gear',rate=(crowdMultiplier(o.id)-1)*100,over=o.total>v.budget,aml=o.amlBooking||o.amlPromotion?`<p><b>AUSTIN MUSIC LOVE</b><br>${amlServiceSummary(o)}</p>`:'',fitNote=o.autoFitMessage?`<p class="${over?'bad':'good'}"><b>AUTO-FIT:</b> ${o.autoFitMessage}</p>`:'';return `<div class="card"><h3>FROM: ${p.name}</h3><b>EQUIPMENT LIST / DATE HOLD</b><p>Performer: ${pkg.name} — $${pkg.bandCost}<br>Van operator: $300<br>Approved gear: ${gear}</p>${aml}<p>Parking-lot budget growth: <b>+${Math.round(rate)}%</b><br><span class="small">Cars increase future venue budgets. They do not change item prices.</span><br>Total approved cost: <b>$${o.total}</b><br>Venue budget: <b>$${Math.round(v.budget)}</b><br>Deposit required: <b>$${o.deposit}</b></p><div class="btns"><button onclick="editGearList()">EDIT GEAR LIST</button><button onclick="autoFitPendingOffer()">AUTO-FIT BUDGET</button></div><button class="green" onclick="confirmOffer()" ${over?'disabled':''}>COLLECT DEPOSIT & CONFIRM DATE</button>${fitNote}${over?'<p class="bad">This draft is over budget. Use Auto-Fit or edit the equipment list before confirming.</p>':'<p class="good">This package fits the venue budget at fixed performer, labor and equipment prices.</p>'}</div>`} window.autoFitPendingOffer=()=>{if(!state.pendingOffer)return;const result=fitOfferToBudget(state.pendingOffer);save();openEmail();setTimeout(()=>toast(result.changed?'Auto-Fit selected the strongest package within budget.':'This package is already the strongest fit for this budget.'),60)}; function gearEditorHtml(){const o=state.pendingOffer;if(!o)return'';recalcOffer(o);const v=state.venues[o.id],minimum=minimumOfferTotal(o.id,'solo');return `<h2>EDIT EQUIPMENT LIST</h2><p><b>${places.find(p=>p.id===o.id).name}</b> can spend $${Math.round(v.budget)}. The current show total is <b class="${o.total<=v.budget?'good':'bad'}">$${o.total}</b>.</p><div class="card"><h3>PERFORMER</h3><div class="btns"><button class="${o.pkg==='solo'?'green':''}" onclick="setOfferPackage('solo')">SOLO ACT • $100</button><button class="${o.pkg==='band'?'green':''}" onclick="setOfferPackage('band')">FULL BAND • $300</button></div></div><div class="grid">${Object.entries(OFFER_LIMITS).map(([k,max])=>`<div class="card"><h3>${k.toUpperCase()}</h3><div class="btns"><button onclick="changeOfferGear('${k}',-1)" ${(o.needs[k]||0)<=(k==='main'?2:0)?'disabled':''}>−</button><b style="font-size:24px;padding:8px">${o.needs[k]||0}</b><button onclick="changeOfferGear('${k}',1)" ${(o.needs[k]||0)>=max?'disabled':''}>+</button></div><span class="small">$${prices[k]} each • fixed price</span></div>`).join('')}</div><p><b>Required minimum:</b> one performer, the $300 van operator and two mains. Auto-Fit never discounts or removes required costs. Cars grow future venue budgets instead of inflating prices.</p>${v.budget<minimum?`<p class="bad">This client needs at least $${minimum} to book the minimum solo show.</p>`:''}<div class="btns"><button class="green" onclick="saveGearEdit()" ${o.total>v.budget?'disabled':''}>SAVE APPROVED LIST</button><button onclick="autoFitPendingOffer();editGearList()">AUTO-FIT BUDGET</button><button class="secondary" onclick="openEmail()">BACK TO EMAIL</button></div>`} window.editGearList=()=>modal(gearEditorHtml()); window.setOfferPackage=type=>{const o=state.pendingOffer;if(!o)return;const before=o.pkg;o.pkg=type;o.needs={...o.needs,main:Math.max(2,o.needs?.main||0)};recalcOffer(o);const v=state.venues[o.id];if(o.total>v.budget&&minimumOfferTotal(o.id,type)>v.budget){o.pkg=before;recalcOffer(o);toast(`${type==='band'?'Full band':'Solo act'} plus the minimum PA is above this budget.`)}save();editGearList()}; window.changeOfferGear=(k,d)=>{const o=state.pendingOffer;if(!o)return;const floor=k==='main'?2:0,before=o.needs[k]||0;o.needs[k]=Math.max(floor,Math.min(OFFER_LIMITS[k],before+d));recalcOffer(o);const v=state.venues[o.id];if(d>0&&o.total>v.budget){o.needs[k]=before;recalcOffer(o);toast('That item would put the venue over budget at its fixed price.')}else if(d<0&&k==='main'&&before<=2)toast('Every show requires a two-main PA system.');save();editGearList()}; window.saveGearEdit=()=>{const o=state.pendingOffer;if(!o)return;recalcOffer(o);if(o.total>state.venues[o.id].budget)return toast('This package is still over budget.');if((o.needs.main||0)<2)return toast('Every show requires two mains.');save();openEmail();toast('Edited equipment list saved at fixed prices.')}; function sponsorEmailCards(){const eligible=eligibleSponsorBusinesses();return eligible.map(p=>`<div class="card" style="border-color:#f1b83e;box-shadow:4px 4px 0 #111"><h3>NEW SPONSOR OFFER: ${p.name}</h3><p>This business reached <b>${p.capacity||16} permanent cars</b> and wants to sponsor Vancerts.</p><p>Accepting will install its banner, add a matching banner at BYOB Austin, reset this visible parking lot to zero, and preserve every earned 10% car-rate increase.</p><p class="small">The newest active sponsor receives a 20% discount. Other clients pay 20% more. Each sponsor banner also adds one Black Star car and three starting snake segments.</p><button class="green" onclick="acceptSponsor('${p.id}')">ACCEPT SPONSOR & INSTALL BANNER</button></div>`).join('')} function openEmail(){const contacts=workedBusinesses(),offer=offerEmailCard(),sponsorOffers=sponsorEmailCards(),festival=festivalEmailCard(),festivalTwo=secondFestivalEmailCard();if(!contacts.length&&!offer&&!sponsorOffers&&!festival&&!festivalTwo)return modal(`<h2>NOOKIA EMAIL</h2><p>No business email contacts yet. Complete a gig before that business appears in your inbox.</p><div class="btns"><button onclick="closeModal()">CLOSE</button></div>`);let activeSponsor='';if(state.sponsor){const p=places.find(x=>x.id===state.sponsor);activeSponsor=`<div class="card"><h3>ACTIVE PRICING SPONSOR: ${p.name}</h3><p>This sponsor receives a 20% discount. Other businesses pay 20% more. Previously earned sponsor banners remain installed.</p></div>`}const emptyCards=!offer&&!sponsorOffers&&!festival&&!festivalTwo?contacts.map(p=>`<div class="card"><h3>${p.name}</h3><span class="small">No new equipment list or sponsor achievement.</span></div>`).join(''):'';modal(`<h2>NOOKIA EMAIL</h2>${sponsorOffers?'<p class="good"><b>NEW SPONSOR ACHIEVEMENT</b> — A client reached full parking capacity.</p>':''}<div class="grid">${festival}${festivalTwo}${sponsorOffers}${offer}${activeSponsor}${emptyCards}</div><div class="btns"><button class="secondary" onclick="closeModal()">CLOSE EMAIL</button></div>`)} window.openEmail=openEmail;window.acceptSponsor=id=>{refreshSponsorOffers();const p=places.find(x=>x.id===id&&x.type==='gig'),v=state.venues[id];if(!p||!v||permanentCars(id)<(p.capacity||16)||v.sign||!state.sponsorOffers.includes(id))return toast('This sponsor offer is not currently available.');if(!state.completed.includes(id))state.completed.push(id);state.sponsor=id;v.sign=true;v.eventCount=0;v.rateCars=0;v.lotCycleFull=false;v.flagCycleArmed=flagEraActive()&&(Number(v.fillFlags)||0)<3;state.sponsorOffers=state.sponsorOffers.filter(offerId=>offerId!==id);state.sponsorEmailSeen=true;syncSpecialCars();roadSnake.length=Math.max(roadSnake.length,5+sponsorSignCount()*3);save();hud();toast(`${p.name} is now sponsoring Vancerts. Banner installed; lot reset; rate growth preserved.`);openEmail()};$('phoneMail').onclick=openEmail; const SPOTIFY_PLAYLIST_ID='6GFKCEJTLgrCZUCKBKHfua'; const SPOTIFY_EMBED_URL='https://open.spotify.com/embed/playlist/'+SPOTIFY_PLAYLIST_ID+'?utm_source=generator&theme=0'; const SPOTIFY_PLAYLIST_URI='spotify:playlist:'+SPOTIFY_PLAYLIST_ID,SPOTIFY_IFRAME_API_SRC='https://open.spotify.com/embed/iframe-api/v1'; const SPOTIFY_KNOWN_ARTIST_BY_TITLE={'vampire':'39th Gate Of Hell','screw it up':'Grandmas House',"where's my family gone":'Andrew Cushin','pills communication':'BLACK AVA'}; let spotifyPlayerLoaded=false,spotifyIframeApi=null,spotifyEmbedController=null,spotifyIframeApiRequested=false,spotifyUsingFallback=false,spotifyFallbackTimer=0,spotifyMetadataRequest=0,spotifyPlayingUri=''; let phoneNowPlaying='COMMUNITY RADIO READY'; function phoneNowPlayingStatus(extra=''){ const track=String(phoneNowPlaying||'COMMUNITY RADIO READY').replace(/^NOW PLAYING\s*•\s*/i,'').trim(); return `NOW PLAYING • ${track}${extra||''}` } function setNowPlaying(text){const value=(text||'512 JAMS • VANCERTS').toUpperCase(),el=$('nowPlayingText'),button=$('radioCollapse');phoneNowPlaying=value;if(el)el.textContent=value;if(button){const compact=value.replace(/^NOW PLAYING\s*•\s*/,'');button.dataset.nowPlaying=compact.length>27?compact.slice(0,26)+'…':compact}const status=$('phoneStatus');if(status)status.textContent=phoneNowPlayingStatus()} function setSpotifyStatus(text){const el=$('spotifyStatus');if(el)el.textContent=(text||'SPOTIFY PLAYLIST').toUpperCase()} function clear512GameplayInput(){for(const k of Object.keys(keys))keys[k]=false;van.speed=0;if(typeof controllerInput!=='undefined'){controllerInput.forward=false;controllerInput.reverse=false;controllerInput.left=false;controllerInput.right=false}} function spotifyPlayerExpanded(){const rr=$('rotaryRadio');return !!rr&&!rr.classList.contains('collapsed')&&!rr.classList.contains('hidden')} function spotifyIframeMarkup(){return '<iframe title="512 Jams Spotify playlist" src="'+SPOTIFY_EMBED_URL+'" allow="autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture" loading="eager"></iframe>'} function spotifyTrackUrl(uri){const m=String(uri||'').match(/^spotify:track:([A-Za-z0-9]+)$/);return m?'https://open.spotify.com/track/'+m[1]:''} async function resolveSpotifyNowPlaying(uri){ const url=spotifyTrackUrl(uri),request=++spotifyMetadataRequest;if(!url)return setNowPlaying('NOW PLAYING • 512 JAMS');setNowPlaying('NOW PLAYING • TUNING…'); try{const response=await fetch('https://open.spotify.com/oembed?url='+encodeURIComponent(url),{mode:'cors'});if(!response.ok)throw new Error('Spotify metadata unavailable');const data=await response.json();if(request!==spotifyMetadataRequest||uri!==spotifyPlayingUri)return;const title=String(data.title||'').trim(),knownArtist=SPOTIFY_KNOWN_ARTIST_BY_TITLE[title.toLowerCase().replace(/[’]/g,"'")]||'',author=String(data.author_name||data.artist_name||knownArtist).trim(),credit=author&&author.toLowerCase()!=='spotify'?author+' — ':'';setNowPlaying(title?'NOW PLAYING • '+credit+title:'NOW PLAYING • SEE SPOTIFY PLAYER')} catch(_){if(request===spotifyMetadataRequest&&uri===spotifyPlayingUri)setNowPlaying('NOW PLAYING • SEE SPOTIFY PLAYER')} } function handleSpotifyPlayback(event,started=false){const data=event?.data||{},uri=String(data.playingURI||'');if(uri&&uri!==spotifyPlayingUri){spotifyPlayingUri=uri;resolveSpotifyNowPlaying(uri)}if(started)setSpotifyStatus('NOW PLAYING • 512 JAMS');else if(data.isBuffering)setSpotifyStatus('TUNING • 512 JAMS');else if(data.isPaused)setSpotifyStatus('PAUSED • 512 JAMS');else setSpotifyStatus('NOW PLAYING • 512 JAMS')} function destroySpotifyController(){if(spotifyEmbedController&&typeof spotifyEmbedController.destroy==='function')try{spotifyEmbedController.destroy()}catch(_){}spotifyEmbedController=null} function mountSpotifyFallback(){if(!spotifyPlayerLoaded||spotifyEmbedController)return;const host=$('spotifyEmbed');if(!host)return;spotifyUsingFallback=true;host.innerHTML=spotifyIframeMarkup();setSpotifyStatus('SPOTIFY READY • PRESS PLAY');setNowPlaying('512 JAMS • SPOTIFY PLAYER')} function mountSpotifyController(){ const host=$('spotifyEmbed');if(!host||!spotifyPlayerLoaded||!spotifyIframeApi)return false;clearTimeout(spotifyFallbackTimer);destroySpotifyController();spotifyUsingFallback=false;host.innerHTML='<div id="spotifyIframeTarget" style="width:100%;height:152px"></div>';const target=$('spotifyIframeTarget'); try{spotifyIframeApi.createController(target,{uri:SPOTIFY_PLAYLIST_URI,width:'100%',height:152},controller=>{if(!spotifyPlayerLoaded){try{controller.destroy()}catch(_){}return}spotifyEmbedController=controller;controller.addListener('ready',()=>{setSpotifyStatus('SPOTIFY READY • PRESS PLAY');scheduleDeviceContainment($('rotaryRadio'))});controller.addListener('playback_started',event=>handleSpotifyPlayback(event,true));controller.addListener('playback_update',event=>handleSpotifyPlayback(event,false))});return true}catch(_){mountSpotifyFallback();return false} } function ensureSpotifyIframeApi(){if(spotifyIframeApi||spotifyIframeApiRequested)return;spotifyIframeApiRequested=true;const script=document.createElement('script');script.src=SPOTIFY_IFRAME_API_SRC;script.async=true;script.onerror=()=>{spotifyIframeApiRequested=false;mountSpotifyFallback()};document.body.appendChild(script)} window.onSpotifyIframeApiReady=IFrameAPI=>{spotifyIframeApi=IFrameAPI;if(spotifyPlayerLoaded&&!spotifyUsingFallback)mountSpotifyController()}; function load512Jams(silent=false){const host=$('spotifyEmbed');if(!host)return;clearTimeout(spotifyFallbackTimer);destroySpotifyController();spotifyPlayerLoaded=true;spotifyUsingFallback=false;spotifyPlayingUri='';spotifyMetadataRequest++;setSpotifyStatus('TUNING 512 JAMS…');setNowPlaying('512 JAMS • PRESS PLAY IN SPOTIFY');host.innerHTML='<div class="spotifyLoading">TUNING 512 JAMS…<br><small>Spotify player loading.</small></div>';if(!mountSpotifyController()){ensureSpotifyIframeApi();spotifyFallbackTimer=setTimeout(mountSpotifyFallback,6500)}if(!silent)toast('512 Jams restored. Game progress was not changed.')} function stop512Jams(){const host=$('spotifyEmbed');if(!host)return;clearTimeout(spotifyFallbackTimer);destroySpotifyController();host.innerHTML='<div class="spotifyLoading">MUSIC STOPPED<br><small>Your game is still exactly where you left it. Press RESTORE PLAYER when ready.</small></div>';spotifyPlayerLoaded=false;spotifyUsingFallback=false;spotifyPlayingUri='';spotifyMetadataRequest++;setSpotifyStatus('MUSIC STOPPED • GAME SAFE');setNowPlaying('512 JAMS • PLAYER STOPPED');clear512GameplayInput();toast('Spotify stopped only. Your game was not reset.')} function open512Jams(){const rr=$('rotaryRadio');if(!rr)return;rr.classList.remove('hidden');if(rr.classList.contains('collapsed'))expandReliable(rr,$('radioCollapse'),$('phone'),$('phoneCollapse'));if(!spotifyPlayerLoaded)load512Jams(true);clear512GameplayInput();toast('512 Jams open • driving paused • minimize to resume.')} function toggleSpotifyPlayback(){open512Jams();toast('Use the Play and Pause controls inside Spotify.')} function toggleSpotifyPower(){spotifyPlayerLoaded?stop512Jams():load512Jams()} function open512PlaylistSubmission(){ const subject='512 Jams, Playlist Submission'; const body=['Spotify link (required):','','Artist name:','Track title:','Contact name:','','Submissions must include a Spotify link.','If accepted, it will be added to 512 Jams within 24–48 hours.'].join('\n'); const mailto='mailto:hello@vancerts.com?subject='+encodeURIComponent(subject)+'&body='+encodeURIComponent(body); const link=document.createElement('a');link.href=mailto;link.target='_blank';link.rel='noopener';link.style.display='none';document.body.appendChild(link);link.click();link.remove(); clear512GameplayInput();toast('Submission email opened • Spotify link required • game not reset.'); } window.open512Jams=open512Jams;window.load512Jams=load512Jams;window.stop512Jams=stop512Jams;window.toggleSpotifyPower=toggleSpotifyPower;window.toggleSpotifyPlayback=toggleSpotifyPlayback;window.open512PlaylistSubmission=open512PlaylistSubmission; $('radioStop').onclick=stop512Jams;$('radioRestore').onclick=()=>load512Jams();$('radioJoinPlaylist').onclick=open512PlaylistSubmission;$('radioCollapse').addEventListener('click',()=>setTimeout(()=>{if(spotifyPlayerExpanded()){if(!spotifyPlayerLoaded)load512Jams(true);clear512GameplayInput();toast('512 Jams open • driving paused • minimize to resume.')}else{for(const k of Object.keys(keys))keys[k]=false;canvas.focus({preventScroll:true});toast('512 Jams minimized • gameplay resumed • no reset.')}},0)); $('spotifyEmbed').addEventListener('mouseenter',clear512GameplayInput);$('spotifyEmbed').addEventListener('touchstart',clear512GameplayInput,{passive:true}); function requestGameFullscreen(){enterLandscape()} if($('fullscreenToggle'))$('fullscreenToggle').onclick=requestGameFullscreen;window.requestGameFullscreen=requestGameFullscreen; function shopModal(){ const pickup=state.activeJob&&state.activeJob.phase==='pickup',order=state.rentalOrder&&state.rentalOrder.status==='delivered'; const missing=pickup?rentalMissingItems(state.activeJob):{},missingText=Object.entries(missing).map(([k,n])=>`${n} ${k}`).join(', '); modal(`<h2>GIG BAG ATX</h2>${order?`<div class="card"><h3>ROCK N ROLL RENTALS DELIVERY</h3><p>${Object.entries(state.rentalOrder.items||{}).map(([k,n])=>`${n} ${k}`).join(', ')}</p><button class="green" onclick="pickupRentalOrder()">PICK UP RENTAL EQUIPMENT</button></div>`:''}${pickup?`<div class="card"><h3>SHOW LOAD-IN</h3><p>${places.find(p=>p.id===state.activeJob.id).name}'s emailed gear list is ready.</p><div class="equipmentManifest"><h4>LOCKED SHOW MANIFEST</h4>${equipmentManifestHtml(state.activeJob)}</div>${missingText?`<p class="bad">MISSING: ${missingText}. Call Rock N Roll Rentals before loading.</p>`:'<p class="good">All approved equipment is available.</p>'}<button class="green" onclick="loadShowGear()" ${missingText?'disabled':''}>LOAD APPROVED GEAR</button></div>`:'<p>Own more equipment to reduce future rental costs and improve production.</p>'}<div class="grid">${store.map((s,i)=>`<div class="card"><h3>${s[0]}</h3><b>$${s[1]}</b><p>Owned: ${state.inventory[s[2]]||0}</p><button onclick="buy(${i})" ${state.cash<s[1]?'disabled':''}>BUY</button></div>`).join('')}</div><div class="btns"><button class="secondary" onclick="closeModal()">LEAVE SHOP</button></div>`) } window.shopModal=shopModal; window.loadShowGear=()=>{const j=state.activeJob;if(!j||j.phase!=='pickup')return;const manifest=ensureEquipmentManifest(j),missing=rentalMissingItems(j);if(Object.keys(missing).length)return toast('Load denied: required equipment is missing. Call Rock N Roll Rentals.');const owned={},rented={};for(const[k,n0]of Object.entries(manifest)){let n=Number(n0)||0;const own=Math.min(n,state.inventory[k]||0);owned[k]=own;n-=own;rented[k]=Math.min(n,(j.rentals&&j.rentals[k])||0)}j.loadedOwned=owned;j.loadedRentals=rented;j.loadedPaul=j.staff?.paul?allocatePaulTruckLoad(owned):{};j.cablesLoaded=['xlr','iec','speakerCable50','snake24'].every(k=>!manifest[k]||((owned[k]||0)+(rented[k]||0)>=manifest[k]));j.backlineDetailedLoaded=['highTom','lowTom','floorTom','bassDrum','drumHardware','guitarAmp','bassAmp','diBox'].every(k=>!manifest[k]||((owned[k]||0)+(rented[k]||0)>=manifest[k]));j.phase='delivery';save();hud();closeModal();toast(j.staff?.paul?'COMPLETE MANIFEST LOADED • PAUL TOOK THE PROTECTED TRUCK LOAD':'Complete show manifest loaded. Drive to the venue loading zone.')}; window.buy=i=>{const s=store[i];if(state.cash<s[1]||!debitCash(s[1],'Equipment',s[0],{vendor:'GIG BAG ATX',businessPurpose:`Equipment purchased for Vancerts production inventory: ${s[0]}.`,deductiblePct:null,paymentMethod:'VANCERTS BUSINESS FUNDS'}))return;state.inventory[s[2]]=(state.inventory[s[2]]||0)+1;save();hud();shopModal();toast(`${s[0]} added.`)}; function expansionPermitCard(id,side){ const p=places.find(x=>x.id===id),owned=businessPermitOwned(id),available=side==='east'?eastPermitAvailableFor(id):westPermitAvailableFor(id); const flags=state.venues[id]?.fillFlags||0,rule=side==='east'?eastPermitProgressText(id):(available?'PREVIOUS BUSINESS COMPLETE':'LOCKED — COMPLETE PREVIOUS BUSINESS'); return `<div class="card"><h3>${p.name}</h3><p>${p.subtitle||'Expansion business'}<br>Sponsor flags: <b>${flags}/3</b></p><p><b>$12,500</b><br>${owned?'PERMIT PURCHASED':available?'AVAILABLE NOW':rule}</p><button onclick="buyBusinessPermit('${id}','${side}')" ${owned||!available||state.cash<EXPANSION_PERMIT_COST?'disabled':''}>${owned?'OPEN':'PURCHASE PERMIT'}</button></div>` } function showExpansionPermits(){ const mamaReady=originalSponsorsComplete(),mamaOwned=mamaPermitUnlocked(); const eastCards=EAST_EXPANSION_ORDER.map(id=>expansionPermitCard(id,'east')).join(''); const westCards=WEST_EXPANSION_ORDER.map(id=>expansionPermitCard(id,'west')).join(''); modal(`<h2>BYOB EXPANSION PERMITS</h2><div class="grid"><div class="card"><h3>MAMA DEAREST</h3><p><b>$12,500</b><br>${mamaReady?'AVAILABLE':'SIGN ALL ACTIVE FOUNDING SPONSORS'}</p><button onclick="buyMamaPermit()" ${!mamaReady||mamaOwned||state.cash<12500?'disabled':''}>${mamaOwned?'OPEN':'PURCHASE PERMIT'}</button></div></div><h3>EAST AUSTIN — $12,500 EACH</h3><p><b>${state.story.chapter3Started?'CHAPTER 3 ACTIVE':'LOCKED UNTIL YOU BOOK A NEW JOB AT A FULL SPONSORED LOT AFTER VAN FEST I'}</b></p><div class="grid">${eastCards}</div><h3>CHAPTER 4 SOUTH SIDE — $12,500 EACH</h3><div class="grid">${westCards}</div><div class="btns"><button class="secondary" onclick="hqModal()">BACK TO BYOB</button></div>`) } window.showExpansionPermits=showExpansionPermits; function buyMamaPermit(){if(mamaPermitUnlocked())return toast('Mama Dearest is already unlocked.');if(!originalSponsorsComplete())return toast('Sign all active founding sponsors first.');if(state.cash<12500||!debitCash(12500,'Permits','Mama Dearest expansion permit'))return toast('You need $12,500 for this permit.');state.expansionPermits.mama=true;state.venues.mama.budget=Math.max(state.venues.mama.budget,2200);save();hud();showExpansionPermits();toast('MAMA DEAREST UNLOCKED')} window.buyMamaPermit=buyMamaPermit; function buyBusinessPermit(id,side){ const available=side==='east'?eastPermitAvailableFor(id):westPermitAvailableFor(id); if(businessPermitOwned(id))return toast('Permit already purchased.'); if(!available)return toast('Complete the previous expansion requirement first.'); if(state.cash<EXPANSION_PERMIT_COST)return toast('You need $12,500 for this permit.'); const p=places.find(x=>x.id===id);if(!debitCash(EXPANSION_PERMIT_COST,'Permits',`${p.name} expansion permit`))return; state.expansionPermits[p.expansionPermit]=true; state.venues[id]=Object.assign({budget:SOLO_COST,eventCount:0,rateCars:0,sign:false,fillFlags:0,lotCycleFull:false,flagCycleArmed:false},state.venues[id]||{}); state.venues[id].budget=Math.max(state.venues[id].budget,2400); save();hud();showExpansionPermits();toast(`${p.name} EXPANSION PERMIT PURCHASED`) } window.buyBusinessPermit=buyBusinessPermit; function hqModal(){const missing=Math.max(0,100-Math.round(state.vanhp)),steps=Math.ceil(missing/10),fullCost=steps*100,projects=Object.values(state.communityUpgrades).reduce((a,b)=>a+(Number(b)||0),0);modal(`<h2>BYOB AUSTIN</h2><p><b>Vancerts HQ • Sponsor wall • Garage • Community upgrade headquarters</b></p><div class="grid"><div class="card">Cash <b>$${rentalMoney(state.cash)}</b><br>Outstanding <b>$${Math.round(totalOwed())}</b><br>Shows <b>${state.shows}</b><br>Van condition <b>${Math.round(state.vanhp)}%</b></div><div class="card">Community <b>${state.rep} ♥</b><br>Community projects <b>${projects}</b><br>BYOB Community Flags <b>${state.byobCommunity.flags}</b><br>Charity Savings <b>$${state.byobCommunity.savings.toLocaleString()}</b><br>Road Snake <b>${roadSnake.active?`ACTIVE • ${roadSnake.length} SEGMENTS`:'RETURNS AT 12:00 PM'}</b><br>${state.completed.filter(id=>order.includes(id)).length>=order.length?'Austin Founders <b>COMPLETE</b>':`Austin Founders <b>${state.completed.filter(id=>order.includes(id)).length}/${order.length}</b>`}<br>Sponsor banners <b>${sponsorSignCount()}</b><br>Mama Dearest <b>${mamaPermitUnlocked()?'UNLOCKED':'LOCKED'}</b><br>East Austin District <b>${state.story.festivalComplete?'OPEN':'LOCKED'}</b><br>World Liquor <b>${worldLiquorShouldBeOpen()?(state.venues.worldliquor.sign?'SPONSORED':'OPEN • UNSPONSORED'):'OPENS AFTER VAN FEST I'}</b></div><div class="card"><b>Vancerts garage</b><br>Repairs cost <b>$100 per 10%</b>.<br>One repair restores up to 10 condition points.<br><span class="small">Black Star cars are never removed by community projects.</span></div>${consumablesHtml()}${armoredVanCard()}</div><div class="btns">${state.story.festivalActive&&FESTIVAL_ROUTE[state.story.festivalIndex]==='hq'?'<button class="red" onclick="completeFestivalFinale()">COMPLETE IT\'S A VAN FEST FINALE</button>':''}${state.story.secondFestivalActive&&(state.story.secondFestivalRoute||[])[state.story.secondFestivalIndex]==='hq'?'<button class="red" onclick="completeSecondFestivalFinale()">COMPLETE VAN FEST II FINALE</button>':''}${state.story.eastAustinUnlocked?'<button onclick="modal(`<h2>EAST AUSTIN DISTRICT</h2><p>Chapter 3 expansion businesses, in permit order:</p><div class=\'grid\'>${FUTURE_EAST_AUSTIN.map(n=>`<div class=\'card\'><b>${n}</b></div>`).join(\'\')}</div><div class=\'btns\'><button onclick=\'hqModal()\'>BACK</button></div>`)">EAST AUSTIN DISTRICT</button>':''}<button onclick="driverPassModal()">PLAYER WALLET • DRIVER PERMIT</button><button class="green" onclick="openStaffManager()">TEAM & CAREER PATHS</button><button onclick="openExpenseTracker()">EXPENSE TRACKER & RECEIPTS</button><button onclick="foodCannonModal()" ${state.vanUpgrades.potatoGun?'':'disabled'}>FOOD CANNON LOADOUT</button><button class="green" onclick="communityShowModal()">HOST FREE COMMUNITY SHOW</button><button class="green" onclick="showCommunityShop()">COMMUNITY PROJECTS</button><button onclick="showExpansionPermits()">EXPANSION PERMITS</button><button onclick="repairTen()" ${state.vanhp>=100||state.cash<100?'disabled':''}>REPAIR +10% • $100</button><button onclick="repairFull()" ${state.vanhp>=100||state.cash<fullCost?'disabled':''}>FULL REPAIR • $${fullCost}</button><button class="secondary" onclick="closeModal()">KEEP BUILDING</button><button class="red" onclick="resetGame()">RESET STORY</button></div>`)} window.repairTen=()=>{if(state.cash<100||state.vanhp>=100||!debitCash(100,'Repairs','BYOB van repair +10%',{vendor:'BYOB VANCERTS GARAGE',businessPurpose:'Business vehicle repair restoring 10% van condition.',deductiblePct:100}))return;state.vanhp=Math.min(100,state.vanhp+10);save();hud();hqModal();toast('BYOB garage repaired 10% van condition.')}; window.repairFull=()=>{const steps=Math.ceil(Math.max(0,100-state.vanhp)/10),cost=steps*100;if(!steps||state.cash<cost||!debitCash(cost,'Repairs','BYOB full van repair',{vendor:'BYOB VANCERTS GARAGE',businessPurpose:'Business vehicle repair restoring the van to full condition.',deductiblePct:100}))return;state.vanhp=100;save();hud();hqModal();toast('Van fully repaired at BYOB Austin.')}; window.resetGame=()=>{if(portableMode){sessionStorage.removeItem(PORTABLE_SESSION_KEY);location.reload();return}safeStorage.removeItem(SAVE_KEY);safeStorage.removeItem(LEGACY_CHECKPOINT_KEY);location.reload()}; const BANK_INTEREST_RATE=.30,MAX_BANK_ADVANCE=999999999; let bankAmountMode='borrow',bankAmountBuffer=''; function bankAdvanceAvailableToday(){return state.bankLastAdvanceDay!==austinDateKey()} function bankActiveLoans(){return (state.bankLoans||[]).filter(loan=>Number(loan.paid||0)<Number(loan.payoff||0))} function bankLoanRowsHtml(){const active=bankActiveLoans();if(!active.length)return '<div class="card"><b class="good">NO ACTIVE LOAN BALANCE</b><br><span class="small">Previous paid-off advances remain included in the lifetime totals and ledger.</span></div>';return active.map((loan,index)=>{const remaining=financeAmount(loan.payoff-loan.paid),pct=Math.max(0,Math.min(100,Math.round(loan.paid/loan.payoff*100)));return `<div class="loanRow"><b>ADVANCE ${index+1} • ${safeFinanceText(loan.day)}</b><br>Received <b>$${rentalMoney(loan.principal)}</b> + 30% interest <b>$${rentalMoney(loan.interest)}</b><br>Paid <b>$${rentalMoney(loan.paid)}</b> • Remaining <b>$${rentalMoney(remaining)}</b><div class="loanProgress"><i style="width:${pct}%"></i></div></div>`}).join('')} function takeBankLoan(amount){ const principal=Math.floor(Number(amount)||0); if(!bankAdvanceAvailableToday()){toast('TODAY’S BANK ADVANCE HAS ALREADY BEEN USED');bankModal();return false} if(principal<1||principal>MAX_BANK_ADVANCE){toast('ENTER A WHOLE-DOLLAR ADVANCE AMOUNT');return false} const interest=financeAmount(principal*BANK_INTEREST_RATE),payoff=financeAmount(principal+interest),createdAt=Date.now(); const loan=normalizeBankLoanRecord({id:`loan-${createdAt}`,day:austinDateKey(),principal,interest,payoff,paid:0,interestPaid:0,principalPaid:0,createdAt}); state.bankLoans.push(loan);state.bankLastAdvanceDay=austinDateKey();state.bankStats.loansTaken+=1;state.bankStats.totalBorrowed=financeAmount(state.bankStats.totalBorrowed+principal);state.bankStats.totalInterestCharged=financeAmount(state.bankStats.totalInterestCharged+interest);state.finance.totalInterestCharged=financeAmount(state.finance.totalInterestCharged+interest);creditCash(principal,'Bank Advance','Vancerts Community Bank advance',{type:'loan'});persistCommittedFinanceState();hud();toast(`BANK ADVANCE +$${rentalMoney(principal)} • PAYOFF $${rentalMoney(payoff)} • SAVED`);bankModal();return true } function repayBankLoan(amount){ const balance=bankLoanBalance(),payment=financeAmount(Math.max(0,Math.min(balance,Number(amount)||0,Number(state.cash)||0))); if(balance<=0){toast('NO ACTIVE BANK DEBT');bankModal();return false} if(payment<=0){toast('ENTER A PAYMENT YOU CAN AFFORD');return false} let left=payment,interestPaid=0; for(const loan of bankActiveLoans().sort((a,b)=>a.createdAt-b.createdAt)){ if(left<=0)break; const openInterest=Math.max(0,loan.interest-loan.interestPaid),interestPart=Math.min(left,openInterest);loan.interestPaid=financeAmount(loan.interestPaid+interestPart);interestPaid+=interestPart;left-=interestPart; const openPrincipal=Math.max(0,loan.principal-loan.principalPaid),principalPart=Math.min(left,openPrincipal);loan.principalPaid=financeAmount(loan.principalPaid+principalPart);left-=principalPart;loan.paid=financeAmount(loan.interestPaid+loan.principalPaid) } debitCash(payment,'Debt Repayment','Vancerts Community Bank payment',{type:'repayment',interest:interestPaid});state.bankStats.totalRepaid=financeAmount(state.bankStats.totalRepaid+payment);state.bankStats.totalInterestPaid=financeAmount(state.bankStats.totalInterestPaid+interestPaid);persistCommittedFinanceState();const remaining=bankLoanBalance();hud();toast(remaining<=0?'BANK DEBT PAID IN FULL • SAVED':`BANK PAYMENT $${rentalMoney(payment)} • $${rentalMoney(remaining)} LEFT • SAVED`);bankModal();return true } function bankAmountEntry(mode){bankAmountMode=mode==='repay'?'repay':'borrow';bankAmountBuffer='';const balance=bankLoanBalance(),title=bankAmountMode==='borrow'?'CHOOSE TODAY’S ADVANCE':'CHOOSE A DEBT PAYMENT',note=bankAmountMode==='borrow'?'Any whole-dollar amount. The bank adds 30% interest once. You may take one new advance per Austin calendar day.':`Available cash: $${rentalMoney(state.cash)} • Current debt: $${rentalMoney(balance)}. Payments go to the oldest advance first.`;modal(`<h2>${title}</h2><p>${note}</p><div class="bankAmountDisplay" id="bankAmountDisplay">$0</div><div class="bankKeypad">${[1,2,3,4,5,6,7,8,9].map(n=>`<button onclick="bankKey('${n}')">${n}</button>`).join('')}<button onclick="bankKey('clear')">CLEAR</button><button onclick="bankKey('0')">0</button><button onclick="bankKey('back')">⌫</button></div><div class="btns"><button class="green" id="bankAmountConfirm" onclick="confirmBankAmount()">${bankAmountMode==='borrow'?'TAKE ADVANCE':'MAKE PAYMENT'}</button><button class="secondary" onclick="bankModal()">BACK TO BANK</button></div><p class="small">Advances and repayments are saved immediately. They do not wait for the main SAVE button.</p>`)} function bankKey(key){if(key==='clear')bankAmountBuffer='';else if(key==='back')bankAmountBuffer=bankAmountBuffer.slice(0,-1);else if(/^\d$/.test(key)&&bankAmountBuffer.length<9)bankAmountBuffer=(bankAmountBuffer+key).replace(/^0+(?=\d)/,'');const value=Math.floor(Number(bankAmountBuffer)||0),display=$('bankAmountDisplay');if(display)display.textContent=`$${rentalMoney(value)}`;const button=$('bankAmountConfirm');if(button){button.disabled=value<1;button.textContent=bankAmountMode==='borrow'?`TAKE $${rentalMoney(value)} • REPAY $${rentalMoney(financeAmount(value+value*BANK_INTEREST_RATE))}`:`PAY $${rentalMoney(value)}`}} function confirmBankAmount(){const value=Math.floor(Number(bankAmountBuffer)||0);if(value<1)return toast('ENTER A WHOLE-DOLLAR AMOUNT');if(bankAmountMode==='borrow')takeBankLoan(value);else repayBankLoan(value)} function bankModal(){ const balance=bankLoanBalance(),available=bankAdvanceAvailableToday(),example=financeAmount(100+100*BANK_INTEREST_RATE); modal(`<h2>VANCERTS COMMUNITY BANK</h2><div class="bankDaily"><h3>DAILY BUSINESS ADVANCE</h3>${available?`<p><b>AVAILABLE TODAY.</b> Choose any whole-dollar amount. One advance per Austin calendar day. Every advance adds <b>30% interest</b>; for example, receive $100 and repay $${example}. You can borrow on a later day even while older debt remains.</p><button onclick="bankAmountEntry('borrow')">CHOOSE TODAY’S ADVANCE</button>`:'<p><b>TODAY’S ADVANCE HAS BEEN USED.</b> Repay at any time, then return on the next Austin calendar day for another advance.</p>'}</div><h3>FINANCIAL STATEMENT</h3>${financeStatementHtml()}<h3>ACTIVE ADVANCES</h3>${bankLoanRowsHtml()}<div class="grid"><div class="card"><b>COMMUNITY SAVINGS ACCOUNT</b><br><span style="font-size:28px">$${rentalMoney(state.byobCommunity.savings)}</span><br><span class="small">Reserved through BYOB free community shows; separate from spendable cash.</span></div><div class="card"><b>LOAN RULES</b><br>Advances taken <b>${state.bankStats.loansTaken}</b><br>Outstanding <b>$${rentalMoney(balance)}</b><br>Interest rate <b>30%</b><br>New advance limit <b>once per Austin day</b></div></div><div class="btns">${balance>0?`<button onclick="repayBankLoan(25)" ${state.cash<25?'disabled':''}>PAY $25</button><button onclick="repayBankLoan(100)" ${state.cash<100?'disabled':''}>PAY $100</button><button onclick="repayBankLoan(500)" ${state.cash<500?'disabled':''}>PAY $500</button><button onclick="bankAmountEntry('repay')">CUSTOM PAYMENT</button><button class="green" onclick="repayBankLoan(${balance})" ${state.cash<balance?'disabled':''}>PAY IN FULL • $${rentalMoney(balance)}</button>`:''}<button onclick="openExpenseTracker()">EXPENSE TRACKER & RECEIPTS</button><button class="secondary" onclick="closeModal()">LEAVE BANK</button></div>`) } window.takeBankLoan=takeBankLoan;window.repayBankLoan=repayBankLoan;window.bankAmountEntry=bankAmountEntry;window.bankKey=bankKey;window.confirmBankAmount=confirmBankAmount;window.bankModal=bankModal; function interact(){if(!near)return;if(near.type==='home')openCareerHome(near.homeId);else if(near.type==='poster')placePromotionPoster(near);else if(near.type==='busstop')startPassengerRide(near.stopIndex);else if(near.type==='passengerDrop')finishPassengerRide();else if(near.type==='gig')gigModal(near.id);else if(near.type==='shop')shopModal();else if(near.type==='bank')bankModal();else if(near.id==='amlhouse')amlHouseModal();else if(near.type==='studio'||near.type==='grounds')leftwayModal();else hqModal()} // 512 Jams is isolated in Spotify's iframe; opening, minimizing, stopping, or restoring it never rebuilds the game document. window.toggleMusic=()=>toggleSpotifyPlayback(); if(portableMode){const b=$('playGameButton');if(b)b.textContent='PLAY LOADED GAME • FULLSCREEN'} function launchButtonLabel(){return portableMode?'PLAY LOADED GAME • FULLSCREEN':'PLAY GAME • FULLSCREEN'} function launchGameAfterFullscreen(){ $('splash').classList.add('hidden');$('hud').classList.remove('hidden');$('mobile').classList.remove('hidden');$('phone').classList.remove('hidden');$('rotaryRadio').classList.add('hidden'); /* R36B47E: every new game session begins with the Nookia open and Training Wheels on. */ setTrainingPreference(true); state.training.enabled=true; const initialPhone=$('phone'); if(initialPhone){ initialPhone.classList.add('collapsed'); initialPhone.classList.remove('deviceSuppressed'); const phoneButton=$('phoneCollapse'); if(phoneButton){phoneButton.textContent='▴';phoneButton.setAttribute('aria-expanded','false')} } if(matchMedia('(pointer:coarse)').matches&&innerWidth<900){const rr=$('rotaryRadio');rr.classList.add('collapsed');if($('radioCollapse'))$('radioCollapse').textContent='MINIMIZE'} if(matchMedia('(pointer:coarse)').matches){requestAnimationFrame(loadDevicePositions);if(deviceOrientation()==='landscape')scheduleLandscapeReset(true)} const initialPlayer=$('rotaryRadio');if(initialPlayer){initialPlayer.classList.add('collapsed');$('radioCollapse').textContent='MINIMIZE';$('radioCollapse').setAttribute('aria-expanded','false')} requestAnimationFrame(()=>{loadDevicePositions();const ph=$('phone'),pb=$('phoneCollapse');if(ph){ph.classList.add('collapsed');ph.classList.remove('deviceSuppressed');ph.classList.remove('deviceReliable')}if(pb){pb.textContent='▴';pb.setAttribute('aria-expanded','false')}hud()});trainingGameStarted=true;canvas.focus({preventScroll:true});setTimeout(()=>canvas.focus({preventScroll:true}),0);hud();rescueVanFromInvalidMapPosition(true);if(state.introVersion<5){state.introVersion=5;state.seenIntro=true;save()}if(!state.driverPass?.name)setTimeout(showDriverPermitGate,120);else setTimeout(maybeShowTrainingChapter,220) } function completeFullscreenLaunch(){ if(gameLaunchComplete)return;clearTimeout(fullscreenLaunchTimer);fullscreenLaunchTimer=0;fullscreenLaunchPending=false;gameLaunchComplete=true; const b=$('playGameButton');if(b){b.disabled=false;b.textContent=launchButtonLabel()} launchGameAfterFullscreen() } function retryFullscreenLaunch(){ if(gameLaunchComplete)return;completeFullscreenLaunch(); } function startGame(){ if(gameLaunchComplete||fullscreenLaunchPending)return; const b=$('playGameButton'); fullscreenLaunchPending=true;if(b){b.disabled=true;b.textContent='OPENING AUSTIN…'} if(gameFullscreenActive||document.fullscreenElement||document.webkitFullscreenElement){setFullscreenUi(true);completeFullscreenLaunch();return} const el=document.documentElement,fn=el.requestFullscreen||el.webkitRequestFullscreen; try{if(fn){const result=fn.call(el);if(result&&typeof result.then==='function')result.then(()=>{setFullscreenUi(true);completeFullscreenLaunch()}).catch(()=>{})}}catch(e){} notifyParentFullscreen('enter'); fullscreenLaunchTimer=setTimeout(()=>{const active=gameFullscreenActive||document.fullscreenElement||document.webkitFullscreenElement;if(active){setFullscreenUi(true);completeFullscreenLaunch()}else retryFullscreenLaunch()},1400) } window.startGame=startGame;window.showHow=()=>modal(`<h2>HOW TO PLAY</h2> <div class="howHero"><b>BUILD THE SCENE → BUILD THE COMMUNITY → BUILD THE CITY.</b><br><small>Follow the current objective box. Email brings offers. The Nookia handles calls, payments, permits, resets, and contacts.</small></div> <div class="chapterStrip"> <div class="chapterBox"><strong>CHAPTER 1</strong>🚐 BUILD THE SCENE<br><small>Book shows • Buy gear • Sign sponsors</small></div> <div class="chapterBox"><strong>CHAPTER 2</strong>🎪 IT'S A VAN FEST<br><small>Citywide route • BYOB finale</small></div> <div class="chapterBox"><strong>CHAPTER 3</strong>🏙 EAST AUSTIN<br><small>5 permits • 3 flags everywhere</small></div> <div class="chapterBox"><strong>CHAPTER 4</strong>📻 SOUTH SIDE<br><small>KAZI • Tascam • JBL • Soup</small></div> </div> <h3 class="howSection">TRAINING WHEELS • TUTORIAL MISSIONS</h3><p>Training Wheels follows the real story instead of creating a separate practice save. Chapter 1 teaches driving, opening and closing the Nookia, opening and minimizing 512 Jams, the FSG booking email, equipment pickup, stage setup, and the final payment call. A new chapter overview appears when Chapters 2, 3, and 4 begin. Use <b>MISSION GUIDE</b> in the gold objective box for the current step. Use <b>Training On</b> or <b>Training Off</b> in the Vancerts Build the Scene box to switch guidance at any time without resetting anything.</p> <h3 class="howSection">NOOKIA SERVICE CODES</h3><p>Use the Nookia keypad, then press CALL. <b>#211</b> provides once-daily emergency Community Services: van restored to 100% and $500. Developer and test codes begin with <b>#512</b>. The master Sandbox code is <b>#4986</b>. It opens a clean empty-road laboratory, disables hard saving, prepares every sponsored business for a real 0/3 flag-cycle test, and lets you add road actors individually with <b>#51230–#51253</b>. NPC and bicycle checks: <b>#51251</b> all NPCs, <b>#51252</b> 100-rider bike group, <b>#51253</b> solo bike.</p> <h3 class="howSection">PRODUCTION PROGRESSION</h3><p><b>Chapter 2:</b> complete the calculated cable package for 80% band happiness. <b>Chapter 3:</b> complete drum shells/hardware, 2 guitar amps, bass amp and 2 DI boxes for 100%. Breakables remain artist-supplied.</p><h3 class="howSection">THE MAIN GAME LOOP</h3> <div class="permitPath"> <span>📧 ACCEPT OFFER</span><span class="chapterArrow">→</span> <span>🎒 LOAD EXACT GEAR</span><span class="chapterArrow">→</span> <span>🚐 DRIVE TO CLIENT</span><span class="chapterArrow">→</span> <span>🎤 COMPLETE SHOW</span><span class="chapterArrow">→</span> <span>📞 CALL FOR BALANCE</span><span class="chapterArrow">→</span> <span>🚗 GROW THE LOT</span> </div> <div class="iconKey"> <div class="iconCard"><div class="iconPic">📧</div><b>EMAIL</b><small>Offers, sponsors, festivals</small></div> <div class="iconCard"><div class="iconPic">💰</div><b>50% DEPOSIT</b><small>Paid when gig is accepted</small></div> <div class="iconCard"><div class="iconPic">🔊</div><b>EXACT EQUIPMENT</b><small>Load only what the gig requires</small></div> <div class="iconCard"><div class="iconPic">📞</div><b>CALL TO COLLECT</b><small>Remaining payment after show</small></div> <div class="iconCard"><div class="iconPic">🛒</div><b>RESOURCES</b><small>Deliver to Gig Bag for Community</small></div> ${BUS_STOPS_ENABLED?'<div class="iconCard"><div class="iconPic">🚌</div><b>PASSENGERS</b><small>Bus stop pickup • $5 drop-off</small></div>':''} </div> <h3 class="howSection">CONTROLS</h3> <div class="controllerHelp"><b>CONTROLLER</b><br>Left stick / D-pad aims and turns • Right bumper/trigger drives forward • Left bumper/trigger reverses • Right stick moves the pointer • Tap Cross/A or press R3 to click; hold Cross/A for 0.65 seconds to open the Nookia • B/Circle closes or goes back; when nothing is open it reopens the radio • Tap Square/X to fire the potato cannon; its original phone-hold shortcut still works • Triangle/Y opens How to Play • Options/Start opens Pause & Controls • Share/Back taps to save and holds to load. Controls can be remapped from Pause → Controller Settings.</div> <div class="iconKey"> <div class="iconCard"><div class="iconPic">⬆️</div><b>FORWARD</b><small>W / Up</small></div> <div class="iconCard"><div class="iconPic">↩️</div><b>LEFT</b><small>A / Left</small></div> <div class="iconCard"><div class="iconPic">↪️</div><b>RIGHT</b><small>S / Right</small></div> <div class="iconCard"><div class="iconPic">⬇️</div><b>REVERSE</b><small>Z / Down</small></div> <div class="iconCard"><div class="iconPic">❗</div><b>INTERACT</b><small>Space / Enter • mobile tap</small></div><div class="iconCard"><div class="iconPic">🚲</div><b>HOURLY SOCIAL RIDE</b><small>100 riders take three quarters of the street for the first four minutes of every hour. Cars pull aside and horns sound.</small></div><div class="iconCard"><div class="iconPic">🦸🏿</div><b>RUSSEL</b><small>Green, black, and yellow collector who returns city resources to Gig Bag.</small></div> <div class="iconCard"><div class="iconPic">🎒</div><b>RETURN HOME</b><small>R → Gig Bag ATX</small></div> <div class="iconCard"><div class="iconPic">💾</div><b>SAVE</b><small>Updates current save point</small></div> <div class="iconCard"><div class="iconPic">⛶</div><b>FULLSCREEN</b><small>Best mobile view in landscape</small></div> </div> <h3 class="howSection">SAVES</h3> <div class="iconKey"> <div class="iconCard"><div class="iconPic">💻</div><b>COMPUTER SAVE</b><small>Stored as vancerts-v8 in this browser</small></div> <div class="iconCard"><div class="iconPic">📤</div><b>EXPORT FILE</b><small>Download a portable .json save</small></div> <div class="iconCard"><div class="iconPic">📥</div><b>LOAD FILE</b><small>Play a USB/computer save anywhere</small></div> <div class="iconCard"><div class="iconPic">🔄</div><b>RESET</b><small>Portable mode returns to computer save</small></div> </div> <h3 class="howSection">PARKING, SPONSORS & FLAGS</h3><p><b>Flags begin only after It’s A Van Fest I is complete and World Liquor appears.</b> Before then, parking and sponsorship still progress normally, but no flags are awarded.</p> <div class="permitPath"> <span>🎤 COMPLETE SHOWS</span><span class="chapterArrow">→</span> <span>🚗 FILL PARKING LOT</span><span class="chapterArrow">→</span> <span>🤝 SIGN SPONSOR</span><span class="chapterArrow">→</span> <span>📅 BOOK NEW GIG</span><span class="chapterArrow">→</span> <span>0️⃣ LOT RESETS</span><span class="chapterArrow">→</span> <span>🚩 REFILL = 1 FLAG</span> </div> <div class="iconKey"> <div class="iconCard"><div class="iconPic">🚗</div><b>LOT CARS</b><small>Permanent client growth</small></div> <div class="iconCard"><div class="iconPic">🤝</div><b>SPONSOR</b><small>Full lots unlock sponsor progress</small></div> <div class="iconCard"><div class="iconPic">0️⃣</div><b>NEW SHOW RESET</b><small>A full sponsored lot returns to 0</small></div> <div class="iconCard"><div class="iconPic">🚩</div><b>ONE FLAG</b><small>Earned only after that reset lot refills</small></div> <div class="iconCard"><div class="iconPic">5️⃣</div><b>THREE FLAGS</b><small>Required at every open business</small></div> </div> <h3 class="howSection">CHAPTER 1 → VAN FEST I</h3> <p><b>Current founding route:</b> FSG Printshop, Republic Square, Blue Owl Brewing, Juan In A Million, and Hope Outdoor Gallery. Purchase the Mama Dearest permit, sponsor Mama Dearest, restore every sponsored lot, and finish the current objectives. The first It's A Van Fest ends at BYOB Austin.</p> <h3 class="howSection">CHAPTER 3 — EAST AUSTIN PERMITS</h3> <p>Each permit costs <b>$12,500</b>. Pork Chop is the first Chapter 3 permit. Every permit after it opens only when every currently open sponsored business—including the newest expansion—has reached <b>3 flags</b>:</p> <div class="iconKey"> <div class="iconCard"><div class="iconPic">1️⃣</div><b>PORK CHOP</b><small>Screen Printing</small></div> <div class="iconCard"><div class="iconPic">2️⃣</div><b>BADD BURGERS</b><small>Tacos • Hotdogs • Hamburgers</small></div> <div class="iconCard"><div class="iconPic">3️⃣</div><b>HIGH NOON</b><small>Austin Bar</small></div> <div class="iconCard"><div class="iconPic">4️⃣</div><b>CHESS CLUB</b><small>Punk Rock Club</small></div> <div class="iconCard"><div class="iconPic">5️⃣</div><b>13TH FLOOR</b><small>Psych Rock Club</small></div> </div> <p><b>Chapter 3 begins when you book the first new job at an already-full sponsored business after Van Fest I.</b> That job resets its lot to zero and makes the first East Austin permit available.</p><p>The expansion starts from the bottom-right closed property and continues upward along the right side. Purchase, sponsor, and earn 3 flags at each business before the next permit becomes available. When all East permits are owned and <b>every currently open business has three flags</b>, It's A Van Fest II becomes available. Its route includes every open sponsored business and finishes at BYOB.</p> <h3 class="howSection">CHAPTER 4 — SOUTH SIDE</h3> <p>Completing Van Fest II unlocks the South Side from the bottom-left closed property:</p> <div class="iconKey"> <div class="iconCard"><div class="iconPic">📻</div><b>KAZI 88.7 FM</b><small>Radio station</small></div> <div class="iconCard"><div class="iconPic">🎚️</div><b>TASCAM</b><small>Model 24 Studio</small></div> <div class="iconCard"><div class="iconPic">🔊</div><b>JBL PRO</b><small>Speaker Land</small></div> <div class="iconCard"><div class="iconPic">🥣</div><b>SOUP PEDDLER</b><small>Soup Shop</small></div> </div> <h3 class="howSection">BYOB COMMUNITY FLAGS & CHARITY SAVINGS</h3> <p>BYOB does not earn its flags from parking. After Van Fest I, every free company community show at BYOB earns <b>1 Community Flag</b>. Before each show, choose an amount of company cash to transfer into the separate <b>Charity Savings Fund</b>. The fund accumulates for a future help-people system and cannot yet be withdrawn or spent.</p> <div class="iconKey"> <div class="iconCard"><div class="iconPic">🎤</div><b>FREE SHOW</b><small>Completed at BYOB</small></div> <div class="iconCard"><div class="iconPic">🚩</div><b>+1 BYOB FLAG</b><small>Every free community show</small></div> <div class="iconCard"><div class="iconPic">💛</div><b>CHARITY SAVINGS</b><small>Separate from player cash</small></div> <div class="iconCard"><div class="iconPic">5️⃣</div><b>3 REQUIRED</b><small>Needed for Van Fest II</small></div> </div> <h3 class="howSection">CAMERA ZOOM</h3> <div class="iconKey"> <div class="iconCard"><div class="iconPic">1×</div><b>STREET VIEW</b><small>Original driving and parking scale</small></div> <div class="iconCard"><div class="iconPic">2×</div><b>NEIGHBORHOOD</b><small>See nearby blocks and traffic</small></div> <div class="iconCard"><div class="iconPic">3×</div><b>DISTRICT</b><small>Track businesses, hazards, and routes</small></div> <div class="iconCard"><div class="iconPic">4×</div><b>CITY VIEW</b><small>Centers the full map when it fits</small></div> </div> <p>The camera level is saved with the game. Zoom changes only the map view—driving speed, collision sizes, loading zones, phone, radio, HUD, and touch controls do not change.</p> <h3 class="howSection">AUSTIN MUSIC LOVE</h3><p>Open CALL on the Nookia and choose Austin Music Love.</p><div class="iconKey"><div class="iconCard"><div class="iconPic">📅</div><b>BOOKING • 10%</b><small>Secures a show with an unlocked client</small></div><div class="iconCard"><div class="iconPic">📣</div><b>PROMOTION • 5%</b><small>Place posters around town; variety controls turnout and payout</small></div><div class="iconCard"><div class="iconPic">🤝</div><b>BOTH • 15%</b><small>Books and promotes the event</small></div></div><p>Booking determines which show happens. Promotion becomes a physical poster campaign. Place posters at local businesses, future or closed properties, and across multiple districts. Variety affects turnout and final payout. Exceptional campaigns can fill the promoted lot and add 2 cars to nearby businesses. Promotion never resets cars, skips flags, changes capacity, or bypasses progression. Fees are deducted from each applicable show’s final payment.</p> <h3 class="howSection">ROAD VEHICLE & HAZARD KEY</h3> <p>The civilian traffic limit is handled quietly in the background. The <b>Road Snake and Black Star cars are permanent core hazards</b>; they are never removed and never count against civilian traffic.</p> <div class="iconKey"> <div class="iconCard"><div class="iconPic">🚗</div><b>SEDAN</b><small>Standard city traffic</small></div> <div class="iconCard"><div class="iconPic">🚙</div><b>HATCHBACK</b><small>Small everyday car</small></div> <div class="iconCard"><div class="iconPic">🚘</div><b>SUV</b><small>Larger collision body</small></div> <div class="iconCard"><div class="iconPic">🛻</div><b>PICKUP</b><small>Truck bed • slower body</small></div> <div class="iconCard"><div class="iconPic">🚐</div><b>DELIVERY VAN</b><small>Local road traffic</small></div> <div class="iconCard"><div class="iconPic">🏍️</div><b>MOTORCYCLE</b><small>Long-haired bearded rider</small></div> <div class="iconCard"><div class="iconPic">🚚</div><b>BOX TRUCK</b><small>Large • slow • blocks space</small></div> <div class="iconCard"><div class="iconPic">🚖</div><b>LIMOUSINE</b><small>Long body • medium speed</small></div> <div class="iconCard"><div class="iconPic">🐎</div><b>HORSEBACK RIDER</b><small>Very slow and relaxed</small></div> <div class="iconCard"><div class="iconPic">🏎️</div><b>TESTAROSSA-STYLE</b><small>Fast • passes traffic</small></div> <div class="iconCard"><div class="iconPic">🏁</div><b>LAMBORGHINI-STYLE</b><small>Very fast • races around cars</small></div> <div class="iconCard"><div class="iconPic">🚑</div><b>AMBULANCE</b><small>Nearby traffic pulls over</small></div> <div class="iconCard"><div class="iconPic">🤖</div><b>DRIVERLESS CAR</b><small>Obeys lights • parks 30 sec • hit for +5% van</small></div> <div class="iconCard"><div class="iconPic">⭐</div><b>BLACK STAR CAR</b><small>Permanent • 1 base + 1 per sponsor • Van top speed is 25% faster</small></div> <div class="iconCard"><div class="iconPic">🐍</div><b>ELON — ROAD SNAKE</b><small>12 PM–midnight • E-L-O-N on cars 2–5 • hit = −25% and +1 segment</small></div> </div> <h3 class="howSection">LIVING CITY TRAFFIC</h3> <p>The current road network is audited continuously. Civilian vehicles that leave valid pavement or remain trapped for more than 3.5 seconds are moved to a valid current-road route. The old perimeter routes are no longer used. Civilian traffic remains capped at 25 total road units; the Road Snake and Black Star cars remain separate and unchanged.</p> <h3 class="howSection">ARMORED VAN & POTATO GUN</h3> <p>Purchase the armored Vancerts van at BYOB for <b>$20,000</b>. It becomes army green with a yellow center stripe and black VANCERTS lettering. On desktop, press <b>Space</b> to fire doughnuts. On phones, use the red <b>🍩</b> button immediately left of the forward arrow. Enter remains the dedicated interaction key. Doughnuts turn any regular road vehicle into a collectible consumable. Black Star cars become doughnuts. Elon segments become eggs. Each shot removes one Elon segment, but Elon can never be reduced below five segments and remains until midnight.</p> <h3 class="howSection">CONSUMABLES</h3> <p>Food crates, gas cans, hazard doughnuts and Elon eggs are stored separately at BYOB. Consume one at a time; every item restores exactly <b>25%</b> van condition up to 100%.</p> <h3 class="howSection">STREET COLLECTIBLES</h3> <div class="iconKey"> <div class="iconCard"><div class="iconPic">🎸</div><b>GUITAR CASE</b><small>Music resource</small></div> <div class="iconCard"><div class="iconPic">🎤</div><b>MICROPHONE</b><small>Music resource</small></div> <div class="iconCard"><div class="iconPic">🥁</div><b>SNARE DRUM</b><small>Music resource</small></div> <div class="iconCard"><div class="iconPic">🎹</div><b>KEYBOARD</b><small>Music resource</small></div> <div class="iconCard"><div class="iconPic">🎷</div><b>SAXOPHONE</b><small>Music resource</small></div> <div class="iconCard"><div class="iconPic">🎺</div><b>TRUMPET</b><small>Music resource</small></div> <div class="iconCard"><div class="iconPic">🔌</div><b>XLR CABLE</b><small>Production resource</small></div> <div class="iconCard"><div class="iconPic">🔊</div><b>PA SPEAKER</b><small>Production resource</small></div> <div class="iconCard"><div class="iconPic">🎚️</div><b>MIXER</b><small>Production resource</small></div> <div class="iconCard"><div class="iconPic">🎟️</div><b>SHOW TICKET</b><small>Event collectible</small></div> <div class="iconCard"><div class="iconPic">🪘</div><b>TAMBOURINE</b><small>Music resource</small></div> <div class="iconCard"><div class="iconPic">📼</div><b>LOCAL MUSIC TAPE</b><small>Community reputation</small></div> <div class="iconCard"><div class="iconPic">🥫</div><b>FOOD DONATION</b><small>Community resource</small></div> <div class="iconCard"><div class="iconPic">📦</div><b>DONATION CRATE</b><small>Community resource</small></div> <div class="iconCard"><div class="iconPic">🌱</div><b>SAPLING</b><small>Community resource</small></div> <div class="iconCard"><div class="iconPic">🎨</div><b>PAINT SUPPLIES</b><small>Community art resource</small></div> <div class="iconCard"><div class="iconPic">⛽</div><b>GAS CAN</b><small>Van support resource</small></div> </div> <h3 class="howSection">MONEY, DAMAGE & HELP</h3> <div class="iconKey"> <div class="iconCard"><div class="iconPic">🏦</div><b>BANK</b><small>Microloans and repayment only</small></div> <div class="iconCard"><div class="iconPic">🧰</div><b>ROCK N ROLL</b><small>25% of missing required gear value</small></div> <div class="iconCard"><div class="iconPic">🚘</div><b>TRAFFIC</b><small>Road vehicles damage the van</small></div> <div class="iconCard"><div class="iconPic">♫</div><b>512 JAMS</b><small>Spotify playlist • Minimize safely • Submit Spotify links</small></div> </div> <h3 class="howSection">512 JAMS • SAFE PLAYER</h3><p>The vintage radio begins in the middle of the lower dashboard. Drag the small radio display while it is minimized, or drag the top radio face while it is open, to place it anywhere inside the visible game screen. Open it and use Spotify's own Play and Pause controls. Its illuminated display updates when Spotify reports a new track; Spotify's embedded player remains the complete artist-and-track source. While the full player is open, driving input pauses so the van cannot move behind it. Choose <b>MINIMIZE</b> to resume the game while Spotify keeps playing. <b>STOP MUSIC ONLY</b> unloads Spotify audio. <b>SUBMIT MUSIC</b> opens an email to hello@vancerts.com with the subject <b>512 Jams, Playlist Submission</b>. A Spotify link is required; accepted submissions are added within 24–48 hours. None of these controls save, load, refresh, reset, exit fullscreen, move the van, or replace your current game progress.</p> <h3 class="howSection">PERMANENT HAZARD RULES</h3><p><b>Elon the Road Snake is never removed, replaced, frozen, or included in the civilian traffic limit. The armored van may temporarily shorten Elon one segment per doughnut, but never below five segments.</b> It appears every Austin day from 12:00 PM until midnight, starts at 5 segments plus 3 per sponsor sign, causes −25% van condition, and grows by 1 segment every time it hits the van. Black Star cars are also permanent and continue using the established rule of one base car plus one per sponsor banner.</p> <h3 class="howSection">COMMUNITY</h3> <p>Community upgrades physically change Austin: Food Pantry, Community Garden, Public Art, Music Education, Housing Initiative, and the Austin Music District. Trees stay on valid grass; bicycles, cars, and hazards stay on approved travel surfaces.</p> <div class="btns"> <button onclick="exportPortableSave()">EXPORT SAVE FILE</button> <button onclick="choosePortableSave()">LOAD GAME FILE</button> <button onclick="showExpansionPermits()">EXPANSION PERMITS</button> <button onclick="resetDeviceLayout()">RESET DEVICE LAYOUT</button> <button onclick="closeModal()">RETURN TO GAME</button> </div>`); function normalizeControlCode(e){const c=e.code||'';if(c)return c;const k=String(e.key||'');const low=k.toLowerCase();if(low==='w')return'KeyW';if(low==='a')return'KeyA';if(low==='s')return'KeyS';if(low==='z')return'KeyZ';if(low==='r')return'KeyR';if(k===' ')return'Space';return k} function setKey(e,v){const code=normalizeControlCode(e);if(code)keys[code]=v;const key=String(e.key||'');if(key)keys[key]=v;if(key.length===1)keys[key.toLowerCase()]=v} function drivePressed(name){if(spotifyPlayerExpanded())return false;if(name==='forward')return!!(keys.KeyW||keys.w||keys.W||keys.ArrowUp||(typeof controllerInput!=='undefined'&&controllerInput.forward));if(name==='reverse')return!!(keys.KeyZ||keys.z||keys.Z||keys.ArrowDown||(typeof controllerInput!=='undefined'&&controllerInput.reverse));if(name==='left')return!!(keys.KeyA||keys.a||keys.A||keys.ArrowLeft||(typeof controllerInput!=='undefined'&&controllerInput.left));if(name==='right')return!!(keys.KeyS||keys.s||keys.S||keys.ArrowRight||(typeof controllerInput!=='undefined'&&controllerInput.right));return false} const CONTROL_KEYS=new Set(['ArrowUp','ArrowDown','ArrowLeft','ArrowRight','KeyW','KeyA','KeyS','KeyZ','Space','Enter','KeyR']); function rescueVanFromInvalidMapPosition(showMessage=false){ if(onRoad(van.x,van.y))return false; van.x=GIGBAG_SPAWN.x;van.y=GIGBAG_SPAWN.y;van.angle=GIGBAG_SPAWN.angle;van.speed=0; if(showMessage)toast('MAP UPDATE • VAN RETURNED TO THE GIG BAG PULL-IN'); return true } window.rescueVanFromInvalidMapPosition=rescueVanFromInvalidMapPosition; function isTextEntryTarget(target){return !!target&&(target.tagName==='INPUT'||target.tagName==='TEXTAREA'||target.tagName==='SELECT'||target.isContentEditable)} function handleKeyDown(e){if(isTextEntryTarget(e.target))return;const code=normalizeControlCode(e);if(CONTROL_KEYS.has(code)){e.preventDefault();setKey(e,true);canvas.focus({preventScroll:true})}if(code==='Space'&&!e.repeat)combatOrInteract(false);if(code==='Enter'&&!e.repeat)combatOrInteract(true);if(code==='KeyR'&&!e.repeat){van.x=GIGBAG_SPAWN.x;van.y=GIGBAG_SPAWN.y;van.angle=GIGBAG_SPAWN.angle;van.speed=0;toast('Returned to the Gig Bag ATX loading zone.')}} function handleKeyUp(e){if(isTextEntryTarget(e.target))return;const code=normalizeControlCode(e);if(CONTROL_KEYS.has(code))e.preventDefault();setKey(e,false)} window.addEventListener('keydown',handleKeyDown,{capture:true});window.addEventListener('keyup',handleKeyUp,{capture:true});document.addEventListener('keydown',handleKeyDown,{capture:true});document.addEventListener('keyup',handleKeyUp,{capture:true}); window.addEventListener('blur',()=>{for(const k of Object.keys(keys))keys[k]=false});document.addEventListener('visibilitychange',()=>{if(document.hidden)for(const k of Object.keys(keys))keys[k]=false});canvas.setAttribute('tabindex','0');canvas.addEventListener('pointerdown',()=>canvas.focus({preventScroll:true})); document.querySelectorAll('[data-key]').forEach(b=>{const k=b.dataset.key;['pointerdown','touchstart'].forEach(ev=>b.addEventListener(ev,e=>{e.preventDefault();keys[k]=true}));['pointerup','pointercancel','pointerleave','touchend'].forEach(ev=>b.addEventListener(ev,e=>{e.preventDefault();keys[k]=false}))}); function inRect(x,y,r){return x>r.x&&x<r.x+r.w&&y>r.y&&y<r.y+r.h} function driveSurfaces(){const rects=[];for(const p of places){if(!placeVisible(p))continue;if(p.parking)rects.push(p.parking);if(p.setup)rects.push(p.setup)}return rects.concat(activeDriveways())} function buildingBlocked(x,y,pad=CITY_POLISH.collisionPad){return places.some(p=>placeVisible(p)&&pointInRect(x,y,p,pad))} function onRoad(x,y){const surface=roads.some(r=>inRect(x,y,r))||driveSurfaces().some(r=>inRect(x,y,r))||(typeof R36B45_HOME_ROADS!=='undefined'&&R36B45_HOME_ROADS.some(r=>inRect(x,y,r)));return surface&&!(typeof homeBuildingBlocked==='function'&&homeBuildingBlocked(x,y))&&!buildingBlocked(x,y,CITY_POLISH.collisionPad)}let crashCooldown=0; function wreckJob(){ if(!state.activeJob)return; const lost=[],protectedItems=[];for(const[k,n]of Object.entries(state.activeJob.loadedOwned||{})){const protectedCount=Math.min(Number(n)||0,Number(state.activeJob.loadedPaul?.[k])||0),lostCount=Math.max(0,(Number(n)||0)-protectedCount);if(lostCount>0){state.inventory[k]=Math.max(0,(state.inventory[k]||0)-lostCount);lost.push(`${lostCount} ${k}`)}if(protectedCount>0)protectedItems.push(`${protectedCount} ${k}`)} state.activeJob.wrecked=true;state.activeJob.loadedOwned={};state.activeJob.loadedRentals={};state.activeJob.loadedPaul={};state.activeJob.rentals={};state.activeJob.phase='pickup';state.rentalOrder=null;save();hud(); const missing=rentalMissingItems(state.activeJob),cost=rentalQuote(missing); modal(`<h2>VAN WRECKED</h2><p class="bad">The player van is disabled. Owned gear inside that van was destroyed.</p><p>${lost.length?`Owned gear lost: <b>${lost.join(', ')}</b>.`:'No owned gear was lost.'}</p>${protectedItems.length?`<p class="good">PAUL'S WHITE TRUCK SAVED: <b>${protectedItems.join(', ')}</b>.</p>`:''}<p>Call <b>Austin Tow Service</b> from the Nookia for $299. After towing and repairs, call <b>Rock N Roll Rentals</b> to replace missing gear. Rentals are delivered to Gig Bag ATX and must be picked up there.</p><p>Current rental estimate: <b>$${rentalMoney(cost)}</b> (25% of missing required equipment purchase value)</p><div class="btns"><button onclick="closeModal();openPhone()">OPEN NOOKIA CONTACTS</button></div>`) } function hazardWreck(reason){state.vanhp=0;van.speed=0;save();hud();toast(reason);if(state.activeJob)wreckJob();else modal(`<h2>VAN DESTROYED</h2><p>${reason}</p><p>The van is stranded. Call Austin Tow Service from the Nookia for <b>$299</b> to return it to BYOB Austin, then repair it in the garage.</p><div class="btns"><button onclick="closeModal();openPhone()">OPEN NOOKIA CONTACTS</button></div>`)} function loopPoint(c){const i=c.inset,w=world.w-i*2,h=world.h-i*2,len=2*(w+h),flip=c.dir<0?Math.PI:0;let d=((c.t%len)+len)%len;if(c.dir<0)d=len-d;if(d<w)return{x:i+d,y:i,angle:flip};d-=w;if(d<h)return{x:world.w-i,y:i+d,angle:Math.PI/2+flip};d-=h;if(d<w)return{x:world.w-i-d,y:world.h-i,angle:Math.PI+flip};d-=w;return{x:i,y:world.h-i-d,angle:-Math.PI/2+flip}}function carXY(c){if(c.route==='loop')return loopPoint(c);return c.axis==='x'?{x:c.pos,y:c.lane,angle:c.dir>0?0:Math.PI}:{x:c.lane,y:c.pos,angle:c.dir>0?Math.PI/2:-Math.PI/2}}function trafficHit(c){if(!trafficVisible(c)||c.entryMode||c.exitMode||inByobSafeZone(van.x,van.y,8))return false;const q=trafficVisualXY(c),edge=c.route==='loop',small=c.vehicleType==='motorcycle'||c.vehicleType==='horse';return Math.abs(van.x-q.x)<(small?25:edge?31:38)&&Math.abs(van.y-q.y)<(small?20:edge?23:29)} function hazardWreck(reason){state.vanhp=0;van.speed=0;save();hud();toast(reason);if(state.activeJob)wreckJob();else{van.x=BYOB_REPAIR.x;van.y=BYOB_REPAIR.y;van.angle=BYOB_REPAIR.angle;modal(`<h2>VAN DESTROYED</h2><p>${reason}</p><p>The van was towed to BYOB Austin. Repair costs remain $100 per 10%.</p><div class="btns"><button onclick="closeModal();hqModal()">OPEN BYOB GARAGE</button></div>`)}} function specialCarHit(car){if(car.hiddenUntil>Date.now()||inByobSafeZone(van.x,van.y,8))return false;return Math.abs(van.x-car.x)<38&&Math.abs(van.y-car.y)<28} function trashBallHit(b){if(inByobSafeZone(van.x,van.y,8))return false;return Math.hypot(van.x-b.x,van.y-b.y)<b.r+24} function update(dt){const f=Math.min(dt,40)/16;if(state.cheats&&state.cheats.invulnerable)state.vanhp=100;if(!$('modalWrap').classList.contains('show')){if((drivePressed('forward')||drivePressed('reverse'))&&state.vanhp<=0&&(!window.__lastDisabledToast||Date.now()-window.__lastDisabledToast>1800)){window.__lastDisabledToast=Date.now();toast('VAN DISABLED • Repair at BYOB Austin before driving.')}const up=drivePressed('forward')&&state.vanhp>0,back=drivePressed('reverse')&&state.vanhp>0,left=drivePressed('left'),right=drivePressed('right');if(left&&!right)van.angle-=.072*f;if(right&&!left)van.angle+=.072*f;if(up&&!back)van.speed+=.19*f;if(back&&!up)van.speed-=.15*f;van.speed=Math.max(-VANCERTS_VAN_REVERSE_SPEED,Math.min(VANCERTS_VAN_TOP_SPEED,van.speed));if(!up&&!back)van.speed*=Math.pow(.94,f);if(Math.abs(van.speed)<.025)van.speed=0;const nx=van.x+Math.cos(van.angle)*van.speed*f,ny=van.y+Math.sin(van.angle)*van.speed*f,redBlocked=movementBlockedByRed(van.x,van.y,nx,ny,'van');if(onRoad(nx,ny)&&!redBlocked){van.x=nx;van.y=ny}else van.speed=0;syncSpecialCars();syncRoadActivityBudget();updateEmergencyPullovers();updateSocialRide(dt);updateDeveloperSoloBike(dt);for(const c of traffic){advanceTrafficCar(c,f);trafficMovementAudit(c)}eastCorridorTrafficAudit();eastCorridorPeopleAudit();if(specialCarActive())for(const car of specialCars)advanceSpecialCar(car,f);updateSnakeWindow();updateRoadSnake(f);updateDonutProjectiles(f);ensurePedestrians();if(daytimePedestriansActive()){const pt=austinTimeParts(),toByob=pt.hour>=11;for(const p of pedestrians){if(toByob){if(!Number.isFinite(p.x)){p.x=p.x1+(p.x2-p.x1)*p.t;p.y=p.y1+(p.y2-p.y1)*p.t}const tx=1185,ty=475,dx=tx-p.x,dy=ty-p.y,d=Math.hypot(dx,dy)||1;const nx=p.x+dx/d*.045*dt,ny=p.y+dy/d*.045*dt;if(!movementBlockedByRed(p.x,p.y,nx,ny,'pedestrian')){p.x=nx;p.y=ny}if(Math.random()<.0007*dt)p.carrying=true}else{const nt=Math.max(0,Math.min(1,p.t+p.dir*p.speed*dt)),cx=p.x1+(p.x2-p.x1)*p.t,cy=p.y1+(p.y2-p.y1)*p.t,nx=p.x1+(p.x2-p.x1)*nt,ny=p.y1+(p.y2-p.y1)*nt;if(!movementBlockedByRed(cx,cy,nx,ny,'pedestrian'))p.t=nt;if(p.t>=1)p.dir=-1;if(p.t<=0)p.dir=1;p.x=undefined;p.y=undefined}}}updateCartCollector(dt);for(const c of collectibles){if(!sandboxRoadTestingActive()&&!c.active&&c.respawnAt&&Date.now()>=c.respawnAt){c.active=true;c.delivered=false;const safe=nearestSafeCollectibleSpawn(c,collectibles.indexOf(c),collectibles.filter(d=>d!==c&&d.active&&!d.delivered).map(d=>({x:d.x,y:d.y})));c.homeX=safe.x;c.homeY=safe.y;c.x=safe.x;c.y=safe.y;c.respawnAt=0}if(collectibleHit(c))collectItem(c)}if(crashCooldown>0)crashCooldown-=dt;if(specialCrashCooldown>0)specialCrashCooldown-=dt;if(snakeCrashCooldown>0)snakeCrashCooldown-=dt;if(crashCooldown<=0){for(const c of traffic){if(trafficHit(c)){if(c.vehicleType==='waymo'){const before=state.vanhp;state.vanhp=Math.min(100,state.vanhp+5);van.speed*=-.18;crashCooldown=1100;save();hud();toast(state.vanhp>before?'WAYMO HIT BONUS! Van +5%':'WAYMO HIT BONUS! Van already 100%');break}if(state.vanUpgrades.armored){van.speed*=-.1;crashCooldown=650;toast('ARMORED VAN • REGULAR TRAFFIC DAMAGE BLOCKED');break}const dmg=Math.max(1,Number(c.damage)||3);state.vanhp=Math.max(0,state.vanhp-dmg);van.speed*=-.35;crashCooldown=1100;save();hud();toast(`TRAFFIC HIT! Van -${dmg}%`);if(state.vanhp<=0){if(state.activeJob)wreckJob();else{state.vanhp=0;van.x=BYOB_REPAIR.x;van.y=BYOB_REPAIR.y;van.angle=BYOB_REPAIR.angle;van.speed=0;save();modal(`<h2>VAN DISABLED</h2><p>Traffic reduced the van to 0%. No show gear was loaded, so nothing was lost. The van was towed into the BYOB Austin loading zone.</p><p>Use the Vancerts garage here. Repairs cost <b>$100 per 10%</b>.</p><div class="btns"><button onclick="closeModal();hqModal()">OPEN BYOB GARAGE</button></div>`)}}break}}}if(specialCarActive()&&specialCrashCooldown<=0){for(const car of specialCars){if(specialCarHit(car)){if(car.vehicleType==='specialwaygo'){const before=state.vanhp;state.vanhp=Math.min(100,state.vanhp+5);van.speed*=-.2;specialCrashCooldown=1200;save();hud();toast(state.vanhp>before?'WAYGO HIT BONUS! Van +5%':'WAYGO HIT • Van already 100%');break}const blackStarDamage=state.vanUpgrades.armored?Math.round(50*.75):50;state.vanhp=Math.max(0,state.vanhp-blackStarDamage);van.speed*=-.7;specialCrashCooldown=1400;save();hud();toast(`BLACK STAR CAR HIT! Van -${blackStarDamage}%${state.vanUpgrades.armored?' • ARMOR REDUCED DAMAGE 25%':''} • ${specialCars.length} active`);if(state.vanhp<=0)hazardWreck('A fast black star car destroyed the van.');break}}}if(roadSnake.active&&snakeCrashCooldown<=0&&snakeHit()){const snakeDamage=state.vanUpgrades.armored?Math.round(25*.75):25;state.vanhp=Math.max(0,state.vanhp-snakeDamage);if(window.marcoSnakeEngage&&window.marcoSnakeEngage())roadSnake.length=Math.max(5,roadSnake.length-1);else roadSnake.length+=1;van.speed*=-.55;snakeCrashCooldown=1700;save();hud();toast(`ROAD SNAKE HIT! Van -${snakeDamage}%${state.vanUpgrades.armored?' • ARMOR REDUCED DAMAGE 25%':''} • Snake length ${roadSnake.length}`);if(state.vanhp<=0)hazardWreck('The road snake destroyed the van.')}}near=activeCareerHomeNear()||activePosterSpotNear()||activePassengerDropNear()||activeBusPickupNear();let best=near?0:92;if(!near)for(const b of places){if(!placeVisible(b))continue;if(businessInteractionNear(b)){const d=Math.hypot(van.x-b.interact.x,van.y-b.interact.y);if(d<best||pointInRect(van.x,van.y,b.interactionRect||b.setup||{x:-1,y:-1,w:0,h:0},22)){best=Math.min(best,d);near=b}}}const tapHint=$('mobileTapHint');if(tapHint)tapHint.classList.toggle('show',!!near&&Math.abs(van.speed)<.7)} function drawByobCommunityFlags(p){ if(p.id!=='hq'||!flagEraActive())return; const total=byobFlagCount(),visible=Math.min(total,3); if(!visible)return; ctx.save(); const startX=p.x+20,baseY=p.y-15,gap=42; for(let i=0;i<visible;i++){ const x=startX+i*gap,y=baseY-(i%2)*5; ctx.strokeStyle='#28231f';ctx.lineWidth=4;ctx.beginPath();ctx.moveTo(x,y);ctx.lineTo(x,y-36);ctx.stroke(); ctx.fillStyle=i%2?'#f1b83e':'#3f84a5';ctx.beginPath();ctx.moveTo(x,y-36);ctx.lineTo(x+24,y-29);ctx.lineTo(x,y-21);ctx.closePath();ctx.fill(); ctx.strokeStyle='#fff5d6';ctx.lineWidth=1;ctx.stroke(); } ctx.fillStyle='#173d20';ctx.font='1000 9px system-ui';ctx.textAlign='left';ctx.fillText(`BYOB COMMUNITY FLAGS ${total}`,p.x+20,p.y-21); ctx.restore() } function drawByobSponsorBanners(p){ if(p.id!=='hq'||!p.parking)return; const signed=places.filter(x=>x.type==='gig'&&state.venues[x.id]?.sign); if(!signed.length)return; const lot=p.parking,cellW=lot.w/lot.cols,cellH=lot.h/lot.rows,limit=Math.min(signed.length,lot.cols*lot.rows); ctx.save(); for(let i=0;i<limit;i++){ const b=signed[i],c=i%lot.cols,r=Math.floor(i/lot.cols),cx=lot.x+c*cellW+cellW/2,cy=lot.y+r*cellH+cellH/2; const w=Math.min(58,cellW-18),h=Math.min(30,cellH-18); ctx.fillStyle='rgba(0,0,0,.28)';ctx.fillRect(cx-w/2+4,cy-h/2+5,w,h); ctx.fillStyle=b.color||'#333';ctx.fillRect(cx-w/2,cy-h/2,w,h); ctx.strokeStyle='#fff5d6';ctx.lineWidth=2;ctx.strokeRect(cx-w/2+1,cy-h/2+1,w-2,h-2); ctx.fillStyle='#fff';ctx.font='1000 7px system-ui';ctx.textAlign='center'; ctx.fillText((b.abbr||b.short||b.name).toUpperCase(),cx,cy+3); } ctx.fillStyle='#173d20';ctx.font='1000 8px system-ui';ctx.textAlign='center'; ctx.fillText(`BYOB SPONSOR PARKING • ${limit}/${lot.cols*lot.rows}`,lot.x+lot.w/2,lot.y+lot.h-5); ctx.restore() } function collectibleHit(c){return c.active&&Math.hypot(van.x-c.x,van.y-c.y)<32} function collectItem(c){ c.active=false;c.delivered=false;c.x=c.homeX;c.y=c.homeY;c.respawnAt=c.temporary?0:Date.now()+collectibleRespawnMs(); const key=collectibleInventoryKey(c),repairValue=Math.max(1,Number(c.hp)||0),before=Math.max(0,Number(state.vanhp)||0),needed=Math.max(0,100-before),applied=Math.min(needed,repairValue),reserve=repairValue-applied; state.vanhp=Math.min(100,before+applied);state.collectibleRepairReserve=state.collectibleRepairReserve&&typeof state.collectibleRepairReserve==='object'?state.collectibleRepairReserve:{}; if(reserve>0)state.collectibleRepairReserve[key]=(Number(state.collectibleRepairReserve[key])||0)+reserve; if(applied===0)state.collectedResources[key]=(Number(state.collectedResources[key])||0)+1; state.rep+=c.rep;normalizeGigBagDeliverySlots();save();hud(); toast(`${c.label} • VAN +${applied}%${reserve>0?` • ${reserve}% SAVED IN INVENTORY`:''}${applied===0?' • ITEM STORED':''} • VAN ${Math.round(state.vanhp)}% • COMMUNITY +${c.rep}`) } function drawCollectible(c,now){if(!c.active)return;const y=c.y+Math.sin(now*.003+c.bob)*2;ctx.save();ctx.translate(c.x,y);ctx.imageSmoothingEnabled=false;ctx.fillStyle='rgba(0,0,0,.28)';ctx.beginPath();ctx.ellipse(5,12,17,6,0,0,Math.PI*2);ctx.fill();switch(c.type){case'egg':ctx.fillStyle='#f3ead2';ctx.beginPath();ctx.ellipse(0,0,9,13,0,0,Math.PI*2);ctx.fill();ctx.strokeStyle='#c9b98e';ctx.lineWidth=2;ctx.stroke();break;case'donut':ctx.fillStyle='#d6a04d';ctx.beginPath();ctx.arc(0,0,13,0,Math.PI*2);ctx.fill();ctx.fillStyle='#f4cad4';ctx.beginPath();ctx.arc(0,0,10,0,Math.PI*2);ctx.fill();ctx.fillStyle='#41464a';ctx.beginPath();ctx.arc(0,0,4,0,Math.PI*2);ctx.fill();break;case'guitarcase':ctx.rotate(-.16);ctx.fillStyle='#191514';ctx.fillRect(-15,-8,25,17);ctx.fillRect(8,-4,9,8);ctx.fillStyle='#4b3023';ctx.fillRect(-12,-5,19,11);ctx.strokeStyle='#c79a58';ctx.lineWidth=2;ctx.strokeRect(-12,-5,19,11);ctx.fillStyle='#d7b267';ctx.fillRect(-2,-10,7,3);break;case'foodcrate':ctx.fillStyle='#7a4b25';ctx.fillRect(-15,-11,30,23);ctx.fillStyle='#a36b35';ctx.fillRect(-12,-8,24,17);ctx.strokeStyle='#4a2a16';ctx.lineWidth=2;ctx.strokeRect(-12,-8,24,17);ctx.beginPath();ctx.moveTo(-12,-8);ctx.lineTo(12,9);ctx.moveTo(12,-8);ctx.lineTo(-12,9);ctx.stroke();ctx.fillStyle='#d9bd73';ctx.fillRect(-7,-15,14,5);break;case'sapling':ctx.fillStyle='#6b4428';ctx.fillRect(-2,-5,5,18);ctx.fillStyle='#315f32';ctx.beginPath();ctx.arc(-5,-10,8,0,Math.PI*2);ctx.arc(5,-13,9,0,Math.PI*2);ctx.fill();ctx.fillStyle='#4b8e49';ctx.beginPath();ctx.arc(1,-15,7,0,Math.PI*2);ctx.fill();ctx.fillStyle='#5f4027';ctx.beginPath();ctx.ellipse(0,12,12,5,0,0,Math.PI*2);ctx.fill();break;case'paint':ctx.fillStyle='#b8bcc2';ctx.fillRect(-10,-10,20,22);ctx.fillStyle='#e64a38';ctx.fillRect(-8,-7,16,8);ctx.strokeStyle='#333';ctx.lineWidth=2;ctx.strokeRect(-10,-10,20,22);ctx.beginPath();ctx.arc(0,-10,10,Math.PI,0);ctx.stroke();ctx.fillStyle='#f1b83e';ctx.fillRect(11,-12,4,24);ctx.fillStyle='#333';ctx.fillRect(10,8,7,5);break;case'gas':ctx.fillStyle='#d44737';ctx.fillRect(-11,-12,22,26);ctx.fillStyle='#111';ctx.fillRect(-4,-17,10,7);ctx.fillStyle='#f4d34b';ctx.fillRect(-5,-2,10,8);ctx.strokeStyle='#71251f';ctx.lineWidth=2;ctx.strokeRect(-11,-12,22,26);break; case'microphone':ctx.fillStyle='#222';ctx.fillRect(-2,-4,4,20);ctx.fillStyle='#aeb3b6';ctx.beginPath();ctx.arc(0,-9,7,0,Math.PI*2);ctx.fill();ctx.strokeStyle='#555';ctx.lineWidth=2;ctx.stroke();break; case'snare':ctx.fillStyle='#d8d4c5';ctx.fillRect(-13,-8,26,17);ctx.strokeStyle='#333';ctx.lineWidth=3;ctx.strokeRect(-13,-8,26,17);ctx.beginPath();ctx.moveTo(-13,-3);ctx.lineTo(13,5);ctx.moveTo(-13,5);ctx.lineTo(13,-3);ctx.stroke();break; case'keyboard':ctx.fillStyle='#222';ctx.fillRect(-18,-8,36,16);for(let i=0;i<9;i++){ctx.fillStyle='#eee';ctx.fillRect(-16+i*3.5,-6,3,11)}break; case'sax':ctx.strokeStyle='#d6a72f';ctx.lineWidth=6;ctx.beginPath();ctx.moveTo(-4,-13);ctx.lineTo(-4,6);ctx.quadraticCurveTo(-4,15,9,12);ctx.stroke();ctx.fillStyle='#d6a72f';ctx.beginPath();ctx.arc(10,11,6,0,Math.PI*2);ctx.fill();break; case'trumpet':ctx.fillStyle='#d6a72f';ctx.fillRect(-15,-4,25,8);ctx.beginPath();ctx.moveTo(10,-9);ctx.lineTo(20,0);ctx.lineTo(10,9);ctx.closePath();ctx.fill();break; case'cable':ctx.strokeStyle='#171717';ctx.lineWidth=4;ctx.beginPath();ctx.arc(0,0,13,0,Math.PI*2);ctx.stroke();ctx.fillStyle='#b9b9b9';ctx.fillRect(10,-3,10,6);break; case'speaker':ctx.fillStyle='#222';ctx.fillRect(-13,-16,26,32);ctx.fillStyle='#555';ctx.beginPath();ctx.arc(0,5,9,0,Math.PI*2);ctx.arc(0,-9,5,0,Math.PI*2);ctx.fill();break; case'mixer':ctx.fillStyle='#555b5e';ctx.fillRect(-18,-12,36,24);for(let i=0;i<6;i++){ctx.fillStyle=i%2?'#e64a38':'#3f84a5';ctx.fillRect(-15+i*5,-8,3,5);ctx.fillStyle='#ddd';ctx.fillRect(-15+i*5,1,3,8)}break; case'ticket':ctx.fillStyle='#f1b83e';ctx.fillRect(-16,-8,32,16);ctx.fillStyle='#222';ctx.font='900 7px system-ui';ctx.textAlign='center';ctx.fillText('SHOW',0,3);break; case'tambourine':ctx.strokeStyle='#b78334';ctx.lineWidth=6;ctx.beginPath();ctx.arc(0,0,13,0,Math.PI*2);ctx.stroke();ctx.fillStyle='#ddd';for(let a=0;a<6;a++){ctx.beginPath();ctx.arc(Math.cos(a)*14,Math.sin(a)*14,3,0,Math.PI*2);ctx.fill()}break; case'cassette':ctx.fillStyle='#27272b';ctx.fillRect(-15,-9,30,18);ctx.fillStyle='#d6d1bd';ctx.fillRect(-11,-5,22,8);ctx.fillStyle='#111';ctx.beginPath();ctx.arc(-6,5,4,0,Math.PI*2);ctx.arc(6,5,4,0,Math.PI*2);ctx.fill();ctx.fillStyle='#e64a38';ctx.fillRect(-8,-3,16,2);break}ctx.restore()} function drawPerson(x,y,seed=0,carrying=false,withDog=false){ const palette=['#654d35','#7a5d40','#335e7c','#714b72','#486b4c','#9a5d3f']; const skin=['#6a4b34','#8b6041','#b67b55','#d5a078'][Math.abs(seed)%4]; const walk=Math.sin(performance.now()/170+seed*1.7)*2.2; ctx.save();ctx.translate(x,y); ctx.fillStyle='rgba(0,0,0,.24)';ctx.beginPath();ctx.ellipse(2,14,9,4,0,0,Math.PI*2);ctx.fill(); ctx.strokeStyle='#26211d';ctx.lineWidth=3;ctx.lineCap='round';ctx.beginPath();ctx.moveTo(-2,7);ctx.lineTo(-5+walk,16);ctx.moveTo(2,7);ctx.lineTo(5-walk,16);ctx.stroke(); ctx.fillStyle=palette[Math.abs(seed)%palette.length];ctx.fillRect(-5,-4,10,13); ctx.fillStyle='rgba(255,255,255,.16)';ctx.fillRect(-4,-3,2,10); ctx.strokeStyle='#2c261f';ctx.lineWidth=2;ctx.beginPath();ctx.moveTo(-4,-1);ctx.lineTo(-8-walk*.35,5);ctx.moveTo(4,-1);ctx.lineTo(8+walk*.35,5);ctx.stroke(); ctx.fillStyle=skin;ctx.beginPath();ctx.arc(0,-10,5,0,Math.PI*2);ctx.fill(); ctx.fillStyle='#2b211c';ctx.fillRect(-4,-14,8,3); if(carrying){ctx.fillStyle='#d9aa48';ctx.fillRect(6,0,9,8);ctx.strokeStyle='#4b3421';ctx.lineWidth=1.5;ctx.strokeRect(6,0,9,8)} if(withDog){ctx.fillStyle='#6b4b34';ctx.fillRect(13,9,10,6);ctx.beginPath();ctx.arc(22,9,4,0,Math.PI*2);ctx.fill();ctx.strokeStyle='#3b2a20';ctx.lineWidth=1.5;ctx.beginPath();ctx.moveTo(7,3);ctx.lineTo(16,8);ctx.stroke()} ctx.restore() } function drawStreetLife(){if(sandboxRoadTestingActive())return;const t=austinTimeParts(),mins=t.hour*60+t.minute;{const visibleStops=visibleBusStops();for(let s=0;s<visibleStops.length;s++){const site=visibleStops[s],count=1+((s+Math.floor(mins/120))%3);for(let i=0;i<count;i++){const px=site.x+18+i*18,py=site.y+(site.side==='north'?-10:site.h+12);drawPerson(px,py,s*4+i,false,false)}}}if(mins>=420&&mins<1320){const loop=[{x1:165,y1:1510,x2:2535,y2:1510},{x1:2535,y1:1510,x2:2535,y2:1885},{x1:2535,y1:1885,x2:165,y2:1885},{x1:165,y1:1885,x2:165,y2:1510}],lens=loop.map(s=>Math.hypot(s.x2-s.x1,s.y2-s.y1)),total=lens.reduce((a,b)=>a+b,0),travel=(performance.now()/42)%total;let d=travel,seg=loop[0],segLen=lens[0];for(let i=0;i<loop.length;i++){if(d<=lens[i]){seg=loop[i];segLen=lens[i];break}d-=lens[i]}const t=segLen?d/segLen:0,cx=seg.x1+(seg.x2-seg.x1)*t,cy=seg.y1+(seg.y2-seg.y1)*t,ang=Math.atan2(seg.y2-seg.y1,seg.x2-seg.x1);ctx.save();ctx.translate(cx,cy);ctx.rotate(ang);ctx.strokeStyle='#252525';ctx.lineWidth=3;ctx.beginPath();ctx.arc(-10,7,7,0,Math.PI*2);ctx.arc(10,7,7,0,Math.PI*2);ctx.moveTo(-10,7);ctx.lineTo(0,-2);ctx.lineTo(10,7);ctx.moveTo(0,-2);ctx.lineTo(4,7);ctx.stroke();ctx.fillStyle='#4f6f93';ctx.fillRect(-3,-15,7,13);ctx.fillStyle='#6a4b34';ctx.beginPath();ctx.arc(0,-19,4,0,Math.PI*2);ctx.fill();ctx.restore()}if(mins>=960||mins<120){const base=places.find(p=>p.id==='mama');if(base&&placeVisible(base)){for(let i=0;i<6;i++){const px=base.x+35+i*38,py=base.y+base.h+38+(i%2)*13;ctx.save();ctx.translate(px,py);ctx.fillStyle=['#7c3546','#333f72','#6a4b34','#4e6b42'][i%4];ctx.beginPath();ctx.arc(0,-8,5,0,Math.PI*2);ctx.fill();ctx.fillRect(-4,-3,8,14);ctx.restore()}}}} function drawPassengerMarkers(){if(!BUS_STOPS_ENABLED)return;ctx.save();if(!state.passengerRide){for(let i=0;i<visibleBusStops().length;i++){const pt=busStopPickupPoint(visibleBusStops()[i]);ctx.fillStyle='#16723a';ctx.beginPath();ctx.arc(pt.x,pt.y-28,13,0,Math.PI*2);ctx.fill();ctx.strokeStyle='#fff';ctx.lineWidth=2;ctx.stroke();ctx.fillStyle='#fff';ctx.font='1000 10px system-ui';ctx.textAlign='center';ctx.fillText('$5',pt.x,pt.y-24)}}else{const dest=activePassengerDestination();if(dest){const bob=Math.sin(performance.now()/180)*5;ctx.fillStyle='#f1b83e';ctx.beginPath();ctx.moveTo(dest.interact.x,dest.interact.y-42+bob);ctx.lineTo(dest.interact.x-11,dest.interact.y-61+bob);ctx.lineTo(dest.interact.x+11,dest.interact.y-61+bob);ctx.closePath();ctx.fill();ctx.strokeStyle='#111';ctx.lineWidth=3;ctx.stroke();ctx.fillStyle='#111';ctx.font='1000 9px system-ui';ctx.textAlign='center';ctx.fillText('DROP',dest.interact.x,dest.interact.y-67+bob)}}ctx.restore()} const WEST_VISUAL_PARCELS=[ {id:'west-main-strip',x:-400,y:150,w:400,h:1750,continuous:true}, {id:'west-lower-parcel',x:-400,y:2050,w:400,h:400,future:true} ]; function drawWestSideParcelBackplates(){ ctx.save(); for(const q of WEST_VISUAL_PARCELS){ ctx.fillStyle='#9dc77f';ctx.fillRect(q.x,q.y,q.w,q.h); ctx.strokeStyle='#aaa99e';ctx.lineWidth=8;ctx.strokeRect(q.x+4,q.y+4,q.w-8,q.h-8); ctx.strokeStyle='#718d60';ctx.lineWidth=2;ctx.setLineDash([10,8]); ctx.strokeRect(q.x+14,q.y+14,q.w-28,q.h-28);ctx.setLineDash([]); if(q.future){ ctx.fillStyle='rgba(244,230,190,.9)';ctx.fillRect(q.x+76,q.y+145,q.w-152,70); ctx.strokeStyle='#171514';ctx.lineWidth=4;ctx.strokeRect(q.x+76,q.y+145,q.w-152,70); ctx.fillStyle='#171514';ctx.textAlign='center';ctx.font='1000 16px system-ui'; ctx.fillText('FUTURE WEST PARCEL',q.x+q.w/2,q.y+176); ctx.font='900 11px system-ui';ctx.fillText('ROAD ACCESS RESERVED',q.x+q.w/2,q.y+197) } } const east={x:2700,y:2050,w:400,h:400}; ctx.fillStyle='rgba(244,230,190,.9)';ctx.fillRect(east.x+76,east.y+145,east.w-152,70); ctx.strokeStyle='#171514';ctx.lineWidth=4;ctx.strokeRect(east.x+76,east.y+145,east.w-152,70); ctx.fillStyle='#171514';ctx.textAlign='center';ctx.font='1000 16px system-ui'; ctx.fillText('FUTURE EAST PARCEL',east.x+east.w/2,east.y+176); ctx.font='900 11px system-ui';ctx.fillText('ROAD ACCESS RESERVED',east.x+east.w/2,east.y+197); ctx.restore() } function drawGroundTexture(){ctx.save();ctx.globalAlpha=.16;for(let y=165;y<world.h-150;y+=34){for(let x=165;x<world.w-150;x+=38){const n=Math.abs(tHash(x+':'+y));ctx.fillStyle=n%3===0?'#6f985f':n%3===1?'#87ad70':'#b7d08d';ctx.fillRect(x+(n%9),y+((n>>3)%7),2+(n%3),2)}}ctx.restore()} function drawLeftwayGroundsParcel(b){ ctx.save(); // Full photo-inspired grounds fill the complete neighboring parcel. ctx.fillStyle='#7dac67';ctx.fillRect(b.x,b.y,b.w,b.h); ctx.strokeStyle='#aaa99e';ctx.lineWidth=8;ctx.strokeRect(b.x+4,b.y+4,b.w-8,b.h-8); ctx.strokeStyle='#718d60';ctx.lineWidth=2;ctx.setLineDash([10,8]); ctx.strokeRect(b.x+14,b.y+14,b.w-28,b.h-28);ctx.setLineDash([]); // Curving paths. ctx.strokeStyle='#d8cfbb';ctx.lineWidth=14;ctx.lineCap='round'; ctx.beginPath(); ctx.moveTo(b.x+24,b.y+b.h-35); ctx.quadraticCurveTo(b.x+100,b.y+220,b.x+180,b.y+150); ctx.quadraticCurveTo(b.x+245,b.y+95,b.x+b.w-30,b.y+73); ctx.stroke(); ctx.beginPath(); ctx.moveTo(b.x+178,b.y+b.h-22); ctx.quadraticCurveTo(b.x+232,b.y+232,b.x+276,b.y+182); ctx.stroke(); // Pond. ctx.fillStyle='#3c899d';ctx.beginPath();ctx.ellipse(b.x+83,b.y+224,52,34,-.18,0,Math.PI*2);ctx.fill(); ctx.strokeStyle='#b8aa82';ctx.lineWidth=7;ctx.stroke(); // Heritage tree. ctx.fillStyle='#4b3525';ctx.fillRect(b.x+157,b.y+92,15,102); ctx.fillStyle='#416f3e'; for(const [dx,dy,r] of [[0,0,43],[-32,8,31],[32,8,32],[-16,-33,32],[20,-34,31],[0,32,34]]){ ctx.beginPath();ctx.arc(b.x+164+dx,b.y+82+dy,r,0,Math.PI*2);ctx.fill() } // Structures along north/east boundaries. const cabins=[ {x:b.x+218,y:b.y+23,w:65,h:58,wall:'#8b5939',roof:'#5f4a3e'}, {x:b.x+290,y:b.y+18,w:70,h:64,wall:'#d5a33c',roof:'#d8d4c5'}, {x:b.x+282,y:b.y+235,w:78,h:65,wall:'#9b8b76',roof:'#595a5a'} ]; for(const c of cabins){ ctx.fillStyle=c.wall;ctx.fillRect(c.x,c.y,c.w,c.h); ctx.fillStyle=c.roof;ctx.fillRect(c.x-5,c.y-7,c.w+10,17); ctx.fillStyle='#315f75';ctx.fillRect(c.x+c.w*.42,c.y+c.h-26,16,26) } // Outdoor stage. ctx.fillStyle='#252525';ctx.fillRect(b.x+18,b.y+28,92,48); ctx.strokeStyle='#f1b83e';ctx.lineWidth=4;ctx.strokeRect(b.x+18,b.y+28,92,48); ctx.fillStyle='#fff';ctx.font='1000 9px system-ui';ctx.textAlign='center'; ctx.fillText('OUTDOOR STAGE',b.x+64,b.y+57); // Shade sails. const sails=[ [[32,108],[101,116],[70,166],'#55b8c7'], [[92,98],[154,132],[120,178],'#d8d2bd'], [[200,145],[260,120],[238,190],'#d8d2bd'], [[264,112],[338,115],[308,184],'#4a91c3'], [[310,170],[370,148],[348,221],'#3277bd'] ]; for(const [a,c,d,color] of sails){ ctx.fillStyle=color;ctx.beginPath();ctx.moveTo(b.x+a[0],b.y+a[1]); ctx.lineTo(b.x+c[0],b.y+c[1]);ctx.lineTo(b.x+d[0],b.y+d[1]); ctx.closePath();ctx.fill(); ctx.strokeStyle='rgba(35,45,45,.55)';ctx.lineWidth=2;ctx.stroke() } // Flowers and garden. for(const [fx,fy,col] of [[30,269,'#e35983'],[54,279,'#f0cf55'],[109,266,'#e35983'],[132,282,'#f0cf55'],[250,257,'#e86f4d'],[352,118,'#f0cf55']]){ ctx.fillStyle=col;ctx.beginPath();ctx.arc(b.x+fx,b.y+fy,5,0,Math.PI*2);ctx.fill() } ctx.fillStyle='rgba(20,55,29,.85)';ctx.fillRect(b.x+112,b.y+b.h-30,180,22); ctx.fillStyle='#fff';ctx.font='1000 12px system-ui'; ctx.fillText('LEFTWAY GROUNDS',b.x+b.w/2,b.y+b.h-14); ctx.restore() } function drawLeftwayCompoundBridge(){ const studio=places.find(x=>x.id==='leftway'),grounds=places.find(x=>x.id==='leftwaygrounds'); if(!studio||!grounds||!placeVisible(studio)||!placeVisible(grounds))return; const apron=Math.round(CITY_POLISH.buildingApron); // R36B33: span only the roadway, from the left sidewalk edge to the right sidewalk edge. // Find the vertical road separating Leftway Studios and Leftway Grounds so neither end // extends over the grass/property parcels. const gapLeft=studio.parking?studio.parking.x+studio.parking.w:studio.x+studio.w; const gapRight=grounds.x; const centerX=(gapLeft+gapRight)/2; const bridgeRoad=roads.filter(r=>r.h>r.w && centerX>=r.x-8 && centerX<=r.x+r.w+8) .sort((a,b)=>Math.abs((a.x+a.w/2)-centerX)-Math.abs((b.x+b.w/2)-centerX))[0]; const x=Math.round(bridgeRoad?bridgeRoad.x:gapLeft+apron); const w=Math.max(36,Math.round(bridgeRoad?bridgeRoad.w:gapRight-gapLeft-apron*2)); // Keep the approved R36B33 vertical placement midway between the north concrete // property edge and the parking/pull-in edge. const concreteEdge=Math.min(studio.y,grounds.y); const pullInEdge=studio.parking?studio.parking.y:studio.y+studio.h+110; const h=42,y=Math.round(concreteEdge+(pullInEdge-concreteEdge)/2-h/2); ctx.save(); // Transparent mesh floor: cars remain visible below. ctx.fillStyle='rgba(118,78,42,.20)';ctx.fillRect(x,y,w,h); ctx.strokeStyle='rgba(68,43,24,.78)';ctx.lineWidth=2; for(let px=x;px<=x+w;px+=10){ctx.beginPath();ctx.moveTo(px,y);ctx.lineTo(px,y+h);ctx.stroke()} for(let py=y;py<=y+h;py+=8){ctx.beginPath();ctx.moveTo(x,py);ctx.lineTo(x+w,py);ctx.stroke()} // Wooden rails. ctx.fillStyle='#80512d';ctx.fillRect(x,y,w,7);ctx.fillRect(x,y+h-7,w,7); ctx.fillStyle='#52321c';ctx.fillRect(x,y,5,h);ctx.fillRect(x+w-5,y,5,h); ctx.fillStyle='#fff5d6';ctx.font='1000 7px system-ui';ctx.textAlign='center'; ctx.fillText('LEFTWAY WOOD BRIDGE',x+w/2,y+6); ctx.fillText('DRIVE UNDER',x+w/2,y+h-1); ctx.restore() } function drawRoadTexture(r){ctx.save();ctx.beginPath();ctx.rect(r.x,r.y,r.w,r.h);ctx.clip();ctx.globalAlpha=.16;for(let i=0;i<Math.ceil((r.w*r.h)/24000);i++){const n=Math.abs(tHash(r.x+':'+r.y+':'+i)),x=r.x+(n%Math.max(1,Math.floor(r.w))),y=r.y+((n>>8)%Math.max(1,Math.floor(r.h)));ctx.fillStyle=i%2?'#25292b':'#6b7072';ctx.fillRect(x,y,10+(n%22),2+(n%4))}ctx.globalAlpha=.22;ctx.strokeStyle='#24282a';ctx.lineWidth=2;for(let i=0;i<4;i++){const n=Math.abs(tHash('crack'+r.x+r.y+i));ctx.beginPath();const x=r.x+(n%Math.max(20,r.w-20)),y=r.y+((n>>6)%Math.max(20,r.h-20));ctx.moveTo(x,y);ctx.lineTo(x+12,y+5);ctx.lineTo(x+18,y-2);ctx.stroke()}ctx.restore()} function shadeColor(hex,amt){let h=hex.replace('#','');if(h.length===3)h=h.split('').map(c=>c+c).join('');let n=parseInt(h,16),r=Math.max(0,Math.min(255,(n>>16)+amt)),g=Math.max(0,Math.min(255,((n>>8)&255)+amt)),b=Math.max(0,Math.min(255,(n&255)+amt));return '#'+[r,g,b].map(v=>v.toString(16).padStart(2,'0')).join('')} const PSEUDO_BUILDING_DEPTH=18; const VANCERTS_LOGO_YELLOW_DATA='data:image/png;base64,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'; const VANCERTS_LOGO_YELLOW=new Image();VANCERTS_LOGO_YELLOW.src=VANCERTS_LOGO_YELLOW_DATA; const QUEUE_LOGO_BW_DATA='data:image/png;base64,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'; const QUEUE_LOGO_BW=new Image();QUEUE_LOGO_BW.src=QUEUE_LOGO_BW_DATA; function drawPseudoBuilding(b){const d=PSEUDO_BUILDING_DEPTH;ctx.save();ctx.fillStyle='rgba(0,0,0,.28)';ctx.beginPath();ctx.moveTo(b.x-10,b.y+12);ctx.lineTo(b.x+b.w-10,b.y+12);ctx.lineTo(b.x+b.w-24,b.y+b.h+26);ctx.lineTo(b.x-24,b.y+b.h+26);ctx.closePath();ctx.fill();ctx.fillStyle=shadeColor(b.color||'#555',-38);ctx.beginPath();ctx.moveTo(b.x,b.y+b.h);ctx.lineTo(b.x-d,b.y+b.h+d);ctx.lineTo(b.x+b.w-d,b.y+b.h+d);ctx.lineTo(b.x+b.w,b.y+b.h);ctx.closePath();ctx.fill();ctx.fillStyle=shadeColor(b.color||'#555',-24);ctx.beginPath();ctx.moveTo(b.x,b.y);ctx.lineTo(b.x-d,b.y+d);ctx.lineTo(b.x-d,b.y+b.h+d);ctx.lineTo(b.x,b.y+b.h);ctx.closePath();ctx.fill();ctx.fillStyle=b.color;ctx.fillRect(b.x,b.y,b.w,b.h);ctx.strokeStyle='#171514';ctx.lineWidth=5;ctx.strokeRect(b.x,b.y,b.w,b.h);ctx.fillStyle='rgba(255,255,255,.10)';ctx.fillRect(b.x+8,b.y+8,b.w-16,8);ctx.fillStyle='rgba(0,0,0,.25)';for(let i=0;i<3;i++)ctx.fillRect(b.x+34+i*72,b.y+b.h-22,42,10);ctx.fillStyle='#747a7b';ctx.fillRect(b.x+b.w-68,b.y+18,42,28);ctx.fillStyle='#3d4243';ctx.fillRect(b.x+b.w-62,b.y+23,30,18);ctx.restore()} function drawLogo(b){ const main=(b.logo&&b.logo[0])||b.name,sub=b.subtitle||''; const isQueue=b.id==='queuetube'; const maxW=isQueue?Math.min(198,b.w-20):Math.max(72,Math.min(b.w*.76,b.w-34)); const signH=isQueue?66:(sub?Math.max(32,Math.min(46,b.h*.35)):Math.max(27,Math.min(38,b.h*.29))); const x=b.x+(b.w-maxW)/2,y=b.y+(isQueue?7:Math.max(9,b.h*.08)); if(isQueue){ ctx.save(); ctx.fillStyle='#fff';ctx.fillRect(x,y,maxW,signH); ctx.strokeStyle='#111';ctx.lineWidth=3;ctx.strokeRect(x+1,y+1,maxW-2,signH-2); if(QUEUE_LOGO_BW.complete&&QUEUE_LOGO_BW.naturalWidth){ const logoW=128,logoH=logoW*260/730; ctx.imageSmoothingEnabled=true;ctx.imageSmoothingQuality='high'; ctx.drawImage(QUEUE_LOGO_BW,b.x+b.w/2-logoW/2,y+3,logoW,logoH) }else{ ctx.fillStyle='#111';ctx.textAlign='center';ctx.font='1000 20px system-ui';ctx.fillText('QUEUE',b.x+b.w/2,y+34) } ctx.fillStyle='#111';ctx.textAlign='center';ctx.font='900 8px system-ui'; ctx.fillText('Community Playlist & Radio',b.x+b.w/2,y+60,maxW-18); ctx.restore(); return } const colors=b.id==='amlhouse' ?{bg:'#fff3bf',stroke:'#b52d2d',text:'#b52d2d'} :b.id==='mama' ?{bg:'#140000',stroke:'#ff2018',text:'#ff3028'} :{bg:'#fff5d6',stroke:'rgba(0,0,0,.28)',text:b.id==='bank'?'#173d20':'#111'}; ctx.save(); ctx.fillStyle=colors.bg;ctx.fillRect(x,y,maxW,signH); ctx.strokeStyle=colors.stroke;ctx.lineWidth=Math.max(2,Math.min(3,b.w/100));ctx.strokeRect(x+1,y+1,maxW-2,signH-2); ctx.fillStyle=colors.text;ctx.textAlign='center'; let size=Math.max(8,Math.min(15,signH*.38,(maxW-16)*1.55/main.length)); ctx.font=`1000 ${size}px system-ui`;ctx.fillText(main,b.x+b.w/2,y+(sub?signH*.48:signH*.62)); if(sub){ let subSize=Math.max(6,Math.min(9,signH*.2,(maxW-14)*1.7/sub.length)); ctx.font=`900 ${subSize}px system-ui`;ctx.fillText(sub,b.x+b.w/2,y+signH*.78) } ctx.restore() } function sponsorSignSite(b){ const bounds=propertyBounds(b),w=Math.max(82,Math.min(132,b.w*.62)),h=26; if(b.parking){ return{ x:b.parking.x+b.parking.w-w-5, y:b.parking.y+b.parking.h-h-4, w,h,mount:'property-edge' } } return{x:bounds.x+bounds.w-w-5,y:bounds.y+bounds.h-h-4,w,h,mount:'property-edge'} } function drawEastAustinExpansionGate(){ if(eastAustinPermitUnlocked())return; // Keep the large festival teaser entirely inside the southeast grass parcel, // east of Red River and clear of every road, crosswalk, driveway, and building. const x=2175,y=1570,w=300,h=108; ctx.save(); ctx.fillStyle='rgba(0,0,0,.32)';ctx.fillRect(x+10,y+10,w,h); ctx.fillStyle='#171514';ctx.fillRect(x,y,w,h);ctx.strokeStyle='#f1b83e';ctx.lineWidth=8;ctx.strokeRect(x+4,y+4,w-8,h-8); ctx.fillStyle='#f1b83e';ctx.textAlign='center';ctx.font='1000 35px system-ui';ctx.fillText('COMING SOON',x+w/2,y+48); ctx.fillStyle='#fff8e5';ctx.font='1000 18px system-ui';ctx.fillText("IT'S A VAN FEST",x+w/2,y+80); ctx.fillStyle='#e64a38';for(let i=0;i<6;i++)ctx.fillRect(x+22+i*48,y+h,24,14); ctx.restore() } function drawSponsorSign(b){ const v=b.type==='gig'?state.venues[b.id]:null;if(!v||!v.sign)return; const s=sponsorSignSite(b),sx=s.x,sy=s.y,w=s.w,h=s.h; ctx.save();ctx.fillStyle='rgba(0,0,0,.25)';ctx.fillRect(sx+4,sy+4,w,h); ctx.fillStyle='#111';ctx.fillRect(sx,sy,w,h);ctx.strokeStyle='#f1b83e';ctx.lineWidth=3;ctx.strokeRect(sx+2,sy+2,w-4,h-4); const padX=7,padY=5,iw=w-padX*2,ih=h-padY*2; if(VANCERTS_LOGO_YELLOW.complete&&VANCERTS_LOGO_YELLOW.naturalWidth){ const ratio=VANCERTS_LOGO_YELLOW.naturalWidth/VANCERTS_LOGO_YELLOW.naturalHeight; let dw=iw,dh=dw/ratio;if(dh>ih){dh=ih;dw=dh*ratio} ctx.drawImage(VANCERTS_LOGO_YELLOW,sx+(w-dw)/2,sy+(h-dh)/2,dw,dh) }else{ ctx.fillStyle='#f1b83e';ctx.textAlign='center';ctx.font='1000 13px system-ui';ctx.fillText('VANCERTS',sx+w/2,sy+h*.67) } ctx.restore() } function drawMamaDistrict(p){ // R36B17A: no shared parcel overlay. Mama Dearest and World Liquor // use the same independent property, sponsor-sign and flag rules as every business. return } function showsPerSponsoredLotFill(p){return Math.max(1,Math.ceil(Math.log2(Math.max(1,p.capacity||16)))+1)} function sponsoredLotFillCount(p){ const v=p&&p.type==='gig'?state.venues[p.id]:null;if(!v||!v.sign)return 0; return Math.max(0,Number(v.fillFlags)||0) } function flagPointBlockedForBusiness(p,x,y){ if(x<12||y<12||x>world.w-12||y>world.h-12)return true; if(onDesignatedRoadPoint(x,y,3))return true; if(pointInRect(x,y,p,9))return true; if(p.parking&&pointInRect(x,y,p.parking,7))return true; if(p.setup&&pointInRect(x,y,p.setup,7))return true; for(const d of activeDriveways())if(d.id!==p.id&&pointInRect(x,y,d,7))return true; for(const other of places){ if(other.id===p.id||!placeVisible(other))continue; if(pointInRect(x,y,other,7))return true; if(other.parking&&pointInRect(x,y,other.parking,5))return true; if(other.setup&&pointInRect(x,y,other.setup,5))return true } return false } function businessFlagCandidates(p){ const b=propertyBounds(p),list=[]; const addLine=(x1,y1,x2,y2,count=9)=>{ for(let i=0;i<count;i++){ const t=count===1?.5:i/(count-1); list.push({x:x1+(x2-x1)*t,y:y1+(y2-y1)*t}) } }; for(let y=b.y+10;y<=b.y+b.h-10;y+=12){ for(let x=b.x+10;x<=b.x+b.w-10;x+=12)list.push({x,y}) } for(const off of [10,18,26,34]){ addLine(b.x+12,b.y-off,b.x+b.w-12,b.y-off); addLine(b.x+12,b.y+b.h+off,b.x+b.w-12,b.y+b.h+off); addLine(b.x-off,b.y+12,b.x-off,b.y+b.h-12); addLine(b.x+b.w+off,b.y+12,b.x+b.w+off,b.y+b.h-12) } return list } function sponsorFlagSites(p,limit=3){ const candidates=businessFlagCandidates(p).filter(q=>!flagPointBlockedForBusiness(p,q.x,q.y)); const selected=[]; const b=propertyBounds(p); for(const q of candidates){ if(selected.every(s=>Math.hypot(s.x-q.x,s.y-q.y)>=24))selected.push({x:q.x,y:q.y,side:q.x>b.x+b.w/2?'right':'left'}); if(selected.length>=limit)break } if(selected.length<limit){ const y=Math.min(world.h-18,p.y+p.h+12); const start=p.x+Math.max(18,p.w*.22); const step=Math.max(25,Math.min(38,p.w*.22)); for(let i=0;selected.length<limit&&i<limit*2;i++){ const q={x:start+i*step,y,side:'right'}; if(selected.every(s=>Math.hypot(s.x-q.x,s.y-q.y)>=22))selected.push(q) } } return selected.slice(0,limit) } function auditAllBusinessFlags(){ const report=[]; for(const p of places.filter(p=>p.type==='gig')){ const v=state.venues[p.id]||{}; const sites=sponsorFlagSites(p,3); report.push({ id:p.id, visible:placeVisible(p), sponsored:!!v.sign, flags:Math.max(0,Math.min(3,Number(v.fillFlags)||0)), sites:sites.length, drawable:sites.length>=3 }) } return report } window.auditAllBusinessFlags=auditAllBusinessFlags; function bankCompletedSponsoredLot(id,announce=true){ const p=places.find(x=>x.id===id&&x.type==='gig'),v=state.venues[id]; if(!p||!v||!v.sign||!flagEraActive())return false; const full=!!v.lotCycleFull||Math.max(Number(v.rateCars)||0,permanentCars(id))>=(p.capacity||16); if(!full)return false; const before=Math.max(0,Math.min(3,Number(v.fillFlags)||0)); if(before<3){ v.fillFlags=before+1; if(announce)toast(`FULL SPONSORED LOT BANKED • FLAG ${v.fillFlags}/3 AT ${p.short||p.name}`) } v.lotCycleFull=true; v.flagCycleArmed=false; return true } function drawSponsorLotBanners(p){ const count=sponsoredLotFillCount(p);if(!count||!p.parking)return; // Flags are earned only after sponsorship and are placed only on verified grass outside the property edge. const sites=sponsorFlagSites(p,Math.min(count,3));if(!sites.length)return; ctx.save();for(let i=0;i<sites.length;i++){const s=sites[i],right=s.side==='right',x=s.x,y=s.y;ctx.strokeStyle='#27231d';ctx.lineWidth=2;ctx.beginPath();ctx.moveTo(x,y+10);ctx.lineTo(x,y-12);ctx.stroke();ctx.fillStyle=(i%4<2)?'#f1b83e':'#e64a38';ctx.beginPath();ctx.moveTo(x,y-12);ctx.lineTo(x+(right?-13:13),y-8);ctx.lineTo(x,y-3);ctx.closePath();ctx.fill();ctx.strokeStyle='#111';ctx.lineWidth=1;ctx.stroke()} if(count>sites.length){const s=sites[sites.length-1],x=s.x,y=s.y+20;ctx.fillStyle='#171514';ctx.fillRect(x-18,y-10,36,18);ctx.strokeStyle='#f1b83e';ctx.strokeRect(x-17,y-9,34,16);ctx.fillStyle='#fff';ctx.font='1000 8px system-ui';ctx.textAlign='center';ctx.fillText(`×${count}`,x,y+2)} ctx.restore() } function drawPseudoVehicle(x,y,angle,body,type='civilian',scale=1){ctx.save();ctx.translate(x,y);ctx.rotate(angle||0);ctx.scale(scale,scale);const L=type==='van'?62:type==='blackstar'?50:38,Wd=type==='van'?34:type==='blackstar'?27:22;ctx.fillStyle='rgba(0,0,0,.30)';ctx.beginPath();ctx.ellipse(5,7,L*.48,Wd*.52,0,0,Math.PI*2);ctx.fill();ctx.fillStyle='#171514';ctx.fillRect(-L/2-2,-Wd/2-2,L+4,Wd+4);ctx.fillStyle=body;ctx.fillRect(-L/2,-Wd/2,L,Wd);ctx.fillStyle='rgba(255,255,255,.13)';ctx.fillRect(-L/2+4,-Wd/2+3,L-8,3);ctx.fillStyle='rgba(165,205,220,.9)';ctx.fillRect(L*.08,-Wd/2+4,L*.26,Wd-8);ctx.fillStyle='#111';for(const sx of [-1,1])for(const sy of [-1,1])ctx.fillRect(sx*L*.24-5,sy*(Wd/2+3)-2,10,4);ctx.fillStyle='#f3e5b8';ctx.fillRect(L/2-3,-Wd/2+3,3,6);ctx.fillRect(L/2-3,Wd/2-9,3,6);ctx.fillStyle='#b51f20';ctx.fillRect(-L/2,-Wd/2+3,3,6);ctx.fillRect(-L/2,Wd/2-9,3,6);if(type==='blackstar'){ctx.fillStyle='#e7e7e7';ctx.fillRect(-7,-Wd/2+4,18,Wd-8);ctx.strokeStyle='#111';ctx.lineWidth=2;ctx.beginPath();ctx.moveTo(-1,-6);ctx.lineTo(8,0);ctx.lineTo(-1,6);ctx.stroke()}if(type==='van'){ctx.fillStyle='#fff';ctx.font='900 7px system-ui';ctx.textAlign='center';ctx.fillText('VANCERTS',-8,2)}ctx.restore()} function drawRoadVehicle(c){ if(!trafficVisible(c))return;const q=trafficDrawPoint(c),type=c.vehicleType||'sedan'; if(type==='sedan')return drawPseudoVehicle(q.x,q.y,q.angle,c.color,'civilian',1); if(type==='hatchback')return drawPseudoVehicle(q.x,q.y,q.angle,c.color,'civilian',.88); if(type==='suv')return drawPseudoVehicle(q.x,q.y,q.angle,c.color,'civilian',1.18); if(type==='pickup'){drawPseudoVehicle(q.x,q.y,q.angle,c.color,'civilian',1.12);ctx.save();ctx.translate(q.x,q.y);ctx.rotate(q.angle);ctx.fillStyle='#202020';ctx.fillRect(-18,-8,13,16);ctx.restore();return} if(type==='deliveryvan')return drawPseudoVehicle(q.x,q.y,q.angle,c.color,'van',.72); ctx.save();ctx.translate(q.x,q.y);ctx.rotate(q.angle);ctx.imageSmoothingEnabled=false; if(type==='motorcycle'){ ctx.strokeStyle='#191919';ctx.lineWidth=3;ctx.beginPath();ctx.arc(-10,7,7,0,Math.PI*2);ctx.arc(10,7,7,0,Math.PI*2);ctx.moveTo(-10,7);ctx.lineTo(0,-2);ctx.lineTo(10,7);ctx.stroke();ctx.fillStyle='#6b472f';ctx.beginPath();ctx.arc(0,-13,5,0,Math.PI*2);ctx.fill();ctx.fillStyle='#2b211c';ctx.fillRect(-5,-18,10,6);ctx.fillRect(-8,-17,4,15);ctx.fillStyle='#333';ctx.fillRect(-5,-7,10,13) }else if(type==='horse'){ ctx.fillStyle='#744b2d';ctx.fillRect(-17,-8,34,16);ctx.beginPath();ctx.arc(17,-8,9,0,Math.PI*2);ctx.fill();ctx.strokeStyle='#4b2e1b';ctx.lineWidth=4;for(const x of[-12,-4,8,14]){ctx.beginPath();ctx.moveTo(x,7);ctx.lineTo(x+(x%2?3:-3),20);ctx.stroke()}ctx.fillStyle='#315d7b';ctx.fillRect(-5,-24,10,16);ctx.fillStyle='#6b472f';ctx.beginPath();ctx.arc(0,-29,5,0,Math.PI*2);ctx.fill() }else{ const dims={boxtruck:[68,31],limousine:[78,24],testarossa:[48,20],lamborghini:[46,19],ambulance:[62,29],waymo:[43,23]}[type]||[40,22],L=dims[0],W=dims[1]; ctx.fillStyle='rgba(0,0,0,.3)';ctx.fillRect(-L/2+4,-W/2+5,L,W);ctx.fillStyle=c.color;ctx.fillRect(-L/2,-W/2,L,W);ctx.fillStyle='#111';for(const sx of[-1,1])for(const sy of[-1,1])ctx.fillRect(sx*L*.28-5,sy*(W/2+3)-2,10,4);ctx.fillStyle='rgba(165,205,220,.9)';ctx.fillRect(L*.05,-W/2+4,L*.24,W-8); if(type==='boxtruck'){ctx.fillStyle='#ece6d5';ctx.fillRect(-L/2+2,-W/2+2,L*.55,W-4);ctx.fillStyle='#333';ctx.font='900 6px system-ui';ctx.textAlign='center';ctx.fillText('LOCAL',-11,2)} if(type==='limousine'){ctx.fillStyle='#c7dbe2';for(let x=-22;x<23;x+=11)ctx.fillRect(x,-W/2+4,8,W-8)} if(type==='testarossa'){ctx.fillStyle='#111';for(let y=-7;y<=7;y+=4)ctx.fillRect(-L/2+4,y,10,2)} if(type==='lamborghini'){ctx.strokeStyle='#111';ctx.lineWidth=3;ctx.beginPath();ctx.moveTo(-L/2,-W/2);ctx.lineTo(L/2,-W/2+4);ctx.lineTo(L/2,W/2-4);ctx.lineTo(-L/2,W/2);ctx.closePath();ctx.stroke()} if(type==='ambulance'){ctx.fillStyle='#d52a2a';ctx.fillRect(-L/2,-3,L,6);ctx.fillStyle=emergencyActive()?'#55b7ff':'#315d7b';ctx.fillRect(-5,-W/2-5,10,5);ctx.fillStyle='#d52a2a';ctx.fillRect(-18,-8,5,16);ctx.fillRect(-24,-2,17,5)} if(type==='waymo'){ctx.fillStyle='#111';ctx.fillRect(-4,-W/2-5,8,6);ctx.fillStyle='#39a7df';ctx.beginPath();ctx.arc(0,-W/2-6,3,0,Math.PI*2);ctx.fill();ctx.fillStyle='#111';ctx.font='1000 7px monospace';ctx.textAlign='center';ctx.fillText('WAYGO',0,2)} } ctx.restore() } function drawSpecialCar(){ if(!specialCarActive())return; for(const car of specialCars){ const style=car.vehicleType==='specialwaygo'?'specialwaygo':'blackstar'; const body=style==='specialwaygo'?'#efe6ca':'#050505'; drawPseudoVehicle(car.x,car.y,car.angle||0,body,style,1) } } function drawPromotionPosterSites(){ // Final property-layer pass: keep every Leftway-style parcel edge visible above buildings and parking. drawParcelEdgeCurbs(); drawRequestedExteriorEdges(); const j=posterCampaignJob();if(!j)return;const used=new Set(j.posterCampaign?.placed||[]); ctx.save();for(const s of posterSpotList()){const placed=used.has(s.id);ctx.fillStyle=placed?'#f1b83e':'rgba(241,184,62,.22)';ctx.strokeStyle=placed?'#111':'#f1b83e';ctx.lineWidth=2;ctx.fillRect(s.x-8,s.y-11,16,22);ctx.strokeRect(s.x-8,s.y-11,16,22);ctx.fillStyle=placed?'#171514':'#f1b83e';ctx.font='1000 7px system-ui';ctx.textAlign='center';ctx.fillText(placed?'V':'P',s.x,s.y+3)}ctx.restore() } function drawRoadSnake(){ if(!roadSnake.active)return; const letters='ELON'; for(let i=roadSnake.length-1;i>=0;i--){ const q=snakeSegmentPoint(i),head=i===0; ctx.save();ctx.translate(q.x,q.y);ctx.rotate(q.angle||0); ctx.fillStyle='#101810';ctx.fillRect(-17,-12,34,24); ctx.fillStyle=head?'#64c34f':(i%2?'#3f983b':'#55ad45');ctx.fillRect(-14,-9,28,18); ctx.fillStyle='#90e36d';ctx.fillRect(-10,-6,20,4); if(head){ ctx.fillStyle='#f4e6be';ctx.fillRect(6,-7,4,4);ctx.fillRect(6,3,4,4); ctx.fillStyle='#111';ctx.fillRect(8,-6,2,2);ctx.fillRect(8,4,2,2); ctx.fillStyle='#e64a38';ctx.fillRect(14,-1,8,2) } ctx.restore(); if(i>=1&&i<=4){ // Upright screen-facing letters: E on car 2 through N on car 5. ctx.save();ctx.translate(q.x,q.y); ctx.fillStyle='#111';ctx.font='1000 15px monospace'; ctx.textAlign='center';ctx.textBaseline='middle'; ctx.fillText(letters[i-1],0,1);ctx.restore() } } } function drawUnifiedCareerVan(x,y,angle,wrap='classic',opts={}){ ctx.save();ctx.translate(x,y);ctx.rotate(angle||0); const L=70,Wd=38,depth=7,armored=!!opts.armored; ctx.fillStyle='rgba(15,15,15,.42)';ctx.beginPath();ctx.ellipse(7,10,41,22,0,0,Math.PI*2);ctx.fill();ctx.fillStyle='rgba(95,95,95,.20)';ctx.beginPath();ctx.ellipse(3,7,35,17,0,0,Math.PI*2);ctx.fill(); let body=armored?'#66784b':'#5f8a72'; if(wrap==='owner')body='#f5f3ea'; else if(wrap==='paul')body='#f7f7f2'; else if(wrap==='band')body='#101010'; ctx.fillStyle=body;ctx.fillRect(-L/2,-Wd/2,L,Wd);ctx.strokeStyle='#171514';ctx.lineWidth=3;ctx.strokeRect(-L/2,-Wd/2,L,Wd); ctx.fillStyle='#b8d2d1';ctx.fillRect(L/2-25,-Wd/2+5,18,Wd-10);ctx.strokeStyle='#171514';ctx.lineWidth=2;ctx.strokeRect(L/2-25,-Wd/2+5,18,Wd-10); ctx.fillStyle='rgba(255,255,255,.16)';ctx.fillRect(-L/2+5,-Wd/2+4,L-36,4); // Same doors, handles, rack, bumpers, lamps, and tire build on every van. ctx.strokeStyle=wrap==='band'?'#6d6d6d':'#263128';ctx.lineWidth=2;ctx.strokeRect(-8,-Wd/2+4,22,Wd-8); ctx.fillStyle=wrap==='band'?'#aaa':'#252525';ctx.fillRect(8,-Wd/2+7,5,2); ctx.fillStyle='#efe0a5';ctx.fillRect(L/2-4,-Wd/2+4,4,7);ctx.fillRect(L/2-4,Wd/2-11,4,7); ctx.fillStyle='#b52222';ctx.fillRect(-L/2,-Wd/2+4,4,7);ctx.fillRect(-L/2,Wd/2-11,4,7); // Flush rectangular tires, matching the original VANCERTS work van. ctx.fillStyle='#171514';for(const sy of [-1,1]){ctx.fillRect(-20,sy*(Wd/2+3)-3,14,6);ctx.fillRect(17,sy*(Wd/2+3)-3,14,6)} ctx.fillStyle=wrap==='band'?'#777':'#c9b783';ctx.fillRect(-L/2+7,Wd/2-3,22,4); ctx.strokeStyle='#171514';ctx.lineWidth=2;ctx.strokeRect(-18,-Wd/2-6,31,7); // Career-specific wrap only; chassis never changes. if(wrap==='classic'){ ctx.fillStyle='#e3c13a';ctx.fillRect(-L/2+3,-4,L-6,9);ctx.fillStyle='#171514';ctx.font='1000 8px system-ui';ctx.textAlign='center';ctx.textBaseline='middle';ctx.fillText('VANCERTS',-5,1); }else if(wrap==='owner'){ for(const sy of [-1,1]){ctx.fillStyle='#e64a38';ctx.beginPath();ctx.moveTo(-L/2+2,sy*14);ctx.lineTo(-10,sy*13);ctx.lineTo(-22,sy*7);ctx.lineTo(11,sy*10);ctx.lineTo(-2,sy*3);ctx.lineTo(-28,sy*4);ctx.closePath();ctx.fill();ctx.fillStyle='#f1b83e';ctx.beginPath();ctx.moveTo(-L/2+6,sy*10);ctx.lineTo(-12,sy*9);ctx.lineTo(-22,sy*4);ctx.lineTo(4,sy*6);ctx.closePath();ctx.fill()} ctx.fillStyle='#171514';ctx.font='1000 7px system-ui';ctx.textAlign='center';ctx.textBaseline='middle';ctx.fillText('VANCERTS',-2,1);ctx.fillStyle='#d52227';ctx.font='1000 12px system-ui';ctx.fillText('V',-29,1); }else if(wrap==='paul'){ ctx.fillStyle='#d52227';ctx.fillRect(-L/2+3,-4,L-6,9);ctx.fillStyle='#fff';ctx.font='1000 8px system-ui';ctx.textAlign='center';ctx.textBaseline='middle';ctx.fillText('VANCERTS',-5,1); }else if(wrap==='band'){ for(const sy of [-1,1]){ctx.fillStyle='#c92d2d';ctx.beginPath();ctx.moveTo(-L/2+2,sy*15);ctx.lineTo(-8,sy*14);ctx.lineTo(-21,sy*8);ctx.lineTo(13,sy*11);ctx.lineTo(-1,sy*4);ctx.lineTo(-28,sy*5);ctx.closePath();ctx.fill();ctx.fillStyle='#f1b83e';ctx.beginPath();ctx.moveTo(-L/2+6,sy*11);ctx.lineTo(-10,sy*10);ctx.lineTo(-21,sy*5);ctx.lineTo(5,sy*7);ctx.closePath();ctx.fill()} ctx.fillStyle='#f5f5f5';ctx.font='1000 7px system-ui';ctx.textAlign='center';ctx.textBaseline='middle';ctx.fillText('BAND',-2,1); } if(opts.potatoGun){ctx.fillStyle='#202020';ctx.fillRect(4,-Wd/2-12,18,8);ctx.fillStyle='#c7c7c7';ctx.fillRect(19,-Wd/2-10,13,4)} if(armored){ctx.strokeStyle='#171514';ctx.lineWidth=2;ctx.strokeRect(L/2-10,-11,8,22);for(let gy=-8;gy<=8;gy+=5){ctx.beginPath();ctx.moveTo(L/2-9,gy);ctx.lineTo(L/2-3,gy);ctx.stroke()}} ctx.restore() } function paulTruckPosition(){const paul=state.staff?.paul;if(!paul?.hired||!paul.truckVisible)return null;if(state.activeJob){if(state.activeJob.phase==='pickup')return{x:1030,y:1138,angle:0};const p=places.find(place=>place.id===state.activeJob.id);if(p?.parking)return{x:p.parking.x+Math.min(68,p.parking.w*.28),y:p.parking.y+Math.min(54,p.parking.h*.32),angle:0}}return{x:1680,y:1138,angle:0}} function drawPaulTruck(){const q=paulTruckPosition();if(!q)return;drawUnifiedCareerVan(q.x,q.y,q.angle||0,'paul');ctx.save();ctx.translate(q.x-16,q.y-32);ctx.fillStyle='#6b4f3d';ctx.beginPath();ctx.arc(0,-7,5,0,Math.PI*2);ctx.fill();ctx.fillStyle='#315d3b';ctx.fillRect(-4,-2,8,13);ctx.strokeStyle='#171514';ctx.lineWidth=3;ctx.beginPath();ctx.moveTo(-2,10);ctx.lineTo(-5,18);ctx.moveTo(2,10);ctx.lineTo(5,18);ctx.stroke();ctx.fillStyle='#111';ctx.font='1000 7px system-ui';ctx.textAlign='center';ctx.fillText('PAUL',0,-16);ctx.restore()} function drawVancertsVanOriginal(){drawUnifiedCareerVan(van.x,van.y,van.angle,'classic',{armored:!!state.vanUpgrades.armored,potatoGun:!!state.vanUpgrades.potatoGun})} function drawPedestrians(){if(!daytimePedestriansActive())return;const t=austinTimeParts(),toByob=t.hour>=11;for(let i=0;i<pedestrians.length;i++){const p=pedestrians[i],x=toByob?p.x:(p.x1+(p.x2-p.x1)*p.t),y=toByob?p.y:(p.y1+(p.y2-p.y1)*p.t);ctx.save();ctx.translate(x,y);ctx.fillStyle=['#654d35','#7a5d40','#335e7c','#714b72'][i%4];ctx.beginPath();ctx.arc(0,-7,5,0,Math.PI*2);ctx.fill();ctx.fillRect(-4,-2,8,13);ctx.strokeStyle='#2c261f';ctx.lineWidth=3;ctx.beginPath();ctx.moveTo(-2,10);ctx.lineTo(-5,18);ctx.moveTo(2,10);ctx.lineTo(5,18);ctx.stroke();if(toByob&&p.carrying){ctx.fillStyle='#d9aa48';ctx.fillRect(5,0,8,7)}ctx.restore()}} const PULL_IN_BUSINESS_IDS=new Set(['porkchop','baddburgers','highnoon','chessclub','thirteenthfloor','amlhouse']); function drawSetupLabel(b){const box=b.setup,label=(PULL_IN_BUSINESS_IDS.has(b.id)||box?.eastPullIn||box?.westParcelPullIn||box?.unifiedPullIn||box?.curbside)?'PULL IN • PARK':'LOADING ZONE/STAGE';ctx.save();ctx.fillStyle='#f2e7c4';ctx.textAlign='center';ctx.textBaseline='middle';const vertical=box.w<145;if(vertical){ctx.translate(box.x+box.w/2,box.y+box.h/2);ctx.rotate(-Math.PI/2);const max=box.h-24;let size=13;ctx.font=`900 ${size}px system-ui`;while(size>8&&ctx.measureText(label).width>max){size--;ctx.font=`900 ${size}px system-ui`}ctx.fillText(label,0,0)}else{const max=box.w-24;let size=13;ctx.font=`900 ${size}px system-ui`;while(size>8&&ctx.measureText(label).width>max){size--;ctx.font=`900 ${size}px system-ui`}ctx.fillText(label,box.x+box.w/2,box.y+box.h/2)}ctx.restore()} function drawOpenDrivewayMouth(p){ const d=drivewayFor(p.id);if(!d||!p.parking)return; if(PULL_IN_BUSINESS_IDS.has(p.id)||p.setup?.eastPullIn||p.setup?.westParcelPullIn||p.setup?.unifiedPullIn||p.setup?.curbside){ // Direct pull-in access: no elevated loading bridge is drawn. return } const lot=p.parking,vertical=d.h>=d.w,overlap={x:Math.max(d.x,lot.x),y:Math.max(d.y,lot.y),w:Math.max(0,Math.min(d.x+d.w,lot.x+lot.w)-Math.max(d.x,lot.x)),h:Math.max(0,Math.min(d.y+d.h,lot.y+lot.h)-Math.max(d.y,lot.y))}; ctx.save(); // R36B31: draw the driveway only outside designated roads. The collision rectangle may overlap // the road by 2px for seamless movement, but the gray asphalt stops exactly at the street edge. ctx.beginPath();ctx.rect(d.x,d.y,d.w,d.h);for(const road of roads){if(rectsOverlap(d,road,0))ctx.rect(road.x,road.y,road.w,road.h)}ctx.clip('evenodd'); // Road approach remains solid asphalt. The parking-lot section becomes an elevated bridge so every stall remains visible and usable below it. ctx.fillStyle='#555b5e'; if(vertical){if(d.y<lot.y)ctx.fillRect(d.x,d.y,d.w,Math.max(0,lot.y-d.y));else ctx.fillRect(d.x,lot.y+lot.h,d.w,Math.max(0,d.y+d.h-(lot.y+lot.h)))} else{if(d.x<lot.x)ctx.fillRect(d.x,d.y,Math.max(0,lot.x-d.x),d.h);else ctx.fillRect(lot.x+lot.w,d.y,Math.max(0,d.x+d.w-(lot.x+lot.w)),d.h)} // Elevated shadow and side faces create the 3-D bridge effect without erasing parking stripes, cars, or the capacity counter. ctx.fillStyle='rgba(0,0,0,.28)';ctx.fillRect(d.x+7,d.y+8,d.w,d.h); ctx.fillStyle='rgba(91,98,101,.30)';ctx.fillRect(d.x,d.y,d.w,d.h); ctx.strokeStyle='#24282a';ctx.lineWidth=7;ctx.strokeRect(d.x+3,d.y+3,d.w-6,d.h-6); ctx.strokeStyle='#c9c4b5';ctx.lineWidth=3;ctx.strokeRect(d.x+8,d.y+8,d.w-16,d.h-16); // Bridge rails and support beams leave the four covered stalls readable underneath. ctx.strokeStyle='#f1b83e';ctx.lineWidth=4;ctx.beginPath(); if(vertical){ctx.moveTo(d.x+7,d.y);ctx.lineTo(d.x+7,d.y+d.h);ctx.moveTo(d.x+d.w-7,d.y);ctx.lineTo(d.x+d.w-7,d.y+d.h)} else{ctx.moveTo(d.x,d.y+7);ctx.lineTo(d.x+d.w,d.y+7);ctx.moveTo(d.x,d.y+d.h-7);ctx.lineTo(d.x+d.w,d.y+d.h-7)}ctx.stroke(); ctx.strokeStyle='rgba(25,25,25,.72)';ctx.lineWidth=3; if(vertical){for(let y=d.y+26;y<d.y+d.h;y+=48){ctx.beginPath();ctx.moveTo(d.x+8,y);ctx.lineTo(d.x+d.w-8,y);ctx.stroke()}} else{for(let x=d.x+26;x<d.x+d.w;x+=48){ctx.beginPath();ctx.moveTo(x,d.y+8);ctx.lineTo(x,d.y+d.h-8);ctx.stroke()}} ctx.fillStyle='#fff';ctx.font='1000 12px monospace';ctx.textAlign='center';ctx.textBaseline='middle';ctx.fillText(vertical?(d.y<lot.y?'↓':'↑'):(d.x<lot.x?'→':'←'),d.x+d.w/2,d.y+d.h/2); if(p.id==='leftwaygrounds'){ctx.font='1000 7px system-ui';ctx.fillStyle='#171514';ctx.fillText('LOADING BRIDGE',d.x+d.w/2,vertical?d.y+18:d.y+d.h/2-12);} ctx.textBaseline='alphabetic';ctx.restore() } function drawParking(p){ const lot=p.parking;if(!lot)return;const count=p.type==='gig'?expectedCars(p.id):0,d=drivewayFor(p.id);ctx.fillStyle='#666b6e';ctx.fillRect(lot.x,lot.y,lot.w,lot.h);ctx.fillStyle='rgba(255,255,255,.035)';for(let y=lot.y+14;y<lot.y+lot.h;y+=28)ctx.fillRect(lot.x,y,lot.w,2);const cellW=lot.w/lot.cols,cellH=lot.h/lot.rows;ctx.strokeStyle='#ece8d9';ctx.lineWidth=3;ctx.lineCap='round';for(let r=0;r<lot.rows;r++){for(let c=0;c<lot.cols;c++){const x=lot.x+c*cellW,y=lot.y+r*cellH;ctx.beginPath();ctx.moveTo(x+7,y+6);ctx.lineTo(x+7,y+cellH-8);ctx.moveTo(x+cellW-7,y+6);ctx.lineTo(x+cellW-7,y+cellH-8);ctx.stroke()}}ctx.lineCap='butt';for(let i=0;i<count;i++){const c=i%lot.cols,r=Math.floor(i/lot.cols);if(r>=lot.rows)break;const x=lot.x+c*cellW+cellW/2,y=lot.y+r*cellH+cellH/2;ctx.save();ctx.translate(x,y);ctx.fillStyle='#202020';ctx.fillRect(-18,-10,36,20);ctx.fillStyle=['#e9ca44','#72a6c7','#eee','#b36b72','#79a96b','#d98245'][i%6];ctx.fillRect(-15,-8,30,16);ctx.fillStyle='rgba(190,220,235,.8)';ctx.fillRect(-8,-6,16,5);ctx.restore()} if(!p.hideParkingLabel){const bridgeAtRight=!!(d&&!d.curbside&&d.x+d.w>lot.x+lot.w-110),labelX=bridgeAtRight?lot.x+50:lot.x+lot.w-50;ctx.fillStyle='rgba(20,20,20,.86)';ctx.fillRect(labelX-42,lot.y+lot.h-24,84,18);ctx.fillStyle='#fff';ctx.font='900 10px system-ui';ctx.textAlign='center';ctx.fillText(`${count}/${p.capacity||16} CARS`,labelX,lot.y+lot.h-11)} } function drawPropertyCurb(p){ const b=propertyBounds(p),pad=CITY_POLISH.propertyBuffer;ctx.save();ctx.strokeStyle='#718d60';ctx.lineWidth=2;ctx.setLineDash([10,8]);ctx.strokeRect(b.x-pad,b.y-pad,b.w+pad*2,b.h+pad*2);ctx.setLineDash([]);ctx.restore() } const STANDARD_CITY_LAND_PARCELS=(()=>{ const columns=[[150,610],[780,1270],[1440,1930],[2100,2550]]; const rows=[[150,600],[780,1300],[1480,1900],[2050,2450]]; const parcels=[]; for(let row=0;row<rows.length;row++)for(let col=0;col<columns.length;col++){ const [left,right]=columns[col],[top,bottom]=rows[row]; parcels.push({id:`city-${row}-${col}`,x:left,y:top,w:right-left,h:bottom-top}) } return parcels })(); const STANDARD_SIDE_LAND_PARCELS=[ {id:'west-0',x:-400,y:150,w:400,h:360},{id:'west-1',x:-400,y:510,w:400,h:360}, {id:'west-2',x:-400,y:870,w:400,h:360},{id:'west-3',x:-400,y:1230,w:400,h:360}, {id:'west-long',x:-400,y:1590,w:400,h:310},{id:'west-south',x:-400,y:2050,w:400,h:400}, {id:'east-0',x:2700,y:150,w:400,h:360},{id:'east-1',x:2700,y:510,w:400,h:360}, {id:'east-2',x:2700,y:870,w:400,h:360},{id:'east-3',x:2700,y:1230,w:400,h:360}, {id:'east-long',x:2700,y:1590,w:400,h:310},{id:'east-south',x:2700,y:2050,w:400,h:400} ]; function drawParcelEdgeCurbs(){ ctx.save(); const curb='#d4d0c4',highlight='#f3f0e7',inner='#77776f',band=16,gap=10; const parcels=[...STANDARD_CITY_LAND_PARCELS,...STANDARD_SIDE_LAND_PARCELS]; for(const b of parcels){ const left=b.x,right=b.x+b.w,top=b.y,bottom=b.y+b.h; const cuts=activeDriveways().filter(d=>d.x<right&&d.x+d.w>left&&d.y<bottom&&d.y+d.h>top); const visibleRuns=(start,end,spans)=>{ const runs=[],ordered=spans.sort((a,z)=>a[0]-z[0]);let cursor=start; for(const span of ordered){if(span[0]>cursor)runs.push([cursor,span[0]]);cursor=Math.max(cursor,span[1])} if(cursor<end)runs.push([cursor,end]);return runs }; const topBottomSpans=y=>cuts.filter(d=>d.y<=y+6&&d.y+d.h>=y-6).map(d=>[Math.max(left,d.x-gap),Math.min(right,d.x+d.w+gap)]); const leftRightSpans=x=>cuts.filter(d=>d.x<=x+6&&d.x+d.w>=x-6).map(d=>[Math.max(top,d.y-gap),Math.min(bottom,d.y+d.h+gap)]); const topRuns=visibleRuns(left,right,topBottomSpans(top)),bottomRuns=visibleRuns(left,right,topBottomSpans(bottom)); const leftRuns=visibleRuns(top,bottom,leftRightSpans(left)),rightRuns=visibleRuns(top,bottom,leftRightSpans(right)); // Solid concrete is painted inward so roads, camera clipping, and adjacent property art cannot hide it. ctx.fillStyle=curb; for(const [a,z] of topRuns)ctx.fillRect(a,top,z-a,band); for(const [a,z] of bottomRuns)ctx.fillRect(a,bottom-band,z-a,band); for(const [a,z] of leftRuns)ctx.fillRect(left,a,band,z-a); for(const [a,z] of rightRuns)ctx.fillRect(right-band,a,band,z-a); ctx.fillStyle=highlight; for(const [a,z] of topRuns)ctx.fillRect(a,top,z-a,3); for(const [a,z] of bottomRuns)ctx.fillRect(a,bottom-3,z-a,3); for(const [a,z] of leftRuns)ctx.fillRect(left,a,3,z-a); for(const [a,z] of rightRuns)ctx.fillRect(right-3,a,3,z-a); ctx.strokeStyle=inner;ctx.lineWidth=2;ctx.lineCap='square';ctx.beginPath(); for(const [a,z] of topRuns){ctx.moveTo(a,top+band);ctx.lineTo(z,top+band)} for(const [a,z] of bottomRuns){ctx.moveTo(a,bottom-band);ctx.lineTo(z,bottom-band)} for(const [a,z] of leftRuns){ctx.moveTo(left+band,a);ctx.lineTo(left+band,z)} for(const [a,z] of rightRuns){ctx.moveTo(right-band,a);ctx.lineTo(right-band,z)} ctx.stroke() } ctx.restore() } const R36B40F_REQUESTED_EDGES={ north:[ {id:'vancerts-bank-west',x1:-400,x2:0,y:150},{id:'gig-bag',x1:150,x2:610,y:150}, {id:'byob',x1:780,x2:1270,y:150},{id:'fsg',x1:1440,x2:1930,y:150}, {id:'blue-owl',x1:2100,x2:2550,y:150},{id:'13th-floor-east',x1:2700,x2:3100,y:150} ], west:[ {id:'west-side-main',x:-400,y1:150,y2:1900},{id:'future-west-left-corner',x:-400,y1:2050,y2:2450}, {id:'gig-bag',x:150,y1:150,y2:600},{id:'juan-in-a-million',x:150,y1:780,y2:1300}, {id:'pork-chop',x:150,y1:1480,y2:1900},{id:'under-pork-chop',x:150,y1:2050,y2:2450} ], east:[ {id:'west-side-main',x:0,y1:150,y2:1900},{id:'future-west-left-corner',x:0,y1:2050,y2:2450}, {id:'entire-east-side',x:3100,y1:150,y2:1900},{id:'lower-east-side',x:3100,y1:2050,y2:2450} ], south:[ {id:'west-side-main',x1:-400,x2:0,y:1900},{id:'lower-west',x1:-400,x2:0,y:2450}, {id:'south-under-pork',x1:150,x2:610,y:2450},{id:'south-community',x1:780,x2:1270,y:2450}, {id:'south-support-local',x1:1440,x2:1930,y:2450},{id:'south-austin-texas',x1:2100,x2:2550,y:2450}, {id:'lower-east-side',x1:2700,x2:3100,y:2450} ] }; function drawRequestedExteriorEdges(){ ctx.save(); const band=24,gap=12,concrete='#d8d5ca',bright='#fffdf5',seam='#77776f'; const runs=(start,end,spans)=>{const out=[];let cursor=start;spans.sort((a,b)=>a[0]-b[0]);for(const s of spans){if(s[0]>cursor)out.push([cursor,s[0]]);cursor=Math.max(cursor,s[1])}if(cursor<end)out.push([cursor,end]);return out}; const horizontalRuns=e=>runs(e.x1,e.x2,activeDriveways().filter(d=>d.y<=e.y+6&&d.y+d.h>=e.y-6&&d.x<e.x2&&d.x+d.w>e.x1).map(d=>[Math.max(e.x1,d.x-gap),Math.min(e.x2,d.x+d.w+gap)])); const verticalRuns=e=>runs(e.y1,e.y2,activeDriveways().filter(d=>d.x<=e.x+6&&d.x+d.w>=e.x-6&&d.y<e.y2&&d.y+d.h>e.y1).map(d=>[Math.max(e.y1,d.y-gap),Math.min(e.y2,d.y+d.h+gap)])); for(const e of R36B40F_REQUESTED_EDGES.north)for(const[a,z]of horizontalRuns(e)){ ctx.fillStyle=concrete;ctx.fillRect(a,e.y,z-a,band);ctx.fillStyle=bright;ctx.fillRect(a,e.y,z-a,4);ctx.fillStyle=seam;ctx.fillRect(a,e.y+band-3,z-a,3) } for(const e of R36B40F_REQUESTED_EDGES.south)for(const[a,z]of horizontalRuns(e)){ ctx.fillStyle=concrete;ctx.fillRect(a,e.y-band,z-a,band);ctx.fillStyle=bright;ctx.fillRect(a,e.y-4,z-a,4);ctx.fillStyle=seam;ctx.fillRect(a,e.y-band,z-a,3) } for(const e of R36B40F_REQUESTED_EDGES.west)for(const[a,z]of verticalRuns(e)){ ctx.fillStyle=concrete;ctx.fillRect(e.x,a,band,z-a);ctx.fillStyle=bright;ctx.fillRect(e.x,a,4,z-a);ctx.fillStyle=seam;ctx.fillRect(e.x+band-3,a,3,z-a) } for(const e of R36B40F_REQUESTED_EDGES.east)for(const[a,z]of verticalRuns(e)){ ctx.fillStyle=concrete;ctx.fillRect(e.x-band,a,band,z-a);ctx.fillStyle=bright;ctx.fillRect(e.x-4,a,4,z-a);ctx.fillStyle=seam;ctx.fillRect(e.x-band,a,3,z-a) } ctx.restore() } const SOUTH_CENTER_SIGNS=[ {parcel:{x:150,y:2050,w:460,h:400},w:290,h:76,text:'#COMMUNITY'}, {parcel:{x:780,y:2050,w:490,h:400},w:310,h:76,text:'#SUPPORTLOCAL'}, {parcel:{x:1440,y:2050,w:490,h:400},w:310,h:76,text:'#AUSTINTEXAS'}, {parcel:{x:2100,y:2050,w:450,h:400},w:330,h:76,text:'#ADVERTISEHERE'} ]; function drawSouthCenterParcelSigns(){ ctx.save(); for(let i=0;i<SOUTH_CENTER_SIGNS.length;i++){ const q=SOUTH_CENTER_SIGNS[i],cx=q.parcel.x+q.parcel.w/2,cy=q.parcel.y+q.parcel.h/2; const x=Math.round(cx-q.w/2),y=Math.round(cy-q.h/2-18),postTop=y+q.h,postBottom=cy+88; // Permanent development-board silhouette: shadow, twin posts, concrete footings, then sign face. ctx.fillStyle='rgba(0,0,0,.20)';ctx.beginPath();ctx.ellipse(cx+8,postBottom+7,q.w*.38,16,0,0,Math.PI*2);ctx.fill(); ctx.fillStyle='#5b3b25';ctx.fillRect(x+42,postTop,13,postBottom-postTop);ctx.fillRect(x+q.w-55,postTop,13,postBottom-postTop); ctx.fillStyle='#aaa99e';ctx.fillRect(x+30,postBottom-5,37,13);ctx.fillRect(x+q.w-67,postBottom-5,37,13); ctx.fillStyle='rgba(0,0,0,.25)';ctx.fillRect(x+8,y+9,q.w,q.h); ctx.fillStyle=i%2?'#f1dfae':'#e7c85f';ctx.fillRect(x,y,q.w,q.h); ctx.strokeStyle='#171514';ctx.lineWidth=5;ctx.strokeRect(x,y,q.w,q.h); ctx.fillStyle='rgba(255,255,255,.28)';ctx.fillRect(x+8,y+8,q.w-16,8); ctx.fillStyle='#171514';ctx.textAlign='center';ctx.textBaseline='middle';let fs=25;ctx.font=`1000 ${fs}px system-ui`; while(fs>14&&ctx.measureText(q.text).width>q.w-28){fs--;ctx.font=`1000 ${fs}px system-ui`} ctx.fillText(q.text,cx,y+q.h/2+2) } ctx.restore() } function drawR36BaseSidewalks(){ ctx.save();const sidewalk=sidewalkWidth(),curb=CITY_POLISH.curbWidth,curbColor='#aaa99e',walk='#c9c4b5',edge='#77776f'; // Expanded south district: continuous sidewalk/curb frontage across the full playable bottom block. ctx.fillStyle=curbColor;ctx.fillRect(150,1834,2400,56);ctx.fillStyle=walk;ctx.fillRect(150,1839,2400,46);ctx.strokeStyle=edge;ctx.lineWidth=2;ctx.strokeRect(152,1841,2396,42); // Uniform property setbacks and building aprons. Loading zones and parking are painted later, preserving clear access. for(const b of places){if(!placeVisible(b))continue;drawPropertyCurb(b);const apron=Math.round(CITY_POLISH.buildingApron),depth=PSEUDO_BUILDING_DEPTH,slabX=Math.round(b.x-depth-apron),slabY=Math.round(b.y-apron),slabW=Math.round(b.w+depth+apron*2),slabH=Math.round(b.h+depth+apron*2);ctx.fillStyle=walk;ctx.fillRect(slabX,slabY,slabW,slabH);ctx.strokeStyle=edge;ctx.lineWidth=2;ctx.strokeRect(slabX+2,slabY+2,slabW-4,slabH-4)} // Continuous, equally sized sidewalks and curbs on both sides of every interior street. for(const r of roads){if(r.edge)continue;ctx.fillStyle=curbColor;if(r.w>r.h){ctx.fillRect(r.x,r.y-sidewalk-curb,r.w,sidewalk+curb);ctx.fillRect(r.x,r.y+r.h,r.w,sidewalk+curb)}else{ctx.fillRect(r.x-sidewalk-curb,r.y,sidewalk+curb,r.h);ctx.fillRect(r.x+r.w,r.y,sidewalk+curb,r.h)}ctx.fillStyle=walk;if(r.w>r.h){ctx.fillRect(r.x,r.y-sidewalk,r.w,sidewalk-curb);ctx.fillRect(r.x,r.y+r.h+curb,r.w,sidewalk-curb)}else{ctx.fillRect(r.x-sidewalk,r.y,sidewalk-curb,r.h);ctx.fillRect(r.x+r.w+curb,r.y,sidewalk-curb,r.h)}} ctx.restore() } function drawParkingCurb(b){ const p=b.parking;if(!p)return;const roadMouth=drivewayFor(b.id),d=(b.setup&&rectsOverlap(b.setup,p,1))?b.setup:roadMouth,gap=8,left=p.x+3,right=p.x+p.w-3,top=p.y+3,bottom=p.y+p.h-3; const cutTop=!!(d&&d.y<=p.y+6&&d.y+d.h>p.y&&d.x<right&&d.x+d.w>left); const cutBottom=!!(d&&d.y<p.y+p.h&&d.y+d.h>=p.y+p.h-6&&d.x<right&&d.x+d.w>left); const cutLeft=!!(d&&d.x<=p.x+6&&d.x+d.w>p.x&&d.y<bottom&&d.y+d.h>top); const cutRight=!!(d&&d.x<p.x+p.w&&d.x+d.w>=p.x+p.w-6&&d.y<bottom&&d.y+d.h>top); ctx.save();ctx.strokeStyle='#9c9a90';ctx.lineWidth=6;ctx.beginPath(); const hSide=(y,cut)=>{if(!cut){ctx.moveTo(left,y);ctx.lineTo(right,y);return}const a=Math.max(left,d.x-gap),z=Math.min(right,d.x+d.w+gap);ctx.moveTo(left,y);ctx.lineTo(a,y);ctx.moveTo(z,y);ctx.lineTo(right,y)}; const vSide=(x,cut)=>{if(!cut){ctx.moveTo(x,top);ctx.lineTo(x,bottom);return}const a=Math.max(top,d.y-gap),z=Math.min(bottom,d.y+d.h+gap);ctx.moveTo(x,top);ctx.lineTo(x,a);ctx.moveTo(x,z);ctx.lineTo(x,bottom)}; hSide(top,cutTop);hSide(bottom,cutBottom);vSide(left,cutLeft);vSide(right,cutRight);ctx.stroke();ctx.restore() } function auditR36B31BusinessAccess(){ const issues=[]; for(const p of places){ if(!placeVisible(p)||p.retiredByReorg||!p.parking||p.id==='leftwaygrounds')continue; const d=drivewayFor(p.id),setup=p.setup; if(!setup)issues.push(`${p.id}: missing pull-in lane`); else if(!rectsOverlap(p.parking,setup,1))issues.push(`${p.id}: parking does not overlap pull-in`); if(!d)issues.push(`${p.id}: missing street mouth`); else{ if(setup&&!rectsOverlap(setup,d,1))issues.push(`${p.id}: pull-in does not overlap street mouth`); if(!roads.some(r=>rectsOverlap(d,r,1)))issues.push(`${p.id}: street mouth does not touch road`) } } return{ok:issues.length===0,issues} } window.auditR36B31BusinessAccess=auditR36B31BusinessAccess; function drawCrosswalkAcrossVerticalRoad(x,yTop){ const half=85,depth=CITY_POLISH.crosswalkDepth,rainbow=projectLevel('rainbowCrosswalks'),colors=['#e53935','#fb8c00','#fdd835','#43a047','#1e88e5','#8e24aa'];let i=0;for(let sx=x-half+12;sx<=x+half-20;sx+=20){ctx.fillStyle=rainbow?colors[i++%colors.length]:'rgba(244,240,220,.9)';ctx.fillRect(sx,yTop,12,depth)} } function drawCrosswalkAcrossHorizontalRoad(xLeft,y){ const half=90,depth=CITY_POLISH.crosswalkDepth,rainbow=projectLevel('rainbowCrosswalks'),colors=['#e53935','#fb8c00','#fdd835','#43a047','#1e88e5','#8e24aa'];let i=0;for(let sy=y-half+12;sy<=y+half-20;sy+=20){ctx.fillStyle=rainbow?colors[i++%colors.length]:'rgba(244,240,220,.9)';ctx.fillRect(xLeft,sy,depth,12)} } function drawR36RoadDetails(){ctx.save();const lvl=projectLevel('crosswalks'),ints=[[695,690],[1355,690],[2015,690],[695,1390],[1355,1390],[2015,1390]];if(lvl>=1)ints.push([2670,690],[2670,1390]);if(lvl>=2)ints.push([695,1980],[1355,1980],[2015,1980]);if(lvl>=3)ints.push([2670,1980]);const vHalf=85,hHalf=90,depth=CITY_POLISH.crosswalkDepth,gap=CITY_POLISH.crosswalkGap,barGap=CITY_POLISH.stopBarGap;for(const[x,y]of ints){const northY=y-hHalf-gap-depth,southY=y+hHalf+gap,westX=x-vHalf-gap-depth,eastX=x+vHalf+gap;drawCrosswalkAcrossVerticalRoad(x,northY);drawCrosswalkAcrossVerticalRoad(x,southY);drawCrosswalkAcrossHorizontalRoad(westX,y);drawCrosswalkAcrossHorizontalRoad(eastX,y);ctx.fillStyle='rgba(255,255,255,.96)';ctx.fillRect(x-vHalf+12,northY-barGap-5,vHalf-20,5);ctx.fillRect(x+8,southY+depth+barGap,vHalf-20,5);ctx.fillRect(westX-barGap-5,y+8,5,hHalf-20);ctx.fillRect(eastX+depth+barGap,y-hHalf+12,5,hHalf-20)}for(const b of places){if(placeVisible(b)&&b.parking)drawParkingCurb(b)}ctx.restore()} function drawCommunityArtBoard(){ const hq=places.find(p=>p.id==='hq');if(!hq)return; const x=hq.x+70,y=hq.y+hq.h-18,w=160,h=44; ctx.save(); ctx.fillStyle='rgba(0,0,0,.30)';ctx.fillRect(x+12,y+13,w,h); ctx.fillStyle='#171514';ctx.fillRect(x,y,w,h); ctx.strokeStyle='#f1b83e';ctx.lineWidth=4;ctx.strokeRect(x+2,y+2,w-4,h-4); ctx.strokeStyle='#3f84a5';ctx.lineWidth=2;ctx.strokeRect(x+7,y+7,w-14,h-14); const splashes=[ [x+13,y+13,7,'#e64a38'],[x+30,y+34,5,'#f1b83e'],[x+w-18,y+14,7,'#9766a3'], [x+w-36,y+34,5,'#4cae68'],[x+58,y+11,4,'#3f84a5'] ]; for(const [sx,sy,r,c] of splashes){ctx.fillStyle=c;ctx.beginPath();ctx.arc(sx,sy,r,0,Math.PI*2);ctx.fill()} ctx.fillStyle='#fff';ctx.textAlign='center';ctx.font='1000 11px system-ui';ctx.fillText('COMMUNITY ART',x+w/2,y+19); ctx.fillStyle='#f1b83e';ctx.font='1000 7px system-ui';ctx.fillText('BOARD — COMING SOON',x+w/2,y+31); ctx.fillStyle='#c9c4b5';ctx.font='900 4px system-ui';ctx.fillText('ARTISTS • MURALS • MUSIC • COMMUNITY',x+w/2,y+39); ctx.strokeStyle='#25211d';ctx.lineWidth=4;ctx.beginPath();ctx.moveTo(x+26,y+h);ctx.lineTo(x+26,y+h+10);ctx.moveTo(x+w-26,y+h);ctx.lineTo(x+w-26,y+h+10);ctx.stroke(); ctx.restore() } /* ===== R36B45D CAREER HOMES + SPAWN CORRECTION ===== */ const R36B45A_STREET_LABELS=[ {name:'E 7TH ST',x:0,y:600,w:2700,h:180,vertical:false}, {name:'E 6TH ST',x:0,y:1300,w:2700,h:180,vertical:false}, {name:'HOLLY ST',x:0,y:1900,w:3250,h:150,vertical:false}, {name:'CONGRESS AVE',x:610,y:0,w:170,h:2600,vertical:true}, {name:'RED RIVER ST',x:1270,y:0,w:170,h:2600,vertical:true}, {name:'TRINITY ST',x:1930,y:0,w:170,h:2600,vertical:true}, {name:'I-35 FRONTAGE RD',x:2550,y:0,w:150,h:2600,vertical:true} ]; const R36B45A_EXTRA_TREES=[ [250,270,.78],[330,365,.9],[520,285,.72],[850,290,.82],[1110,335,.68],[1460,290,.85],[1730,340,.72],[2180,285,.82],[2390,355,.7],[2850,300,.9], [280,1280,.76],[520,1360,.68],[830,1300,.84],[1110,1370,.7],[1490,1320,.9],[1780,1380,.7],[2180,1325,.86],[2400,1390,.72],[2840,1310,.88], [280,2160,.82],[520,2240,.7],[850,2160,.9],[1140,2230,.72],[1490,2160,.88],[1780,2240,.68],[2180,2160,.86],[2450,2240,.72],[2860,2170,.9] ]; const R36B45A_CONSTRUCTION=[]; let r36b45Celebration={active:false,x:0,y:0,start:0,size:0}; function startWorldCelebration(x,y,size){r36b45Celebration={active:true,x:Number(x)||van.x,y:Number(y)||van.y,start:performance.now(),size:Math.max(1,Number(size)||1)};if(typeof window.pulseVancertsBrand==='function')window.pulseVancertsBrand()} var R36B45_HOMES={ owner:{id:'owner',label:'OWNER HOME',lot:{x:40,y:-1010,w:900,h:665},building:{x:170,y:-855,w:460,h:240},door:{x:364,y:-625,w:72,h:54},spawn:{x:438,y:-445,angle:Math.PI/2},road:{x:288,y:-430,w:300,h:430},pullin:{x:220,y:-555,w:436,h:140},yard:'#668d52',border:'wood'}, audio:{id:'audio',label:'AUDIO ENGINEER HOME',lot:{x:1850,y:-1010,w:980,h:665},building:{x:2020,y:-855,w:500,h:250},door:{x:2234,y:-615,w:74,h:54},spawn:{x:2320,y:-445,angle:Math.PI/2},road:{x:2170,y:-430,w:300,h:430},pullin:{x:2075,y:-555,w:490,h:140},yard:'#657b61',border:'industrial'}, band:{id:'band',label:'BAND HOUSE',lot:{x:1000,y:2790,w:1040,h:700},building:{x:1300,y:3070,w:455,h:230},door:{x:1489,y:3290,w:72,h:54},spawn:{x:1510,y:2938,angle:-Math.PI/2},road:{x:1360,y:2600,w:300,h:420},pullin:{x:1265,y:2910,w:490,h:140},yard:'#668d52',border:'wood'} }; var R36B45_HOME_ROADS=Object.values(R36B45_HOMES).flatMap(h=>[h.road,h.pullin]); function careerHomeId(path=state.career?.path){return path==='owner'?'owner':path==='band'?'band':'audio'} function spawnCareerAtHome(path=state.career?.path,role=state.career?.teamRole){const h=R36B45_HOMES[careerHomeId(path)];if(!h)return;van.x=h.spawn.x;van.y=h.spawn.y;van.angle=h.spawn.angle;van.speed=0;near=null} function homeBuildingBlocked(x,y){if(!R36B45_HOMES||typeof R36B45_HOMES!=='object')return false;return Object.values(R36B45_HOMES).some(h=>h&&h.building&&x>=h.building.x-42&&x<=h.building.x+h.building.w+28&&y>=h.building.y-80&&y<=h.building.y+h.building.h+42)} function activeCareerHomeNear(){if(!R36B45_HOMES||typeof R36B45_HOMES!=='object')return null;for(const h of Object.values(R36B45_HOMES)){if(!h||!h.door)continue;const ix=h.door.x+h.door.w/2,iy=h.door.y+h.door.h+20;if(Math.hypot(van.x-ix,van.y-iy)<92)return{type:'home',homeId:h.id,interact:{x:ix,y:iy}}}return null} function openCareerHome(homeId){const h=R36B45_HOMES[homeId];if(!h)return;const assigned=careerHomeId()===homeId;modal(`<h2>${h.label}</h2><p>${assigned?'This is your current character’s home base.':'This home belongs to another career in the shared Austin world.'}</p>${assigned?'<p>Use the bed to save the game, restore your character for work, and advance to the next Austin morning.</p><div class="btns"><button class="green" onclick="sleepAtCareerHome()">💤 SLEEP UNTIL NEXT DAY</button><button onclick="closeModal()">LEAVE HOUSE</button></div>':'<div class="btns"><button onclick="closeModal()">LEAVE PROPERTY</button></div>'}`)} function sleepAtCareerHome(){const t=austinTimeParts(),hoursToEight=((24-t.hour+8)%24)||24;state.gameTimeOffsetHours=Number(state.gameTimeOffsetHours||0)+hoursToEight;state.bankLastAdvanceDay='';save();closeModal();spawnCareerAtHome();hud();toast('SLEPT UNTIL THE NEXT MORNING • GAME SAVED')} function drawR36B45PropertyBorder(h){const l=h.lot,gapStart=h.road.x-18,gapEnd=h.road.x+h.road.w+18,topGap=h.id==='band',post=18;ctx.save();ctx.lineCap='square';ctx.strokeStyle=h.border==='industrial'?'#454c50':'#6b452c';ctx.lineWidth=h.border==='industrial'?8:10;function seg(x1,y1,x2,y2){ctx.beginPath();ctx.moveTo(x1,y1);ctx.lineTo(x2,y2);ctx.stroke()}seg(l.x,l.y,l.x+l.w,l.y);seg(l.x,l.y,l.x,l.y+l.h);seg(l.x+l.w,l.y,l.x+l.w,l.y+l.h);if(topGap){seg(l.x,l.y,gapStart,l.y);seg(gapEnd,l.y,l.x+l.w,l.y);seg(l.x,l.y+l.h,l.x+l.w,l.y+l.h)}else{seg(l.x,l.y+l.h,gapStart,l.y+l.h);seg(gapEnd,l.y+l.h,l.x+l.w,l.y+l.h)}if(h.border==='industrial'){ctx.strokeStyle='#9aa1a5';ctx.lineWidth=2;for(let x=l.x+post;x<l.x+l.w;x+=42){if(topGap&&x>gapStart&&x<gapEnd)continue;ctx.beginPath();ctx.moveTo(x,l.y+2);ctx.lineTo(x,l.y+20);ctx.stroke()}}else{ctx.fillStyle='#8c5c35';for(let x=l.x+post;x<l.x+l.w;x+=46){if(topGap&&x>gapStart&&x<gapEnd)continue;ctx.fillRect(x-3,l.y-6,6,18);ctx.fillRect(x-3,l.y+l.h-12,6,18)}}ctx.restore()} function drawR36B45ResidentialGround(h){const{x,y,w,h:lh}=h.lot;ctx.save();ctx.fillStyle=h.yard;ctx.fillRect(x,y,w,lh);ctx.fillStyle='rgba(255,255,255,.035)';for(let i=0;i<9;i++)ctx.fillRect(x+28+i*101,y+30,45,lh-60);ctx.fillStyle='#41464a';ctx.fillRect(h.road.x,h.road.y,h.road.w,h.road.h);ctx.fillRect(h.pullin.x,h.pullin.y,h.pullin.w,h.pullin.h);ctx.fillStyle='rgba(255,255,255,.055)';ctx.fillRect(h.road.x+14,h.road.y,h.road.w-28,h.road.h);ctx.strokeStyle='#d7b64e';ctx.lineWidth=4;ctx.setLineDash([25,20]);ctx.beginPath();ctx.moveTo(h.road.x+h.road.w/2,h.road.y+10);ctx.lineTo(h.road.x+h.road.w/2,h.road.y+h.road.h-10);ctx.stroke();ctx.setLineDash([]);ctx.strokeStyle='#e6e3d8';ctx.lineWidth=6;ctx.strokeRect(h.pullin.x+6,h.pullin.y+6,h.pullin.w-12,h.pullin.h-12);ctx.fillStyle='#f4e6be';ctx.font='1000 11px system-ui';ctx.textAlign='center';ctx.fillText('HOME PARKING',h.pullin.x+h.pullin.w/2,h.pullin.y+h.pullin.h-15);drawR36B45PropertyBorder(h);ctx.restore()} function drawR36B45HouseShell(h,wall,roof){const b=h.building,x=b.x,y=b.y,w=b.w,hh=b.h,d=58;ctx.save();ctx.fillStyle='rgba(0,0,0,.30)';ctx.beginPath();ctx.moveTo(x-20,y+28);ctx.lineTo(x+w-20,y+28);ctx.lineTo(x+w-d-10,y+hh+d+26);ctx.lineTo(x-d-30,y+hh+d+26);ctx.closePath();ctx.fill();ctx.fillStyle=shadeColor(wall,-38);ctx.beginPath();ctx.moveTo(x,y);ctx.lineTo(x-d,y+d);ctx.lineTo(x-d,y+hh+d);ctx.lineTo(x,y+hh);ctx.closePath();ctx.fill();ctx.strokeStyle='#171514';ctx.lineWidth=5;ctx.stroke();ctx.fillStyle=shadeColor(wall,-28);ctx.beginPath();ctx.moveTo(x,y+hh);ctx.lineTo(x-d,y+hh+d);ctx.lineTo(x+w-d,y+hh+d);ctx.lineTo(x+w,y+hh);ctx.closePath();ctx.fill();ctx.stroke();ctx.fillStyle=wall;ctx.fillRect(x,y,w,hh);ctx.strokeRect(x,y,w,hh);ctx.fillStyle=roof;ctx.beginPath();ctx.moveTo(x-10,y+20);ctx.lineTo(x+w*.46,y-88);ctx.lineTo(x+w+16,y+4);ctx.lineTo(x+w-4,y+52);ctx.lineTo(x+w*.46,y-28);ctx.lineTo(x,y+62);ctx.closePath();ctx.fill();ctx.stroke();ctx.fillStyle=shadeColor(roof,-22);ctx.beginPath();ctx.moveTo(x+w*.46,y-88);ctx.lineTo(x+w+16,y+4);ctx.lineTo(x+w-4,y+52);ctx.lineTo(x+w*.46,y-28);ctx.closePath();ctx.fill();ctx.stroke();ctx.fillStyle='#b9d9e8';ctx.fillRect(x+48,y+hh-72,62,38);ctx.fillRect(x+w-116,y+hh-72,62,38);ctx.strokeStyle='#4a5960';ctx.lineWidth=3;ctx.strokeRect(x+48,y+hh-72,62,38);ctx.strokeRect(x+w-116,y+hh-72,62,38);ctx.fillStyle='#33261c';ctx.fillRect(h.door.x,h.door.y,h.door.w,h.door.h);ctx.fillStyle='#f1b83e';ctx.beginPath();ctx.arc(h.door.x+h.door.w-12,h.door.y+h.door.h/2,4,0,Math.PI*2);ctx.fill();ctx.fillStyle='rgba(17,21,20,.82)';ctx.fillRect(x+32,y+hh+24,w-64,29);ctx.fillStyle='#f4e6be';ctx.font='1000 12px system-ui';ctx.textAlign='center';ctx.fillText(h.label,x+w/2,y+hh+44);ctx.restore()} function drawR36B45RealStage(x,y,w,h,label){ctx.save();const d=20;ctx.fillStyle='rgba(0,0,0,.28)';ctx.fillRect(x-10,y+16,w+22,h+24);ctx.fillStyle='#232323';ctx.fillRect(x,y,w,h);ctx.strokeStyle='#111';ctx.lineWidth=5;ctx.strokeRect(x,y,w,h);ctx.fillStyle='#555';ctx.beginPath();ctx.moveTo(x,y+h);ctx.lineTo(x-d,y+h+d);ctx.lineTo(x+w-d,y+h+d);ctx.lineTo(x+w,y+h);ctx.closePath();ctx.fill();ctx.stroke();ctx.strokeStyle='#8d9699';ctx.lineWidth=5;ctx.strokeRect(x+8,y-48,w-16,48);for(let i=0;i<4;i++){ctx.fillStyle=i%2?'#f1b83e':'#e64a38';ctx.beginPath();ctx.arc(x+30+i*(w-60)/3,y-30,7,0,Math.PI*2);ctx.fill()}ctx.fillStyle='#111';ctx.fillRect(x+12,y+h-48,34,40);ctx.fillRect(x+w-46,y+h-48,34,40);ctx.fillStyle='#777';ctx.fillRect(x+w/2-25,y+h-12,50,12);ctx.fillStyle='#f4e6be';ctx.font='1000 10px system-ui';ctx.textAlign='center';ctx.fillText(label,x+w/2,y+h/2+4);ctx.restore()} function drawR36B45OwnerHome(h){drawR36B45HouseShell(h,'#9b6b47','#4d3428');const b=h.building;drawR36B45RealStage(b.x+b.w+42,b.y+36,210,112,'WOOD STAGE');drawHomeParkedVehicle(h,'owner')} function drawR36B45FngineerHome(h){drawR36B45HouseShell(h,'#60676b','#303437');const b=h.building;ctx.save();ctx.fillStyle='#202326';ctx.fillRect(b.x+34,b.y+128,198,74);ctx.strokeStyle='#111';ctx.lineWidth=4;ctx.strokeRect(b.x+34,b.y+128,198,74);for(let i=0;i<4;i++){ctx.fillStyle='#222';ctx.fillRect(b.x+44+i*64,b.y+b.h+90,46,60);ctx.fillStyle='#777';ctx.fillRect(b.x+52+i*64,b.y+b.h+102,30,10)}for(let i=0;i<3;i++){ctx.strokeStyle=['#e64a38','#f1b83e','#3f84a5'][i];ctx.lineWidth=6;ctx.beginPath();ctx.arc(b.x+336+i*40,b.y+b.h+118,18,0,Math.PI*2);ctx.stroke()}ctx.restore();drawR36B45RealStage(b.x+b.w+42,b.y+48,220,108,'PRODUCTION TEST STAGE');drawHomeParkedVehicle(h,'audio')} function drawR36B45BandHome(h){drawR36B45HouseShell(h,'#c5a47a','#53352c');const b=h.building;drawR36B45RealStage(b.x-232,b.y+54,205,112,'PRACTICE STAGE');drawHomeParkedVehicle(h,'band')} function drawHomeParkedVehicle(h,kind){const active=careerHomeId()===h.id;if(active&&Math.hypot(van.x-h.spawn.x,van.y-h.spawn.y)<190)return;const px=h.pullin.x+h.pullin.w/2,py=h.pullin.y+h.pullin.h/2,ang=h.id==='band'?-Math.PI/2:Math.PI/2;if(kind==='owner')drawR36B45WhiteFlameVan(px,py,ang);else if(kind==='band')drawR36B45FlameVan(px,py,ang);else drawR36B45PaulVan(px,py,ang)} function drawR36B45LakeAndHomes(){if(!R36B45_HOMES||typeof R36B45_HOMES!=='object')return;ctx.save();for(const h of Object.values(R36B45_HOMES)){if(h)drawR36B45ResidentialGround(h)}if(R36B45_HOMES.owner)drawR36B45OwnerHome(R36B45_HOMES.owner);if(R36B45_HOMES.audio)drawR36B45FngineerHome(R36B45_HOMES.audio);if(R36B45_HOMES.band)drawR36B45BandHome(R36B45_HOMES.band);for(const h of Object.values(R36B45_HOMES)){if(h)drawR36B45PropertyBorder(h)}ctx.restore()} function drawR36B45FlameVan(x,y,angle){drawUnifiedCareerVan(x,y,angle,'band')} function drawR36B45WhiteFlameVan(x,y,angle){drawUnifiedCareerVan(x,y,angle,'owner')} function drawR36B45PaulVan(x,y,angle){drawUnifiedCareerVan(x,y,angle,'paul')} function drawSharedWorldVancertsVan(){if(state.career?.path==='owner'||state.career?.vancertsVanOwned)return;const route=[{x:695,y:330},{x:695,y:1210},{x:2015,y:1210},{x:2015,y:1810},{x:695,y:1810}],seg=Math.floor((performance.now()/6000)%route.length),next=(seg+1)%route.length,p=((performance.now()%6000)/6000),a=route[seg],b=route[next],x=a.x+(b.x-a.x)*p,y=a.y+(b.y-a.y)*p,ang=Math.atan2(b.y-a.y,b.x-a.x);drawUnifiedCareerVan(x,y,ang,'classic')} function spawnCurrentCareerIfNeeded(){if(state.__careerSpawnVersion===2)return;state.__careerSpawnVersion=2;spawnCareerAtHome();save()} function drawPlayerCareerVehicle(){const p=state.career?.path,garage=state.vanWrapGarage&&typeof state.vanWrapGarage==='object'?state.vanWrapGarage:null,owned=garage&&garage.owned&&typeof garage.owned==='object'?garage.owned:{},active=garage&&owned[garage.active]?garage.active:null;if(active){drawUnifiedCareerVan(van.x,van.y,van.angle,active,{armored:!!state.vanUpgrades.armored,potatoGun:!!state.vanUpgrades.potatoGun});return}if(p==='band')drawR36B45FlameVan(van.x,van.y,van.angle);else if(p==='team')drawR36B45PaulVan(van.x,van.y,van.angle);else if(!state.career?.vancertsVanOwned)drawR36B45WhiteFlameVan(van.x,van.y,van.angle);else drawVancertsVanOriginal()} function drawR36B45StreetNames(){ ctx.save();ctx.globalAlpha=.68;ctx.font='1000 18px system-ui';ctx.textAlign='center';ctx.textBaseline='middle'; function paintStreetName(name,x,y,vertical){ctx.save();ctx.translate(x,y);if(vertical)ctx.rotate(-Math.PI/2);const width=Math.max(130,ctx.measureText(name).width+28);ctx.fillStyle='rgba(65,70,74,.72)';ctx.fillRect(-width/2,-16,width,32);ctx.fillStyle='rgba(255,244,200,.88)';ctx.fillText(name,0,1);ctx.restore()} for(const s of R36B45A_STREET_LABELS){ if(s.vertical){for(let y=350;y<world.h-250;y+=560)paintStreetName(s.name,s.x+s.w/2,y,true)} else{for(let x=330;x<s.x+s.w-180;x+=620)paintStreetName(s.name,x,s.y+s.h/2,false)} } ctx.restore() } function r36b45TreeAllowed(x,y){ const pad=30;if(x<175||x>world.w-175||y<175||y>world.h-175)return false; if(roads.some(r=>x>=r.x-pad&&x<=r.x+r.w+pad&&y>=r.y-pad&&y<=r.y+r.h+pad))return false; if(places.some(p=>{if(!placeVisible(p))return false;const b=propertyBounds(p);return x>=b.x-pad&&x<=b.x+b.w+pad&&y>=b.y-pad&&y<=b.y+b.h+pad}))return false; if(activeDriveways().some(d=>x>=d.x-pad&&x<=d.x+d.w+pad&&y>=d.y-pad&&y<=d.y+d.h+pad))return false; return true } function drawR36B45Landscaping(){for(const t of R36B45A_EXTRA_TREES)if(r36b45TreeAllowed(t[0],t[1]))drawTree(t[0],t[1],t[2]);ctx.save();for(let i=0;i<28;i++){const x=190+(i*173)%2860,y=250+((i*307)%2050);if(!r36b45TreeAllowed(x,y))continue;ctx.fillStyle=i%2?'#d65d77':'#f1b83e';ctx.beginPath();ctx.arc(x,y,3,0,Math.PI*2);ctx.fill()}ctx.restore()} function drawR36B45Donstruction(){} function drawR36B45Delebration(){if(!r36b45Celebration.active)return;const elapsed=performance.now()-r36b45Celebration.start;if(elapsed>5200){r36b45Celebration.active=false;return}const p=Math.min(1,elapsed/5200),count=Math.min(70,26+r36b45Celebration.size*3);ctx.save();for(let i=0;i<count;i++){const seed=i*97.13,life=(elapsed/1000+seed)%3.2,ang=seed%6.28,speed=28+(i%9)*7,x=r36b45Celebration.x+Math.cos(ang)*speed*life,y=r36b45Celebration.y-Math.sin(ang)*speed*life+life*life*17;ctx.fillStyle=['#e64a38','#f1b83e','#79c88e','#3f84a5','#fff'][i%5];ctx.save();ctx.translate(x,y);ctx.rotate(life+i);ctx.fillRect(-3,-7,6,14);ctx.restore()}if(elapsed<2600){for(let f=0;f<3;f++){const fx=r36b45Celebration.x+(f-1)*85,fy=r36b45Celebration.y-150-(f%2)*45,r=18+((elapsed/13+f*17)%95);ctx.strokeStyle=['#f1b83e','#e64a38','#fff'][f];ctx.globalAlpha=Math.max(0,1-r/105);ctx.lineWidth=5;ctx.beginPath();ctx.arc(fx,fy,r,0,Math.PI*2);ctx.stroke()}}ctx.globalAlpha=1-p*.5;ctx.fillStyle='#111';ctx.fillRect(r36b45Celebration.x-120,r36b45Celebration.y-95,240,30);ctx.fillStyle='#fff';ctx.font='1000 15px system-ui';ctx.textAlign='center';ctx.fillText('CHEERS! • SHOW COMPLETE',r36b45Celebration.x,r36b45Celebration.y-74);ctx.restore()} function r36b45StreetPosterPoint(p){const d=typeof drivewayFor==='function'?drivewayFor(p.id):null;if(d){let best=null,bestDist=Infinity;for(const r of roads){const x=Math.max(r.x,Math.min(d.x+d.w/2,r.x+r.w)),y=Math.max(r.y,Math.min(d.y+d.h/2,r.y+r.h)),dist=Math.hypot(x-(d.x+d.w/2),y-(d.y+d.h/2));if(dist<bestDist){bestDist=dist;best={x,y}}}if(best)return best}const b=propertyBounds(p);let best=null,bestDist=Infinity;for(const r of roads){const candidates=[{x:Math.max(r.x,Math.min(b.x+b.w/2,r.x+r.w)),y:r.y},{x:Math.max(r.x,Math.min(b.x+b.w/2,r.x+r.w)),y:r.y+r.h},{x:r.x,y:Math.max(r.y,Math.min(b.y+b.h/2,r.y+r.h))},{x:r.x+r.w,y:Math.max(r.y,Math.min(b.y+b.h/2,r.y+r.h))}];for(const q of candidates){const dist=Math.hypot(q.x-(b.x+b.w/2),q.y-(b.y+b.h/2));if(dist<bestDist){bestDist=dist;best=q}}}return best||{x:p.interact.x,y:p.interact.y}} function drawCommunityCity(){ const sw=projectLevel('sidewalks'),lights=projectLevel('stoplights'),pantry=projectLevel('foodPantry'),garden=projectLevel('garden'),art=projectLevel('publicArt'); if(sw){/* R36A sidewalks are drawn by drawR36BaseSidewalks; this upgrade widens them there. */} if(lights)for(const node of activeTrafficSignals())drawTrafficSignal(node); if(pantry){ctx.fillStyle='#f1dfae';ctx.fillRect(910,1180,130,68);ctx.strokeStyle='#222';ctx.lineWidth=4;ctx.strokeRect(910,1180,130,68);ctx.fillStyle='#c24c38';ctx.fillRect(910,1180,130,20);ctx.fillStyle='#111';ctx.font='900 11px system-ui';ctx.textAlign='center';ctx.fillText('FOOD PANTRY',975,1222)} for(const site of visibleBusStops())drawBusStop(site); if(garden){ctx.fillStyle='#5f8f4e';ctx.fillRect(1050,1180,135,72);ctx.strokeStyle='#6e4324';ctx.lineWidth=5;ctx.strokeRect(1050,1180,135,72);for(let i=0;i<8;i++){ctx.fillStyle=i%2?'#f1b83e':'#e64a38';ctx.beginPath();ctx.arc(1065+(i%4)*31,1198+Math.floor(i/4)*31,5,0,Math.PI*2);ctx.fill()}} } function draw(){spawnCurrentCareerIfNeeded(); // Five levels. 4× is the adaptive Full City view. 5× is a doubled-distance bird’s-eye view that includes future north and south expansion space. const zoom=cameraZoomLevel(),scale=cameraScale(),viewW=W/scale,viewH=H/scale; const camX=zoom===4 ? FULL_CITY_VIEW_BOUNDS.x-(viewW-FULL_CITY_VIEW_BOUNDS.w)/2 : zoom===5 ? BIRD_EYE_VIEW_BOUNDS.x-(viewW-BIRD_EYE_VIEW_BOUNDS.w)/2 : van.x-viewW/2; const camY=zoom===4 ? FULL_CITY_VIEW_BOUNDS.y-(viewH-FULL_CITY_VIEW_BOUNDS.h)/2 : zoom===5 ? BIRD_EYE_VIEW_BOUNDS.y-(viewH-BIRD_EYE_VIEW_BOUNDS.h)/2 : van.y-viewH/2; ctx.clearRect(0,0,W,H);ctx.fillStyle='#2f3437';ctx.fillRect(0,0,W,H);ctx.save();ctx.scale(scale,scale);ctx.translate(-camX,-camY); // Extend the perimeter-road environment beyond the current district so the // player never sees an empty edge while the centered camera looks past the map. const edgePad=Math.max(viewW,viewH)+300;ctx.fillStyle='#51634b';ctx.fillRect(-edgePad,-edgePad,world.w+edgePad*2,world.h+edgePad*2);ctx.fillStyle='#41464a';ctx.fillRect(-edgePad,-edgePad,world.w+edgePad*2,edgePad+150);ctx.fillRect(-edgePad,1900,world.w+edgePad*2,edgePad+150);ctx.fillRect(-edgePad,-edgePad,edgePad+150,world.h+edgePad*2);ctx.fillRect(2550,-edgePad,edgePad+150,world.h+edgePad*2);ctx.fillStyle='#9dc77f';ctx.fillRect(150,150,world.w-300,world.h-300);drawGroundTexture();drawWestSideParcelBackplates();drawR36BaseSidewalks();drawTreeBases();for(const r of roads){ctx.fillStyle='#41464a';ctx.fillRect(r.x,r.y,r.w,r.h);drawRoadTexture(r);ctx.strokeStyle='#d7b64e';ctx.lineWidth=4;ctx.setLineDash([25,20]);ctx.beginPath();if(r.w>r.h){ctx.moveTo(r.x,r.y+r.h/2);ctx.lineTo(r.x+r.w,r.y+r.h/2)}else{ctx.moveTo(r.x+r.w/2,r.y);ctx.lineTo(r.x+r.w/2,r.y+r.h)}ctx.stroke();ctx.setLineDash([]); // Painted arrows make each lane's one-way direction obvious. ctx.fillStyle='rgba(255,255,255,.48)';ctx.font='900 20px monospace';ctx.textAlign='center';ctx.textBaseline='middle'; if(r.w>r.h){for(let ax=r.x+180;ax<r.x+r.w;ax+=420){ctx.fillText('←',ax,r.y+r.h*.25);ctx.fillText('→',ax,r.y+r.h*.75)}}else{for(let ay=r.y+180;ay<r.y+r.h;ay+=420){ctx.fillText('↓',r.x+r.w*.25,ay);ctx.fillText('↑',r.x+r.w*.75,ay)}} ctx.textBaseline='alphabetic'}drawParcelEdgeCurbs();drawR36RoadDetails();drawR36B45StreetNames();drawCommunityCity();ctx.save();ctx.fillStyle='rgba(76,154,101,.10)';ctx.fillRect(BYOB_SAFE_ZONE.x,BYOB_SAFE_ZONE.y,BYOB_SAFE_ZONE.w,BYOB_SAFE_ZONE.h);ctx.strokeStyle='#79c88e';ctx.lineWidth=5;ctx.setLineDash([18,10]);ctx.strokeRect(BYOB_SAFE_ZONE.x+4,BYOB_SAFE_ZONE.y+4,BYOB_SAFE_ZONE.w-8,BYOB_SAFE_ZONE.h-8);ctx.setLineDash([]);ctx.fillStyle='#173d20';ctx.font='1000 15px system-ui';ctx.textAlign='center';ctx.fillText('BYOB SAFE GROUND',BYOB_SAFE_ZONE.x+BYOB_SAFE_ZONE.w/2,BYOB_SAFE_ZONE.y+BYOB_SAFE_ZONE.h-12);ctx.restore();for(const b of lockedEdgeBusinesses){if(b.id){const occupied=places.find(p=>p.id===b.id);if(occupied&&placeVisible(occupied))continue;if(state.expansionPermits[b.id])continue;}ctx.fillStyle='rgba(0,0,0,.28)';ctx.fillRect(b.x+8,b.y+8,b.w,b.h);ctx.fillStyle='#5a5a58';ctx.fillRect(b.x,b.y,b.w,b.h);ctx.strokeStyle='#181818';ctx.lineWidth=5;ctx.strokeRect(b.x,b.y,b.w,b.h);ctx.fillStyle='#242424';ctx.fillRect(b.x+16,b.y+16,b.w-32,50);ctx.fillStyle='#888';ctx.fillRect(b.x+20,b.y+b.h-54,b.w-40,38);ctx.fillStyle='rgba(0,0,0,.68)';ctx.fillRect(b.x,b.y,b.w,b.h);ctx.fillStyle='#fff';ctx.font='1000 17px system-ui';ctx.textAlign='center';ctx.fillText('LOCKED',b.x+b.w/2,b.y+b.h/2-2);ctx.font='900 11px system-ui';ctx.fillText('FUTURE BUSINESS',b.x+b.w/2,b.y+b.h/2+19)}drawSouthCenterParcelSigns();for(const r of activeDriveways()){if(r.invisible)continue;ctx.fillStyle='#555b5e';ctx.fillRect(r.x,r.y,r.w,r.h)}drawEastAustinExpansionGate();for(const b of places){if(!placeVisible(b))continue;drawMamaDistrict(b);if(b.id==='leftwaygrounds'){drawLeftwayGroundsParcel(b);continue}if(b.setup){ctx.fillStyle='#5b6265';ctx.fillRect(b.setup.x,b.setup.y,b.setup.w,b.setup.h);ctx.strokeStyle='#fff';ctx.lineWidth=3;ctx.setLineDash([12,8]);ctx.strokeRect(b.setup.x+7,b.setup.y+7,b.setup.w-14,b.setup.h-14);ctx.setLineDash([]);if(b.type!=='bank')drawSetupLabel(b)}if(b.parking){drawParking(b);drawOpenDrivewayMouth(b)}drawSponsorLotBanners(b);drawPseudoBuilding(b);drawLogo(b);if(b.id==='mama'){ctx.fillStyle='#d71919';for(let i=0;i<7;i++){ctx.beginPath();ctx.arc(b.x+35+i*38,b.y+b.h-16,4,0,Math.PI*2);ctx.fill()}}drawSponsorSign(b);if(b.id==='hq'){drawByobSponsorBanners(b);drawByobCommunityFlags(b)}if(b.type==='gig'){if(!unlocked(b.id)){ctx.fillStyle='rgba(0,0,0,.6)';ctx.fillRect(b.x,b.y,b.w,b.h);ctx.fillStyle='#fff';ctx.font='900 18px system-ui';ctx.fillText('LOCKED',b.x+b.w/2,b.y+b.h/2)}else{ctx.fillStyle='#e64a38';ctx.beginPath();ctx.arc(b.interact.x,b.interact.y,15,0,Math.PI*2);ctx.fill();ctx.fillStyle='#fff';ctx.font='900 16px system-ui';ctx.fillText('!',b.interact.x,b.interact.y+6)}}}if(projectLevel('publicArt'))drawCommunityArtBoard();drawPromotionPosterSites();drawForegroundTrees();drawR36B45Landscaping();drawStreetLife();drawPassengerMarkers();for(const c of traffic)drawRoadVehicle(c);drawSocialRide();drawDeveloperSoloBike();drawSpecialCar();drawRoadSnake();drawDonutProjectiles();for(const c of collectibles)drawCollectible(c,performance.now());drawPedestrians();drawCartCollector();drawDevSpawnOverlay();drawR36B45LakeAndHomes();drawPaulTruck();drawVan();drawLeftwayCompoundBridge();drawR36B45Delebration();if(near){ctx.strokeStyle='#f1b83e';ctx.lineWidth=5;ctx.beginPath();ctx.arc(near.interact.x,near.interact.y,28,0,Math.PI*2);ctx.stroke();ctx.fillStyle='#111';ctx.fillRect(van.x-92,van.y-62,184,28);ctx.fillStyle='#fff';ctx.font='900 12px system-ui';ctx.fillText(near.type==='home'?'ENTER HOME • SLEEP TO NEXT DAY':near.type==='poster'?'PLACE PROMOTION POSTER':near.type==='busstop'?'PICK UP PASSENGER • $5':near.type==='passengerDrop'?'DROP OFF PASSENGER • +$5':near.type==='bank'?'BANK • MICRO LOANS':near.type==='gig'&&!unlocked(near.id)?'COMPLETE EARLIER SHOWS':(matchMedia('(pointer:coarse)').matches?'TAP TO INTERACT':'SPACE / ENTER'),van.x,van.y-43)}const timeNow=austinTimeParts(),minsNow=timeNow.hour*60+timeNow.minute;if(minsNow>=1170||minsNow<360){ctx.fillStyle='rgba(18,24,46,.22)';ctx.fillRect(camX,camY,viewW,viewH)}ctx.restore();drawMini()} function drawVan(){drawSharedWorldVancertsVan();drawPlayerCareerVehicle()} function drawMini(){const c=miniCtx,w=340,h=190;c.clearRect(0,0,w,h);c.fillStyle='#a9bd86';c.fillRect(0,0,w,h);c.fillStyle='#4c5941';for(const r of roads)c.fillRect(r.x/world.w*w,r.y/world.h*h,r.w/world.w*w,r.h/world.h*h); // Draw each business as a green square, then center its abbreviation inside it. c.textAlign='center';c.textBaseline='middle';for(const b of places){if(!placeVisible(b))continue;const x=b.x/world.w*w,y=b.y/world.h*h,bw=Math.max(24,b.w/world.w*w),bh=Math.max(18,b.h/world.h*h),abbr=b.abbr||b.short.slice(0,3).toUpperCase();c.fillStyle='#8fa96f';c.fillRect(Math.round(x),Math.round(y),Math.round(bw),Math.round(bh));let fontSize=abbr.length>3?10:12;c.font=`1000 ${fontSize}px monospace`;while(c.measureText(abbr).width>bw-4&&fontSize>7){fontSize--;c.font=`1000 ${fontSize}px monospace`}c.fillStyle='#172016';c.fillText(abbr,Math.round(x+bw/2),Math.round(y+bh/2))} const vx=van.x/world.w*w,vy=van.y/world.h*h;c.save();c.translate(vx,vy);c.rotate(van.angle);c.fillStyle='#111';c.beginPath();c.moveTo(10,0);c.lineTo(-7,-6);c.lineTo(-3,0);c.lineTo(-7,6);c.closePath();c.fill();c.restore();c.strokeStyle='#26351f';c.lineWidth=2;c.strokeRect(1,1,w-2,h-2)} function validateCityGeometry(){ const issues=[],access=[]; for(const p of places.filter(place=>!place.retiredByReorg)){const loadingRequired=!!(p.setup&&p.parking),d=drivewayFor(p.id),surface=p.setup||p.parking||p;const interactClear=!!surface&&pointInRect(p.interact.x,p.interact.y,surface,0)&&!buildingBlocked(p.interact.x,p.interact.y,0);const drivewayTouchesSurface=!loadingRequired||!!(d&&surface&&rectsOverlap(d,surface,1));const drivewayTouchesRoad=!loadingRequired||!!(d&&roads.some(r=>rectsOverlap(d,r,1)));access.push({id:p.id,loadingRequired,interactClear,drivewayTouchesSurface,drivewayTouchesRoad});if(loadingRequired&&(!interactClear||!drivewayTouchesSurface||!drivewayTouchesRoad))issues.push(`LOADING ACCESS: ${p.id}`);const centerBlocked=pointInRect(p.x+p.w/2,p.y+p.h/2,p,0)&&(!placeVisible(p)||buildingBlocked(p.x+p.w/2,p.y+p.h/2,0));if(!centerBlocked)issues.push(`BUILDING COLLISION: ${p.id}`)} const invalidTrees=TREE_SITES.filter(t=>!treeSiteAllowed(t.x,t.y));if(invalidTrees.length)issues.push(`TREE SITES: ${invalidTrees.length} invalid`); const rentalCheck=rentalQuote({main:1,sub:1,mic:2,monitor:1,lights:1,backline:1}),rentalExpected=Number(((650+750+220+425+300+900)*0.25).toFixed(2));if(rentalCheck!==rentalExpected)issues.push(`RENTAL MATH: ${rentalCheck} !== ${rentalExpected}`); if(SAVE_KEY!=='vancerts-v8')issues.push('SAVE KEY CHANGED'); if(!Object.prototype.hasOwnProperty.call(state.expansionPermits,'eastAustin'))issues.push('EAST AUSTIN PERMIT STATE MISSING'); const worldLiquor=places.find(p=>p.id==='worldliquor');if(!worldLiquor||worldLiquor.w!==300||worldLiquor.h!==180)issues.push('WORLD LIQUOR SIZE ERROR');if(state.story.festivalComplete&&!placeVisible(worldLiquor))issues.push('WORLD LIQUOR FESTIVAL UNLOCK ERROR');if(state.story.festivalComplete&&state.story.worldLiquorProgressionNormalized&&state.venues.worldliquor.sign&&(state.venues.worldliquor.fillFlags||0)===0&&(state.venues.worldliquor.rateCars||0)===8)issues.push('WORLD LIQUOR AUTO-SPONSOR STATE ERROR'); const flagThresholds={sixteen:showsPerSponsoredLotFill({capacity:16}),eight:showsPerSponsoredLotFill({capacity:8})};if(flagThresholds.sixteen!==5||flagThresholds.eight!==4)issues.push('SPONSOR FILL FLAG THRESHOLD ERROR');const hazardSegments=[];for(const x of BLACKSTAR_GRAPH_XS)for(const y of BLACKSTAR_GRAPH_YS)for(const [nx,ny] of blackStarNeighbors(x,y))if(!segmentStaysOnRoad(x,y,nx,ny))hazardSegments.push([x,y,nx,ny]);if(hazardSegments.length)issues.push(`HAZARD ROAD ROUTING: ${hazardSegments.length} invalid segments`);const lowerDriveways=['mama','worldliquor'].map(id=>({id,driveway:drivewayFor(id)}));for(const item of lowerDriveways)if(!item.driveway||!roads.some(r=>rectsOverlap(item.driveway,r,1)))issues.push(`LOWER DRIVEWAY CLOSED: ${item.id}`); const allDriveways=places.filter(p=>p.parking&&!p.retiredByReorg).map(p=>({id:p.id,d:drivewayFor(p.id),lot:p.parking,setup:p.setup}));for(const item of allDriveways){const connected=!!(item.d&&item.lot&&item.setup&&rectsOverlap(item.lot,item.setup,1)&&rectsOverlap(item.setup,item.d,1)&&roads.some(r=>rectsOverlap(item.d,r,1)));if(!connected)issues.push(`DRIVEWAY CONNECTION: ${item.id}`)} const civilianRoadErrors=[];for(const c of traffic){const q=carXY(c);if(!onDesignatedRoadPoint(q.x,q.y,1))civilianRoadErrors.push(c)}if(civilianRoadErrors.length)issues.push(`CIVILIAN ROAD CONTAINMENT: ${civilianRoadErrors.length}`); const perimeterLoopErrors=[];for(const c of traffic.filter(c=>c.route==='loop')){const len=loopLength(c.inset);for(let i=0;i<24;i++){const q=loopPoint({...c,t:len*i/24});if(!onDesignatedRoadPoint(q.x,q.y,1))perimeterLoopErrors.push({inset:c.inset,t:q})}}if(perimeterLoopErrors.length)issues.push(`PERIMETER LOOP ROUTING: ${perimeterLoopErrors.length}`); const bridgeErrors=[];for(const p of places.filter(place=>!place.retiredByReorg&&place.parking&&place.setup)){const d=drivewayFor(p.id),lot=p.parking;if(!d||!lot)bridgeErrors.push(p.id);else if(!(PULL_IN_BUSINESS_IDS.has(p.id)||p.setup?.eastPullIn||p.setup?.westParcelPullIn||p.setup?.unifiedPullIn||p.setup?.curbside)&&!rectsOverlap(d,lot,1))bridgeErrors.push(p.id)}if(bridgeErrors.length)issues.push(`LOADING BRIDGE COVERAGE: ${bridgeErrors.join(', ')}`); const flagSiteErrors=auditAllBusinessFlags().filter(r=>r.visible&&r.sites<3);if(flagSiteErrors.length)issues.push(`SPONSOR FLAG SITES: ${flagSiteErrors.map(r=>r.id).join(', ')}`); return{build:'R36B45D CAREER HOMES + SPAWN CORRECTION',saveKey:SAVE_KEY,pass:issues.length===0,issues,loadingAccess:access,treeSites:TREE_SITES.length,invalidTrees:invalidTrees.length,rentalCheck,rentalExpected,flagThresholds,hazardRoadSegments:hazardSegments.length,lowerDriveways,allDriveways:allDriveways.map(x=>({id:x.id,connected:!!(x.d&&x.lot&&x.setup&&rectsOverlap(x.lot,x.setup,1)&&rectsOverlap(x.setup,x.d,1)&&roads.some(r=>rectsOverlap(x.d,r,1)))})),civilianRoadErrors:civilianRoadErrors.length,perimeterLoopErrors:perimeterLoopErrors.length,loadingBridgeErrors:bridgeErrors,flagGrassErrors:flagSiteErrors.length} } window.__VANCERTS_RENTAL_MISSING=rentalMissingItems;window.__VANCERTS_RENTAL_QUOTE=rentalQuote;window.__VANCERTS_CITY_REPORT=validateCityGeometry();if(!window.__VANCERTS_CITY_REPORT.pass)console.warn('R36B40T CITY VALIDATION',window.__VANCERTS_CITY_REPORT); /* ===== R36B40R CONTROLLER ENGINE: PS4 CROSS HOLD + RIGHT-STICK POINTER ===== */ const CONTROLLER_SAVE_KEY='vancerts-controller-v1'; const CONTROLLER_DEFAULTS={ interact:[0],back:[1],phone:[2],howto:[3],reverse:[4,6],accelerate:[5,7],saveLoad:[8],pause:[9] }; const CONTROLLER_LABELS={interact:'INTERACT / CONFIRM',back:'BACK / CLOSE / 512 JAMS',phone:'SQUARE UTILITY / PHONE HOLD',howto:'HOW TO PLAY',reverse:'REVERSE',accelerate:'ACCELERATE',saveLoad:'SAVE TAP / LOAD HOLD',pause:'PAUSE / CONTROLS'}; const CONTROLLER_BUTTON_NAMES=['A / CROSS','B / CIRCLE','X / SQUARE','Y / TRIANGLE','LEFT BUMPER','RIGHT BUMPER','LEFT TRIGGER','RIGHT TRIGGER','BACK / SHARE','START / OPTIONS','LEFT STICK','RIGHT STICK','D-PAD UP','D-PAD DOWN','D-PAD LEFT','D-PAD RIGHT','HOME']; let controllerBindings=loadControllerBindings(),controllerConnected=false,controllerActivated=false,controllerPrevious=[],controllerInput={left:false,right:false,forward:false,reverse:false},controllerMenuIndex=0,controllerListening=null,controllerSaveDownAt=0,controllerUtilityDownAt=0,controllerUtilityHoldOpened=false,controllerPrimaryDownAt=0,controllerPrimaryHoldOpened=false,controllerLastNav=0,controllerOverlayTimer=0; let controllerPointerX=NaN,controllerPointerY=NaN,controllerPointerLastFrame=performance.now(),controllerPointerVisible=false,controllerPointerTarget=null; function loadControllerBindings(){try{const raw=localStorage.getItem(CONTROLLER_SAVE_KEY);if(raw){const v=JSON.parse(raw);return Object.assign({},CONTROLLER_DEFAULTS,v)}}catch(e){}return JSON.parse(JSON.stringify(CONTROLLER_DEFAULTS))} function saveControllerBindings(){try{localStorage.setItem(CONTROLLER_SAVE_KEY,JSON.stringify(controllerBindings))}catch(e){}} function controllerButtonName(i){return CONTROLLER_BUTTON_NAMES[i]||`BUTTON ${i}`} function controllerBindingText(action){const a=Array.isArray(controllerBindings[action])?controllerBindings[action]:[controllerBindings[action]];return a.map(controllerButtonName).join(' OR ')} function controllerStatus(message,ms=1800){const el=$('controllerStatus');if(!el)return;el.textContent=message;el.classList.add('show');clearTimeout(controllerOverlayTimer);controllerOverlayTimer=setTimeout(()=>el.classList.remove('show'),ms)} function showControllerWake(gp){const wake=$('controllerWake'),name=$('controllerWakeName');if(name)name.textContent=(gp&&gp.id?gp.id:'GAMEPAD READY').slice(0,64);if(wake&&!controllerActivated)wake.classList.add('show')} function hideControllerWake(){const wake=$('controllerWake');if(wake)wake.classList.remove('show')} function currentGamepad(){const pads=navigator.getGamepads?navigator.getGamepads():[];for(const p of pads)if(p&&p.connected)return p;return null} window.addEventListener('gamepadconnected',e=>{controllerConnected=true;showControllerWake(e.gamepad);controllerStatus('CONTROLLER CONNECTED • PRESS ANY BUTTON',2600)}); window.addEventListener('gamepaddisconnected',()=>{controllerConnected=!!currentGamepad();controllerInput={left:false,right:false,forward:false,reverse:false};hideControllerPointer();controllerStatus('CONTROLLER DISCONNECTED')}); function gpPressed(gp,index){const b=gp&&gp.buttons&&gp.buttons[index];return !!(b&&(b.pressed||b.value>.55))} function actionPressed(gp,action){const arr=Array.isArray(controllerBindings[action])?controllerBindings[action]:[controllerBindings[action]];return arr.some(i=>gpPressed(gp,Number(i)))} function actionEdge(gp,action){const arr=Array.isArray(controllerBindings[action])?controllerBindings[action]:[controllerBindings[action]];return arr.some(i=>gpPressed(gp,Number(i))&&!controllerPrevious[Number(i)])} function actionPressedExcluding(gp,action,excluded){const arr=Array.isArray(controllerBindings[action])?controllerBindings[action]:[controllerBindings[action]];return arr.some(i=>Number(i)!==excluded&&gpPressed(gp,Number(i)))} function actionEdgeExcluding(gp,action,excluded){const arr=Array.isArray(controllerBindings[action])?controllerBindings[action]:[controllerBindings[action]];return arr.some(i=>Number(i)!==excluded&&gpPressed(gp,Number(i))&&!controllerPrevious[Number(i)])} function anyButtonEdge(gp){for(let i=0;i<gp.buttons.length;i++)if(gpPressed(gp,i)&&!controllerPrevious[i])return i;return -1} const CONTROLLER_POINTER_SELECTOR='button:not([disabled]),a[href],input:not([disabled]),select:not([disabled]),textarea:not([disabled]),[role="button"],[tabindex]:not([tabindex="-1"]),iframe'; function controllerPointerCurve(value){const a=Math.abs(Number(value)||0),dead=.18;if(a<=dead)return 0;return Math.sign(value)*Math.pow(Math.min(1,(a-dead)/(1-dead)),1.45)} function controllerPointerBounds(){const v=visibleViewportRect(),m=12;return{left:v.left+m,top:v.top+m,right:v.left+v.width-m,bottom:v.top+v.height-m}} function controllerPointerActionAt(x=controllerPointerX,y=controllerPointerY){const raw=document.elementFromPoint(Math.round(x),Math.round(y));if(!raw||typeof raw.closest!=='function')return null;const el=raw.closest(CONTROLLER_POINTER_SELECTOR);if(!el||el.id==='game'||el.offsetParent===null)return null;return el} function setControllerPointerTarget(target){if(controllerPointerTarget&&controllerPointerTarget!==target)controllerPointerTarget.classList.remove('controllerPointerTarget');controllerPointerTarget=target||null;if(controllerPointerTarget)controllerPointerTarget.classList.add('controllerPointerTarget');const p=$('controllerPointer');if(p)p.classList.toggle('action',!!controllerPointerTarget)} function renderControllerPointer(){const p=$('controllerPointer');if(!p||!Number.isFinite(controllerPointerX)||!Number.isFinite(controllerPointerY))return;p.style.left=Math.round(controllerPointerX)+'px';p.style.top=Math.round(controllerPointerY)+'px';p.classList.toggle('show',controllerPointerVisible);setControllerPointerTarget(controllerPointerVisible?controllerPointerActionAt():null)} function showControllerPointerAtCenter(){if(!Number.isFinite(controllerPointerX)||!Number.isFinite(controllerPointerY)){const v=visibleViewportRect();controllerPointerX=v.left+v.width/2;controllerPointerY=v.top+v.height/2}controllerPointerVisible=true;renderControllerPointer()} function hideControllerPointer(){controllerPointerVisible=false;setControllerPointerTarget(null);const p=$('controllerPointer');if(p)p.classList.remove('show','action')} function updateControllerPointer(gp){const now=performance.now(),dt=Math.max(8,Math.min(34,now-controllerPointerLastFrame||16));controllerPointerLastFrame=now;if(!gp||!gp.axes||gp.axes.length<4){if(controllerPointerVisible)renderControllerPointer();return false}const dx=controllerPointerCurve(gp.axes[2]),dy=controllerPointerCurve(gp.axes[3]);if(!dx&&!dy){if(controllerPointerVisible)renderControllerPointer();return false}showControllerPointerAtCenter();const b=controllerPointerBounds(),speed=.88;controllerPointerX=Math.max(b.left,Math.min(b.right,controllerPointerX+dx*speed*dt));controllerPointerY=Math.max(b.top,Math.min(b.bottom,controllerPointerY+dy*speed*dt));renderControllerPointer();return true} function controllerPointerClick(forceVisible=false){if(!controllerPointerVisible&&!forceVisible)return false;if(forceVisible)showControllerPointerAtCenter();const target=controllerPointerActionAt();setControllerPointerTarget(target);if(!target)return false;try{target.focus({preventScroll:true})}catch(e){try{target.focus()}catch(_){}}if(target.tagName==='IFRAME'){controllerStatus('PLAYER FOCUSED • USE SPOTIFY CONTROLS',1800);return true}target.click();controllerStatus('POINTER CLICK',650);return true} window.addEventListener('resize',()=>{if(!controllerPointerVisible)return;const b=controllerPointerBounds();controllerPointerX=Math.max(b.left,Math.min(b.right,controllerPointerX));controllerPointerY=Math.max(b.top,Math.min(b.bottom,controllerPointerY));renderControllerPointer()},{passive:true}); function controllerFocusable(){const wrap=$('modalWrap');if(!wrap||!wrap.classList.contains('show'))return[];return Array.from($('modal').querySelectorAll('button:not([disabled]),input:not([disabled]),select:not([disabled])')).filter(el=>el.offsetParent!==null)} function focusControllerItem(delta){const items=controllerFocusable();if(!items.length)return;const now=Date.now();if(now-controllerLastNav<150)return;controllerLastNav=now;let idx=items.indexOf(document.activeElement);if(idx<0)idx=controllerMenuIndex||0;idx=(idx+delta+items.length)%items.length;controllerMenuIndex=idx;items[idx].focus({preventScroll:true});items.forEach(x=>x.classList.remove('controllerFocus'));items[idx].classList.add('controllerFocus');items[idx].scrollIntoView({block:'nearest'})} function controllerConfirm(){const wrap=$('modalWrap');if(wrap&&wrap.classList.contains('show')){const items=controllerFocusable();let el=document.activeElement;if(!items.includes(el)){el=items[0];if(el)el.focus({preventScroll:true})}if(el){el.click();return}}combatOrInteract(true)} function controllerBack(){if(permitGateActive){toast('ISSUE YOUR DRIVER PERMIT FIRST');return}if(controllerListening){controllerListening=null;controllerSettingsModal();return}const wrap=$('modalWrap');if(wrap&&wrap.classList.contains('show')){closeModal();return}const ph=$('phone'),rr=$('rotaryRadio');if(ph&&!ph.classList.contains('collapsed')){collapseReliable(ph,$('phoneCollapse'),true);return}if(rr&&!rr.classList.contains('collapsed')){collapseReliable(rr,$('radioCollapse'),true);return}if(rr){rr.classList.remove('hidden');expandReliable(rr,$('radioCollapse'),ph,$('phoneCollapse'));clear512GameplayInput();controllerStatus('512 JAMS OPEN • DRIVING PAUSED')}} function controllerOpenPhone(){const ph=$('phone');if(!ph)return;openPhone();if(ph.classList.contains('collapsed'))expandReliable(ph,$('phoneCollapse'),true)} function controllerPrimaryOpenPhone(){const wrap=$('modalWrap');if(wrap&&wrap.classList.contains('show'))closeModal();controllerOpenPhone();controllerStatus('NOOKIA OPEN • HOLD CROSS / A')} function controllerPauseMenu(){modal(`<h2>PAUSED</h2><p>Controller, keyboard, and touch controls remain available together.</p><div class="btns"><button autofocus onclick="closeModal()">RESUME</button><button onclick="controllerSettingsModal()">CONTROLLER SETTINGS</button><button onclick="showHow()">HOW TO PLAY</button><button onclick="manualSave()">SAVE GAME</button><button onclick="choosePortableSave()">LOAD GAME</button></div>`);setTimeout(()=>focusControllerItem(0),0)} function controllerSettingsModal(){controllerListening=null;const rows=Object.keys(CONTROLLER_LABELS).map(action=>`<button class="controllerMapRow" data-controller-action="${action}"><span><b>${CONTROLLER_LABELS[action]}</b><br><small>Highlight and press Cross / A to remap</small></span><span class="binding">${controllerBindingText(action)}</span></button>`).join('');modal(`<h2>CONTROLLER SETTINGS</h2><p>Select an action with the left stick or D-pad. Press <b>Cross / A</b> to change it, then press the new controller button.</p><div class="controllerHelp"><b>PS4 / POINTER:</b> Move the right stick like a mouse pointer. Tap <b>Cross / A</b> or press <b>R3</b> to click. Hold <b>Cross / A</b> for 0.65 seconds to open the Nookia. Square / X keeps the potato-cannon utility and its original phone-hold shortcut.</div><div class="controllerGrid">${rows}</div><div class="btns"><button onclick="resetControllerBindings()">RESTORE DEFAULTS</button><button class="secondary" onclick="controllerPauseMenu()">BACK</button><button class="secondary" onclick="closeModal()">RESUME</button></div>`);$('modal').querySelectorAll('[data-controller-action]').forEach(b=>b.addEventListener('click',()=>beginControllerRemap(b.dataset.controllerAction)));setTimeout(()=>focusControllerItem(0),0)} function beginControllerRemap(action){controllerListening=action;const row=$('modal').querySelector(`[data-controller-action="${action}"]`);if(row){row.classList.add('listening');row.querySelector('.binding').textContent='PRESS NEW BUTTON…'}controllerStatus(`REMAPPING ${CONTROLLER_LABELS[action]} • PRESS A BUTTON`,4000)} function finishControllerRemap(buttonIndex){if(!controllerListening)return;controllerBindings[controllerListening]=[buttonIndex];saveControllerBindings();controllerStatus(`${CONTROLLER_LABELS[controllerListening]} → ${controllerButtonName(buttonIndex)}`,2400);controllerListening=null;controllerSettingsModal()} function resetControllerBindings(){controllerBindings=JSON.parse(JSON.stringify(CONTROLLER_DEFAULTS));saveControllerBindings();controllerStatus('DEFAULT CONTROLS RESTORED');controllerSettingsModal()} window.controllerPauseMenu=controllerPauseMenu;window.controllerSettingsModal=controllerSettingsModal;window.beginControllerRemap=beginControllerRemap;window.resetControllerBindings=resetControllerBindings; function approachAngle(current,target,amount){let d=((target-current+Math.PI*3)%(Math.PI*2))-Math.PI;return current+Math.max(-amount,Math.min(amount,d))} function pollController(){ const gp=currentGamepad();if(!gp){requestAnimationFrame(pollController);return}controllerConnected=true; const firstEdge=anyButtonEdge(gp);let justActivated=false; if(!controllerActivated&&firstEdge>=0){controllerActivated=true;justActivated=true;hideControllerWake();controllerStatus('CONTROLLER ACTIVE • RIGHT STICK = POINTER');if($('splash')&&!$('splash').classList.contains('hidden'))startGame()} if(controllerListening&&firstEdge>=0){finishControllerRemap(firstEdge);controllerPrevious=gp.buttons.map((_,i)=>gpPressed(gp,i));requestAnimationFrame(pollController);return} if(justActivated){controllerPrevious=gp.buttons.map((_,i)=>gpPressed(gp,i));requestAnimationFrame(pollController);return} updateControllerPointer(gp); const ax0=Math.abs(gp.axes[0]||0)>.24?(gp.axes[0]||0):0,ax1=Math.abs(gp.axes[1]||0)>.30?(gp.axes[1]||0):0; const dUp=gpPressed(gp,12),dDown=gpPressed(gp,13),dLeft=gpPressed(gp,14),dRight=gpPressed(gp,15); const modalOpen=$('modalWrap')&&$('modalWrap').classList.contains('show'); if(modalOpen){const modalEl=$('modal');if(modalEl&&Math.abs(ax1)>.28){modalEl.scrollTop+=ax1*18}if(dUp&&!controllerPrevious[12])focusControllerItem(-1);if(dDown&&!controllerPrevious[13])focusControllerItem(1);controllerInput={left:false,right:false,forward:false,reverse:false}} else{controllerInput.left=dLeft||ax0<-.25;controllerInput.right=dRight||ax0>.25;controllerInput.forward=actionPressed(gp,'accelerate');controllerInput.reverse=actionPressed(gp,'reverse');if(dUp||ax1<-.70)van.angle=approachAngle(van.angle,-Math.PI/2,.20);if(dDown||ax1>.70)van.angle=approachAngle(van.angle,Math.PI/2,.20)} // PS4 Cross / standard button 0 is now a dependable dual-purpose control: // tap confirms or pointer-clicks; hold opens the Nookia without firing the tap action first. const primaryHeld=gpPressed(gp,0); if(primaryHeld&&!controllerPrimaryDownAt){controllerPrimaryDownAt=Date.now();controllerPrimaryHoldOpened=false} if(primaryHeld&&controllerPrimaryDownAt&&!controllerPrimaryHoldOpened&&Date.now()-controllerPrimaryDownAt>=650){controllerPrimaryHoldOpened=true;controllerPrimaryOpenPhone()} if(!primaryHeld&&controllerPrimaryDownAt){const wasHold=controllerPrimaryHoldOpened;controllerPrimaryDownAt=0;controllerPrimaryHoldOpened=false;if(!wasHold&&!controllerPointerClick())controllerConfirm()} if(actionEdgeExcluding(gp,'interact',0))controllerConfirm(); if(gpPressed(gp,11)&&!controllerPrevious[11]){if(!controllerPointerClick(true))controllerStatus('MOVE THE RIGHT STICK OVER A BUTTON',1300)} if(actionEdge(gp,'back'))controllerBack(); if(modalOpen&&actionEdgeExcluding(gp,'phone',0)){const focused=document.activeElement;if(focused&&focused.dataset&&focused.dataset.controllerAction)beginControllerRemap(focused.dataset.controllerAction)} if(!modalOpen){const utilityHeld=actionPressedExcluding(gp,'phone',0);if(utilityHeld&&!controllerUtilityDownAt){controllerUtilityDownAt=Date.now();controllerUtilityHoldOpened=false}if(utilityHeld&&controllerUtilityDownAt&&!controllerUtilityHoldOpened&&Date.now()-controllerUtilityDownAt>=650){controllerUtilityHoldOpened=true;controllerOpenPhone();controllerStatus('NOOKIA OPEN • LEGACY SQUARE / X HOLD')}if(!utilityHeld&&controllerUtilityDownAt){const wasHold=controllerUtilityHoldOpened;controllerUtilityDownAt=0;controllerUtilityHoldOpened=false;if(!wasHold){if(state.vanUpgrades&&state.vanUpgrades.potatoGun){fireDonut();controllerStatus('POTATO FIRED',700)}else controllerStatus('POTATO CANNON LOCKED • HOLD CROSS / A FOR PHONE',1500)}}}else{controllerUtilityDownAt=0;controllerUtilityHoldOpened=false} if(actionEdge(gp,'howto'))showHow();if(actionEdge(gp,'pause'))controllerPauseMenu(); const saveHeld=actionPressed(gp,'saveLoad');if(saveHeld&&!controllerSaveDownAt)controllerSaveDownAt=Date.now();if(!saveHeld&&controllerSaveDownAt){const held=Date.now()-controllerSaveDownAt;controllerSaveDownAt=0;if(held>=700){choosePortableSave();controllerStatus('LOAD GAME')}else{manualSave();controllerStatus('GAME SAVED')}} controllerPrevious=gp.buttons.map((_,i)=>gpPressed(gp,i));requestAnimationFrame(pollController) } requestAnimationFrame(pollController); /* ===== END R36B40R CONTROLLER ENGINE ===== */ (function(){ const phoneFitEl=document.getElementById('phone'); function fitNookiaPhone(){ if(!phoneFitEl||phoneFitEl.classList.contains('collapsed'))return; const vv=window.visualViewport; const vw=Math.max(1,Math.round(vv?vv.width:window.innerWidth)); const vh=Math.max(1,Math.round(vv?vv.height:window.innerHeight)); const margin=8; const availableW=Math.max(1,vw-(margin*2)); const availableH=Math.max(1,vh-(margin*2)); const scale=Math.max(.30,Math.min(1,availableW/230,availableH/430)); const offsetLeft=Math.round(vv?vv.offsetLeft:0); const offsetTop=Math.round(vv?vv.offsetTop:0); const rightGap=Math.max(margin,Math.round((window.innerWidth-(offsetLeft+vw))+margin)); phoneFitEl.style.setProperty('--phone-fit-scale',scale.toFixed(4)); phoneFitEl.style.setProperty('--nookia-top',(offsetTop+margin)+'px'); phoneFitEl.style.setProperty('--nookia-right',rightGap+'px'); phoneFitEl.classList.remove('deviceFreePosition'); phoneFitEl.style.removeProperty('left');phoneFitEl.style.removeProperty('bottom'); } window.addEventListener('resize',fitNookiaPhone,{passive:true}); window.addEventListener('orientationchange',function(){setTimeout(fitNookiaPhone,80)},{passive:true}); if(window.visualViewport)window.visualViewport.addEventListener('resize',fitNookiaPhone,{passive:true}); document.addEventListener('fullscreenchange',function(){setTimeout(fitNookiaPhone,50)}); window.addEventListener('load',fitNookiaPhone,{once:true}); setTimeout(fitNookiaPhone,0); })(); function loop(t){const dt=Math.min(35,t-last);last=t;update(dt);draw();requestAnimationFrame(loop)}requestAnimationFrame(loop); </script> <script>try{window.parent.postMessage({type:"vancerts-game-ready"},"*")}catch(e){}</script> <script> (function(){ const intro=document.getElementById('vancertsBrandIntro'); const mark=document.getElementById('vancertsHudMark'); let introTimer=0; function finishBrandIntro(){ if(!intro||intro.classList.contains('done'))return; intro.classList.add('done'); clearTimeout(introTimer); setTimeout(()=>intro.remove(),520); } function pulseBrandMark(){ if(!mark)return; mark.classList.remove('pulse'); void mark.offsetWidth; mark.classList.add('pulse'); setTimeout(()=>mark.classList.remove('pulse'),1150); } window.pulseVancertsBrand=pulseBrandMark; if(intro){ intro.addEventListener('click',finishBrandIntro,{once:true}); introTimer=setTimeout(finishBrandIntro,2850); } window.addEventListener('vancerts-brand-pulse',pulseBrandMark); })(); // R36B46F: mirror the live mission into the Nookia and display numeric app alerts. function syncR36B46FPhoneObjective(){ const title=document.getElementById('objectiveTitle'),text=document.getElementById('objectiveText'); const pt=document.getElementById('phoneObjectiveTitle'),px=document.getElementById('phoneObjectiveText'); if(pt&&title)pt.textContent=title.textContent||'CURRENT OBJECTIVE'; if(px&&text)px.textContent=text.textContent||'Drive to the next marked location.'; } function setR36B46FBadge(id,count){const badge=document.getElementById(id);if(!badge)return;const n=Math.max(0,Number(count)||0);badge.hidden=!n;badge.textContent=n>99?'99+':String(n)} function updateR36B46FPhoneBadges(){ try{ const sponsorCount=Array.isArray(state.sponsorOffers)?state.sponsorOffers.length:0; const emailCount=(state.pendingOffer?1:0)+sponsorCount+(state.festivalMail?1:0); const contactCount=Array.isArray(state.invoices)?state.invoices.filter(i=>!i.paid).length:0; const teamCount=state.staff&&state.staff.paul&&state.staff.paul.nextShift?1:0; const waygoCount=state.passengerRide?1:0; setR36B46FBadge('emailBadge',emailCount);setR36B46FBadge('contactsBadge',contactCount);setR36B46FBadge('teamBadge',teamCount);setR36B46FBadge('waygoBadge',waygoCount); }catch(e){} } (()=>{ // R36B52A: one initial badge sync; the authoritative HUD renderer mirrors objectives. syncR36B46FPhoneObjective();updateR36B46FPhoneBadges(); })(); // R36B46H — smartphone-style cumulative unread badges and more realistic career homes. function ensureR36B46HBadge(buttonId,badgeId){ const button=document.getElementById(buttonId);if(!button)return null; let badge=document.getElementById(badgeId);if(!badge){badge=document.createElement('i');badge.className='appBadge';badge.id=badgeId;badge.hidden=true;badge.textContent='0';button.appendChild(badge)}return badge } function r36b46hUnreadState(){ state.phoneUnread=state.phoneUnread||{email:0,contacts:0,team:0,waygo:0,business:0,bank:0,wallet:0}; state.phoneSignals=state.phoneSignals||{};return state.phoneUnread } function r36b46hSignalCounts(){ const sponsorCount=Array.isArray(state.sponsorOffers)?state.sponsorOffers.length:0; const email=(state.pendingOffer?1:0)+sponsorCount+(state.festivalMail?1:0); const contacts=Array.isArray(state.invoices)?state.invoices.filter(i=>!i.paid).length:0; const team=state.staff&&state.staff.paul&&state.staff.paul.nextShift?1:0; const waygo=state.passengerRide?1:0; const business=Array.isArray(state.receipts)?state.receipts.length:0; const bank=contacts; const wallet=state.driverPass&&state.driverPass.name?0:1; return{email,contacts,team,waygo,business,bank,wallet} } function updateR36B46FPhoneBadges(){ try{ ensureR36B46HBadge('phoneEmailApp','emailBadge');ensureR36B46HBadge('phoneContacts','contactsBadge');ensureR36B46HBadge('phoneStaffApp','teamBadge');ensureR36B46HBadge('phoneWaygoApp','waygoBadge'); ensureR36B46HBadge('phoneLedgerApp','businessBadge');ensureR36B46HBadge('phoneBankApp','bankBadge');ensureR36B46HBadge('phoneWallet','walletBadge'); const unread=r36b46hUnreadState(),signals=r36b46hSignalCounts(),last=state.phoneSignals||{}; for(const key of Object.keys(signals)){ const previous=Number(last[key]||0),current=Number(signals[key]||0); if(current>previous)unread[key]=Math.min(999,Number(unread[key]||0)+(current-previous)); last[key]=current; } state.phoneSignals=last; setR36B46FBadge('emailBadge',unread.email);setR36B46FBadge('contactsBadge',unread.contacts);setR36B46FBadge('teamBadge',unread.team);setR36B46FBadge('waygoBadge',unread.waygo); setR36B46FBadge('businessBadge',unread.business);setR36B46FBadge('bankBadge',unread.bank);setR36B46FBadge('walletBadge',unread.wallet); }catch(e){} } function clearR36B46HUnread(key){const unread=r36b46hUnreadState();unread[key]=0;save();updateR36B46FPhoneBadges()} [['phoneEmailApp','email'],['phoneContacts','contacts'],['phoneStaffApp','team'],['phoneWaygoApp','waygo'],['phoneLedgerApp','business'],['phoneBankApp','bank'],['phoneWallet','wallet']].forEach(([id,key])=>{const el=document.getElementById(id);if(el&&!el.dataset.unreadBound){el.dataset.unreadBound='1';el.addEventListener('click',()=>clearR36B46HUnread(key),{capture:true})}}); function drawR36B45HouseShell(h,wall,roof){ const b=h.building,x=b.x,y=b.y,w=b.w,hh=b.h,depth=66; ctx.save(); // broad property shadow and foundation ctx.fillStyle='rgba(0,0,0,.28)';ctx.beginPath();ctx.moveTo(x-26,y+28);ctx.lineTo(x+w+26,y+28);ctx.lineTo(x+w+depth,y+hh+depth+20);ctx.lineTo(x-depth,y+hh+depth+20);ctx.closePath();ctx.fill(); ctx.fillStyle='#6b6258';ctx.fillRect(x-8,y+hh-4,w+16,18); // front wall ctx.fillStyle=wall;ctx.fillRect(x,y,w,hh);ctx.strokeStyle='#171514';ctx.lineWidth=5;ctx.strokeRect(x,y,w,hh); // right side wall ctx.fillStyle=shadeColor(wall,-30);ctx.beginPath();ctx.moveTo(x+w,y);ctx.lineTo(x+w+depth,y+depth);ctx.lineTo(x+w+depth,y+hh+depth);ctx.lineTo(x+w,y+hh);ctx.closePath();ctx.fill();ctx.stroke(); // complete roof planes covering the whole top const ridgeX=x+w*.46,ridgeY=y-92; ctx.fillStyle=roof;ctx.beginPath();ctx.moveTo(x-18,y+10);ctx.lineTo(ridgeX,ridgeY);ctx.lineTo(x+w+22,y+10);ctx.lineTo(x+w,y+58);ctx.lineTo(ridgeX,y-20);ctx.lineTo(x,y+58);ctx.closePath();ctx.fill();ctx.stroke(); ctx.fillStyle=shadeColor(roof,-24);ctx.beginPath();ctx.moveTo(ridgeX,ridgeY);ctx.lineTo(x+w+22,y+10);ctx.lineTo(x+w+depth+12,y+depth+12);ctx.lineTo(ridgeX+depth,y-20+depth);ctx.closePath();ctx.fill();ctx.stroke(); // fascia and roof edge ctx.strokeStyle='#221b18';ctx.lineWidth=8;ctx.beginPath();ctx.moveTo(x-18,y+10);ctx.lineTo(ridgeX,ridgeY);ctx.lineTo(x+w+22,y+10);ctx.stroke(); // windows live only on vertical walls ctx.fillStyle='#b9d9e8';ctx.fillRect(x+42,y+hh-82,66,42);ctx.fillRect(x+w-118,y+hh-82,66,42);ctx.strokeStyle='#4a5960';ctx.lineWidth=3;ctx.strokeRect(x+42,y+hh-82,66,42);ctx.strokeRect(x+w-118,y+hh-82,66,42); ctx.fillStyle='#88aebf';ctx.beginPath();ctx.moveTo(x+w+18,y+hh-92);ctx.lineTo(x+w+52,y+hh-58);ctx.lineTo(x+w+52,y+hh-18);ctx.lineTo(x+w+18,y+hh-52);ctx.closePath();ctx.fill();ctx.stroke(); // front door and porch ctx.fillStyle='#33261c';ctx.fillRect(h.door.x,h.door.y,h.door.w,h.door.h);ctx.strokeStyle='#171514';ctx.lineWidth=4;ctx.strokeRect(h.door.x,h.door.y,h.door.w,h.door.h); ctx.fillStyle='#7d7366';ctx.fillRect(h.door.x-18,h.door.y+h.door.h,h.door.w+36,14);ctx.fillStyle='#f1b83e';ctx.beginPath();ctx.arc(h.door.x+h.door.w-10,h.door.y+h.door.h/2,4,0,Math.PI*2);ctx.fill(); // property label ctx.fillStyle='rgba(17,21,20,.84)';ctx.fillRect(x+26,y+hh+28,w-52,30);ctx.fillStyle='#f4e6be';ctx.font='1000 12px system-ui';ctx.textAlign='center';ctx.fillText(h.label,x+w/2,y+hh+49); ctx.restore() } function drawR36B45PropertyBorder(h){ const l=h.lot,gapStart=h.road.x-28,gapEnd=h.road.x+h.road.w+28,topGap=h.id==='band';ctx.save(); const industrial=h.border==='industrial';ctx.strokeStyle=industrial?'#3e474b':'#765035';ctx.lineWidth=industrial?10:11;ctx.lineCap='square'; function seg(x1,y1,x2,y2){ctx.beginPath();ctx.moveTo(x1,y1);ctx.lineTo(x2,y2);ctx.stroke()} seg(l.x,l.y,l.x+l.w,l.y);seg(l.x,l.y,l.x,l.y+l.h);seg(l.x+l.w,l.y,l.x+l.w,l.y+l.h); if(topGap){seg(l.x,l.y,gapStart,l.y);seg(gapEnd,l.y,l.x+l.w,l.y);seg(l.x,l.y+l.h,l.x+l.w,l.y+l.h)}else{seg(l.x,l.y+l.h,gapStart,l.y+l.h);seg(gapEnd,l.y+l.h,l.x+l.w,l.y+l.h)} if(industrial){ctx.strokeStyle='#9ea8ab';ctx.lineWidth=2;for(let x=l.x+20;x<l.x+l.w;x+=38){if((topGap&&x>gapStart&&x<gapEnd)||(!topGap&&x>gapStart&&x<gapEnd))continue;ctx.beginPath();ctx.moveTo(x,l.y+2);ctx.lineTo(x,l.y+24);ctx.stroke()}} else{ctx.fillStyle='#9b673e';for(let x=l.x+18;x<l.x+l.w;x+=44){if(x>gapStart&&x<gapEnd)continue;ctx.fillRect(x-4,l.y-8,8,22);ctx.fillRect(x-4,l.y+l.h-14,8,22)}} ctx.restore() } </script> <script> /* R36B46I — draw a red objective marker over the Nookia map and preserve full artist/song credit. */ (function(){ function objectivePoint(){ try{ if(state.passengerRide&&typeof activePassengerDestination==='function'){ const p=activePassengerDestination(); if(p)return p.interact||{x:p.x+p.w/2,y:p.y+p.h/2}; } if(state.activeJob){ if(state.activeJob.phase==='pickup'){ const g=places.find(p=>p.id==='gigbag'); if(g)return g.interact||{x:g.x+g.w/2,y:g.y+g.h/2}; } const p=places.find(p=>p.id===state.activeJob.id); if(p)return p.interact||{x:p.x+p.w/2,y:p.y+p.h/2}; } const id=order.find(id=>!state.completed.includes(id))||((typeof mamaPermitUnlocked==='function'&&mamaPermitUnlocked()&&!state.completed.includes('mama'))?'mama':null); const p=id&&places.find(p=>p.id===id); if(p)return p.interact||{x:p.x+p.w/2,y:p.y+p.h/2}; }catch(e){} return null; } if(typeof drawMini==='function'){ const originalDrawMini=drawMini; drawMini=function(){ originalDrawMini(); const p=objectivePoint(); if(!p)return; const w=340,h=190,x=p.x/world.w*w,y=p.y/world.h*h; miniCtx.save(); miniCtx.shadowColor='rgba(0,0,0,.65)';miniCtx.shadowBlur=4; miniCtx.fillStyle='#e32222';miniCtx.beginPath();miniCtx.arc(x,y,7,0,Math.PI*2);miniCtx.fill(); miniCtx.shadowBlur=0;miniCtx.strokeStyle='#fff8e5';miniCtx.lineWidth=3;miniCtx.stroke(); miniCtx.fillStyle='#fff8e5';miniCtx.beginPath();miniCtx.arc(x,y,2.2,0,Math.PI*2);miniCtx.fill(); miniCtx.restore(); }; } const status=document.getElementById('phoneStatus'); if(status){ const sync=()=>{const text=String(status.textContent||'').trim();status.setAttribute('aria-label',text);status.title=text}; new MutationObserver(sync).observe(status,{childList:true,subtree:true,characterData:true});sync(); } })(); </script> <style id="r36b46j-final-phone-map-home-road"> /* R36B46J — final compact Nookia geometry. The body ends immediately below Training except landscape fullscreen. */ html body #phone.phone:not(.collapsed){height:auto!important;min-height:0!important;padding:9px 10px 8px!important} html body #phone .phoneScreen{height:194px!important;padding:4px!important;background:#b8c994!important;border-color:#668071!important;box-shadow:inset 0 0 0 3px rgba(38,53,31,.28)!important} html body #phone .phoneScreen #miniCanvas{display:block!important;width:100%!important;height:154px!important;max-height:none!important;image-rendering:pixelated!important;background:#a9bd86!important} html body #phone .phoneStatus{display:block!important;height:32px!important;line-height:15px!important;padding:2px 4px!important;margin:0!important;border-top:2px solid #466d64!important;font-size:9px!important;letter-spacing:.035em!important;overflow:hidden!important;white-space:nowrap!important;text-overflow:clip!important;animation:nookiaTrackScrollJ 17s linear infinite!important} @keyframes nookiaTrackScrollJ{0%,12%{text-indent:0}88%,100%{text-indent:-185%}} html body #phone .phoneKeys{grid-template-columns:repeat(4,minmax(0,1fr))!important;grid-template-rows:repeat(3,44px)!important;gap:5px!important;padding:6px 0 0!important} html body #phone .phoneKeys .phoneApp{height:44px!important;min-height:44px!important} html body #phone .phoneHint{margin:5px 0 2px!important} html body #phone .phoneTraining{height:48px!important;min-height:48px!important;margin:2px 0 0!important} @media(max-width:760px),(pointer:coarse){ html body #phone.phone:not(.collapsed){height:auto!important;min-height:0!important;padding-bottom:7px!important} html body #phone .phoneScreen{height:196px!important} html body #phone .phoneScreen #miniCanvas{height:156px!important} html body #phone .phoneKeys{grid-template-rows:repeat(3,45px)!important} html body #phone .phoneKeys .phoneApp{height:45px!important;min-height:45px!important} html body #phone .phoneTraining{height:50px!important;min-height:50px!important} } /* Fullscreen phone landscape retains the slightly longer shell requested for reachability. */ @media(pointer:coarse) and (orientation:landscape){ html.mobileFullscreen body #phone.phone:not(.collapsed){height:322px!important;min-height:322px!important;padding-bottom:8px!important} html.mobileFullscreen body #phone .phoneScreen{height:112px!important} html.mobileFullscreen body #phone .phoneScreen #miniCanvas{height:82px!important} html.mobileFullscreen body #phone .phoneStatus{height:20px!important;line-height:17px!important;font-size:7px!important} html.mobileFullscreen body #phone .phoneKeys{grid-template-rows:repeat(3,31px)!important;gap:3px!important;padding-top:4px!important} html.mobileFullscreen body #phone .phoneKeys .phoneApp{height:31px!important;min-height:31px!important} html.mobileFullscreen body #phone .phoneTraining{height:31px!important;min-height:31px!important} } </style> <script> /* R36B46J — old-digital-phone map, full west-side inset, solid objective dot, and clean residential road access. */ (function(){ const mapCanvas=document.getElementById('miniCanvas'); if(mapCanvas){mapCanvas.width=340;mapCanvas.height=190} function objectivePointJ(){ try{ if(state.passengerRide&&typeof activePassengerDestination==='function'){ const p=activePassengerDestination();if(p)return p.interact||{x:p.x+p.w/2,y:p.y+p.h/2}; } if(state.activeJob){ if(state.activeJob.phase==='pickup'){ const g=places.find(p=>p.id==='gigbag');if(g)return g.interact||{x:g.x+g.w/2,y:g.y+g.h/2}; } const p=places.find(p=>p.id===state.activeJob.id);if(p)return p.interact||{x:p.x+p.w/2,y:p.y+p.h/2}; } const id=order.find(id=>!state.completed.includes(id))||((typeof mamaPermitUnlocked==='function'&&mamaPermitUnlocked()&&!state.completed.includes('mama'))?'mama':null); const p=id&&places.find(p=>p.id===id);if(p)return p.interact||{x:p.x+p.w/2,y:p.y+p.h/2}; }catch(_){ } return null; } function drawMiniJ(){ const c=miniCtx,w=340,h=190,padX=11,padY=8,plotW=w-padX*2,plotH=h-padY*2; c.save();c.clearRect(0,0,w,h); c.fillStyle='#b2c58f';c.fillRect(0,0,w,h); c.fillStyle='rgba(38,53,31,.13)'; for(let x=padX;x<w-padX;x+=12)c.fillRect(x,padY,1,plotH); for(let y=padY;y<h-padY;y+=12)c.fillRect(padX,y,plotW,1); const sx=x=>padX+(x/world.w)*plotW,sy=y=>padY+(y/world.h)*plotH; c.fillStyle='#4b5843'; for(const r of roads)c.fillRect(Math.round(sx(r.x)),Math.round(sy(r.y)),Math.max(2,Math.round(r.w/world.w*plotW)),Math.max(2,Math.round(r.h/world.h*plotH))); c.textAlign='center';c.textBaseline='middle'; for(const b of places){ if(!placeVisible(b))continue; const x=sx(b.x),y=sy(b.y),bw=Math.max(20,b.w/world.w*plotW),bh=Math.max(15,b.h/world.h*plotH),abbr=b.abbr||b.short.slice(0,3).toUpperCase(); c.fillStyle='#91aa70';c.fillRect(Math.round(x),Math.round(y),Math.round(bw),Math.round(bh)); c.strokeStyle='rgba(38,53,31,.45)';c.lineWidth=1;c.strokeRect(Math.round(x)+.5,Math.round(y)+.5,Math.max(1,Math.round(bw)-1),Math.max(1,Math.round(bh)-1)); let fs=abbr.length>3?8:10;c.font=`1000 ${fs}px monospace`; while(c.measureText(abbr).width>bw-3&&fs>6){fs--;c.font=`1000 ${fs}px monospace`} c.fillStyle='#172016';c.fillText(abbr,Math.round(x+bw/2),Math.round(y+bh/2)); } const p=objectivePointJ(); if(p){c.fillStyle='#e32222';c.beginPath();c.arc(sx(p.x),sy(p.y),6,0,Math.PI*2);c.fill()} const vx=sx(van.x),vy=sy(van.y);c.save();c.translate(vx,vy);c.rotate(van.angle);c.fillStyle='#111';c.beginPath();c.moveTo(9,0);c.lineTo(-6,-6);c.lineTo(-3,0);c.lineTo(-6,6);c.closePath();c.fill();c.restore(); c.strokeStyle='#26351f';c.lineWidth=2;c.strokeRect(1,1,w-2,h-2);c.restore(); } drawMini=drawMiniJ; /* Keep the home access road as the same city asphalt, remove the driveway/parking rectangle and its label. */ drawR36B45ResidentialGround=function(h){ const{x,y,w,h:lh}=h.lot;ctx.save(); ctx.fillStyle=h.yard;ctx.fillRect(x,y,w,lh); ctx.fillStyle='rgba(255,255,255,.028)';for(let i=0;i<9;i++)ctx.fillRect(x+28+i*101,y+30,45,lh-60); ctx.fillStyle='#3e454e';ctx.fillRect(h.road.x,h.road.y,h.road.w,h.road.h); ctx.fillStyle='rgba(255,255,255,.018)';ctx.fillRect(h.road.x+1,h.road.y,h.road.w-2,h.road.h); ctx.strokeStyle='#d7b64e';ctx.lineWidth=4;ctx.setLineDash([25,20]);ctx.beginPath();ctx.moveTo(h.road.x+h.road.w/2,h.road.y+10);ctx.lineTo(h.road.x+h.road.w/2,h.road.y+h.road.h-10);ctx.stroke();ctx.setLineDash([]); drawR36B45PropertyBorder(h);ctx.restore(); }; /* The former pull-in remains an invisible drivable safety surface, but cannot draw or block the road. */ if(Array.isArray(R36B45_HOME_ROADS))for(const h of Object.values(R36B45_HOMES||{})){ if(!h)continue; if(h.pullin){h.pullin.invisible=true} const half=44; if(h.id==='band')h.spawn={x:h.road.x+h.road.w/2,y:h.road.y+h.road.h-half,angle:-Math.PI/2}; else h.spawn={x:h.road.x+h.road.w/2,y:h.road.y+half,angle:Math.PI/2}; } const status=document.getElementById('phoneStatus'); if(status){ const ensureTrack=()=>{ const full=(typeof phoneNowPlayingStatus==='function'?phoneNowPlayingStatus():status.textContent)||'NOW PLAYING • COMMUNITY RADIO READY'; if(status.textContent!==full)status.textContent=full; status.title=full;status.setAttribute('aria-label',full); }; setInterval(ensureTrack,1200);ensureTrack(); } })(); </script> <style id="r36b46k-road-crosswalk-phone-fixes"> /* R36B46K — scrolling artist/track restored on the Nookia. */ #phone .phoneStatus{position:relative!important;overflow:hidden!important;white-space:nowrap!important;text-indent:0!important;animation:none!important} #phone .phoneStatus .r36b46k-track{display:inline-block;min-width:max-content;padding-left:100%;will-change:transform;animation:r36b46kMarquee 15s linear infinite} @keyframes r36b46kMarquee{0%,8%{transform:translateX(0)}92%,100%{transform:translateX(-100%)}} </style> <script> /* R36B46K — align home access lines to named streets, remove doubled asphalt, complete crosswalk grid, restore now-playing marquee. */ (function(){ function alignHomeRoad(h,x,w,spawnY,angle){ if(!h)return; h.road.x=x;h.road.w=w; h.spawn.x=x+w/2;h.spawn.y=spawnY;h.spawn.angle=angle; } alignHomeRoad(R36B45_HOMES&&R36B45_HOMES.owner,610,170,-370,Math.PI/2); // Congress Avenue center 695 alignHomeRoad(R36B45_HOMES&&R36B45_HOMES.audio,1930,170,-370,Math.PI/2); // Trinity Street center 2015 alignHomeRoad(R36B45_HOMES&&R36B45_HOMES.band,1270,170,2960,-Math.PI/2); // Red River center 1355 /* Draw yards and property borders only. The street itself is the existing world road surface; no second asphalt rectangle. */ drawR36B45ResidentialGround=function(h){ const{x,y,w,h:lh}=h.lot;ctx.save(); ctx.fillStyle=h.yard;ctx.fillRect(x,y,w,lh); ctx.fillStyle='rgba(255,255,255,.028)';for(let i=0;i<9;i++)ctx.fillRect(x+28+i*101,y+30,45,lh-60); ctx.strokeStyle='#d7b64e';ctx.lineWidth=4;ctx.setLineDash([25,20]); ctx.beginPath();ctx.moveTo(h.road.x+h.road.w/2,h.road.y+8);ctx.lineTo(h.road.x+h.road.w/2,h.road.y+h.road.h-8);ctx.stroke(); ctx.setLineDash([]);drawR36B45PropertyBorder(h);ctx.restore(); }; /* Keep every driveway opening clear while making the industrial audio border unmistakable. */ const oldBorder=drawR36B45PropertyBorder; drawR36B45PropertyBorder=function(h){ oldBorder(h); if(h&&h.id==='audio'){ const l=h.lot,g0=h.road.x-18,g1=h.road.x+h.road.w+18; ctx.save();ctx.strokeStyle='#b9c1c5';ctx.lineWidth=3;ctx.setLineDash([14,10]); ctx.beginPath();ctx.moveTo(l.x+8,l.y+8);ctx.lineTo(l.x+l.w-8,l.y+8);ctx.stroke(); ctx.beginPath();ctx.moveTo(l.x+8,l.y+l.h-8);ctx.lineTo(g0,l.y+l.h-8);ctx.moveTo(g1,l.y+l.h-8);ctx.lineTo(l.x+l.w-8,l.y+l.h-8);ctx.stroke(); ctx.setLineDash([]);ctx.restore(); } }; /* All twelve downtown intersections receive four crosswalk approaches, independent of upgrade level. */ drawR36RoadDetails=function(){ ctx.save(); const ints=[];for(const x of [695,1355,2015,2670])for(const y of [690,1390,1980])ints.push([x,y]); const vHalf=85,hHalf=90,depth=CITY_POLISH.crosswalkDepth,gap=CITY_POLISH.crosswalkGap,barGap=CITY_POLISH.stopBarGap; for(const[x,y]of ints){ const northY=y-hHalf-gap-depth,southY=y+hHalf+gap,westX=x-vHalf-gap-depth,eastX=x+vHalf+gap; drawCrosswalkAcrossVerticalRoad(x,northY);drawCrosswalkAcrossVerticalRoad(x,southY); drawCrosswalkAcrossHorizontalRoad(westX,y);drawCrosswalkAcrossHorizontalRoad(eastX,y); ctx.fillStyle='rgba(255,255,255,.96)'; ctx.fillRect(x-vHalf+12,northY-barGap-5,vHalf-20,5);ctx.fillRect(x+8,southY+depth+barGap,vHalf-20,5); ctx.fillRect(westX-barGap-5,y+8,5,hHalf-20);ctx.fillRect(eastX+depth+barGap,y-hHalf+12,5,hHalf-20); } for(const b of places){if(placeVisible(b)&&b.parking)drawParkingCurb(b)}ctx.restore(); }; /* Force the Nookia ticker to retain full artist and song metadata whenever the radio reports it. */ const status=document.getElementById('phoneStatus'); if(status){ let last=''; const esc=s=>String(s).replace(/[&<>"]/g,ch=>({'&':'&','<':'<','>':'>','"':'"'}[ch])); const sync=()=>{ let full=''; try{full=typeof phoneNowPlayingStatus==='function'?phoneNowPlayingStatus():''}catch(_){ } if(!full||/COMMUNITY RADIO READY$/i.test(full)){ const np=document.getElementById('nowPlayingText'); if(np&&np.textContent.trim())full=np.textContent.trim(); } full=full||'NOW PLAYING • COMMUNITY RADIO READY'; if(full!==last||!status.querySelector('.r36b46k-track')){ last=full;status.innerHTML='<span class="r36b46k-track">'+esc(full)+'</span>'; status.title=full;status.setAttribute('aria-label',full); } }; setInterval(sync,300);sync(); } })(); </script> <script id="r36b47a-core-audit"> /* R36B47A — core road-safety audit. Crosswalks derive from actual street geometry instead of hard-coded guesses. */ (function(){ function coreStreetGrid(){ const vertical=roads.filter(r=>!r.edge && r.h>r.w).map(r=>({road:r,center:r.x+r.w/2})).sort((a,b)=>a.center-b.center); const horizontal=roads.filter(r=>!r.edge && r.w>r.h).map(r=>({road:r,center:r.y+r.h/2})).sort((a,b)=>a.center-b.center); const intersections=[]; for(const v of vertical)for(const h of horizontal){ if(v.center>=h.road.x && v.center<=h.road.x+h.road.w && h.center>=v.road.y && h.center<=v.road.y+v.road.h)intersections.push([v.center,h.center]); } return{vertical,horizontal,intersections}; } drawR36RoadDetails=function(){ ctx.save(); const grid=coreStreetGrid(),depth=CITY_POLISH.crosswalkDepth,gap=CITY_POLISH.crosswalkGap,barGap=CITY_POLISH.stopBarGap; for(const[x,y]of grid.intersections){ const v=grid.vertical.find(q=>q.center===x).road,h=grid.horizontal.find(q=>q.center===y).road; const vHalf=v.w/2,hHalf=h.h/2; const northY=y-hHalf-gap-depth,southY=y+hHalf+gap,westX=x-vHalf-gap-depth,eastX=x+vHalf+gap; drawCrosswalkAcrossVerticalRoad(x,northY);drawCrosswalkAcrossVerticalRoad(x,southY); drawCrosswalkAcrossHorizontalRoad(westX,y);drawCrosswalkAcrossHorizontalRoad(eastX,y); ctx.fillStyle='rgba(255,255,255,.96)'; ctx.fillRect(x-vHalf+12,northY-barGap-5,Math.max(24,vHalf-20),5); ctx.fillRect(x+8,southY+depth+barGap,Math.max(24,vHalf-20),5); ctx.fillRect(westX-barGap-5,y+8,5,Math.max(24,hHalf-20)); ctx.fillRect(eastX+depth+barGap,y-hHalf+12,5,Math.max(24,hHalf-20)); } for(const b of places){if(placeVisible(b)&&b.parking)drawParkingCurb(b)} ctx.restore(); }; function runCoreAudit(){ const issues=[],grid=coreStreetGrid(),sw=sidewalkWidth(),curb=CITY_POLISH.curbWidth; if(grid.vertical.length!==4)issues.push('Expected 4 interior north/south streets; found '+grid.vertical.length); if(grid.horizontal.length!==3)issues.push('Expected 3 interior east/west streets; found '+grid.horizontal.length); if(grid.intersections.length!==12)issues.push('Expected 12 street intersections; found '+grid.intersections.length); if(grid.intersections.length*4!==48)issues.push('Expected 48 crosswalk approaches'); for(const q of [...grid.vertical,...grid.horizontal]){ const r=q.road;if(sw<10||curb<3)issues.push('Sidewalk/curb width too small near '+Math.round(q.center)); if(r.w<150 && r.h<150)issues.push('Road is too narrow at '+Math.round(q.center)); } if(typeof auditR36B31BusinessAccess==='function'){const a=auditR36B31BusinessAccess();if(!a.ok)issues.push(...a.issues)} const homes=['owner','audio','band']; for(const id of homes){const h=R36B45_HOMES&&R36B45_HOMES[id];if(!h)issues.push(id+': missing home');else{ if(!roads.some(r=>rectsOverlap(h.road,r,1)))issues.push(id+': home access does not touch a city street'); if(!h.spawn||!Number.isFinite(h.spawn.x)||!Number.isFinite(h.spawn.y))issues.push(id+': invalid spawn'); }} const requiredFns=['drawVan','drawR36RoadDetails','drawR36BaseSidewalks','drawR36B45LakeAndHomes','showDriverPermitGate','openPhone']; for(const name of requiredFns)if(typeof window[name]!=='function')issues.push('Missing core function: '+name); return{ok:issues.length===0,issues,streetGrid:{vertical:grid.vertical.map(q=>q.center),horizontal:grid.horizontal.map(q=>q.center),intersections:grid.intersections},crosswalkApproaches:grid.intersections.length*4,sidewalkWidth:sw,curbWidth:curb,businessCount:places.filter(placeVisible).length}; } window.runCoreAudit=runCoreAudit; window.__VANCERTS_CORE_BUILD__='R36B47G'; })(); </script> <style id="r36b47c-permit-phone-polish"> /* R36B47D — balanced permit, stable Nookia ticker, and collapsed total-notification badge. */ .permitGateGrid{ grid-template-columns:minmax(360px,.95fr) minmax(430px,1.05fr)!important; gap:14px!important; align-items:stretch!important; } .permitGatePhoto{ height:auto!important; min-height:445px!important; max-height:520px!important; } .permitGatePhoto img{ min-height:0!important; height:100%!important; } .permitGateFields{ min-height:445px!important; display:flex!important; flex-direction:column!important; gap:9px!important; } .permitGateFields>label:first-child{margin:0!important} .permitGateId,.permitGateNote{margin:0!important} .permitCareerGrid{ flex:1 1 auto!important; display:grid!important; grid-template-columns:repeat(2,minmax(0,1fr))!important; grid-auto-rows:minmax(76px,1fr)!important; gap:9px!important; align-content:stretch!important; } .permitCareerChoice{ min-height:76px!important; height:100%!important; box-sizing:border-box!important; padding:12px!important; display:block!important; } .permitGateActionsWide{ margin-top:12px!important; gap:10px!important; grid-template-columns:repeat(2,minmax(0,1fr))!important; } .permitGateActionsWide button{ width:100%!important; min-height:58px!important; margin:0!important; } .permitGateActionsWide .permitGateCamera, .permitGateActionsWide .permitGateIssue{grid-column:1/-1!important} .permitGateLock{margin-top:8px!important} /* Keep the old status node as the data source, but never let frame-by-frame HUD writes blink visibly. */ #phone .phoneScreen{position:relative!important} #phone #phoneStatus{ color:transparent!important; text-shadow:none!important; animation:none!important; user-select:none!important; } #phone .phoneTickerStable{ position:absolute!important; left:4px!important; right:4px!important; bottom:4px!important; height:32px!important; line-height:15px!important; padding:2px 4px!important; box-sizing:border-box!important; border-top:2px solid #466d64!important; color:#10211e!important; background:#b8c994!important; font:900 9px/15px monospace!important; letter-spacing:.035em!important; overflow:hidden!important; white-space:nowrap!important; z-index:4!important; } #phone .phoneTickerStable .tickerText{ display:inline-block!important; min-width:max-content!important; } #phone .phoneTickerStable.isPlaying .tickerText{ padding-left:100%!important; animation:r36b47cTicker 16s linear infinite!important; } @keyframes r36b47cTicker{ 0%,8%{transform:translateX(0)} 92%,100%{transform:translateX(-100%)} } #phone .phoneTotalBadge{ display:none; position:absolute!important; top:-10px!important; left:-10px!important; right:auto!important; z-index:80!important; min-width:28px!important; height:28px!important; padding:0 7px!important; box-sizing:border-box!important; border:3px solid #fff8e5!important; border-radius:16px!important; background:#e53935!important; color:#fff!important; box-shadow:2px 2px 0 rgba(0,0,0,.75)!important; font:1000 12px/22px system-ui!important; text-align:center!important; pointer-events:none!important; } #phone.collapsed .phoneTotalBadge.hasNotifications{display:block!important} #phone.collapsed{overflow:visible!important} #phone.collapsed .phoneCollapse{position:relative!important;z-index:3!important} @media(max-width:760px),(pointer:coarse){ .permitGateShell{padding:8px!important} .permitGateGrid{grid-template-columns:1fr!important;gap:9px!important} .permitGatePhoto{min-height:280px!important;max-height:42vh!important} .permitGateFields{min-height:0!important;gap:8px!important} .permitCareerGrid{grid-auto-rows:minmax(72px,auto)!important} .permitCareerChoice{min-height:72px!important;padding:9px!important} .permitGateActionsWide{margin-top:9px!important;gap:8px!important} .permitGateActionsWide button{min-height:52px!important} #phone .phoneTickerStable{height:32px!important;font-size:9px!important} } @media(pointer:coarse) and (orientation:landscape){ #phone .phoneTickerStable{height:20px!important;line-height:16px!important;font-size:7px!important;padding:1px 3px!important} } </style> <script id="r36b47c-phone-runtime"> (function(){ const phone=document.getElementById('phone'); const source=document.getElementById('phoneStatus'); if(!phone||!source)return; let stable=phone.querySelector('.phoneTickerStable'); if(!stable){ stable=document.createElement('div'); stable.className='phoneTickerStable'; stable.setAttribute('aria-live','polite'); stable.innerHTML='<span class="tickerText"></span>'; const screen=phone.querySelector('.phoneScreen'); if(screen)screen.appendChild(stable); } let totalBadge=phone.querySelector('.phoneTotalBadge'); if(!totalBadge){ totalBadge=document.createElement('span'); totalBadge.className='phoneTotalBadge'; totalBadge.setAttribute('aria-label','0 total notifications'); phone.appendChild(totalBadge); } let lastTicker=''; function getTickerText(){ let full=''; try{full=typeof phoneNowPlayingStatus==='function'?String(phoneNowPlayingStatus()||''):''}catch(_){ } const now=document.getElementById('nowPlayingText'); const nowText=String(now?.textContent||'').trim(); if((!full||/COMMUNITY RADIO READY$/i.test(full))&&nowText)full=nowText; return full||'NOW PLAYING • COMMUNITY RADIO READY'; } function syncTicker(){ const full=getTickerText(); if(full===lastTicker)return; lastTicker=full; const text=stable.querySelector('.tickerText'); if(text)text.textContent=full; const playing=!/COMMUNITY RADIO READY$/i.test(full)&&!/RADIO READY$/i.test(full); stable.classList.toggle('isPlaying',playing); stable.title=full; stable.setAttribute('aria-label',full); } function parseBadgeValue(el){ const raw=String(el.textContent||'').trim(); if(!raw)return 0; if(raw.includes('+'))return 99; const n=parseInt(raw.replace(/\D/g,''),10); return Number.isFinite(n)?n:0; } function syncTotal(){ let total=0; phone.querySelectorAll('.appBadge').forEach(b=>{if(getComputedStyle(b).display!=='none')total+=parseBadgeValue(b)}); const shown=total>99?'99+':String(total); if(totalBadge.textContent!==shown)totalBadge.textContent=shown; totalBadge.classList.toggle('hasNotifications',total>0); const label=`${total} total notification${total===1?'':'s'}`; if(totalBadge.getAttribute('aria-label')!==label)totalBadge.setAttribute('aria-label',label); } const observer=new MutationObserver(()=>{syncTicker();syncTotal()}); observer.observe(phone,{subtree:true,childList:true,characterData:true,attributes:true,attributeFilter:['class','style']}); setInterval(()=>{syncTicker();syncTotal()},500); syncTicker();syncTotal(); })(); </script> <style id="r36b47d-collapsed-phone-fix"> /* R36B47D — collapsed Nookia is one compact control plus one total unread badge. */ #phone.phone.collapsed{ overflow:visible!important; } #phone.phone.collapsed > .phoneScreen, #phone.phone.collapsed > .phoneLegacyQuick, #phone.phone.collapsed > .phoneKeys, #phone.phone.collapsed > .phoneHint, #phone.phone.collapsed > .phoneBigReset, #phone.phone.collapsed > .phoneTrainingButton, #phone.phone.collapsed > .phoneBuildScene{ display:none!important; visibility:hidden!important; pointer-events:none!important; } #phone.phone.collapsed > .phoneTop{ display:flex!important; visibility:visible!important; } #phone.phone.collapsed .phoneTotalBadge{ display:none!important; } #phone.phone.collapsed .phoneTotalBadge.hasNotifications{ display:block!important; top:-10px!important; left:-10px!important; right:auto!important; } #phone.phone.collapsed .phoneCollapse{ pointer-events:auto!important; } </style> <style id="r36b47e-start-open-training-fix"> /* R36B47E — collapsed phone exposes only its compact opener and one total unread badge. */ #phone.phone.collapsed > .phoneTraining, #phone.phone.collapsed > #phoneReset, #phone.phone.collapsed > .phoneHint, #phone.phone.collapsed > .phoneKeys, #phone.phone.collapsed > .phoneScreen, #phone.phone.collapsed > .phoneLegacyQuick{ display:none!important; visibility:hidden!important; opacity:0!important; pointer-events:none!important; } #phone.phone.collapsed > .phoneTop{display:flex!important;visibility:visible!important;opacity:1!important} </style> <script> /* R36B49L — source-level north artifact fix for both VANCERTS and Paul properties. */ (function(){ if(window.R36B45_HOMES){ if(R36B45_HOMES.owner)R36B45_HOMES.owner.heroVersion='R36B49L'; if(R36B45_HOMES.audio)R36B45_HOMES.audio.heroVersion='R36B49L'; } })(); </script> <style id="r36b49o-audit-layout-fix"> /* R36B49O — final audited HUD placement. Landscape phones may be wider than 760px, so pointer type—not width alone—selects the phone layout. */ @media (pointer:coarse) and (orientation:landscape){ html body .objective.objectiveTop, html body.trainingWheelsActive .objective.objectiveTop, html.mobileFullscreen body .objective.objectiveTop, html.mobileFullscreen body.trainingWheelsActive .objective.objectiveTop{ position:fixed!important; left:132px!important;right:132px!important;top:auto!important; bottom:max(8px,env(safe-area-inset-bottom,0px))!important; width:auto!important;max-width:none!important;min-width:0!important; max-height:108px!important;overflow:auto!important; transform:none!important;z-index:66!important;box-sizing:border-box!important; } } </style> <script> /* R36B49Q — wallet upgrade catalog, Marco controls, chapter celebrations and original arcade chiptune. */ (function(){ const BUILD='R36B49Q', PARTY_MS=10*60*1000, WRAP_PRICE=5000; const WRAPS={ classic:{name:'CLASSIC GREEN + YELLOW',need:()=>state.shows>=1,requirement:'Complete the first show.'}, owner:{name:'WHITE FLAME + RED V',need:()=>state.completed?.includes('fsg'),requirement:'Complete FSG Printshop.'}, paul:{name:'PLAIN WHITE VANCERTS',need:()=>(state.completed||[]).filter(id=>order.includes(id)).length>=3,requirement:'Complete three main Chapter 1 businesses.'}, band:{name:'BLACK BAND FLAMES',need:()=>order.every(id=>state.completed?.includes(id)),requirement:'Complete every main Chapter 1 business.'} }; function marco(){ state.marco=Object.assign({unlocked:false,enabled:true,partyEndsAt:0,shieldReadyAt:0,partyHistory:{},fullLots:{},lastChapter:currentChapter()},state.marco||{}); state.marco.partyHistory=state.marco.partyHistory||{};state.marco.fullLots=state.marco.fullLots||{}; if(typeof state.marco.enabled!=='boolean')state.marco.enabled=true; return state.marco; } function allMainDone(){return Array.isArray(state.completed)&&order.every(id=>state.completed.includes(id))} window.marcoSnakeEngage=function(){const m=marco();return !!(m.unlocked&&m.enabled!==false&&state.career?.path==='owner')} window.toggleMarco=function(){const m=marco();if(!m.unlocked)return toast('MARCO UNLOCKS AFTER EVERY MAIN CHAPTER 1 BUSINESS');m.enabled=!m.enabled;save();hud();toast(m.enabled?'MARCO FLYING WITH THE VAN':'MARCO RESTING AT VANCERTS HOUSE');driverPassModal()} function byobSpawn(){ const p=places.find(p=>p.id==='byob'); if(p&&p.interact){van.x=p.interact.x;van.y=p.interact.y+72;van.angle=-Math.PI/2} else {van.x=BYOB_REPAIR.x;van.y=BYOB_REPAIR.y;van.angle=BYOB_REPAIR.angle} van.speed=0;if(typeof camera!=='undefined'&&camera){camera.x=van.x;camera.y=van.y}save();hud(); } function garage(){return window.vancertsWrapGarage?window.vancertsWrapGarage():(state.vanWrapGarage||(state.vanWrapGarage={owned:{owner:true},active:'owner'}))} function lockClass(ok){return ok?'':' style="filter:grayscale(1);opacity:.52"'} function upgradeCard(id,data){ const g=garage(),owned=!!g.owned[id],active=g.active===id,unlocked=!!data.need(); let action=''; if(owned)action=`<button class="${active?'green':''}" onclick="walletEquipWrap('${id}')" ${active?'disabled':''}>${active?'EQUIPPED':'EQUIP'}</button>`; else action=`<button class="green" onclick="walletBuyWrap('${id}')" ${!unlocked||state.cash<WRAP_PRICE?'disabled':''}>BUY • $${WRAP_PRICE.toLocaleString()}</button>`; return `<div class="card"${lockClass(unlocked||owned)}><h3>${data.name}</h3><p><b>PROMOTIONAL VAN WRAP • $5,000</b></p><p class="small">${owned?'Owned permanently.':unlocked?'Unlocked and ready to purchase.':`LOCKED • ${data.requirement}`}</p><div class="btns">${action}</div></div>`; } window.openWalletUpgrades=function(){ const armorReady=order.every(id=>{const p=places.find(x=>x.id===id),v=state.venues[id];return p&&v&&Number(v.rateCars||0)>=(p.capacity||16)}); const armorOwned=!!state.vanUpgrades.armored; const cards=Object.entries(WRAPS).map(([id,d])=>upgradeCard(id,d)).join(''); modal(`<h2>PLAYER WALLET • UPGRADES</h2><p>Upgrades stay visible here from the start. Locked upgrades are grey until their story requirement is complete. Purchased vehicle upgrades are installed at BYOB Austin, so the van returns there automatically.</p><div class="grid">${cards}<div class="card"${lockClass(armorReady||armorOwned)}><h3>ARMORED VAN + POTATO CANNON</h3><p><b>$20,000</b></p><p class="small">${armorOwned?'OWNED':armorReady?'Every main business reached a full parking lot. Ready to purchase.':'LOCKED • Fill every main Chapter 1 business parking lot once.'}</p><button class="green" onclick="walletBuyArmor()" ${armorOwned||!armorReady||state.cash<20000?'disabled':''}>${armorOwned?'OWNED':'BUY • $20,000'}</button></div><div class="card" style="filter:grayscale(1);opacity:.52"><h3>FUTURE UPGRADE BAY</h3><p>Additional wraps and van systems will appear here in later updates.</p><button disabled>COMING SOON</button></div></div><div class="btns"><button onclick="driverPassModal()">BACK TO WALLET</button><button class="secondary" onclick="closeModal()">CLOSE</button></div>`) } window.walletBuyWrap=function(id){ const data=WRAPS[id],g=garage();if(!data)return toast('UPGRADE NOT FOUND');if(!data.need())return toast(data.requirement.toUpperCase()); if(g.owned[id])return walletEquipWrap(id);if(state.cash<WRAP_PRICE)return toast('NEED $5,000'); const ok=typeof debitCash==='function'?debitCash(WRAP_PRICE,'Advertising & promotion',data.name,{vendor:'VANCERTS WRAP GARAGE',businessPurpose:'Promotional van branding'}):(state.cash-=WRAP_PRICE,true); if(!ok)return;g.owned[id]=true;g.active=id;byobSpawn();toast(`${data.name} INSTALLED AT BYOB AUSTIN`);openWalletUpgrades(); } window.walletEquipWrap=function(id){const g=garage();if(!g.owned[id])return toast('BUY THIS WRAP FIRST');g.active=id;byobSpawn();toast(`${WRAPS[id]?.name||'WRAP'} EQUIPPED AT BYOB AUSTIN`);openWalletUpgrades()} window.walletBuyArmor=function(){ const ready=order.every(id=>{const p=places.find(x=>x.id===id),v=state.venues[id];return p&&v&&Number(v.rateCars||0)>=(p.capacity||16)}); if(!ready)return toast('FILL EVERY MAIN BUSINESS PARKING LOT FIRST');if(state.vanUpgrades.armored)return toast('ALREADY OWNED');if(state.cash<20000)return toast('NEED $20,000'); if(typeof buyArmoredVan==='function')buyArmoredVan();byobSpawn();setTimeout(openWalletUpgrades,80) } const oldWallet=window.driverPassModal||driverPassModal; window.driverPassModal=driverPassModal=function(){ oldWallet();setTimeout(()=>{ const modalEl=document.querySelector('#modal');if(!modalEl)return; const header=modalEl.querySelector('div[style*="justify-content:space-between"]'); if(header&&!header.querySelector('[data-marco-toggle]')){ const m=marco(),b=document.createElement('button');b.dataset.marcoToggle='1';b.style.cssText='margin-left:auto;padding:7px 10px;font-size:10px'; b.textContent=m.unlocked?`MARCO • ${m.enabled!==false?'ON':'OFF'}`:'MARCO • LOCKED';b.disabled=!m.unlocked;b.onclick=toggleMarco;header.insertBefore(b,header.lastElementChild); } const btns=modalEl.querySelector('.btns');if(btns&&!btns.querySelector('[data-wallet-upgrades]')){const b=document.createElement('button');b.dataset.walletUpgrades='1';b.className='green';b.textContent='UPGRADES';b.onclick=openWalletUpgrades;btns.insertBefore(b,btns.firstChild)} },0) } let partyAudio=null,partyTimer=null; function stopPartyMusic(){if(partyTimer){clearInterval(partyTimer);partyTimer=null}if(partyAudio){try{partyAudio.close()}catch(e){}partyAudio=null}} function playPartyMusic(){ if(partyAudio)return;try{if(typeof stop512Jams==='function')stop512Jams()}catch(e){} try{ partyAudio=new (window.AudioContext||window.webkitAudioContext)();if(partyAudio.state==='suspended')partyAudio.resume(); const notes=[261.63,329.63,392,523.25,392,440,349.23,293.66,329.63,392,493.88,587.33,493.88,392,329.63,293.66];let step=0; const tick=()=>{if(!partyAudio)return;const now=partyAudio.currentTime,f=notes[step++%notes.length];[f,f/2].forEach((freq,i)=>{const o=partyAudio.createOscillator(),g=partyAudio.createGain();o.type=i?'square':'triangle';o.frequency.setValueAtTime(freq,now);g.gain.setValueAtTime(.0001,now);g.gain.exponentialRampToValueAtTime(i?.025:.045,now+.01);g.gain.exponentialRampToValueAtTime(.0001,now+.16);o.connect(g);g.connect(partyAudio.destination);o.start(now);o.stop(now+.18)});}; tick();partyTimer=setInterval(tick,190); }catch(e){partyAudio=null} } function startHouseParty(key,title){ const m=marco();if(m.partyHistory[key])return false;m.partyHistory[key]=Date.now();m.partyEndsAt=Date.now()+PARTY_MS;save();playPartyMusic();toast(`${title} • 10-MINUTE PARTY AT VANCERTS HOUSE`);return true } function partyChecks(){ const m=marco(); if(state.shows>=1)startHouseParty('first-mission','FIRST MISSION COMPLETE'); for(const id of order){const p=places.find(x=>x.id===id),v=state.venues[id];if(p&&v&&Number(v.rateCars||0)>=(p.capacity||16))startHouseParty(`full-${id}`,`${p.name} PARKING LOT FILLED`)} const ch=currentChapter();if(!m.lastChapter)m.lastChapter=ch;if(ch>m.lastChapter){startHouseParty(`chapter-${m.lastChapter}`,`CHAPTER ${m.lastChapter} COMPLETE`);m.lastChapter=ch;save()} if(m.partyEndsAt&&Date.now()<m.partyEndsAt)playPartyMusic();else stopPartyMusic(); if(!m.unlocked&&allMainDone()){m.unlocked=true;m.enabled=true;save();toast('MARCO UNLOCKED • CONTROL HIM FROM PLAYER WALLET')} } const oldUpdate=window.update||update;window.update=update=function(dt){oldUpdate(dt);partyChecks()} const oldSubmit=window.submitBmiQuarter||submitBmiQuarter;window.submitBmiQuarter=submitBmiQuarter=function(q){const was=(state.compliance?.bmi?.submittedQuarters||[]).includes(q);oldSubmit(q);if(!was&&(state.compliance?.bmi?.submittedQuarters||[]).includes(q))startHouseParty(`quarter-${q}-${currentChapter()}`,`${q} QUARTERLY REPORT COMPLETE`)} // Add Russel, extra guests, and randomized parked groups to every active house party. const oldOwnerDraw=window.drawR36B45OwnerHome||drawR36B45OwnerHome; window.drawR36B45OwnerHome=drawR36B45OwnerHome=function(h){ oldOwnerDraw(h);const m=marco();if(!m.partyEndsAt||Date.now()>=m.partyEndsAt)return; const l=R36B45_HOMES.owner.lot,t=performance.now()/1000; ctx.save(); // Parked vehicle groups line the entrance and drive without blocking the lane center. const wraps=['classic','owner','paul','band'];for(let i=0;i<12;i++){const side=i%2?-1:1,x=(R36B45_HOMES.owner.roadCenterX||695)+side*(72+Math.floor(i/2)*43),y=l.y+l.h-46-(i%3)*26;drawUnifiedCareerVan(x,y,side<0?0:Math.PI,wraps[i%wraps.length],{})} // Crowd fills the yard, including one recognizable Russel guest near the BBQ. const cols=['#e64a38','#f1b83e','#3f84a5','#9766a3','#5c9a55','#eee'];for(let i=0;i<64;i++){const x=l.x+80+(i*97)%Math.max(100,l.w-160),y=l.y+120+((i*61)%Math.max(100,l.h-250));ctx.fillStyle=cols[i%cols.length];ctx.beginPath();ctx.arc(x,y+Math.sin(t*5+i)*2,6,0,Math.PI*2);ctx.fill();ctx.fillStyle='#202020';ctx.fillRect(x-3,y+6,6,10)} const rx=l.x+l.w/2+24,ry=l.y+112;ctx.fillStyle='#d6a57a';ctx.beginPath();ctx.arc(rx,ry,9,0,Math.PI*2);ctx.fill();ctx.fillStyle='#202020';ctx.fillRect(rx-7,ry+8,14,24);ctx.fillStyle='#f4e6be';ctx.font='900 10px system-ui';ctx.textAlign='center';ctx.fillText('RUSSEL',rx,ry-14); ctx.restore(); } marco(); })(); </script> <script id="r36b50f-career-training-pass"> /* R36B50F — career-specific, self-explanatory Training Wheels. */ (function(){ const ownerCurrentTrainingMission=window.currentTrainingMission||currentTrainingMission; const ownerShowTrainingChapterIntro=window.showTrainingChapterIntro||showTrainingChapterIntro; function careerLabel(){if(state.career.path==='band')return 'BAND';if(state.career.path==='team')return state.career.teamRole==='audio'?'AUDIO ENGINEER':'STAGEHAND';return 'VANCERTS OWNER'} function bandMission(){ const b=typeof bandStory==='function'?bandStory():state.bandStory||{}, assets=typeof leftwayBandAssets==='function'?leftwayBandAssets():[], c=b.campaign||{}, goal=typeof currentBandGoal==='function'?currentBandGoal():{crowd:25,revenue:200,label:'GET PEOPLE THERE'}, metrics=typeof bandCampaignMetrics==='function'?bandCampaignMetrics():{projected:0}; if(!b.started)return trainingMissionData(1,1,12,'START THE BAND STORY','Open the Band Story board. Name the band and choose your instrument/role. You already have a band, $1,000, the Band House, and the black flame Band Van.','objective','OPEN BAND STORY','openBandStory()'); if(!assets.length)return trainingMissionData(1,2,12,'CREATE YOUR FIRST LEFTWAY MEDIA','Drive the black Band Van to LEFTWAY STUDIOS. Pull into the studio interaction area and interact. Choose DEMO RECORDING ($150). This gives the band real media to promote before the first home show.','drive','OPEN LEFTWAY','leftwayModal()'); if(b.homeShows===0 && !c.flyers && !c.social)return trainingMissionData(1,3,12,'START PROMOTING HOME SHOW 1','Open the Band House show planner. Buy STREET FLYERS ($50) or SOCIAL PUSH ($75). The projected crowd changes from the marketing you actually buy.','objective','PLAN HOME SHOW','bandHomeModal()'); if(b.homeShows===0 && (!Array.isArray(c.kaziBuys)||!c.kaziBuys.length))return trainingMissionData(1,4,12,'USE KAZI TO PROMOTE THE SHOW','From the Band House planner choose VIEW KAZI RATE SHEET. For a strong first lesson, book the PROMOTIONAL INTERVIEW ($150) or another affordable KAZI option. Return to the show planner afterward.','objective','OPEN KAZI','kaziMarketingModal()'); if(b.homeShows===0 && metrics.projected<goal.crowd)return trainingMissionData(1,5,12,'REACH THE FIRST CROWD TARGET',`Your current projection is about ${metrics.projected}; the goal is ${goal.crowd}+. Add another affordable promotion through KAZI or direct marketing until the projection reaches the target. Then return to the Band House planner.`,'objective','PLAN HOME SHOW','bandHomeModal()'); if(b.homeShows===0)return trainingMissionData(1,6,12,'PLAY HOME SHOW 1',`You have prepared the first campaign. Open PLAN BAND HOUSE SHOW and press PLAY HOME SHOW. Goal: ${goal.crowd}+ people and $${goal.revenue}+ from donations + merch.`,'objective','PLAY / PLAN SHOW','bandHomeModal()'); if(b.homeShows===1 && !c.vancerts)return trainingMissionData(1,7,12,'BRING IN VANCERTS FOR HOME SHOW 2','Your audience is growing. Open the Band House planner and press HIRE VANCERTS ($300). VANCERTS production starts the Band-to-team relationship and activates the 2× KAZI chance + successful outcome boost for this show.','objective','PLAN HOME SHOW 2','bandHomeModal()'); if(b.homeShows===1 && (!Array.isArray(c.kaziBuys)||!c.kaziBuys.length))return trainingMissionData(1,8,12,'USE THE VANCERTS × KAZI BOOST','With VANCERTS booked, open KAZI from the show planner and buy an affordable promotion. The screen will show the 2× relationship boost. Return to the Band House planner when finished.','objective','OPEN KAZI','kaziMarketingModal()'); if(b.homeShows===1)return trainingMissionData(1,9,12,'PLAY HOME SHOW 2',`Review the projected crowd, donations, merch stock, and campaign. Add promotion if needed, then press PLAY HOME SHOW. Your target is ${goal.crowd}+ people and $${goal.revenue}+ donations + merch.`,'objective','PLAN / PLAY SHOW 2','bandHomeModal()'); if(b.homeShows===2 && b.merchStock<10)return trainingMissionData(1,10,12,'RESTOCK MERCH FOR THE FINAL TEST','Open the Band House planner and print a 20-piece merch run ($120). Home Show 3 tests whether your audience can turn into enough donations or merch sales to prove a real draw.','objective','OPEN SHOW PLANNER','bandHomeModal()'); if(b.homeShows===2)return trainingMissionData(1,11,12,'BUILD AND PLAY HOME SHOW 3',`This is PROVE YOUR DRAW. Use Leftway media, KAZI, direct promotion, merch, and VANCERTS if affordable. Reach the show target, then press PLAY HOME SHOW. Chapter 1 requires at least 3 home shows plus $700 total donations OR 30 total merch sold.`,'objective','PLAN FINAL HOME SHOW','bandHomeModal()'); if(typeof bandChapterOneComplete==='function' && !bandChapterOneComplete())return trainingMissionData(1,12,12,'KEEP BUILDING UNTIL THE DRAW IS PROVEN',`You completed ${b.homeShows} home shows. Current totals: $${Math.round(b.totalDonations||0)} donations and ${b.totalMerchSold||0} merch sold. Continue home shows and improve the campaign until you reach $700 donations OR 30 merch sold.`,'objective','OPEN BAND STORY','openBandStory()'); return trainingMissionData(2,1,8,'CHAPTER 2 • GET OUT OF THE BACKYARD','Your draw is proven. Open the Band Story board. The next phase moves into Austin bookings while keeping Leftway, KAZI, VANCERTS, Paul / Audio, and stagehands connected to the band career.','objective','OPEN BAND STORY','openBandStory()'); } function teamMission(){ const audio=state.career.teamRole==='audio', xp=audio?Number(state.career.audioXp||0):Number(state.career.stagehandXp||0); const role=audio?'AUDIO ENGINEER':'STAGEHAND'; if(!state.training.flags.moved)return trainingMissionData(1,1,7,`${role} • LEARN YOUR WORK VAN`,audio?'Paul starts at Audio House in the plain white VANCERTS work van. He grew up around church music and sound, learning to listen carefully, stay calm, and solve problems before touching the mixer. Move the van out through the open driveway.':'You start in the team career. Use the driving controls and move the work vehicle so you know how to reach load-ins and venues.','drive'); if(!state.activeJob && !state.pendingOffer && unpaidTotal()<=0 && xp===0)return trainingMissionData(1,2,7,`${role} • FIRST WORK ORDER — FSG`,'Drive to FSG PRINTSHOP first. Enter the marked loading zone and interact. FSG is the client; the equipment cannot be prepared until you receive and confirm the work order.','drive'); if(state.pendingOffer)return trainingMissionData(1,3,7,`${role} • READ THE FSG WORK ORDER`,audio?'Open EMAIL. Review the requested mains, subs, microphones, monitors, cables, and stage needs. Confirm the deposit only after you understand the signal path from stage inputs to the Tascam Model 24, mains, and monitors.':'Open EMAIL and review the exact equipment list before the show is confirmed. Pay attention to every item that must be loaded, carried, placed, and returned.','email','OPEN EMAIL','openEmail()'); if(state.activeJob && state.activeJob.phase==='pickup')return trainingMissionData(1,4,7,`${role} • PICK UP THE APPROVED GEAR`,audio?'Now drive to GIG BAG ATX. Enter the loading area, interact, and load only the approved PA, microphones, monitors, and cables from the confirmed FSG work order.':'Drive to GIG BAG ATX and interact in the loading area. Load the approved gear list exactly; missing items create problems at load-in and strike.','drive'); if(state.activeJob)return trainingMissionData(1,5,7,audio?`${role} • RETURN TO FSG FOR SOUNDCHECK`:`${role} • BUILD THE STAGE`,audio?'Return to the FSG loading zone and interact. Set the Tascam Model 24 on the rear shelf facing the stage, place mains, subs, and monitors, complete the signal path, line-check every input, and prepare the band soundcheck. The Stage Manager handles communication so Paul can stay focused on sound.':'Drive to the client loading zone and interact. Place every requested stage item in its correct slot, then finish setup. The stagehand lesson is accurate placement, cable care, speed, and protecting the gear.','drive'); if(unpaidTotal()>0)return trainingMissionData(1,6,7,`${role} • CLOSE THE FSG WORK ORDER`,audio?'The performance is complete. Open the Nookia and use CALL to confirm the show closeout and final payment with the Owner. This completes Paul’s first full signal-flow shift from work order through soundcheck and settlement.':'The performance is complete. Open the Nookia and use CALL to close the client payment loop.','call','OPEN NOOKIA','openPhone()'); if(xp>0)return trainingMissionData(1,7,7,`${role} • FIRST SHIFT COMPLETE`,audio?'Paul completed his first VANCERTS Audio Engineer shift. Repeat jobs to improve signal-flow judgment, monitor mixes, troubleshooting, reliability, and larger-production responsibility.':'You completed a Stagehand show. Repeat jobs to improve load-in speed, equipment care, setup reliability, and team experience.','objective','OPEN TEAM / CAREERS','openStaffManager()'); return trainingMissionData(1,2,7,`${role} • GO TO FSG FIRST`,'Drive to FSG PRINTSHOP, enter the loading zone, and interact to receive the first work order.','drive'); } window.currentTrainingMission=currentTrainingMission=function(){ if(state.career.path==='band')return bandMission(); if(state.career.path==='team')return teamMission(); return ownerCurrentTrainingMission(); }; const careerInfo={ band:{title:'BAND • BUILD YOUR DRAW',summary:'Start as an existing band in the black flame Band Van. Build real demand through Leftway media, KAZI, direct promotion, merch, three Band House shows, and a growing relationship with VANCERTS.',points:['Create a Leftway demo','Plan Home Show 1','Use direct promotion and KAZI','Play Home Show 1','Hire VANCERTS for later home shows','Use the 2× VANCERTS × KAZI relationship','Complete at least 3 home shows','Reach $700 donations OR 30 merch sold']}, audio:{title:'AUDIO ENGINEER • RUN THE SOUND',summary:'Learn the shared VANCERTS show from the audio side: work order, equipment requirements, PA load, setup, soundcheck thinking, and closeout.',points:['Drive the audio work vehicle','Take the first work order at FSG','Read the equipment requirements','Load the exact PA at Gig Bag','Build the PA and monitors','Finish the show and close payment','Repeat to grow Audio experience']}, stagehand:{title:'STAGEHAND • BUILD THE SHOW',summary:'Learn the same events from the stagehand side: load lists, carrying and placing gear, cable care, stage setup, strike mindset, and team reliability.',points:['Drive to the first work order','Read the load list','Load exact gear at Gig Bag','Place equipment correctly','Finish the stage build','Close out the shared show','Repeat to grow Stagehand experience']} }; window.showTrainingChapterIntro=showTrainingChapterIntro=function(chapter=trainingStoryChapter(),replay=false){ if(state.career.path==='owner')return ownerShowTrainingChapterIntro(chapter,replay); const key=state.career.path==='band'?'band':(state.career.teamRole==='audio'?'audio':'stagehand'),info=careerInfo[key]; if(!state.training.chapterSeen.includes(chapter))state.training.chapterSeen.push(chapter); modal(`<h2>TRAINING WHEELS • ${careerLabel()}</h2><div class="card"><h3>${info.title}</h3><p>${info.summary}</p><ol>${info.points.map(p=>`<li>${p}</li>`).join('')}</ol></div><p><b>Follow one gold objective at a time.</b> Open MISSION GUIDE whenever you need the exact next button, location, purchase, target, or completion condition. Training never changes rewards or resets progress.</p><div class="btns"><button class="green" onclick="startChapterTraining(${chapter})">${trainingChapterStarted(chapter)?'CONTINUE STEP-BY-STEP TRAINING':'START STEP-BY-STEP TRAINING'}</button><button onclick="disableTrainingWheels()">TURN OFF TRAINING WHEELS</button>${replay?'<button class="secondary" onclick="closeModal()">BACK</button>':''}</div>`); }; window.__R36B50FButtonAudit=function(){ const buttons=[...document.querySelectorAll('button')], problems=[]; for(const b of buttons){if(b.disabled)continue;const oc=b.getAttribute('onclick');if(!oc)continue;const m=oc.match(/^\s*([A-Za-z_$][\w$]*)\s*\(/);if(m && typeof window[m[1]]!=='function')problems.push({text:(b.textContent||'').trim(),handler:m[1]});} return {buttons:buttons.length,problems}; }; setTimeout(()=>{try{const a=window.__R36B50FButtonAudit();if(a.problems.length)console.error('R36B50F BUTTON AUDIT',a.problems)}catch(e){console.error('R36B50F BUTTON AUDIT FAILED',e)}},500); })(); </script> \n<script id="r36b51a-player-experience"> /* R36B51A — player-experience navigation and distinct career routes. */ (function(){ function homeTarget(id,label){ const h=(typeof R36B45_HOMES!=='undefined'&&R36B45_HOMES)?R36B45_HOMES[id]:null; if(!h)return null; const l=h.lot||h; return{x:(h.roadCenterX||l.x+l.w/2),y:(l.y+l.h-55),label}; } function placeTarget(id,label){ const p=window.places&&places.find(x=>x.id===id); return p?{x:p.interact?.x??p.x+p.w/2,y:p.interact?.y??p.y+p.h/2,label:label||p.short||p.name}:null; } function activeDestination(){ if(typeof state==='undefined'||typeof van==='undefined')return null; const path=state.career?.path||'owner'; if(state.activeJob){ if(state.activeJob.phase==='pickup')return placeTarget('shop','GIG BAG ATX'); return placeTarget(state.activeJob.id); } if(state.pendingOffer)return null; if(path==='band'){ const b=typeof bandStory==='function'?bandStory():(state.bandStory||{}); const assets=typeof leftwayBandAssets==='function'?leftwayBandAssets():[]; const c=b.campaign||{}; if(!b.started)return homeTarget('band','BAND HOUSE'); if(!assets.length)return placeTarget('leftway','LEFTWAY STUDIOS'); if(b.homeShows===0&&(!Array.isArray(c.kaziBuys)||!c.kaziBuys.length))return placeTarget('kazi','KAZI 88.7 FM'); return homeTarget('band','BAND HOUSE'); } if(path==='team'){ const xp=state.career.teamRole==='audio'?Number(state.career.audioXp||0):Number(state.career.stagehandXp||0); if(!xp&&!state.activeJob)return placeTarget('fsg','FSG PRINTSHOP'); return state.career.teamRole==='audio'?homeTarget('audio','PAUL • AUDIO HOUSE'):placeTarget('hq','VANCERTS HQ'); } if(state.story?.festivalActive){const id=window.FESTIVAL_ROUTE?.[state.story.festivalIndex];return id?placeTarget(id):null} const order=typeof ORDER!=='undefined'?ORDER:['fsg','blueowl','republic','hope','topnotch','leftway']; const next=order.find(id=>!state.completed?.includes(id)); if(next)return placeTarget(next); return placeTarget('hq','VANCERTS HQ'); } window.__VANCERTS_ACTIVE_DESTINATION=activeDestination; function drawMissionArrow(){ return; /* R36B52G: retired floating gold arrow */ const t=activeDestination();if(!t||!window.ctx||!window.canvas)return; const dx=t.x-van.x,dy=t.y-van.y,d=Math.hypot(dx,dy); if(d<75)return; const a=Math.atan2(dy,dx),cx=W/2,cy=H/2; const radius=Math.min(W,H)*(matchMedia('(pointer:coarse)').matches?.18:.22); const x=cx+Math.cos(a)*radius,y=cy+Math.sin(a)*radius; ctx.save();ctx.globalAlpha=.72;ctx.translate(x,y);ctx.rotate(a); ctx.fillStyle='#f1b83e';ctx.strokeStyle='#fff8e5';ctx.lineWidth=3;ctx.beginPath();ctx.moveTo(24,0);ctx.lineTo(-12,-13);ctx.lineTo(-5,0);ctx.lineTo(-12,13);ctx.closePath();ctx.fill();ctx.stroke();ctx.restore(); ctx.save();ctx.globalAlpha=.82;ctx.font='1000 11px system-ui';ctx.textAlign='center';ctx.textBaseline='middle'; const feet=Math.max(0,Math.round(d));const label=`NEXT: ${t.label} • ${feet} FT`;const w=Math.min(W-24,ctx.measureText(label).width+20); const lx=Math.max(w/2+8,Math.min(W-w/2-8,x)),ly=Math.max(18,Math.min(H-18,y+31)); ctx.fillStyle='rgba(17,17,17,.84)';ctx.fillRect(lx-w/2,ly-11,w,22);ctx.strokeStyle='#f1b83e';ctx.lineWidth=2;ctx.strokeRect(lx-w/2,ly-11,w,22);ctx.fillStyle='#fff8e5';ctx.fillText(label,lx,ly);ctx.restore(); } const priorDraw=window.draw||draw; window.draw=draw=function(){const r=priorDraw();try{drawMissionArrow()}catch(e){console.warn('R36B51A mission arrow',e)}return r}; const priorMission=window.currentTrainingMission||currentTrainingMission; window.currentTrainingMission=currentTrainingMission=function(){ const m=priorMission();if(!m)return m; const path=state.career?.path||'owner'; const role=path==='team'?(state.career.teamRole==='audio'?'AUDIO':'STAGEHAND'):path.toUpperCase(); const prefix=path==='owner'?'OWNER BUSINESS ROUTE':path==='band'?'BAND AUDIENCE ROUTE':role==='AUDIO'?'PAUL AUDIO ROUTE':'STAGEHAND CREW ROUTE'; return Object.assign({},m,{title:`${prefix} • ${m.title}`}); }; const priorHud=window.hud||hud; window.hud=hud=function(){const r=priorHud();try{ const t=activeDestination(),el=document.getElementById('objectiveText'); if(t&&el&&!el.dataset.r36b51a){el.dataset.r36b51a='1'} if(t&&el&&!el.textContent.includes('DESTINATION:'))el.textContent+=` DESTINATION: ${t.label}. Follow the gold arrow.`; }catch(e){}return r}; window.__R36B51AButtonAudit=function(){ const buttons=[...document.querySelectorAll('button')],problems=[]; for(const b of buttons){if(b.disabled)continue;const oc=b.getAttribute('onclick');if(!oc)continue;const m=oc.match(/^\s*([A-Za-z_$][\w$]*)\s*\(/);if(m&&typeof window[m[1]]!=='function')problems.push({text:(b.textContent||'').trim(),handler:m[1]})} return{build:'R36B51A',buttons:buttons.length,problems}; }; setTimeout(()=>{try{hud();const a=window.__R36B51AButtonAudit();if(a.problems.length)console.error('R36B51A BUTTON AUDIT',a.problems)}catch(e){console.error(e)}},700); })(); </script>\n\n<script id="r36b51b-exact-guidance-road-trail"> /* R36B51B — exact onboarding instructions, road chevrons, and shrinking Nookia route. */ (function(){ function target(){try{return window.__VANCERTS_ACTIVE_DESTINATION?window.__VANCERTS_ACTIVE_DESTINATION():null}catch(_){return null}} function bandExactMission(){ const b=typeof bandStory==='function'?bandStory():(state.bandStory||{}),assets=typeof leftwayBandAssets==='function'?leftwayBandAssets():[],c=b.campaign||{}; if(!b.started)return{title:'BAND STEP 1 OF 12 • START YOUR BAND STORY',text:'DO THIS NOW: Tap MISSION GUIDE, enter your band name, choose your instrument, then press START BAND STORY. You will begin at the Band House in the black flame Band Van.',button:'OPEN BAND STORY',action:'openBandStory()'}; if(!assets.length)return{title:'BAND STEP 2 OF 12 • DRIVE TO LEFTWAY STUDIOS',text:'DO THIS NOW: 1) Follow the faint blinking gold road markers to LEFTWAY STUDIOS. 2) Pull completely into the marked interaction area. 3) Stop the van. 4) Tap the on-screen interact prompt, or press Space / Enter. 5) Choose DEMO RECORDING — $150. Your first home-show promotion does not begin until the demo is created.',button:'OPEN LEFTWAY SERVICES',action:'leftwayModal()'}; if(b.homeShows===0&&!c.flyers&&!c.social)return{title:'BAND STEP 3 OF 12 • RETURN TO THE BAND HOUSE',text:'DO THIS NOW: Follow the road markers back to BAND HOUSE. Stop inside the property interaction area, open the show planner, then buy STREET FLYERS — $50 or SOCIAL PUSH — $75. Watch the projected crowd increase.',button:'OPEN HOME-SHOW PLANNER',action:'bandHomeModal()'}; if(b.homeShows===0&&(!Array.isArray(c.kaziBuys)||!c.kaziBuys.length))return{title:'BAND STEP 4 OF 12 • PROMOTE THROUGH KAZI',text:'DO THIS NOW: Open the KAZI rate sheet from the Band House planner, then purchase PROMOTIONAL INTERVIEW — $150 or another affordable option. Return to the planner after the purchase.',button:'OPEN KAZI RATE SHEET',action:'kaziMarketingModal()'}; return null; } function applyExactObjective(){ if(!window.state||state.career?.path!=='band')return; const m=bandExactMission();if(!m)return; const title=document.getElementById('objectiveTitle'),text=document.getElementById('objectiveText'),guide=document.getElementById('trainingGuide'); if(title)title.textContent=m.title;if(text)text.textContent=m.text; if(guide){guide.textContent=m.button;guide.setAttribute('onclick',m.action)} const pt=document.getElementById('phoneObjectiveTitle'),px=document.getElementById('phoneObjectiveText'); if(pt)pt.textContent=m.title.replace(/^BAND /,'');if(px)px.textContent=m.text; } const oldHud=window.hud||hud;window.hud=hud=function(){const r=oldHud();try{applyExactObjective()}catch(e){console.warn('R36B51B objective',e)}return r}; function routePoints(t){ if(!t||!window.van)return[];const sx=van.x,sy=van.y,tx=t.x,ty=t.y; const horizontalFirst=Math.abs(tx-sx)>Math.abs(ty-sy); return horizontalFirst?[{x:sx,y:sy},{x:tx,y:sy},{x:tx,y:ty}]:[{x:sx,y:sy},{x:sx,y:ty},{x:tx,y:ty}]; } function pointAt(points,dist){ let left=dist;for(let i=0;i<points.length-1;i++){const a=points[i],b=points[i+1],len=Math.hypot(b.x-a.x,b.y-a.y);if(left<=len){const q=len?left/len:0;return{x:a.x+(b.x-a.x)*q,y:a.y+(b.y-a.y)*q,a:Math.atan2(b.y-a.y,b.x-a.x)}}left-=len}return null; } function totalLen(points){let n=0;for(let i=0;i<points.length-1;i++)n+=Math.hypot(points[i+1].x-points[i].x,points[i+1].y-points[i].y);return n} function drawRoadTrail(){ const t=target();if(!t||!window.ctx||!window.van)return;const pts=routePoints(t),len=totalLen(pts);if(len<70)return; const pulse=.30+.22*(.5+.5*Math.sin(performance.now()/260)); ctx.save();ctx.globalAlpha=pulse;ctx.strokeStyle='#f1b83e';ctx.fillStyle='#f1b83e';ctx.lineWidth=3; for(let d=70;d<len;d+=85){const p=pointAt(pts,d);if(!p)break;ctx.save();ctx.translate(p.x,p.y);ctx.rotate(p.a);ctx.beginPath();ctx.moveTo(13,0);ctx.lineTo(-8,-7);ctx.lineTo(-3,0);ctx.lineTo(-8,7);ctx.closePath();ctx.fill();ctx.restore()} ctx.restore(); } const oldDraw=window.draw||draw;window.draw=draw=function(){const r=oldDraw();try{drawRoadTrail()}catch(e){console.warn('R36B51B road trail',e)}return r}; const oldMini=window.drawMini||drawMini;window.drawMini=drawMini=function(){const r=oldMini();try{ const t=target();if(!t||!window.miniCtx||!window.world)return r;const c=miniCtx,w=340,h=190,padX=11,padY=8,plotW=w-padX*2,plotH=h-padY*2,sx=x=>padX+(x/world.w)*plotW,sy=y=>padY+(y/world.h)*plotH,pts=routePoints(t),len=totalLen(pts);if(len<20)return r; c.save();c.setLineDash([8,6]);c.lineCap='round';c.strokeStyle='rgba(220,45,45,.82)';c.lineWidth=4;c.beginPath();c.moveTo(sx(pts[0].x),sy(pts[0].y));for(let i=1;i<pts.length;i++)c.lineTo(sx(pts[i].x),sy(pts[i].y));c.stroke();c.setLineDash([]); for(let d=0;d<len;d+=Math.max(55,len/12)){const p=pointAt(pts,d);if(!p)break;const remain=Math.max(0,1-d/len),rad=2+remain*3;c.fillStyle=`rgba(220,45,45,${.35+.5*remain})`;c.beginPath();c.arc(sx(p.x),sy(p.y),rad,0,Math.PI*2);c.fill()} c.restore(); }catch(e){console.warn('R36B51B mini route',e)}return r}; setTimeout(()=>{try{hud()}catch(_){}},250); })(); </script> <style id="r36b51e-integrated-training-style"> /* R36B51E — preserve the original HUD dimensions; training lives inside the existing objective panel. */ #objective.r36b51eTraining{overflow:auto!important;pointer-events:auto!important} #objective.r36b51eTraining #objectiveTitle{color:#f1b83e!important} #objective.r36b51eTraining #objectiveText{display:block!important;line-height:1.28!important} #objective.r36b51eTraining .trainingActions{display:flex!important;margin-top:7px!important} #objective.r36b51eTraining .trainingGuide{min-height:30px!important;padding:5px 8px!important;font-size:9px!important} #trainingProgress{white-space:nowrap} #phoneRadioApp .spotifyPhoneLogo{display:grid!important;place-items:center!important;width:26px!important;height:26px!important;margin:0 auto 3px!important;border-radius:50%!important;background:#1db954!important;color:#07150b!important;font:1000 17px/1 system-ui!important;letter-spacing:-3px!important;padding-right:3px!important} #phoneRadioApp .spotifyPhoneLogo:before{content:'≋';transform:rotate(5deg)} #rotaryRadio .radioTicker span,#rotaryRadio.inPhoneApp .radioTicker span{display:inline-block!important;min-width:100%!important;width:max-content!important;max-width:none!important;padding-left:100%!important;overflow:visible!important;text-overflow:clip!important;animation:r36b51eTrackScroll 13s linear infinite!important;white-space:nowrap!important} @keyframes r36b51eTrackScroll{0%{transform:translateX(0)}100%{transform:translateX(-100%)}} @media(prefers-reduced-motion:reduce){#rotaryRadio .radioTicker span{animation-duration:26s!important}} /* Keep the frame, HUD, canvas and controls in the same viewport without hiding game UI. */ html.mobileFullscreen,html.mobileFullscreen body{width:100%!important;height:100%!important;min-height:100dvh!important;margin:0!important;overflow:hidden!important} html.mobileFullscreen #game{width:100vw!important;height:100dvh!important;max-width:none!important;max-height:none!important} @media(orientation:landscape){.objective{max-height:25vh!important}.objectiveTop{width:min(43vw,520px)!important}} @media(max-width:760px),(pointer:coarse){#objective.r36b51eTraining{max-height:108px!important}.objectiveTop{max-width:calc(100vw - 20px)!important}} </style> <script id="r36b51e-integrated-training-audit"> /* R36B51E — rollback-safe integrated training, separate career saves, route guidance and Spotify phone identity. */ (function(){ const BUILD='R36B51E', SLOT_PREFIX='vancerts-career-r36b51e-'; const deep=v=>JSON.parse(JSON.stringify(v)); const $id=id=>document.getElementById(id); function careerId(path=state?.career?.path,role=state?.career?.teamRole){return path==='team'?(role==='audio'?'audio':'stagehand'):(path||'owner')} function careerLabel(id=careerId()){return id==='band'?'BAND':id==='audio'?'PAUL • AUDIO ENGINEER':id==='stagehand'?'STAGEHAND':'VANCERTS OWNER'} function permitIssued(){return !!(state?.driverPass?.name||state?.driverPass?.issued||state?.driverPass?.started)} function storageGet(k){try{return safeStorage.getItem(k)}catch(_){try{return localStorage.getItem(k)}catch(e){return null}}} function storageSet(k,v){try{safeStorage.setItem(k,v);return true}catch(_){try{localStorage.setItem(k,v);return true}catch(e){return false}}} function saveCareerSnapshot(){if(!permitIssued())return false;try{storageSet(SLOT_PREFIX+careerId(),JSON.stringify(state));return true}catch(e){console.error(BUILD+' slot save',e);return false}} function freshFor(id,shared){const f=deep(defaults);f.driverPass=deep(shared.driverPass||defaults.driverPass);f.seenIntro=!!shared.seenIntro;f.introVersion=Number(shared.introVersion||0);f.cameraZoom=Number(shared.cameraZoom||1);f.zoomHelpSeen=!!shared.zoomHelpSeen;f.training=deep(shared.training||defaults.training);f.career=deep(defaults.career);if(id==='band')f.career.path='band';else if(id==='audio'){f.career.path='team';f.career.teamRole='audio'}else if(id==='stagehand'){f.career.path='team';f.career.teamRole='stagehand'}else f.career.path='owner';f.cash=1000;return f} function restoreCareerSnapshot(id){const shared=state;let loaded=null;try{const raw=storageGet(SLOT_PREFIX+id);if(raw)loaded=JSON.parse(raw)}catch(e){console.warn(BUILD+' slot parse',e)}state=loaded&&typeof loaded==='object'?loaded:freshFor(id,shared);state.driverPass=deep(shared.driverPass||state.driverPass||defaults.driverPass);state.training=Object.assign({},defaults.training,state.training||{});state.training.flags=Object.assign({},defaults.training.flags,state.training.flags||{});state.career=Object.assign({},defaults.career,state.career||{});if(id==='band')state.career.path='band';else if(id==='audio'){state.career.path='team';state.career.teamRole='audio'}else if(id==='stagehand'){state.career.path='team';state.career.teamRole='stagehand'}else state.career.path='owner';return state} const originalSave=window.save||save; window.save=save=function(){let r;try{r=originalSave.apply(this,arguments)}finally{saveCareerSnapshot()}return r}; const originalManual=window.manualSave||manualSave; window.manualSave=manualSave=function(){const r=originalManual.apply(this,arguments);saveCareerSnapshot();return r}; const originalChoose=window.chooseCareerPath||chooseCareerPath; window.chooseCareerPath=chooseCareerPath=function(path,role){if(!['owner','team','band'].includes(path))return;saveCareerSnapshot();const id=path==='team'?(role==='audio'?'audio':'stagehand'):path;restoreCareerSnapshot(id);spawnCareerAtHome(state.career.path,state.career.teamRole);originalSave();hud();openStaffManager();toast(careerLabel(id)+' STORY RESTORED • SEPARATE SAVE')}; addEventListener('pagehide',saveCareerSnapshot);setInterval(saveCareerSnapshot,5000); function tutorial(){state.guidedTraining=state.guidedTraining&&typeof state.guidedTraining==='object'?state.guidedTraining:{};const id=careerId();return state.guidedTraining[id]||(state.guidedTraining[id]={step:0,done:false,startX:van.x,startY:van.y,startAngle:van.angle,started:false})} function resetTutorialAfterPermit(){const t=tutorial();if(!t.done){t.step=0;t.started=true;t.startX=van.x;t.startY=van.y;t.startAngle=van.angle}const ph=$id('phone'),pb=$id('phoneCollapse');if(ph){ph.classList.add('collapsed');ph.classList.remove('deviceSuppressed');if(pb){pb.textContent='▴';pb.setAttribute('aria-expanded','false')}}saveCareerSnapshot();hud()} const originalIssue=window.issueDriverPermitFromGate||issueDriverPermitFromGate; window.issueDriverPermitFromGate=issueDriverPermitFromGate=function(){const before=permitIssued();const r=originalIssue.apply(this,arguments);setTimeout(()=>{if(!before&&permitIssued())resetTutorialAfterPermit()},350);return r}; function firstDestination(){const id=careerId();if(id==='band')return{label:'LEFTWAY STUDIOS',action:'Create DEMO RECORDING — $150.'};if(id==='audio')return{label:'FSG PRINTSHOP',action:'Receive the first Audio Engineer work order before any equipment is prepared.'};if(id==='stagehand')return{label:'FSG PRINTSHOP',action:'Receive the first crew work order before any equipment is loaded.'};return{label:'FSG PRINTSHOP',action:'Park in the loading zone and begin the first VANCERTS booking.'}} function firstActionDone(){const id=careerId();if(id==='band'){try{return (typeof leftwayBandAssets==='function'?leftwayBandAssets():[]).length>0}catch(_){return false}}if(id==='audio')return Number(state.career?.audioXp||0)>0||!!state.pendingOffer||!!state.activeJob;if(id==='stagehand')return Number(state.career?.stagehandXp||0)>0||!!state.pendingOffer||!!state.activeJob;return !!state.pendingOffer||!!state.activeJob||state.completed?.includes('fsg')} function exactMission(){const id=careerId();if(id==='band'&&typeof bandStory==='function'){const b=bandStory(),assets=typeof leftwayBandAssets==='function'?leftwayBandAssets():[],c=b.campaign||{};if(!assets.length)return{title:'BAND • CREATE YOUR FIRST DEMO',text:'Follow the faint yellow driver-side route to LEFTWAY STUDIOS. Pull fully into the interaction circle, stop, tap INTERACT (or Space / Enter), then purchase DEMO RECORDING — $150.'};if(b.homeShows===0&&!c.flyers&&!c.social)return{title:'BAND • PROMOTE HOME SHOW 1',text:'Follow the route to BAND HOUSE. Stop in the property interaction area, open the Home Show Planner, then buy STREET FLYERS — $50 or SOCIAL PUSH — $75.'};if(b.homeShows===0&&(!Array.isArray(c.kaziBuys)||!c.kaziBuys.length))return{title:'BAND • USE KAZI PROMOTION',text:'Open the KAZI rate sheet through the Home Show Planner. Purchase a PROMOTIONAL INTERVIEW — $150 or another campaign, then return to the planner.'};return{title:'BAND • BUILD YOUR DRAW',text:`Prepare and play at least 3 Band House shows. Current: ${Number(b.homeShows||0)}/3 shows • $${Number(b.totalDonations||0)} donations • ${Number(b.totalMerchSold||0)} merch. Finish with $700 donations OR 30 merch sold.`}} if(id==='audio'){ if(state.pendingOffer)return{title:'PAUL • READ THE FSG WORK ORDER',text:'Open EMAIL, review the requested PA and stage needs, then confirm the deposit. Equipment pickup comes after the work order is approved.'}; if(state.activeJob && state.activeJob.phase==='pickup')return{title:'PAUL • PICK UP THE APPROVED PA',text:'Drive to GIG BAG ATX and load only the equipment approved for the FSG show.'}; if(state.activeJob){const p=places.find(x=>x.id===state.activeJob.id);return{title:'PAUL • BUILD FOR SOUNDCHECK',text:`Return to ${p?.name||'the client'}, place the PA and monitors, complete the signal path, line-check the inputs, and prepare soundcheck.`}} if(unpaidTotal()>0)return{title:'PAUL • CLOSE THE WORK ORDER',text:'Open the Nookia and use CALL to confirm show closeout and the final payment with the Owner.'}; if(Number(state.career?.audioXp||0)>0)return{title:'PAUL • FIRST SHIFT COMPLETE',text:'The first Audio Engineer shift is complete. Continue taking work orders to build soundcheck, troubleshooting, and monitor-mix experience.'}; return{title:'PAUL • FIRST WORK ORDER',text:'Drive to FSG PRINTSHOP first, enter the loading zone, and interact. Receive the client work order before going to Gig Bag ATX.'}; } if(id==='stagehand'){ if(state.pendingOffer)return{title:'STAGEHAND • READ THE FSG LOAD LIST',text:'Open EMAIL, review the exact equipment list, and confirm the work order before pickup.'}; if(state.activeJob && state.activeJob.phase==='pickup')return{title:'STAGEHAND • PICK UP THE APPROVED GEAR',text:'Drive to GIG BAG ATX and load the confirmed FSG manifest.'}; if(state.activeJob){const p=places.find(x=>x.id===state.activeJob.id);return{title:'STAGEHAND • BUILD THE SHOW',text:`Return to ${p?.name||'the client'}, unload, place, cable, and secure the stage safely.`}} return{title:'STAGEHAND • FIRST WORK ORDER',text:'Drive to FSG PRINTSHOP first, enter the loading zone, and interact before going to Gig Bag ATX.'}; } return{title:'OWNER • FIRST BOOKING',text:'Follow the route to FSG PRINTSHOP. Park in the loading zone and interact. Review the client request, collect the 50% deposit, then pick up the exact equipment from Gig Bag ATX.'} } const lessons=[ ['PHONE 1/5 • OPEN THE NOOKIA','Tap the small Nookia phone icon. Driving is locked in Training Wheels until the phone opens.'], ['PHONE 2/5 • MINIMIZE THE NOOKIA','Tap the ▾ button at the top-right of the Nookia. This clears the driving view.'], ['DRIVING 3/5 • MOVE FORWARD','Hold ▲ on the screen, W on a keyboard, or the controller accelerator until the van moves.'], ['DRIVING 4/5 • STEER','Keep moving slowly and press ◀ / ▶, A / S, or the controller stick to turn.'], ['DRIVING 5/5 • REVERSE','Hold ▼, Z, or the controller reverse control for a short distance.'] ]; function guidance(){const t=tutorial();if(t.done)return exactMission();if(t.step<5)return{title:lessons[t.step][0],text:lessons[t.step][1]};const d=firstDestination();return{title:careerLabel()+' • FIRST MISSION',text:`Follow the faint blinking yellow line on the driver's side to ${d.label}. Stop in the marked interaction area and tap INTERACT / Space / Enter. ${d.action}`}} function applyGuidance(){if(!permitIssued()||$id('splash')&&!$id('splash').classList.contains('hidden'))return;const t=tutorial(),g=guidance(),obj=$id('objective'),title=$id('objectiveTitle'),text=$id('objectiveText'),badge=$id('trainingBadge'),progress=$id('trainingProgress'),guide=$id('trainingGuide');if(obj)obj.classList.add('r36b51eTraining');if(title)title.textContent=g.title;if(text)text.textContent=g.text;if(badge)badge.textContent=state.training?.enabled===false?'GUIDED ROUTE':'TRAINING WHEELS';if(progress)progress.textContent=t.done?'MISSION GUIDE':`STEP ${Math.min(t.step+1,6)} / 6`;if(guide){guide.textContent=t.done?'OPEN MISSION GUIDE':'SHOW EXACT STEP';guide.onclick=function(){toast(g.text)}}const pt=$id('phoneObjectiveTitle'),px=$id('phoneObjectiveText');if(pt)pt.textContent=g.title;if(px)px.textContent=g.text} const originalHud=window.hud||hud;window.hud=hud=function(){const r=originalHud.apply(this,arguments);try{applyGuidance()}catch(e){console.error(BUILD+' guidance',e)}return r}; const originalDrivePressed=window.drivePressed||drivePressed; window.drivePressed=drivePressed=function(name){const t=tutorial();if(!permitIssued()||t.done||state.training?.enabled===false)return originalDrivePressed(name);if(t.step<2)return false;if(t.step===2)return name==='forward'&&originalDrivePressed(name);if(t.step===3)return ['forward','left','right'].includes(name)&&originalDrivePressed(name);return originalDrivePressed(name)}; function advance(n){const t=tutorial();if(n<=t.step)return;t.step=n;t.startX=van.x;t.startY=van.y;t.startAngle=van.angle;saveCareerSnapshot();hud();toast('TRAINING STEP COMPLETE')} setInterval(()=>{if(!permitIssued()||!$id('splash')?.classList.contains('hidden'))return;const t=tutorial(),ph=$id('phone');if(t.done)return;if(t.step===0&&ph&&!ph.classList.contains('collapsed'))advance(1);else if(t.step===1&&ph&&ph.classList.contains('collapsed'))advance(2);else if(t.step===2&&Math.hypot(van.x-t.startX,van.y-t.startY)>18)advance(3);else if(t.step===3&&Math.abs(van.angle-t.startAngle)>.22)advance(4);else if(t.step===4&&originalDrivePressed('reverse'))advance(5);else if(t.step===5&&firstActionDone()){t.done=true;saveCareerSnapshot();hud();toast(careerLabel()+' CONTROL TRAINING COMPLETE')}} ,120); /* Route starts only after controls; preserve R36B51B's route engine and change the phone copy to red. */ const oldDestination=window.__VANCERTS_ACTIVE_DESTINATION; if(oldDestination)window.__VANCERTS_ACTIVE_DESTINATION=function(){const t=tutorial();if(!permitIssued()||(!t.done&&t.step<5))return null;return oldDestination()}; const oldMini=window.drawMini||drawMini;window.drawMini=drawMini=function(){const r=oldMini.apply(this,arguments);try{const c=window.miniCtx;if(c){c.save();c.globalCompositeOperation='source-atop';c.restore()}}catch(_){}return r}; /* Change existing gold mini-map route strokes/fills to red without changing world route color. */ try{const miniScript=$id('r36b51b-exact-guidance-road-trail');if(miniScript){} }catch(_){} function applySpotifyIdentity(){const b=$id('phoneRadioApp');if(b){b.innerHTML='<span class="spotifyPhoneLogo" aria-hidden="true"></span>SPOTIFY';b.setAttribute('aria-label','Spotify community radio')}const status=$id('spotifyStatus');if(status&&/CASSETTE RADIO|COMMUNITY RADIO/.test(status.textContent))status.textContent='SPOTIFY • COMMUNITY RADIO'} // R36B52A: legacy Spotify identity updater retired. function sanity(){const splash=$id('splash'),hudEl=$id('hud');if(splash?.classList.contains('hidden')&&permitIssued()){hudEl?.classList.remove('hidden');$id('mobile')?.classList.remove('hidden');$id('phone')?.classList.remove('hidden');applyGuidance()}const buttons=[...document.querySelectorAll('button')],problems=[];for(const b of buttons){if(b.disabled)continue;const oc=b.getAttribute('onclick');if(!oc)continue;const m=oc.match(/^\s*([A-Za-z_$][\w$]*)\s*\(/);if(m&&typeof window[m[1]]!=='function')problems.push({text:(b.textContent||'').trim(),handler:m[1]})}window.__R36B51EAudit={build:BUILD,buttons:buttons.length,missingHandlers:problems,permit:permitIssued(),hudVisible:!!hudEl&&!hudEl.classList.contains('hidden'),career:careerId()};if(problems.length)console.error(BUILD+' BUTTON AUDIT',problems)} setTimeout(sanity,700); window.__VANCERTS_R36B52A_GUIDANCE=guidance;window.__VANCERTS_R36B52A_APPLY_GUIDANCE=applyGuidance;window.__VANCERTS_R36B52A_TUTORIAL=tutorial; })(); </script> <style id="r36b51f-progression-fullscreen-style"> /* R36B51K — stop Squarespace layout constraints from leaving a website border around the active game. */ html.vancertsGameOnly,html.vancertsGameOnly body{margin:0!important;padding:0!important;width:100%!important;max-width:none!important;height:100%!important;min-height:100dvh!important;overflow:hidden!important;background:#111!important} html.vancertsGameOnly #game{position:fixed!important;inset:0!important;margin:0!important;padding:0!important;width:100vw!important;width:100dvw!important;height:100vh!important;height:100dvh!important;max-width:none!important;max-height:none!important;z-index:2147483000!important;transform:none!important} html.vancertsGameOnly #game canvas{max-width:none!important;max-height:none!important} html.vancertsGameOnly .sqs-announcement-bar-dropzone,html.vancertsGameOnly header,html.vancertsGameOnly footer{display:none!important} html.vancertsGameOnly #modalWrap{z-index:2147483646!important} /* First demo is a one-time story checkpoint, not a repeat-purchase trap. */ button[data-r36b51f-demo-complete="1"]{opacity:.72!important;background:#3e8f53!important;color:#fff!important;cursor:default!important} </style> <script id="r36b51f-progression-fullscreen-fix"> (function(){ const BUILD='R36B51K'; const $id=id=>document.getElementById(id); function bandState(){try{return typeof bandStory==='function'?bandStory():(state.bandStory=state.bandStory||{})}catch(_){return state.bandStory=state.bandStory||{}}} function demoProjects(){try{return (leftwayState().projects||[]).filter(p=>p&&p.serviceId==='demo')}catch(_){return []}} function demoComplete(){const b=bandState();return !!b.firstDemoComplete||demoProjects().length>0} function commitDemoCheckpoint(){ const projects=demoProjects(),b=bandState(); b.firstDemoComplete=true; b.firstDemoProjectId=projects[0]?.id||b.firstDemoProjectId||''; b.firstDemoCompletedAt=b.firstDemoCompletedAt||new Date().toISOString(); state.guidedTraining=state.guidedTraining&&typeof state.guidedTraining==='object'?state.guidedTraining:{}; const t=state.guidedTraining.band||(state.guidedTraining.band={step:5,done:false}); t.step=Math.max(5,Number(t.step)||0);t.done=true; try{if(typeof save==='function')save()}catch(e){console.warn(BUILD+' demo save',e)} } /* Keep the existing asset API truthful even after career-slot restores. */ try{ const originalAssets=typeof leftwayBandAssets==='function'?leftwayBandAssets:null; if(originalAssets){leftwayBandAssets=function(){const items=originalAssets()||[];if(items.length)return items;if(bandState().firstDemoComplete)return[{id:bandState().firstDemoProjectId||'first-demo-checkpoint',serviceId:'demo',asset:'Demo Recording',checkpoint:true}];return[]};window.leftwayBandAssets=leftwayBandAssets} }catch(e){console.warn(BUILD+' asset bridge',e)} const originalProduce=window.produceLeftwayService; if(typeof originalProduce==='function'){ window.produceLeftwayService=produceLeftwayService=function(id){ if(id==='demo'&&demoComplete()){ commitDemoCheckpoint(); try{closeModal()}catch(_){} try{hud()}catch(_){} toast('FIRST DEMO COMPLETE • NEXT: RETURN TO BAND HOUSE'); return false; } const beforeCash=Number(state.cash||0),beforeCount=demoProjects().length; const result=originalProduce.apply(this,arguments); if(id==='demo')setTimeout(()=>{ const created=demoProjects().length>beforeCount||Number(state.cash||0)<beforeCash; if(!created)return; commitDemoCheckpoint(); try{closeModal()}catch(_){} try{hud()}catch(_){} toast('DEMO COMPLETE • FOLLOW THE ROUTE BACK TO BAND HOUSE'); },40); return result } } const originalLeftway=window.leftwayModal; if(typeof originalLeftway==='function'){ window.leftwayModal=leftwayModal=function(){ const r=originalLeftway.apply(this,arguments); setTimeout(()=>{ if(!demoComplete())return; document.querySelectorAll('button[onclick*="produceLeftwayService(\'demo\')"]').forEach(btn=>{ btn.disabled=true;btn.dataset.r36b51fDemoComplete='1';btn.textContent='FIRST DEMO COMPLETE'; }); },0); return r } } if(demoComplete())commitDemoCheckpoint(); function visibleViewport(){const vv=window.visualViewport;return{w:Math.max(1,Math.round(vv?vv.width:innerWidth)),h:Math.max(1,Math.round(vv?vv.height:innerHeight))}} function clearLayoutConstraint(el){ if(!el||el===document.documentElement)return; try{ el.style.setProperty('max-width','none','important'); el.style.setProperty('margin','0','important'); el.style.setProperty('padding','0','important'); el.style.setProperty('transform','none','important'); el.style.setProperty('contain','none','important'); el.style.setProperty('filter','none','important'); el.style.setProperty('perspective','none','important'); el.style.setProperty('overflow','visible','important'); }catch(_){} } function forceGameOnlyViewport(){ const game=$id('game');if(!game)return; document.documentElement.classList.add('vancertsGameOnly','mobileFullscreen'); document.body.classList.add('vancertsGameOnly','mobileFullscreen'); let p=game.parentElement;while(p&&p!==document.body){clearLayoutConstraint(p);p=p.parentElement} const v=visibleViewport(); game.style.setProperty('position','fixed','important');game.style.setProperty('left','0','important');game.style.setProperty('top','0','important'); game.style.setProperty('right','auto','important');game.style.setProperty('bottom','auto','important'); game.style.setProperty('width',v.w+'px','important');game.style.setProperty('height',v.h+'px','important'); game.style.setProperty('max-width','none','important');game.style.setProperty('max-height','none','important'); game.style.setProperty('margin','0','important');game.style.setProperty('transform','none','important'); try{if(typeof setFullscreenUi==='function')setFullscreenUi(true)}catch(_){} try{if(typeof resize==='function')resize()}catch(_){} } const originalLaunch=window.launchGameAfterFullscreen; if(typeof originalLaunch==='function')window.launchGameAfterFullscreen=launchGameAfterFullscreen=function(){const r=originalLaunch.apply(this,arguments);requestAnimationFrame(forceGameOnlyViewport);setTimeout(forceGameOnlyViewport,120);setTimeout(forceGameOnlyViewport,600);return r}; const originalSet=window.setFullscreenUi; if(typeof originalSet==='function')window.setFullscreenUi=setFullscreenUi=function(active){const r=originalSet.apply(this,arguments);if(active)setTimeout(forceGameOnlyViewport,0);return r}; addEventListener('resize',()=>{if(document.documentElement.classList.contains('vancertsGameOnly'))forceGameOnlyViewport()},{passive:true}); if(window.visualViewport)visualViewport.addEventListener('resize',()=>{if(document.documentElement.classList.contains('vancertsGameOnly'))forceGameOnlyViewport()},{passive:true}); /* Repair an already-open session without requiring a reset. */ setTimeout(()=>{if($id('splash')?.classList.contains('hidden'))forceGameOnlyViewport();if(demoComplete()){commitDemoCheckpoint();try{hud()}catch(_){}}},500); function applyPostDemoBandGuide(){ if(state?.career?.path!=='band'||!demoComplete())return; const b=bandState(),c=b.campaign||{},title=$id('objectiveTitle'),text=$id('objectiveText'),pt=$id('phoneObjectiveTitle'),px=$id('phoneObjectiveText'); let h='BAND • RETURN TO BAND HOUSE',copy='FIRST DEMO COMPLETE. Follow the faint yellow road-side route back to BAND HOUSE. Pull into the interaction area, tap INTERACT, open the Home Show Planner, then buy STREET FLYERS — $50 or SOCIAL PUSH — $75.'; if(c.flyers||c.social){h='BAND • PROMOTE WITH KAZI';copy='Direct promotion is ready. Open the Home Show Planner at BAND HOUSE, choose KAZI, and purchase a PROMOTIONAL INTERVIEW — $150 or another affordable campaign.'} if(Array.isArray(c.kaziBuys)&&c.kaziBuys.length){h='BAND • PLAY HOME SHOW 1';copy='Your first campaign is ready. Return to BAND HOUSE, open the Home Show Planner, confirm the projected crowd, then choose PLAY HOME SHOW when the target is met.'} if(title)title.textContent=h;if(text)text.textContent=copy;if(pt)pt.textContent=h;if(px)px.textContent=copy; } // R36B52A: post-demo guidance is now rendered only through HUD updates. window.__R36B51K={build:BUILD,demoComplete,forceGameOnlyViewport}; })(); </script> <style id="r36b51k-interface-recovery"> /* Restore the original interface stack above the map in every play mode. */ #game{position:relative!important;z-index:0!important} .hud{z-index:30!important} .objective{z-index:34!important} .mobile{z-index:38!important} .phone{z-index:42!important} .toast{z-index:80!important} .modalWrap{z-index:90!important} .gameError{z-index:100!important} html.vancertsGameOnly #game{z-index:0!important} html.vancertsGameOnly .hud{z-index:30!important} html.vancertsGameOnly .objective{z-index:34!important} html.vancertsGameOnly .mobile{z-index:38!important} html.vancertsGameOnly .phone{z-index:42!important} </style> <script id="r36b51k-interface-watchdog"> (function(){ const BUILD='R36B51K'; const byId=id=>document.getElementById(id); function gameHasStarted(){ const splash=byId('splash'); if(!splash||!splash.classList.contains('hidden'))return false; try{return typeof permitIssued==='function'?!!permitIssued():true}catch(_){return true} } function restoreInterface(){ if(!gameHasStarted())return; const hud=byId('hud'),phone=byId('phone'),mobile=byId('mobile'),objective=byId('objective'); [hud,phone,mobile].forEach(el=>el&&el.classList.remove('hidden')); if(hud){hud.style.setProperty('display','block','important');hud.style.setProperty('visibility','visible','important');hud.style.setProperty('opacity','1','important')} if(phone){phone.style.setProperty('visibility','visible','important');phone.style.setProperty('opacity','1','important')} if(mobile){mobile.style.setProperty('visibility','visible','important');mobile.style.setProperty('opacity','1','important')} if(objective){objective.style.setProperty('visibility','visible','important');objective.style.setProperty('opacity','1','important')} } window.addEventListener('vancerts-story-started',restoreInterface); window.addEventListener('resize',restoreInterface,{passive:true}); setTimeout(restoreInterface,100);setTimeout(restoreInterface,500);setInterval(restoreInterface,1000); window.__R36B51KRestoreInterface=restoreInterface; })(); </script> <script id="r36b51l-story-foundation"> /* R36B51L — Studio Reference Bible implementation package 1. Non-invasive Paul character + relationship foundation. Existing missions, economy, vehicles, controls, HUD, phone, map, and progression remain unchanged. */ (function(){ 'use strict'; const BUILD='R36B51L'; const PAUL_CANON={ id:'paul', name:'Paul', age:42, joinedProduction:'February 2025', startedThrough:'VANCERTS open jams at BYOB Austin', role:'Stage Manager / Lead Stage Technician', dayJob:'Mail courier for City of Austin workers and departments', motivation:'Help bands get what they need and deliver their best show possible.', teaches:['Guitar gear','Cables','Backline','Stage preparation','Equipment organization','Load-in and load-out','Stage etiquette','Calm problem-solving'], strengths:['Quick learner','Calm','Reliable','Team-focused','Sees the complete production'], growthAreas:['Pricing','Contracts','Marketing','Sponsorships','Company finances','Business negotiations'], favoriteSaying:'We got this!', favoriteMusic:'Gojira' }; function storyRoot(){ state.storyBible=state.storyBible&&typeof state.storyBible==='object'?state.storyBible:{}; state.storyBible.version=1; state.storyBible.characters=state.storyBible.characters&&typeof state.storyBible.characters==='object'?state.storyBible.characters:{}; const p=state.storyBible.characters.paul=Object.assign({ met:false,trust:0,dialogueState:'unmet',firstHireSeen:false,firstScheduleSeen:false, milestones:{joinedTeam:false,firstShow:false,crewLeader:false},lastDialogue:'' },state.storyBible.characters.paul||{}); p.milestones=Object.assign({joinedTeam:false,firstShow:false,crewLeader:false},p.milestones||{}); p.trust=Math.max(0,Math.min(100,Number(p.trust)||0)); return state.storyBible; } function paulRel(){return storyRoot().characters.paul} function trustLabel(v){return v>=75?'TRUSTED CREW LEADER':v>=50?'DEPENDABLE PARTNER':v>=25?'BUILDING TRUST':v>0?'NEW TEAMMATE':'NOT MET'} function addTrust(amount,reason){ const p=paulRel(),before=p.trust;p.trust=Math.max(0,Math.min(100,before+(Number(amount)||0))); if(reason)p.lastDialogue=String(reason); try{save()}catch(_){ } if(p.trust!==before&&typeof toast==='function')toast(`PAUL TRUST +${p.trust-before} • ${trustLabel(p.trust)}`); return p.trust; } function paulDialogue(title,body,button){ const p=paulRel();p.met=true;p.dialogueState='active';p.lastDialogue=body;try{save()}catch(_){ } if(typeof modal==='function')modal(`<h2>${title}</h2><div class="card"><h3>PAUL • STAGE MANAGER / LEAD STAGE TECHNICIAN</h3><p>${body}</p><p><b>PAUL:</b> “We got this!”</p></div><div class="btns"><button class="green" onclick="closeModal()">${button||'LET’S WORK'}</button></div>`); } window.VANCERTS_STORY_BIBLE=window.VANCERTS_STORY_BIBLE||{}; window.VANCERTS_STORY_BIBLE.characters=window.VANCERTS_STORY_BIBLE.characters||{}; window.VANCERTS_STORY_BIBLE.characters.paul=PAUL_CANON; window.getPaulRelationship=function(){const p=paulRel();return JSON.parse(JSON.stringify(p))}; window.addPaulTrust=addTrust; storyRoot(); function wrap(name,after){ const old=window[name];if(typeof old!=='function'||old.__r36b51lWrapped)return; const fn=function(){const result=old.apply(this,arguments);try{after.apply(this,arguments)}catch(e){console.warn(BUILD,name,e)}return result}; fn.__r36b51lWrapped=true;window[name]=fn;try{eval(name+'=fn')}catch(_){ } } wrap('hirePaul',function(){ const p=paulRel(); if(!p.firstHireSeen){p.firstHireSeen=true;p.met=true;p.dialogueState='teammate';p.milestones.joinedTeam=true;addTrust(10,'Paul joined the team.');setTimeout(()=>paulDialogue('PAUL JOINS THE TEAM','Paul came to VANCERTS through the open jams at BYOB Austin. He watches the whole stage, helps artists stay comfortable, and makes sure the Owner and Audio Engineer have what they need. He is strongest in cables, guitar gear, backline, organization, and calm problem-solving.','WELCOME PAUL'),120)} }); wrap('schedulePaul',function(){ const p=paulRel(); if(!p.firstScheduleSeen){p.firstScheduleSeen=true;p.dialogueState='scheduled';addTrust(5,'Paul was trusted with his first scheduled production shift.');setTimeout(()=>paulDialogue('FIRST SHIFT WITH PAUL','Paul checks the stage, verifies the cable path, and asks what the artists need before load-in begins. This mission teaches a real production lesson: the Stage Manager is the communication bridge between the band, audience, Owner, and Audio Engineer.','START LOAD-IN'),120)} }); wrap('payPaulForShow',function(){const p=paulRel();if(!p.milestones.firstShow){p.milestones.firstShow=true;p.dialogueState='reliable';addTrust(15,'Paul completed and was paid for his first show.')}}); // Enrich the existing Team screen without replacing any current cards or controls. const previousOpenStaff=window.openStaffManager; if(typeof previousOpenStaff==='function'&&!previousOpenStaff.__r36b51lStory){ const enriched=function(){ const r=previousOpenStaff.apply(this,arguments); setTimeout(function(){ const host=document.getElementById('modal');if(!host||host.querySelector('[data-paul-story-foundation]'))return; const p=paulRel(),card=document.createElement('div');card.className='card';card.dataset.paulStoryFoundation='1'; card.innerHTML=`<h3>PAUL RELATIONSHIP</h3><p><b>${trustLabel(p.trust)}</b> • Trust ${p.trust}/100</p><p>${p.met?'Paul remembers the work you have completed together. Reliable communication, safe setups, fair pay, and calm problem-solving build trust.':'You have not formally met Paul in this story save yet. He becomes part of the story through BYOB Austin and the VANCERTS team.'}</p><p class="small"><b>ROLE:</b> ${PAUL_CANON.role}<br><b>TEACHES:</b> ${PAUL_CANON.teaches.join(' • ')}</p>`; const btns=host.querySelector('.btns');if(btns&&btns.parentNode)btns.parentNode.insertBefore(card,btns);else host.appendChild(card); },0);return r }; enriched.__r36b51lStory=true;window.openStaffManager=enriched;try{openStaffManager=enriched}catch(_){ } } // Keep relationship data initialized after career restores and portable save loads. setInterval(function(){try{storyRoot()}catch(_){ }},2500); console.info(BUILD,'Paul character framework ready'); })(); </script> <style id="r36b52f-core-stability-style"> /* R36B52F — preserve QueueTube behavior and keep the Nookia fully on-screen whenever it opens. */ #rotateHint{display:none!important;visibility:hidden!important;opacity:0!important;pointer-events:none!important} #spotifyPanel,.spotifyPanel,iframe[src*="open.spotify.com"],iframe[src*="spotify.com"],iframe[title*="Spotify"]{display:none!important;visibility:hidden!important;pointer-events:none!important} #phoneRadioApp{position:relative!important;font-size:0!important;line-height:1!important;overflow:hidden!important} #phoneRadioApp>*{display:none!important} #phoneRadioApp:before{content:'♪'!important;display:grid!important;place-items:center!important;width:27px!important;height:27px!important;margin:0 auto 3px!important;border-radius:50%!important;border:2px solid #111!important;background:#f1b83e!important;color:#111!important;font:1000 18px/1 system-ui!important} #phoneRadioApp:after{content:'MUSIC'!important;display:block!important;color:#222!important;font:1000 8px/1 system-ui!important;letter-spacing:.04em!important} #spotifyToggle{display:none!important;visibility:hidden!important;pointer-events:none!important} #rotaryRadio.vcQueueTubeDirect{display:block;position:fixed;left:12px;top:96px;right:auto;bottom:auto;transform:none!important;width:min(520px,calc(100vw - 24px));height:auto!important;max-height:none!important;overflow:hidden!important;box-sizing:border-box!important;contain:paint!important;filter:none!important;background:#0b0b0e!important;border:3px solid #f4e6be!important;border-radius:16px!important;box-shadow:7px 7px 0 rgba(0,0,0,.72)!important;z-index:66!important;pointer-events:auto!important;color:#f2f2f2!important;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,'Liberation Mono','Courier New',monospace!important} #rotaryRadio.vcQueueTubeDirect.hidden,#rotaryRadio.vcQueueTubeDirect.collapsed{display:none!important;visibility:hidden!important;pointer-events:none!important} #rotaryRadio.vcQueueTubeDirect.dragging,#phone.vcStablePhone.dragging{transition:none!important;cursor:grabbing!important;user-select:none!important;-webkit-user-select:none!important} #rotaryRadio.vcQueueTubeDirect .vcQtDockHead{position:absolute;left:0;right:0;top:0;z-index:8;height:46px;display:flex;align-items:flex-start;justify-content:flex-end;padding:8px;background:transparent;border:0;color:#9cff57;cursor:grab;touch-action:none;user-select:none;-webkit-user-select:none} #rotaryRadio.vcQueueTubeDirect .vcQtDockTitle{display:none!important} #rotaryRadio.vcQueueTubeDirect .vcQtDockActions{display:flex;align-items:center;justify-content:flex-end;gap:6px;margin-left:auto} #rotaryRadio.vcQueueTubeDirect .vcQtDockButton{height:30px;min-width:74px;margin:0;padding:4px 9px;border:2px solid #9cff57;border-radius:9px;box-shadow:none;background:#0b0b0e;color:#9cff57;font:1000 8px/1 system-ui;cursor:pointer;touch-action:manipulation} #rotaryRadio.vcQueueTubeDirect .vcQtSignUp{min-width:72px;border-color:#111!important;background:#f1b83e!important;color:#111!important} #qtPlayerMount{display:block!important;width:100%!important;max-height:none!important;overflow:hidden!important;box-sizing:border-box!important;border-radius:13px!important;background:#0b0b0e!important} .qt-player{display:block;box-sizing:border-box;width:100%;max-width:100%;overflow:hidden;border-radius:13px;background:#0b0b0e;color:#f2f2f2} .qt-head{display:none!important} .qt-brand{font-size:17px;font-weight:1000;letter-spacing:.02em}.qt-station{margin-top:3px;font-size:8px;color:rgba(242,242,242,.62);letter-spacing:.07em}.qt-live{margin-top:3px;font-size:8px;color:#9cff57} .qt-body{display:block;box-sizing:border-box;min-width:0;padding:14px 176px 9px 12px;background:#12121a;border-radius:13px 13px 0 0} .qt-art,.qt-art-fallback{display:none!important} .qt-meta{min-width:0;display:flex;flex-direction:column;justify-content:center}.qt-artist{font-size:11px;color:#6cf2ff;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.qt-title{margin-top:3px;font-size:14px;font-weight:1000;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.qt-event{margin-top:4px;font-size:8px;color:rgba(242,242,242,.58);white-space:nowrap;overflow:hidden;text-overflow:ellipsis} .qt-progress-row{margin-top:9px}.qt-progress{width:100%;accent-color:#9cff57;height:12px;margin:0}.qt-time{display:flex;justify-content:space-between;margin-top:1px;font-size:8px;color:rgba(242,242,242,.65);font-variant-numeric:tabular-nums} .qt-controls{display:grid;grid-template-columns:repeat(7,minmax(0,1fr));gap:5px;padding:8px 10px;border-top:1px solid rgba(255,255,255,.08);background:#0f0f16}.qt-controls button,.qt-volume button,.qt-queue-head button,.qt-queue-item button,.qt-retry{min-width:0;height:34px;padding:0 4px;border:1px solid rgba(255,255,255,.12);border-radius:8px;background:#17171f;color:#f2f2f2;box-shadow:none;font:1000 10px/1 ui-monospace,SFMono-Regular,Menlo,monospace}.qt-controls button.active{border-color:#9cff57;color:#9cff57;background:rgba(156,255,87,.08)}.qt-controls .qt-play{background:#9cff57;color:#071008;font-size:14px}.qt-controls button:disabled{opacity:.35} .qt-volume{display:grid;grid-template-columns:35px minmax(0,1fr) 35px 42px;gap:7px;align-items:center;padding:0 10px 8px;background:#0f0f16}.qt-volume input{width:100%;accent-color:#6cf2ff}.qt-volume output{font-size:8px;text-align:right;color:rgba(242,242,242,.65)} .qt-status-row{display:flex;align-items:center;gap:8px;padding:7px 10px;border-top:1px solid rgba(255,255,255,.07);border-radius:0 0 12px 12px;background:#0b0b0e}.qt-status{flex:1 1 auto;color:rgba(242,242,242,.72);font-size:8px;line-height:1.35;min-height:20px}.qt-status strong{color:#9cff57}.qt-status.qt-error{color:#ff9c91}.qt-retry{display:none;width:58px;height:25px;font-size:8px}.qt-retry.show{display:block} .qt-queue{border-top:1px solid rgba(255,255,255,.08);background:#101017;max-height:170px;overflow:auto}.qt-queue[hidden]{display:none}.qt-queue-head{position:sticky;top:0;display:flex;justify-content:space-between;align-items:center;padding:7px 9px;background:#0f0f16;border-bottom:1px solid rgba(255,255,255,.08);font-size:9px;font-weight:1000;z-index:1}.qt-queue-head button{height:24px;padding:0 8px;font-size:8px}.qt-queue-list{list-style:none;padding:5px;margin:0}.qt-queue-item{display:grid;grid-template-columns:27px minmax(0,1fr) auto;gap:7px;align-items:center;padding:6px;border-radius:8px}.qt-queue-item.current{background:rgba(156,255,87,.08);outline:1px solid rgba(156,255,87,.25)}.qt-queue-item>button:first-child{height:24px}.qt-queue-info{min-width:0}.qt-queue-info b,.qt-queue-info span{display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.qt-queue-info b{font-size:9px}.qt-queue-info span{font-size:7px;color:rgba(242,242,242,.58);margin-top:2px}.qt-queue-actions{display:flex;gap:3px}.qt-queue-actions button{width:24px;height:24px;padding:0;font-size:8px} @media(max-width:760px),(pointer:coarse){ #phone.vcStablePhone{position:fixed!important;left:7px!important;right:auto!important;top:70px!important;bottom:auto!important;transform:scale(.68)!important;transform-origin:top left!important;z-index:58!important;pointer-events:auto!important} #phone.vcStablePhone .phoneTop{cursor:grab!important;touch-action:none!important;user-select:none!important;-webkit-user-select:none!important} #phone.vcStablePhone.collapsed{width:58px!important;height:46px!important;padding:5px 7px!important;transform:none!important;cursor:pointer!important} #phone.vcStablePhone .phoneCollapse{pointer-events:auto!important;touch-action:manipulation!important;z-index:100!important} #rotaryRadio.vcQueueTubeDirect{left:6px;top:68px;width:min(430px,calc(100vw - 12px));height:auto!important;max-height:none!important;z-index:64!important} #qtPlayerMount{max-height:none!important;overflow:hidden!important} .qt-body{padding:12px 168px 7px 10px}.qt-title{font-size:11px}.qt-controls{gap:3px;padding:6px}.qt-controls button{height:30px;font-size:8px}.qt-controls .qt-play{font-size:12px}.qt-volume{padding:0 7px 6px;grid-template-columns:30px minmax(0,1fr) 30px 35px}.qt-status-row{padding:6px 8px}.qt-status{font-size:7px;min-height:18px}.qt-queue{max-height:145px} #objective{max-height:112px!important;overflow:auto!important} } </style> <script id="r36b52f-core-stability"> (function(){ 'use strict'; const BUILD='R36B52F'; const API_URL='https://script.google.com/macros/s/AKfycbzy7FobduC0pjxVesNiGPUos33db1K4sV5Mw2BADRMh9NPjzorYj0jLJaCFg93fjZOAkg/exec?page=api'; const POS_KEY='vancerts-queuetube-position-r36b52f'; const PHONE_OPEN_POS_KEY='vancerts-phone-open-position-r36b52f'; const PHONE_CLOSED_POS_KEY='vancerts-phone-closed-position-r36b52f'; const SIGN_UP_URL='https://vancerts.com/queuetube/account?mode=signup'; const $q=id=>document.getElementById(id); const clamp=(n,a,b)=>Math.min(b,Math.max(a,n)); const fmt=s=>{s=Number.isFinite(s)?Math.max(0,s):0;return Math.floor(s/60)+':'+String(Math.floor(s%60)).padStart(2,'0')}; const esc=v=>String(v??'').replace(/[&<>"']/g,c=>({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c])); const sessionId=(()=>{try{let id=sessionStorage.getItem('queuetube_session_id');if(!id){id='qt-'+Date.now().toString(36)+'-'+Math.random().toString(36).slice(2);sessionStorage.setItem('queuetube_session_id',id)}return id}catch(_){return 'qt-'+Date.now().toString(36)}})(); function stableObjective(){try{if(typeof window.__VANCERTS_R36B52G_RENDER==='function')window.__VANCERTS_R36B52G_RENDER();else if(typeof window.__VANCERTS_R36B52A_APPLY_GUIDANCE==='function')window.__VANCERTS_R36B52A_APPLY_GUIDANCE();else if(typeof syncR36B46FPhoneObjective==='function')syncR36B46FPhoneObjective()}catch(e){console.error(BUILD+' objective',e)}} const previousHud=window.hud;if(typeof previousHud==='function'){window.hud=hud=function(){const r=previousHud.apply(this,arguments);stableObjective();return r}} window.__VANCERTS_STABLE_OBJECTIVE=stableObjective; function viewportBox(){const v=window.visualViewport;return{x:v?Number(v.offsetLeft)||0:0,y:v?Number(v.offsetTop)||0:0,w:Math.max(1,v?Number(v.width)||innerWidth:innerWidth),h:Math.max(1,v?Number(v.height)||innerHeight:innerHeight)}} function clampNode(node,x,y){const r=node.getBoundingClientRect(),v=viewportBox(),m=6,maxX=Math.max(v.x+m,v.x+v.w-r.width-m),maxY=Math.max(v.y+m,v.y+v.h-r.height-m);return{x:Math.max(v.x+m,Math.min(maxX,Number(x)||v.x+m)),y:Math.max(v.y+m,Math.min(maxY,Number(y)||v.y+m))}} function readPosition(key){try{const p=JSON.parse(localStorage.getItem(key)||'null');return p&&Number.isFinite(Number(p.x))&&Number.isFinite(Number(p.y))?{x:Number(p.x),y:Number(p.y)}:null}catch(_){return null}} function savePosition(node,key){try{if(!key)return;const r=node.getBoundingClientRect();localStorage.setItem(key,JSON.stringify({x:Math.round(r.left),y:Math.round(r.top)}))}catch(_){}} function placeNode(node,key,defaults){const stored=readPosition(key),r=node.getBoundingClientRect(),fallback=typeof defaults==='function'?defaults(r):defaults,q=clampNode(node,stored?.x??fallback.x,stored?.y??fallback.y);node.style.setProperty('left',q.x+'px','important');node.style.setProperty('top',q.y+'px','important');node.style.setProperty('right','auto','important');node.style.setProperty('bottom','auto','important')} function resolvedKey(key){return typeof key==='function'?key():key} function installFreeDrag(node,handle,key,options={}){if(!node||!handle||handle.dataset.freeDrag==='1')return;handle.dataset.freeDrag='1';let drag=null,ignoreClickUntil=0;const excluded=options.excluded||'button,input,a,select,textarea';const down=e=>{if((e.pointerType==='mouse'&&e.button!==0)||e.target.closest(excluded))return;const r=node.getBoundingClientRect();drag={id:e.pointerId,dx:e.clientX-r.left,dy:e.clientY-r.top,moved:false};node.classList.add('dragging');try{handle.setPointerCapture(e.pointerId)}catch(_){}e.preventDefault();e.stopImmediatePropagation()};const move=e=>{if(!drag||drag.id!==e.pointerId)return;const x=e.clientX-drag.dx,y=e.clientY-drag.dy;if(!drag.moved&&Math.hypot(x-node.getBoundingClientRect().left,y-node.getBoundingClientRect().top)>4)drag.moved=true;const q=clampNode(node,x,y);node.style.setProperty('left',q.x+'px','important');node.style.setProperty('top',q.y+'px','important');node.style.setProperty('right','auto','important');node.style.setProperty('bottom','auto','important');e.preventDefault();e.stopImmediatePropagation()};const end=e=>{if(!drag||drag.id!==e.pointerId)return;const moved=drag.moved;drag=null;node.classList.remove('dragging');savePosition(node,resolvedKey(key));if(moved)ignoreClickUntil=Date.now()+300;e.preventDefault();e.stopImmediatePropagation()};handle.addEventListener('pointerdown',down,true);document.addEventListener('pointermove',move,true);document.addEventListener('pointerup',end,true);document.addEventListener('pointercancel',end,true);handle.addEventListener('click',e=>{if(Date.now()<ignoreClickUntil){e.preventDefault();e.stopImmediatePropagation()}},true)} function phoneKey(phone){return phone&&phone.classList.contains('collapsed')?PHONE_CLOSED_POS_KEY:PHONE_OPEN_POS_KEY} function phoneDefault(phone,open){return r=>{const v=viewportBox(),coarse=matchMedia('(pointer:coarse)').matches,portrait=v.h>=v.w;if(open&&coarse&&portrait)return{x:v.x+7,y:v.y+70};return{x:Math.max(v.x+7,v.x+v.w-r.width-7),y:v.y+70}}} function settlePhone(phone,open){if(!phone)return;const key=open?PHONE_OPEN_POS_KEY:PHONE_CLOSED_POS_KEY,apply=()=>placeNode(phone,key,phoneDefault(phone,open));apply();requestAnimationFrame(()=>requestAnimationFrame(apply));setTimeout(apply,80);setTimeout(apply,220)} function setPhone(open){const phone=$q('phone'),button=$q('phoneCollapse');if(!phone)return;const wasOpen=!phone.classList.contains('collapsed');savePosition(phone,wasOpen?PHONE_OPEN_POS_KEY:PHONE_CLOSED_POS_KEY);phone.classList.add('vcStablePhone','vcQueueTube');phone.classList.remove('deviceSuppressed','deviceReliable');phone.classList.toggle('collapsed',!open);['inset','right','bottom','--device-fit-scale'].forEach(name=>phone.style.removeProperty(name));if(open&&matchMedia('(pointer:coarse)').matches){const v=viewportBox();phone.style.setProperty('left',(v.x+7)+'px','important');phone.style.setProperty('top',(v.y+70)+'px','important')}if(button){button.textContent=open?'▾':'▴';button.setAttribute('aria-expanded',open?'true':'false');button.setAttribute('aria-label',open?'Minimize phone':'Open phone')}settlePhone(phone,open);stableObjective()} function installPhone(){const phone=$q('phone'),old=$q('phoneCollapse');if(!phone||!old||old.dataset.r36b52f)return;phone.classList.add('vcStablePhone','vcQueueTube');const button=old.cloneNode(true);button.dataset.r36b52f='1';old.replaceWith(button);let lastToggle=0;const toggle=e=>{const now=Date.now();if(now-lastToggle<220){e.preventDefault();e.stopImmediatePropagation();return}lastToggle=now;e.preventDefault();e.stopImmediatePropagation();setPhone(phone.classList.contains('collapsed'))};button.addEventListener('pointerup',toggle,true);button.addEventListener('click',toggle,true);const handle=phone.querySelector('.phoneTop');installFreeDrag(phone,handle,()=>phoneKey(phone),{excluded:'button,input,a,select,textarea'});setPhone($q('splash')?.classList.contains('hidden')?!phone.classList.contains('collapsed'):false)} window.__VANCERTS_DIRECT_SET_PHONE=setPhone; class QueueTubePlayer{ constructor(root,options={}){this.root=root;this.options=Object.assign({apiUrl:API_URL,playerSource:'game'},options);this.audio=new Audio();this.audio.preload='metadata';this.audio.playsInline=true;this.tracks=[];this.queue=[];this.index=-1;this.shuffle=false;this.repeat=false;this.minimumSeconds=30;this.listened=0;this.eventSent=false;this.queueOpen=false;this.timer=0;this.render();this.bind();this.loadPlaylist()} render(){this.root.innerHTML=`<section class="qt-player" aria-label="QueueTube player"><header class="qt-head"><div class="qt-brand">QueueTube</div><div class="qt-station">VANCERTS LIVE RECORDING LIBRARY</div><div class="qt-live">Same music library as Vancerts.com/queuetube</div></header><div class="qt-body"><div id="qtArtworkFallback" class="qt-art-fallback">QUEUE<br>TUBE</div><img id="qtArtwork" class="qt-art" alt="Album artwork" hidden><div class="qt-meta"><div id="qtArtist" class="qt-artist">QueueTube</div><div id="qtTitle" class="qt-title">Loading live recordings…</div><div id="qtEvent" class="qt-event">VANCERTS community music player</div></div><div class="qt-progress-row"><input id="qtProgress" class="qt-progress" type="range" min="0" max="1000" value="0" aria-label="Track progress"><div class="qt-time"><span id="qtCurrent">0:00</span><span id="qtDuration">0:00</span></div></div></div><div class="qt-controls"><button id="qtShuffle" type="button" aria-label="Shuffle">⇄</button><button id="qtPrev" type="button" aria-label="Previous">|◀</button><button id="qtPlay" class="qt-play" type="button" aria-label="Play or pause">▶</button><button id="qtNext" type="button" aria-label="Next">▶|</button><button id="qtRepeat" type="button" aria-label="Repeat">↻</button><button id="qtMute" type="button" aria-label="Mute">🔊</button><button id="qtQueueToggle" type="button" aria-label="Show queue">QUEUE</button></div><div class="qt-volume"><button id="qtVolumeDown" type="button" aria-label="Volume down">−</button><input id="qtVolume" type="range" min="0" max="1" step="0.01" value="0.85" aria-label="Volume"><button id="qtVolumeUp" type="button" aria-label="Volume up">+</button><output id="qtVolumeOut">85%</output></div><div class="qt-status-row"><div id="qtStatus" class="qt-status">Connecting to QueueTube…</div><button id="qtRetry" class="qt-retry" type="button">RETRY</button></div><section id="qtQueue" class="qt-queue" hidden><div class="qt-queue-head"><span>PLAY QUEUE</span><button id="qtCloseQueue" type="button">CLOSE</button></div><ol id="qtQueueList" class="qt-queue-list"></ol></section></section>`;this.el={art:$q('qtArtwork'),fallback:$q('qtArtworkFallback'),artist:$q('qtArtist'),title:$q('qtTitle'),event:$q('qtEvent'),progress:$q('qtProgress'),current:$q('qtCurrent'),duration:$q('qtDuration'),play:$q('qtPlay'),prev:$q('qtPrev'),next:$q('qtNext'),shuffle:$q('qtShuffle'),repeat:$q('qtRepeat'),mute:$q('qtMute'),queueToggle:$q('qtQueueToggle'),volume:$q('qtVolume'),volumeDown:$q('qtVolumeDown'),volumeUp:$q('qtVolumeUp'),volumeOut:$q('qtVolumeOut'),status:$q('qtStatus'),retry:$q('qtRetry'),queue:$q('qtQueue'),queueList:$q('qtQueueList'),closeQueue:$q('qtCloseQueue')}} bind(){this.audio.volume=.85;this.el.play.onclick=()=>this.toggle();this.el.prev.onclick=()=>this.previous();this.el.next.onclick=()=>this.next();this.el.shuffle.onclick=()=>{this.shuffle=!this.shuffle;this.el.shuffle.classList.toggle('active',this.shuffle)};this.el.repeat.onclick=()=>{this.repeat=!this.repeat;this.el.repeat.classList.toggle('active',this.repeat)};this.el.mute.onclick=()=>{this.audio.muted=!this.audio.muted;this.el.mute.textContent=this.audio.muted?'🔇':'🔊';this.el.mute.classList.toggle('active',this.audio.muted)};this.el.queueToggle.onclick=()=>this.toggleQueue();this.el.closeQueue.onclick=()=>this.toggleQueue(false);this.el.retry.onclick=()=>this.loadPlaylist();this.el.volume.oninput=()=>this.setVolume(Number(this.el.volume.value));this.el.volumeDown.onclick=()=>this.setVolume(this.audio.volume-.1);this.el.volumeUp.onclick=()=>this.setVolume(this.audio.volume+.1);this.el.progress.oninput=()=>{if(this.audio.duration)this.audio.currentTime=Number(this.el.progress.value)/1000*this.audio.duration};this.audio.addEventListener('play',()=>{this.el.play.textContent='❚❚';this.post('play');this.startTimer()});this.audio.addEventListener('pause',()=>{this.el.play.textContent='▶';this.stopTimer();this.post('pause')});this.audio.addEventListener('loadedmetadata',()=>{this.el.duration.textContent=fmt(this.audio.duration)});this.audio.addEventListener('durationchange',()=>{this.el.duration.textContent=fmt(this.audio.duration)});this.audio.addEventListener('timeupdate',()=>{this.el.current.textContent=fmt(this.audio.currentTime);if(this.audio.duration)this.el.progress.value=Math.round(this.audio.currentTime/this.audio.duration*1000)});this.audio.addEventListener('ended',()=>{this.stopTimer();if(this.repeat){this.audio.currentTime=0;this.safePlay()}else this.next()});this.audio.addEventListener('error',()=>this.status('This recording could not be loaded. Choose another track.',true));addEventListener('pagehide',()=>this.stopTimer(),{once:true})} status(message,error=false){this.el.status.textContent=message;this.el.status.classList.toggle('qt-error',!!error)} setVolume(value){value=clamp(Number(value)||0,0,1);this.audio.volume=value;this.audio.muted=false;this.el.volume.value=String(value);this.el.volumeOut.value=Math.round(value*100)+'%';this.el.mute.textContent='🔊';this.el.mute.classList.remove('active')} async loadPlaylist(){this.el.retry.classList.remove('show');this.status('Connecting to QueueTube…');const controller=new AbortController(),timeout=setTimeout(()=>controller.abort(),30000);try{const response=await fetch(this.options.apiUrl+'&_ts='+Date.now(),{cache:'no-store',signal:controller.signal});if(!response.ok)throw Error('QueueTube returned '+response.status);const data=await response.json();if(!data||data.ok===false)throw Error(data?.error||'QueueTube API error');this.minimumSeconds=Number(data.qualification?.minimum_seconds)||30;const source=Array.isArray(data.tracks)?data.tracks:Array.isArray(data.recordings)?data.recordings:[];this.tracks=source.filter(t=>t&&t.streaming_url&&t.active!==false&&(!t.stream_status||['TEST_READY','READY','LIVE','ACTIVE'].includes(String(t.stream_status).toUpperCase())));this.queue=this.tracks.slice();if(!this.queue.length)throw Error('No active QueueTube recordings were returned');this.loadTrack(0,false);this.status(this.queue.length+' live recording'+(this.queue.length===1?'':'s')+' • tap to play');this.renderQueue()}catch(error){this.status(error?.name==='AbortError'?'QueueTube connection timed out. Tap RETRY.':'QueueTube could not connect: '+(error?.message||'unknown error'),true);this.el.title.textContent='QueueTube unavailable';this.el.retry.classList.add('show')}finally{clearTimeout(timeout)}} currentTrack(){return this.queue[this.index]||null} loadTrack(index,autoplay=true){if(!this.queue.length)return;index=(index+this.queue.length)%this.queue.length;this.stopTimer();this.audio.pause();this.index=index;this.listened=0;this.eventSent=false;const t=this.currentTrack();this.audio.src=t.streaming_url;this.audio.load();this.el.artist.textContent=t.artist_name||t.artist||'Unknown Artist';this.el.title.textContent=t.track_name||t.title||'Untitled';this.el.event.textContent=t.event_name||t.session_name||t.venue||'VANCERTS live recording';const art=t.artwork_url||t.image_url||t.cover_url||'';if(art){this.el.art.hidden=false;this.el.fallback.hidden=true;this.el.art.src=art;this.el.art.onerror=()=>{this.el.art.hidden=true;this.el.fallback.hidden=false}}else{this.el.art.hidden=true;this.el.fallback.hidden=false}this.el.current.textContent='0:00';this.el.duration.textContent='0:00';this.el.progress.value=0;this.renderQueue();this.post('trackchange');if(autoplay)this.safePlay()} safePlay(){const promise=this.audio.play();if(promise&&promise.catch)promise.catch(()=>this.status('Tap PLAY to start this recording.'))} toggle(){if(this.index<0&&this.queue.length)this.loadTrack(0,false);if(this.index<0){this.status('No recording is ready yet.',true);return}this.audio.paused?this.safePlay():this.audio.pause()} next(){if(!this.queue.length)return;let i=this.shuffle?Math.floor(Math.random()*this.queue.length):this.index+1;if(this.queue.length>1&&i===this.index)i=(i+1)%this.queue.length;this.loadTrack(i,true)} previous(){if(!this.queue.length)return;this.loadTrack(this.index-1,true)} toggleQueue(force){this.queueOpen=typeof force==='boolean'?force:!this.queueOpen;this.el.queue.hidden=!this.queueOpen;this.el.queueToggle.classList.toggle('active',this.queueOpen);if(this.queueOpen)this.renderQueue()} renderQueue(){this.el.queueList.innerHTML='';this.queue.forEach((t,i)=>{const li=document.createElement('li');li.className='qt-queue-item'+(i===this.index?' current':'');li.innerHTML='<button type="button" aria-label="Play track">'+(i===this.index?'▶':String(i+1).padStart(2,'0'))+'</button><div class="qt-queue-info"><b>'+esc(t.track_name||t.title||'Untitled')+'</b><span>'+esc(t.artist_name||t.artist||'Unknown Artist')+'</span></div><div class="qt-queue-actions"><button type="button" aria-label="Move up">↑</button><button type="button" aria-label="Move down">↓</button></div>';li.children[0].onclick=()=>this.loadTrack(i,true);const actions=li.querySelectorAll('.qt-queue-actions button');actions[0].onclick=()=>this.moveQueue(i,-1);actions[1].onclick=()=>this.moveQueue(i,1);this.el.queueList.appendChild(li)})} moveQueue(i,dir){const j=i+dir;if(j<0||j>=this.queue.length)return;const current=this.currentTrack()?.track_id;[this.queue[i],this.queue[j]]=[this.queue[j],this.queue[i]];this.index=Math.max(0,this.queue.findIndex(t=>t.track_id===current));this.renderQueue()} startTimer(){this.stopTimer();this.timer=setInterval(()=>{if(this.audio.paused||this.audio.ended||document.visibilityState!=='visible')return;this.listened++;const remaining=Math.max(0,this.minimumSeconds-this.listened);this.status(remaining?'Qualified listen in '+remaining+' sec':'Qualified listen reached • supporting '+(this.currentTrack()?.artist_name||'the artist'));if(this.listened>=this.minimumSeconds&&!this.eventSent)this.sendPlay()},1000)} stopTimer(){if(this.timer){clearInterval(this.timer);this.timer=0}} async sendPlay(){const t=this.currentTrack();if(!t||this.eventSent)return;this.eventSent=true;try{const response=await fetch(this.options.apiUrl,{method:'POST',headers:{'Content-Type':'text/plain;charset=utf-8'},body:JSON.stringify({action:'play',track_id:t.track_id,seconds_listened:this.listened,player_source:this.options.playerSource,session_id:sessionId,user_agent:navigator.userAgent||'',referrer:'vancerts-game',internal_test:false})});const data=await response.json();this.status(data?.qualified_play?'Qualified play recorded • supporting '+(t.artist_name||'the artist'):'Listen recorded')}catch(_){this.status('Music is playing • listen tracking will retry next track')};this.post('qualifiedplay')} post(type){const t=this.currentTrack();try{parent.postMessage({source:'queuetube',type,track_id:t?.track_id||null,artist:t?.artist_name||'',title:t?.track_name||''},'*')}catch(_){}} open(){const shell=$q('rotaryRadio');if(!shell)return;shell.classList.remove('hidden','collapsed');const button=$q('radioCollapse');if(button)button.textContent='MINIMIZE';restorePlayer(shell);if(matchMedia('(pointer:coarse)').matches)setPhone(false)} minimize(){const shell=$q('rotaryRadio');if(!shell)return;savePlayer(shell);shell.classList.remove('collapsed');shell.classList.add('hidden');const button=$q('radioCollapse');if(button)button.textContent='MINIMIZE'} } function savePlayer(player){savePosition(player,POS_KEY)} function restorePlayer(player){placeNode(player,POS_KEY,()=>({x:matchMedia('(pointer:coarse)').matches?6:12,y:matchMedia('(pointer:coarse)').matches?68:96}));player.style.setProperty('transform','none','important')} function installQueueTube(){ try{if(typeof destroySpotifyController==='function')destroySpotifyController();if(typeof spotifyFallbackTimer!=='undefined')clearTimeout(spotifyFallbackTimer)}catch(_){} document.querySelectorAll('#spotifyPanel,.spotifyPanel,iframe[src*="spotify.com"],iframe[title*="Spotify"]').forEach(el=>el.remove()); const old=$q('rotaryRadio');if(!old)return; const shell=old.cloneNode(false);shell.id='rotaryRadio';shell.className='rotaryRadio vcQueueTube vcQueueTubeDirect hidden';shell.dataset.playerSource='game';shell.setAttribute('aria-label','QueueTube music player');shell.innerHTML='<div class="vcQtDockHead" aria-label="Drag QueueTube player"><span class="vcQtDockTitle">QUEUETUBE • VANCERTS MUSIC</span><div class="vcQtDockActions"><button id="qtSignUp" class="vcQtDockButton vcQtSignUp" type="button">SIGN UP</button><button id="radioCollapse" class="vcQtDockButton" type="button">MINIMIZE</button></div></div><div id="qtPlayerMount"></div>';old.replaceWith(shell); const player=new QueueTubePlayer($q('qtPlayerMount'),{apiUrl:API_URL,playerSource:'game'});window.queueTubePlayer=player; const head=shell.querySelector('.vcQtDockHead'),button=$q('radioCollapse'),signUp=$q('qtSignUp');installFreeDrag(shell,head,POS_KEY,{excluded:'button,input,a,select,textarea'});button.addEventListener('click',e=>{e.preventDefault();e.stopImmediatePropagation();player.minimize()},true);signUp.addEventListener('click',e=>{e.preventDefault();e.stopImmediatePropagation();const opened=window.open(SIGN_UP_URL,'_blank','noopener,noreferrer');if(!opened)location.href=SIGN_UP_URL},true); let app=$q('phoneRadioApp');if(app){const clean=app.cloneNode(false);app.replaceWith(clean);app=clean;app.innerHTML='<span aria-hidden="true">♪</span>MUSIC';app.setAttribute('aria-label','Open QueueTube Music');app.addEventListener('click',e=>{e.preventDefault();e.stopImmediatePropagation();player.open()},true)} let top=$q('spotifyToggle');if(top){const clean=top.cloneNode(false);top.replaceWith(clean);top=clean;top.textContent='MUSIC';top.setAttribute('aria-label','Open QueueTube Music');top.addEventListener('click',e=>{e.preventDefault();e.stopImmediatePropagation();player.open()},true)} const status=$q('spotifyStatus');if(status)status.textContent='QUEUETUBE • MUSIC'; window.openQueueTube=()=>player.open();window.minimizeQueueTube=()=>player.minimize();window.open512Jams=()=>{};window.load512Jams=()=>{};window.stop512Jams=()=>{player.audio.pause();player.status('Playback paused • game progress unchanged')};window.toggleSpotifyPlayback=()=>player.toggle();window.toggleSpotifyPower=()=>{};window.toggleMusic=()=>player.open();window.destroySpotifyController=()=>{}; addEventListener('resize',()=>{if(!shell.classList.contains('hidden'))restorePlayer(shell);const phone=$q('phone');if(phone)settlePhone(phone,!phone.classList.contains('collapsed'))},{passive:true});if(window.visualViewport)visualViewport.addEventListener('resize',()=>{const phone=$q('phone');if(phone)settlePhone(phone,!phone.classList.contains('collapsed'))},{passive:true}); } window.startGame=function(){if(window.gameLaunchComplete||window.fullscreenLaunchPending)return;window.fullscreenLaunchPending=true;const b=$q('playGameButton');if(b){b.disabled=true;b.textContent='OPENING AUSTIN…'}try{notifyParentFullscreen('enter')}catch(_){}try{const el=document.documentElement,fn=el.requestFullscreen||el.webkitRequestFullscreen;if(fn&&!document.fullscreenElement&&!document.webkitFullscreenElement){const p=fn.call(el);if(p&&p.catch)p.catch(()=>{})}}catch(_){}setTimeout(()=>{try{setFullscreenUi(true)}catch(_){};try{completeFullscreenLaunch()}catch(e){console.error(BUILD+' launch',e)};$q('rotateHint')?.classList.add('hiddenByUser')},180)}; installQueueTube();installPhone();$q('rotateHint')?.classList.add('hiddenByUser');setTimeout(()=>{installPhone();stableObjective()},0);setTimeout(stableObjective,250);window.__R36B52F={build:BUILD,openPhone:()=>setPhone(true),closePhone:()=>setPhone(false),openQueueTube:()=>window.queueTubePlayer?.open(),stableObjective}; })(); </script> <style id="r36b52g-story-gps-style"> /* R36B52G — one story objective, red road guidance, and a direct Nookia GPS line. */ #objective.r36b52gStoryAuthority{border-color:#f1b83e!important;box-shadow:5px 5px 0 #000!important} #objective.r36b52gStoryAuthority #objectiveTitle{color:#f1b83e!important} #objective.r36b52gStoryAuthority #objectiveText{white-space:normal!important} #trainingProgress.r36b52gProgress{color:#fff8e5!important;letter-spacing:.04em!important} #miniCanvas.r36b52gGpsActive{outline:2px solid rgba(230,74,56,.5)!important;outline-offset:-2px!important} </style> <script id="r36b52g-story-gps-authority"> (function(){ 'use strict'; const BUILD='R36B52G'; const RED='#e64a38', PAPER='#fff8e5', INK='#171514'; const $id=id=>document.getElementById(id); let lastSignature='', saveSyncQueued=false; function controlTutorial(){ try{return typeof window.__VANCERTS_R36B52A_TUTORIAL==='function'?window.__VANCERTS_R36B52A_TUTORIAL():null}catch(_){return null} } function careerId(){ const path=state?.career?.path||'owner'; return path==='team'?(state.career?.teamRole==='audio'?'audio':'stagehand'):path; } function careerLabel(){ const id=careerId();return id==='band'?'BAND':id==='audio'?'PAUL • AUDIO ENGINEER':id==='stagehand'?'STAGEHAND':'VANCERTS OWNER'; } function queueSaveSync(){ if(saveSyncQueued)return;saveSyncQueued=true; setTimeout(()=>{saveSyncQueued=false;try{if(typeof save==='function')save()}catch(_){}},0); } function syncTrainingSystems(){ const t=controlTutorial();if(!t||!t.done||!state)return; state.training=state.training&&typeof state.training==='object'?state.training:{}; state.training.flags=state.training.flags&&typeof state.training.flags==='object'?state.training.flags:{}; let changed=false; for(const key of ['moved','phoneClosed','radioClosed'])if(!state.training.flags[key]){state.training.flags[key]=true;changed=true} state.training.chapterStarted=Array.isArray(state.training.chapterStarted)?state.training.chapterStarted:[]; let chapter=1;try{if(typeof trainingStoryChapter==='function')chapter=Number(trainingStoryChapter())||1}catch(_){} if(!state.training.chapterStarted.includes(chapter)){state.training.chapterStarted.push(chapter);changed=true} if(changed)queueSaveSync(); } function controlMission(){ const t=controlTutorial();if(!t||t.done)return null; try{ const g=typeof window.__VANCERTS_R36B52A_GUIDANCE==='function'?window.__VANCERTS_R36B52A_GUIDANCE():null; if(g)return{mode:'controls',chapter:0,index:Math.min(Number(t.step||0)+1,6),total:6,title:g.title,text:g.text,focus:Number(t.step||0)>=5?'drive':'controls',actionLabel:'SHOW EXACT STEP',action:''}; }catch(_){} return null; } function currentStoryMission(){ const controls=controlMission();if(controls)return controls; syncTrainingSystems(); try{ const m=typeof window.currentTrainingMission==='function'?window.currentTrainingMission():null; if(m)return Object.assign({mode:'story'},m); }catch(e){console.warn(BUILD+' mission',e)} return{mode:'story',chapter:1,index:1,total:1,title:careerLabel()+' • CONTINUE THE STORY',text:'Follow the current objective and interact with the highlighted business, phone app, or story board.',focus:'objective',actionLabel:'SHOW EXACT STEP',action:''}; } function placeTarget(id,label){ const p=(typeof places!=='undefined'&&Array.isArray(places))?places.find(x=>x.id===id):null;if(!p)return null; const rect=p.interactionRect||p.setup||p.parking||null; return{id:p.id,label:label||p.name||p.short||id,x:p.interact?.x??p.x+p.w/2,y:p.interact?.y??p.y+p.h/2,rect,radius:95}; } function homeTarget(id,label){ const h=(typeof R36B45_HOMES!=='undefined'&&R36B45_HOMES)?R36B45_HOMES[id]:null;if(!h)return null; const rect=h.pullin||h.lot||null; return{id:'home-'+id,label:label||h.label||id,x:h.door?h.door.x+h.door.w/2:(h.spawn?.x||0),y:h.door?h.door.y+h.door.h+20:(h.spawn?.y||0),rect,radius:105}; } function insideRect(x,y,r,pad=0){return !!r&&x>=r.x-pad&&x<=r.x+r.w+pad&&y>=r.y-pad&&y<=r.y+r.h+pad} function reached(t){ if(!t||typeof van==='undefined')return true; if(insideRect(van.x,van.y,t.rect,12))return true; return Math.hypot(van.x-t.x,van.y-t.y)<=Number(t.radius||95); } function textDestination(m){ const hay=((m?.title||'')+' '+(m?.text||'')).toUpperCase(); const homes=[['BAND HOUSE','band'],['PAUL • AUDIO HOUSE','audio'],['AUDIO HOUSE','audio'],['OWNER HOME','owner'],['VANCERTS HOUSE','owner']]; for(const [name,id] of homes)if(hay.includes(name))return homeTarget(id,name); const aliases={ shop:['GIG BAG ATX','GIG BAG'],hq:['BYOB AUSTIN','VANCERTS HQ','BYOB'],fsg:['FSG PRINTSHOP','FSG'], leftway:['LEFTWAY STUDIOS','LEFTWAY'],kazi:['KAZI 88.7 FM','KAZI'],worldliquor:['WORLD LIQUOR'], blueowl:['BLUE OWL'],republic:['REPUBLIC SQUARE'],hope:['HOPE OUTDOOR'],topnotch:['TOP NOTCH'], mama:['MAMA DEAREST'],juan:['JUAN IN A MILLION'],tascam:['TASCAM'],jbl:['JBL PRO'] }; for(const [id,names] of Object.entries(aliases))if(names.some(n=>hay.includes(n)))return placeTarget(id,names[0]); if(typeof places!=='undefined'&&Array.isArray(places)){ const candidates=places.filter(p=>p&&p.id).sort((a,b)=>String(b.name||'').length-String(a.name||'').length); for(const p of candidates){const names=[p.name,p.short,p.abbr].filter(Boolean).map(v=>String(v).toUpperCase());if(names.some(n=>n.length>2&&hay.includes(n)))return placeTarget(p.id,p.name)} } return null; } function physicalDestination(m=currentStoryMission()){ const t=controlTutorial(); if(t&&!t.done&&Number(t.step||0)<5)return null; if(typeof state==='undefined'||typeof van==='undefined')return null; if(state.activeJob){ const target=state.activeJob.phase==='pickup'?placeTarget('shop','GIG BAG ATX'):placeTarget(state.activeJob.id); return reached(target)?null:target; } if(state.pendingOffer||((typeof unpaidTotal==='function')&&unpaidTotal()>0))return null; if(state.story?.festivalActive){const route=typeof FESTIVAL_ROUTE!=='undefined'?FESTIVAL_ROUTE:[],id=route[Number(state.story.festivalIndex)||0],q=id?placeTarget(id):null;return reached(q)?null:q} if(state.story?.secondFestivalActive){const route=state.story.secondFestivalRoute||[],id=route[Number(state.story.secondFestivalIndex)||0],q=id==='hq'?placeTarget('hq','BYOB AUSTIN'):placeTarget(id);return reached(q)?null:q} const id=careerId();let q=null; if(id==='band'){ const b=typeof bandStory==='function'?bandStory():(state.bandStory||{}),assets=typeof leftwayBandAssets==='function'?leftwayBandAssets():[]; if(!b.started)q=homeTarget('band','BAND HOUSE'); else if(!assets.length)q=placeTarget('leftway','LEFTWAY STUDIOS'); else q=homeTarget('band','BAND HOUSE'); }else if(id==='audio'||id==='stagehand'){ const title=String(m?.title||'').toUpperCase(); if(title.includes('LOAD THE SHOW'))q=placeTarget('shop','GIG BAG ATX'); else if(title.includes('FIRST')||title.includes('WORK ORDER')||title.includes('GO TO THE FIRST JOB'))q=placeTarget('fsg','FSG PRINTSHOP'); else q=textDestination(m); }else{ const title=String(m?.title||'').toUpperCase(); if(title.includes('BUY THE NEXT')&&title.includes('PERMIT'))q=placeTarget('hq','BYOB AUSTIN'); else if(title.includes('BOOK WORLD LIQUOR'))q=placeTarget('worldliquor','WORLD LIQUOR'); else if(title.includes('BUILD THE SOUTH SIDE ROUTE')){ const order=typeof WEST_EXPANSION_ORDER!=='undefined'?WEST_EXPANSION_ORDER:[];const next=order.find(pid=>!state.completed?.includes(pid));q=next?placeTarget(next):null; }else q=textDestination(m); if(!q&&m?.focus==='drive'){ const order=typeof ORDER!=='undefined'?ORDER:['fsg','blueowl','republic','hope','topnotch','leftway'];const next=order.find(pid=>!state.completed?.includes(pid));q=next?placeTarget(next):placeTarget('hq','BYOB AUSTIN'); } } return reached(q)?null:q; } function navigationCopy(text,destination){ let copy=String(text||''); copy=copy .replace(/faint blinking yellow line/gi,'red road arrows') .replace(/faint yellow road-side route/gi,'red road arrows') .replace(/faint yellow[^.]*route/gi,'red road arrows') .replace(/faint blinking gold road markers/gi,'red road arrows') .replace(/gold road markers/gi,'red road arrows') .replace(/gold arrow/gi,'red road arrows') .replace(/gold Training Wheels box/gi,'Training Wheels objective box') .replace(/Follow the route/gi,'Follow the red road arrows and Nookia GPS line'); if(destination&&!/NOOKIA GPS/i.test(copy))copy+=` GPS: Follow the red road arrows and the red line on the Nookia map to ${destination.label}.`; return copy; } function safeAction(action){ const source=String(action||'').trim();if(!source)return false; const match=source.match(/^([A-Za-z_$][\w$]*)\s*\(\s*\)\s*;?$/);if(!match||typeof window[match[1]]!=='function')return false; window[match[1]]();return true; } function renderObjective(force=false){ try{ if(!$id('splash')?.classList.contains('hidden'))return; const m=currentStoryMission(),dest=physicalDestination(m),title=String(m.title||careerLabel()+' • CURRENT STORY'),text=navigationCopy(m.text,dest); const progress=m.mode==='controls'?`STEP ${Math.min(Number(m.index)||1,6)} / 6`:`CHAPTER ${Number(m.chapter)||1} • STEP ${Number(m.index)||1} / ${Number(m.total)||1}`; const signature=[careerId(),m.key||'',title,text,progress,dest?.id||''].join('|'); const obj=$id('objective'),titleEl=$id('objectiveTitle'),textEl=$id('objectiveText'),badge=$id('trainingBadge'),progressEl=$id('trainingProgress'),guide=$id('trainingGuide'); if(obj)obj.classList.add('r36b51eTraining','r36b52gStoryAuthority'); if(titleEl&&titleEl.textContent!==title)titleEl.textContent=title; if(textEl&&textEl.textContent!==text)textEl.textContent=text; if(badge){const b=state.training?.enabled===false?'MISSION GUIDE':'TRAINING WHEELS';if(badge.textContent!==b)badge.textContent=b} if(progressEl){progressEl.classList.add('r36b52gProgress');if(progressEl.textContent!==progress)progressEl.textContent=progress} if(guide){ const label=m.actionLabel||'SHOW EXACT STEP';if(guide.textContent!==label)guide.textContent=label; guide.onclick=function(){if(!safeAction(m.action)&&typeof toast==='function')toast(text)}; } const pt=$id('phoneObjectiveTitle'),px=$id('phoneObjectiveText');if(pt&&pt.textContent!==title)pt.textContent=title;if(px&&px.textContent!==text)px.textContent=text; lastSignature=signature; return{mission:m,destination:dest,signature}; }catch(e){console.error(BUILD+' render',e);return null} } function cameraTransform(){ const zoom=typeof cameraZoomLevel==='function'?cameraZoomLevel():1,scale=typeof cameraScale==='function'?cameraScale():1,viewW=W/scale,viewH=H/scale; const full=typeof FULL_CITY_VIEW_BOUNDS!=='undefined'?FULL_CITY_VIEW_BOUNDS:{x:0,y:0,w:world.w,h:world.h},bird=typeof BIRD_EYE_VIEW_BOUNDS!=='undefined'?BIRD_EYE_VIEW_BOUNDS:full; const camX=zoom===4?full.x-(viewW-full.w)/2:zoom===5?bird.x-(viewW-bird.w)/2:van.x-viewW/2; const camY=zoom===4?full.y-(viewH-full.h)/2:zoom===5?bird.y-(viewH-bird.h)/2:van.y-viewH/2; return{scale,camX,camY}; } function arrowHelps(x,y,dx,dy,t){ const before=Math.hypot(t.x-x,t.y-y),after=Math.hypot(t.x-(x+dx*70),t.y-(y+dy*70));return after+2<before; } function paintArrow(x,y,symbol,dx,dy,t){ if(!arrowHelps(x,y,dx,dy,t))return; ctx.lineWidth=5;ctx.strokeStyle='rgba(23,21,20,.82)';ctx.fillStyle=RED;ctx.strokeText(symbol,x,y);ctx.fillText(symbol,x,y); } function drawRedRoadGuidance(){ const t=physicalDestination();if(!t||typeof ctx==='undefined'||typeof roads==='undefined'||!Array.isArray(roads))return; const tr=cameraTransform();ctx.save();ctx.scale(tr.scale,tr.scale);ctx.translate(-tr.camX,-tr.camY);ctx.globalAlpha=.98;ctx.font='1000 22px monospace';ctx.textAlign='center';ctx.textBaseline='middle';ctx.lineJoin='round'; for(const r of roads){ if(r.w>r.h){for(let x=r.x+180;x<r.x+r.w;x+=420){paintArrow(x,r.y+r.h*.25,'←',-1,0,t);paintArrow(x,r.y+r.h*.75,'→',1,0,t)}} else{for(let y=r.y+180;y<r.y+r.h;y+=420){paintArrow(r.x+r.w*.25,y,'↓',0,1,t);paintArrow(r.x+r.w*.75,y,'↑',0,-1,t)}} } const pulse=1+.18*Math.sin(performance.now()/180);ctx.strokeStyle=RED;ctx.fillStyle='rgba(230,74,56,.18)';ctx.lineWidth=6;ctx.beginPath();ctx.arc(t.x,t.y,28*pulse,0,Math.PI*2);ctx.fill();ctx.stroke();ctx.fillStyle=PAPER;ctx.font='1000 12px system-ui';ctx.fillText('DESTINATION',t.x,t.y-38);ctx.restore(); } function mapPoint(x,y,w,h){return{x:Math.max(7,Math.min(w-7,x/world.w*w)),y:Math.max(7,Math.min(h-7,y/world.h*h))}} function drawPhoneGps(){ const t=physicalDestination(),c=typeof miniCtx!=='undefined'?miniCtx:null,canvas=$id('miniCanvas');if(!c||!canvas){return}canvas.classList.toggle('r36b52gGpsActive',!!t);if(!t)return; const w=Number(canvas.width)||340,h=Number(canvas.height)||190,a=mapPoint(van.x,van.y,w,h),b=mapPoint(t.x,t.y,w,h),ang=Math.atan2(b.y-a.y,b.x-a.x),sx=a.x+Math.cos(ang)*10,sy=a.y+Math.sin(ang)*10; c.save();c.lineCap='round';c.lineJoin='round';c.shadowColor='rgba(23,21,20,.75)';c.shadowBlur=3;c.strokeStyle=INK;c.lineWidth=7;c.beginPath();c.moveTo(sx,sy);c.lineTo(b.x,b.y);c.stroke();c.shadowBlur=0;c.strokeStyle=RED;c.lineWidth=4;c.beginPath();c.moveTo(sx,sy);c.lineTo(b.x,b.y);c.stroke(); c.translate(a.x,a.y);c.rotate(ang);c.fillStyle=RED;c.strokeStyle=PAPER;c.lineWidth=2;c.beginPath();c.moveTo(11,0);c.lineTo(-7,-6);c.lineTo(-3,0);c.lineTo(-7,6);c.closePath();c.fill();c.stroke();c.setTransform(1,0,0,1,0,0); const pulse=5+2*Math.sin(performance.now()/200);c.fillStyle=RED;c.strokeStyle=PAPER;c.lineWidth=2;c.beginPath();c.arc(b.x,b.y,pulse,0,Math.PI*2);c.fill();c.stroke(); const label='NEXT • '+String(t.label||'DESTINATION').toUpperCase();c.font='1000 9px monospace';const tw=Math.min(w-12,c.measureText(label).width+12),lx=Math.max(tw/2+4,Math.min(w-tw/2-4,b.x)),ly=Math.max(12,Math.min(h-12,b.y-14));c.fillStyle='rgba(23,21,20,.9)';c.fillRect(lx-tw/2,ly-9,tw,18);c.strokeStyle=RED;c.lineWidth=1.5;c.strokeRect(lx-tw/2,ly-9,tw,18);c.fillStyle=PAPER;c.textAlign='center';c.textBaseline='middle';c.fillText(label,lx,ly);c.restore(); } /* Old route renderers receive no destination; this build owns all visible GPS guidance. */ window.__VANCERTS_ACTIVE_DESTINATION=function(){return null}; window.__VANCERTS_R36B52G_DESTINATION=physicalDestination; window.__VANCERTS_R36B52G_MISSION=currentStoryMission; window.__VANCERTS_R36B52G_RENDER=renderObjective; window.__VANCERTS_STABLE_OBJECTIVE=renderObjective; const previousHud=window.hud; if(typeof previousHud==='function')window.hud=hud=function(){const r=previousHud.apply(this,arguments);renderObjective(true);return r}; const previousDraw=window.draw||draw; window.draw=draw=function(){return previousDraw.apply(this,arguments)}; const previousMini=window.drawMini||drawMini; window.drawMini=drawMini=function(){return previousMini.apply(this,arguments)}; const previousSave=window.save; if(typeof previousSave==='function')window.save=save=function(){const r=previousSave.apply(this,arguments);queueMicrotask(()=>renderObjective());return r}; document.addEventListener('click',()=>{setTimeout(()=>renderObjective(),0);setTimeout(()=>renderObjective(),90)},true); document.addEventListener('pointerup',()=>setTimeout(()=>renderObjective(),0),true); addEventListener('resize',()=>setTimeout(()=>renderObjective(),50),{passive:true}); setTimeout(()=>{syncTrainingSystems();renderObjective(true);try{if(typeof hud==='function')hud()}catch(_){}},500); console.info(BUILD,'story and GPS authority ready'); })(); </script> </body></html> <style id="r36b47f-permit-action-alignment"> /* R36B47F — keep every permit action aligned to the same full inner frame width. */ .permitGateShell{box-sizing:border-box!important} .permitGateGrid,.permitGateActionsWide,.permitGateLock{box-sizing:border-box!important;width:100%!important;max-width:none!important} .permitGateActionsWide{ display:grid!important; grid-template-columns:repeat(2,minmax(0,1fr))!important; column-gap:10px!important; row-gap:10px!important; padding:0!important; margin-left:0!important; margin-right:0!important; justify-self:stretch!important; align-self:stretch!important; } .permitGateActionsWide button{ box-sizing:border-box!important; width:100%!important; max-width:none!important; min-width:0!important; margin:0!important; } .permitGateActionsWide .permitGateCamera,.permitGateActionsWide .permitGateIssue{grid-column:1/-1!important} @media(max-width:760px),(pointer:coarse){ .permitGateActionsWide{column-gap:8px!important;row-gap:8px!important} } </style> <style id="r36b47g-permit-full-bleed"> /* R36B47I — desktop Take Picture uses a live camera preview before opening the permit crop editor. */ .permitGateActionsWide{ width:calc(100% + 16px)!important; max-width:none!important; margin-left:0!important; margin-right:-16px!important; padding-left:0!important; padding-right:0!important; } .permitGateActionsWide button{border-left-width:4px!important;border-right-width:4px!important} @media(max-width:760px),(pointer:coarse){ .permitGateActionsWide{ width:calc(100% + 8px)!important; margin-left:0!important; margin-right:-8px!important; } } </style> <script> /* R36B48B — Band House hero-property rebuild. */ (function(){ if(!window.R36B45_HOMES || !R36B45_HOMES.band) return; const band=R36B45_HOMES.band; band.building={x:1410,y:3025,w:365,h:210}; band.door={x:1557,y:3191,w:70,h:50}; band.spawn={x:1355,y:2896,angle:-Math.PI/2}; band.road={x:1270,y:2600,w:170,h:190}; band.pullin={x:1260,y:2885,w:190,h:110}; band.stage={x:1062,y:3020,w:245,h:158}; band.heroVersion='R36B48B'; R36B45_HOME_ROADS=Object.values(R36B45_HOMES).flatMap(h=>[h.road,h.pullin]); const oldGround=drawR36B45ResidentialGround; drawR36B45ResidentialGround=function(h){ if(!h || h.id!=='band') return oldGround(h); const l=h.lot; ctx.save(); ctx.fillStyle='#668d52';ctx.fillRect(l.x,l.y,l.w,l.h); // mown lawn strips and a subtle drive-around loop, while keeping the lot fully drivable. for(let i=0;i<12;i++){ ctx.fillStyle=i%2?'rgba(255,255,255,.022)':'rgba(0,0,0,.018)'; ctx.fillRect(l.x+i*l.w/12,l.y,l.w/12,l.h); } ctx.strokeStyle='rgba(210,196,142,.14)';ctx.lineWidth=58;ctx.lineJoin='round'; ctx.strokeRect(l.x+58,l.y+58,l.w-116,l.h-116); ctx.strokeStyle='rgba(255,255,255,.055)';ctx.lineWidth=3; ctx.strokeRect(l.x+58,l.y+58,l.w-116,l.h-116); // City road stops at the property line; the yard itself stays open grass. ctx.fillStyle='#41464a';ctx.fillRect(h.road.x,h.road.y,h.road.w,h.road.h); ctx.fillStyle='rgba(255,255,255,.045)';ctx.fillRect(h.road.x+12,h.road.y,h.road.w-24,h.road.h); ctx.strokeStyle='#d7b64e';ctx.lineWidth=4;ctx.setLineDash([24,19]); ctx.beginPath();ctx.moveTo(h.road.x+h.road.w/2,h.road.y+8);ctx.lineTo(h.road.x+h.road.w/2,l.y-4);ctx.stroke();ctx.setLineDash([]); // Soft tire-worn entry, not a second road layer. const cx=h.road.x+h.road.w/2; ctx.strokeStyle='rgba(91,77,52,.22)';ctx.lineWidth=12; ctx.beginPath();ctx.moveTo(cx-24,l.y);ctx.lineTo(cx-24,l.y+132);ctx.moveTo(cx+24,l.y);ctx.lineTo(cx+24,l.y+132);ctx.stroke(); ctx.restore(); }; function poly(points,fill,stroke='#171514',lw=4){ ctx.beginPath();ctx.moveTo(points[0][0],points[0][1]);for(let i=1;i<points.length;i++)ctx.lineTo(points[i][0],points[i][1]);ctx.closePath();ctx.fillStyle=fill;ctx.fill();if(stroke){ctx.strokeStyle=stroke;ctx.lineWidth=lw;ctx.stroke();} } function roundedRect(x,y,w,h,r,fill,stroke='#171514',lw=3){ ctx.beginPath();ctx.roundRect(x,y,w,h,r);ctx.fillStyle=fill;ctx.fill();if(stroke){ctx.strokeStyle=stroke;ctx.lineWidth=lw;ctx.stroke();} } function bandFlower(x,y,c){ ctx.fillStyle='#315f2d';ctx.fillRect(x-1,y,2,10);ctx.fillStyle=c;for(let a=0;a<Math.PI*2;a+=Math.PI/2){ctx.beginPath();ctx.arc(x+Math.cos(a)*4,y+Math.sin(a)*4,3,0,Math.PI*2);ctx.fill()}ctx.fillStyle='#f1b83e';ctx.beginPath();ctx.arc(x,y,2.2,0,Math.PI*2);ctx.fill(); } function drawBandHouseHero(h){ const b=h.building,x=b.x,y=b.y,w=b.w,hh=b.h,d=54; ctx.save(); // Shadow follows the same northeast-light / southwest-shadow logic as the city parcels. poly([[x-34,y+44],[x+w-34,y+44],[x+w+d-34,y+hh+d+38],[x+d-34,y+hh+d+38]],'rgba(0,0,0,.30)',null); // Front and right walls, viewed from above. ctx.fillStyle='#d6b786';ctx.fillRect(x,y+38,w,hh-38);ctx.strokeStyle='#171514';ctx.lineWidth=5;ctx.strokeRect(x,y+38,w,hh-38); poly([[x+w,y+38],[x+w+d,y+38+d],[x+w+d,y+hh+d],[x+w,y+hh]],'#ae875f','#171514',5); // Wide roof plane facing the viewer; it covers the whole building footprint. const ridgeY=y-58; poly([[x-18,y+44],[x+70,ridgeY],[x+w-62,ridgeY],[x+w+20,y+44],[x+w,y+78],[x,y+78]],'#6a3731','#171514',5); poly([[x+70,ridgeY],[x+w-62,ridgeY],[x+w+d-20,y-5+d],[x+d+32,y-5+d]],'#4f2827','#171514',5); // Shingle texture and fascia. ctx.save();ctx.beginPath();ctx.rect(x-10,y-48,w+20,122);ctx.clip();ctx.strokeStyle='rgba(255,255,255,.10)';ctx.lineWidth=2; for(let sy=y-42;sy<y+72;sy+=13){ctx.beginPath();ctx.moveTo(x-30,sy);ctx.lineTo(x+w+35,sy);ctx.stroke()} for(let sx=x;sx<x+w;sx+=26){ctx.beginPath();ctx.moveTo(sx,y-55);ctx.lineTo(sx+36,y+75);ctx.stroke()} ctx.restore(); ctx.strokeStyle='#241817';ctx.lineWidth=8;ctx.beginPath();ctx.moveTo(x-18,y+44);ctx.lineTo(x+70,ridgeY);ctx.lineTo(x+w-62,ridgeY);ctx.lineTo(x+w+20,y+44);ctx.stroke(); // Chimney on the back roof plane. ctx.fillStyle='#5e4033';ctx.fillRect(x+w-92,y-68,34,48);ctx.strokeStyle='#171514';ctx.lineWidth=4;ctx.strokeRect(x+w-92,y-68,34,48);ctx.fillStyle='#2a2522';ctx.fillRect(x+w-98,y-73,46,10); // Wall windows only, never on the roof. const windows=[[x+36,y+118,62,42],[x+w-105,y+118,62,42]]; for(const q of windows){ctx.fillStyle='#a7d5e6';ctx.fillRect(...q);ctx.strokeStyle='#40535b';ctx.lineWidth=3;ctx.strokeRect(...q);ctx.strokeStyle='rgba(255,255,255,.75)';ctx.lineWidth=2;ctx.beginPath();ctx.moveTo(q[0]+q[2]/2,q[1]+2);ctx.lineTo(q[0]+q[2]/2,q[1]+q[3]-2);ctx.moveTo(q[0]+2,q[1]+q[3]/2);ctx.lineTo(q[0]+q[2]-2,q[1]+q[3]/2);ctx.stroke()} poly([[x+w+15,y+126],[x+w+44,y+155],[x+w+44,y+194],[x+w+15,y+165]],'#8dbed0','#40535b',3); // Front door, porch and steps. ctx.fillStyle='#38251f';ctx.fillRect(h.door.x,h.door.y,h.door.w,h.door.h);ctx.strokeStyle='#171514';ctx.lineWidth=4;ctx.strokeRect(h.door.x,h.door.y,h.door.w,h.door.h); ctx.fillStyle='#a17e58';ctx.fillRect(h.door.x-28,h.door.y+h.door.h,h.door.w+56,18);ctx.fillStyle='#7a6046';ctx.fillRect(h.door.x-18,h.door.y+h.door.h+18,h.door.w+36,10); ctx.fillStyle='#f1b83e';ctx.beginPath();ctx.arc(h.door.x+h.door.w-11,h.door.y+26,4,0,Math.PI*2);ctx.fill(); // Foundation flowers. const colors=['#e64a38','#f1b83e','#9766a3','#f0e9dc'];for(let i=0;i<11;i++)bandFlower(x+20+i*31,y+hh+12,colors[i%colors.length]); ctx.fillStyle='rgba(17,21,20,.84)';ctx.fillRect(x+24,y+hh+34,w-48,30);ctx.fillStyle='#f4e6be';ctx.font='1000 12px system-ui';ctx.textAlign='center';ctx.fillText('BAND HOUSE',x+w/2,y+hh+55); ctx.restore(); } function drawBandStageHero(s){ const{x,y,w,h}=s,d=24;ctx.save(); // Southwest shadow. poly([[x-24,y+26],[x+w-24,y+26],[x+w+d-24,y+h+d+28],[x+d-24,y+h+d+28]],'rgba(0,0,0,.30)',null); // Raised wooden deck and front apron. ctx.fillStyle='#2c2b2a';ctx.fillRect(x,y,w,h);ctx.strokeStyle='#111';ctx.lineWidth=5;ctx.strokeRect(x,y,w,h); poly([[x,y+h],[x-d,y+h+d],[x+w-d,y+h+d],[x+w,y+h]],'#70543c','#171514',4); // Back wall / canopy frame at the north end. ctx.fillStyle='#171719';ctx.fillRect(x+10,y+12,w-20,42);ctx.strokeStyle='#47494b';ctx.lineWidth=4;ctx.strokeRect(x+10,y+12,w-20,42); ctx.strokeStyle='#8e989b';ctx.lineWidth=5;ctx.strokeRect(x+12,y-30,w-24,38); ctx.fillStyle='rgba(30,30,32,.92)';ctx.fillRect(x+13,y-29,w-26,22); // Drum riser and kit. ctx.fillStyle='#595959';ctx.fillRect(x+w/2-42,y+56,84,38);ctx.strokeStyle='#111';ctx.lineWidth=3;ctx.strokeRect(x+w/2-42,y+56,84,38); ctx.fillStyle='#b9b9b9';ctx.beginPath();ctx.arc(x+w/2,y+73,16,0,Math.PI*2);ctx.fill();ctx.stroke();ctx.fillStyle='#333';ctx.beginPath();ctx.arc(x+w/2-26,y+65,8,0,Math.PI*2);ctx.arc(x+w/2+26,y+65,8,0,Math.PI*2);ctx.fill(); // Speaker stacks. for(const sx of [x+15,x+w-43]){ctx.fillStyle='#111';ctx.fillRect(sx,y+70,28,54);ctx.strokeStyle='#555';ctx.lineWidth=3;ctx.strokeRect(sx,y+70,28,54);ctx.fillStyle='#4d4d4d';ctx.beginPath();ctx.arc(sx+14,y+87,8,0,Math.PI*2);ctx.arc(sx+14,y+108,10,0,Math.PI*2);ctx.fill()} // Mic stands and monitor wedges. ctx.strokeStyle='#c4c7c8';ctx.lineWidth=3;for(const mx of [x+76,x+w-76]){ctx.beginPath();ctx.moveTo(mx,y+74);ctx.lineTo(mx,y+122);ctx.moveTo(mx,y+82);ctx.lineTo(mx+13,y+76);ctx.stroke();poly([[mx-15,y+132],[mx+15,y+132],[mx+10,y+146],[mx-10,y+146]],'#373737','#111',2)} // SOUTH-END light truss, clearly on the audience edge of the stage. const ty=y+h+9;ctx.strokeStyle='#aab2b4';ctx.lineWidth=6;ctx.beginPath();ctx.moveTo(x+9,ty);ctx.lineTo(x+w-9,ty);ctx.moveTo(x+13,y+h-14);ctx.lineTo(x+13,ty+24);ctx.moveTo(x+w-13,y+h-14);ctx.lineTo(x+w-13,ty+24);ctx.stroke(); const lightColors=['#e64a38','#f1b83e','#3f84a5','#9766a3','#e64a38'];for(let i=0;i<5;i++){const lx=x+35+i*(w-70)/4;ctx.fillStyle=lightColors[i];ctx.beginPath();ctx.arc(lx,ty,7,0,Math.PI*2);ctx.fill();ctx.strokeStyle='#222';ctx.lineWidth=2;ctx.stroke();ctx.fillStyle='rgba(241,184,62,.10)';poly([[lx-5,ty+7],[lx+5,ty+7],[lx+22,ty+42],[lx-22,ty+42]],'rgba(241,184,62,.08)',null)} ctx.fillStyle='#f4e6be';ctx.font='1000 10px system-ui';ctx.textAlign='center';ctx.fillText('BACKYARD PRACTICE STAGE',x+w/2,y+34); ctx.restore(); } function drawBandYardFun(h){ const l=h.lot;ctx.save(); // Hot tub with water and steps. roundedRect(1815,3072,132,90,18,'#6d665c','#2d2b29',4);roundedRect(1828,3084,106,64,14,'#3f91a9','#d8d0be',4);ctx.fillStyle='rgba(255,255,255,.28)';for(let i=0;i<4;i++){ctx.beginPath();ctx.arc(1845+i*23,3115+(i%2)*7,5,0,Math.PI*2);ctx.fill()}ctx.fillStyle='#8c704f';ctx.fillRect(1855,3164,54,12); // Beer pong table. ctx.fillStyle='#256a53';ctx.fillRect(1080,3245,126,50);ctx.strokeStyle='#f0e9dc';ctx.lineWidth=3;ctx.strokeRect(1080,3245,126,50);ctx.beginPath();ctx.moveTo(1143,3245);ctx.lineTo(1143,3295);ctx.stroke();ctx.fillStyle='#e64a38';for(let i=0;i<6;i++){ctx.beginPath();ctx.arc(1093+(i%3)*12,3260+Math.floor(i/3)*13,4,0,Math.PI*2);ctx.fill();ctx.beginPath();ctx.arc(1193-(i%3)*12,3260+Math.floor(i/3)*13,4,0,Math.PI*2);ctx.fill()} // Fire pit and chairs. ctx.fillStyle='#4c4237';ctx.beginPath();ctx.arc(1278,3342,33,0,Math.PI*2);ctx.fill();ctx.strokeStyle='#9c8265';ctx.lineWidth=6;ctx.stroke();ctx.fillStyle='#e64a38';ctx.beginPath();ctx.arc(1278,3342,13,0,Math.PI*2);ctx.fill();ctx.fillStyle='#d7b64e';ctx.beginPath();ctx.arc(1278,3338,7,0,Math.PI*2);ctx.fill(); for(const [cx,cy,a] of [[1228,3318,-.4],[1327,3318,.4],[1228,3375,.3],[1327,3375,-.3]]){ctx.save();ctx.translate(cx,cy);ctx.rotate(a);ctx.fillStyle='#83684c';ctx.fillRect(-16,-9,32,18);ctx.restore()} // Raised garden beds and flowers. for(let i=0;i<2;i++){const gy=3315+i*48;ctx.fillStyle='#775033';ctx.fillRect(1450,gy,188,34);ctx.strokeStyle='#3b2d22';ctx.lineWidth=4;ctx.strokeRect(1450,gy,188,34);for(let j=0;j<8;j++){ctx.fillStyle=j%2?'#4d8d42':'#6aa556';ctx.beginPath();ctx.arc(1464+j*22,gy+17,6,0,Math.PI*2);ctx.fill()}} for(let i=0;i<12;i++)bandFlower(1660+(i%6)*24,3312+Math.floor(i/6)*42,['#e64a38','#f1b83e','#9766a3'][i%3]); // Archery lane and target, kept inside the yard and away from the perimeter loop. ctx.strokeStyle='rgba(239,229,190,.32)';ctx.lineWidth=3;ctx.setLineDash([10,9]);ctx.beginPath();ctx.moveTo(1745,3380);ctx.lineTo(1930,3380);ctx.stroke();ctx.setLineDash([]); ctx.fillStyle='#e7ddc7';ctx.beginPath();ctx.arc(1935,3380,34,0,Math.PI*2);ctx.fill();ctx.strokeStyle='#433c33';ctx.lineWidth=4;ctx.stroke();for(const [r,c] of [[25,'#2b2b2b'],[18,'#e7ddc7'],[12,'#e64a38'],[6,'#f1b83e']]){ctx.fillStyle=c;ctx.beginPath();ctx.arc(1935,3380,r,0,Math.PI*2);ctx.fill()}ctx.fillStyle='#5a4936';ctx.fillRect(1929,3413,12,25); // Grill and cooler near the stage hangout area. ctx.fillStyle='#242424';ctx.beginPath();ctx.arc(1332,3158,22,Math.PI,0);ctx.fill();ctx.fillRect(1310,3158,44,9);ctx.strokeStyle='#242424';ctx.lineWidth=4;ctx.beginPath();ctx.moveTo(1318,3165);ctx.lineTo(1312,3193);ctx.moveTo(1346,3165);ctx.lineTo(1352,3193);ctx.stroke(); roundedRect(1338,3230,58,34,5,'#e9e5d8','#323232',3);ctx.fillStyle='#e64a38';ctx.fillRect(1342,3234,50,9); ctx.restore(); } drawR36B45BandHome=function(h){ drawBandStageHero(h.stage||band.stage); drawBandHouseHero(h); drawBandYardFun(h); drawHomeParkedVehicle(h,'band'); }; const oldBlocked=homeBuildingBlocked; homeBuildingBlocked=function(x,y){ if(oldBlocked(x,y)) return true; const h=R36B45_HOMES&&R36B45_HOMES.band,s=h&&h.stage;if(!s)return false; return x>=s.x-22&&x<=s.x+s.w+22&&y>=s.y-42&&y<=s.y+s.h+42; }; })(); </script> <script> /* R36B48B — Band House oblique-aerial geometry, NE light, open drivable lot. */ (function(){ if(!window.R36B45_HOMES || !R36B45_HOMES.band) return; const band=R36B45_HOMES.band; band.heroVersion='R36B48B'; band.building={x:1392,y:3010,w:390,h:238}; band.door={x:1547,y:3202,w:70,h:46}; band.stage={x:1050,y:3010,w:265,h:176}; band.spawn={x:1355,y:2888,angle:-Math.PI/2}; // The complete Band House grass lot is a legal driving surface. The house and stage remain solid. if(!Array.isArray(R36B45_HOME_ROADS)) R36B45_HOME_ROADS=[]; R36B45_HOME_ROADS=R36B45_HOME_ROADS.filter(r=>r!==band.lot); R36B45_HOME_ROADS.push(band.lot); // Remove the hard Band House fence that visually and physically trapped the player. const oldBorder=drawR36B45PropertyBorder; drawR36B45PropertyBorder=function(h){ if(h && h.id==='band') return; return oldBorder(h); }; function poly(points,fill,stroke='#171514',lw=4){ ctx.beginPath();ctx.moveTo(points[0][0],points[0][1]); for(let i=1;i<points.length;i++)ctx.lineTo(points[i][0],points[i][1]); ctx.closePath();ctx.fillStyle=fill;ctx.fill(); if(stroke){ctx.strokeStyle=stroke;ctx.lineWidth=lw;ctx.stroke()} } function rr(x,y,w,h,r,fill,stroke='#171514',lw=3){ ctx.beginPath();ctx.roundRect(x,y,w,h,r);ctx.fillStyle=fill;ctx.fill(); if(stroke){ctx.strokeStyle=stroke;ctx.lineWidth=lw;ctx.stroke()} } function shadowPoly(points){ poly(points.map(([x,y])=>[x-54,y+54]),'rgba(0,0,0,.29)',null,0); } function windowPanel(x,y,w,h,side=false){ if(side) poly([[x,y],[x+w,y+12],[x+w,y+h+12],[x,y+h]],'#9ccfe0','#40535b',3); else {ctx.fillStyle='#9ccfe0';ctx.fillRect(x,y,w,h);ctx.strokeStyle='#40535b';ctx.lineWidth=3;ctx.strokeRect(x,y,w,h)} ctx.strokeStyle='rgba(255,255,255,.72)';ctx.lineWidth=2; ctx.beginPath();ctx.moveTo(x+w/2,y+3);ctx.lineTo(x+w/2,y+h-3+(side?10:0));ctx.moveTo(x+3,y+h/2);ctx.lineTo(x+w-3,y+h/2+(side?10:0));ctx.stroke(); } function flower(x,y,c){ ctx.fillStyle='#315f2d';ctx.fillRect(x-1,y,2,9);ctx.fillStyle=c; for(let a=0;a<Math.PI*2;a+=Math.PI/2){ctx.beginPath();ctx.arc(x+Math.cos(a)*4,y+Math.sin(a)*4,3,0,Math.PI*2);ctx.fill()} ctx.fillStyle='#f1b83e';ctx.beginPath();ctx.arc(x,y,2,0,Math.PI*2);ctx.fill(); } function drawBandHouseB(h){ const b=h.building,x=b.x,y=b.y,w=b.w,hh=b.h,depth=64; ctx.save(); // Sun: northeast (upper-right). Shadow: southwest (lower-left), long at ~45-degree elevation. shadowPoly([[x-14,y+92],[x+w+44,y+92],[x+w+depth+44,y+hh+depth],[x+depth-14,y+hh+depth]]); // Vertical walls are intentionally shorter than the roof depth to create a 45–60° oblique aerial camera. const wallTop=y+122,wallBottom=y+hh; ctx.fillStyle='#d8bd91';ctx.fillRect(x,wallTop,w,wallBottom-wallTop); ctx.strokeStyle='#171514';ctx.lineWidth=5;ctx.strokeRect(x,wallTop,w,wallBottom-wallTop); poly([[x+w,wallTop],[x+w+depth,wallTop+depth],[x+w+depth,wallBottom+depth],[x+w,wallBottom]],'#b18b65','#171514',5); // Dominant roof top plane faces the viewer. Ridge runs east-west; front eave sits low on screen. const ridgeY=y+18,frontEave=y+136; poly([[x-26,frontEave],[x+72,ridgeY],[x+w-68,ridgeY],[x+w+30,frontEave],[x+w,frontEave+24],[x,frontEave+24]],'#783d38','#171514',5); // East roof return, darker but still visible from above. poly([[x+w-68,ridgeY],[x+w+30,frontEave],[x+w+depth+18,frontEave+depth-8],[x+w+depth-18,frontEave+depth+18],[x+w,frontEave+24]],'#542c2b','#171514',5); // Shingles remain inside the actual top roof plane. ctx.save();ctx.beginPath();ctx.moveTo(x-20,frontEave);ctx.lineTo(x+72,ridgeY);ctx.lineTo(x+w-68,ridgeY);ctx.lineTo(x+w+26,frontEave);ctx.lineTo(x+w,frontEave+20);ctx.lineTo(x,frontEave+20);ctx.closePath();ctx.clip(); ctx.strokeStyle='rgba(255,255,255,.11)';ctx.lineWidth=2; for(let sy=ridgeY+12;sy<frontEave+28;sy+=15){ctx.beginPath();ctx.moveTo(x-40,sy);ctx.lineTo(x+w+45,sy);ctx.stroke()} for(let sx=x-40;sx<x+w+60;sx+=28){ctx.beginPath();ctx.moveTo(sx,ridgeY-10);ctx.lineTo(sx+50,frontEave+35);ctx.stroke()} ctx.restore(); // Chimney on rear/east roof, with the same southwest cast shadow. ctx.fillStyle='rgba(0,0,0,.24)';ctx.fillRect(x+w-91-18,y+48+18,42,48); ctx.fillStyle='#5e4033';ctx.fillRect(x+w-91,y+36,36,54);ctx.strokeStyle='#171514';ctx.lineWidth=4;ctx.strokeRect(x+w-91,y+36,36,54);ctx.fillStyle='#2a2522';ctx.fillRect(x+w-98,y+30,50,10); // Windows sit only on vertical walls. windowPanel(x+42,wallTop+35,66,43,false); windowPanel(x+w-112,wallTop+35,66,43,false); windowPanel(x+w+18,wallTop+depth+18,36,44,true); // Door, porch and stairs on south/front face. ctx.fillStyle='#38251f';ctx.fillRect(h.door.x,h.door.y,h.door.w,h.door.h);ctx.strokeStyle='#171514';ctx.lineWidth=4;ctx.strokeRect(h.door.x,h.door.y,h.door.w,h.door.h); ctx.fillStyle='#a17e58';ctx.fillRect(h.door.x-28,h.door.y+h.door.h,h.door.w+56,18); ctx.fillStyle='#765d45';ctx.fillRect(h.door.x-18,h.door.y+h.door.h+18,h.door.w+36,10); ctx.fillStyle='#f1b83e';ctx.beginPath();ctx.arc(h.door.x+h.door.w-11,h.door.y+23,4,0,Math.PI*2);ctx.fill(); const colors=['#e64a38','#f1b83e','#9766a3','#f0e9dc']; for(let i=0;i<11;i++)flower(x+24+i*31,wallBottom+14,colors[i%colors.length]); ctx.fillStyle='rgba(17,21,20,.84)';ctx.fillRect(x+34,wallBottom+37,w-68,28);ctx.fillStyle='#f4e6be';ctx.font='1000 12px system-ui';ctx.textAlign='center';ctx.fillText('BAND HOUSE',x+w/2,wallBottom+56); ctx.restore(); } function drawBandStageB(s){ const{x,y,w,h}=s,depth=30; ctx.save(); shadowPoly([[x,y+28],[x+w,y+28],[x+w+depth,y+h+depth],[x+depth,y+h+depth]]); // True top deck in the same oblique aerial perspective as the house. poly([[x,y+24],[x+w,y+24],[x+w+depth,y+24+depth],[x+depth,y+24+depth]],'#343332','#111',5); // South/front fascia and east side face. poly([[x+depth,y+24+depth],[x+w+depth,y+24+depth],[x+w+depth,y+h+depth],[x+depth,y+h+depth]],'#6f523b','#171514',4); poly([[x+w,y+24],[x+w+depth,y+24+depth],[x+w+depth,y+h+depth],[x+w,y+h]],'#4b3b31','#171514',4); // Back canopy at north edge. poly([[x+14,y+24],[x+w-14,y+24],[x+w+5,y+60],[x+24,y+60]],'#171719','#3f4346',4); ctx.strokeStyle='#929b9e';ctx.lineWidth=5;ctx.beginPath();ctx.moveTo(x+18,y-20);ctx.lineTo(x+w-18,y-20);ctx.moveTo(x+18,y-20);ctx.lineTo(x+18,y+42);ctx.moveTo(x+w-18,y-20);ctx.lineTo(x+w-18,y+42);ctx.stroke(); // Drum riser, kit, speakers, mics and monitors, all placed on the visible deck. ctx.fillStyle='#5b5b5b';ctx.fillRect(x+w/2-45,y+63,90,38);ctx.strokeStyle='#111';ctx.lineWidth=3;ctx.strokeRect(x+w/2-45,y+63,90,38); ctx.fillStyle='#c2c2c2';ctx.beginPath();ctx.arc(x+w/2,y+79,16,0,Math.PI*2);ctx.fill();ctx.stroke(); ctx.fillStyle='#333';for(const dx of [-27,27]){ctx.beginPath();ctx.arc(x+w/2+dx,y+70,8,0,Math.PI*2);ctx.fill()} for(const sx of [x+18,x+w-47]){ctx.fillStyle='#111';ctx.fillRect(sx,y+71,30,58);ctx.strokeStyle='#5a5a5a';ctx.lineWidth=3;ctx.strokeRect(sx,y+71,30,58);ctx.fillStyle='#4e4e4e';ctx.beginPath();ctx.arc(sx+15,y+90,8,0,Math.PI*2);ctx.arc(sx+15,y+114,10,0,Math.PI*2);ctx.fill()} ctx.strokeStyle='#c4c7c8';ctx.lineWidth=3;for(const mx of [x+82,x+w-82]){ctx.beginPath();ctx.moveTo(mx,y+78);ctx.lineTo(mx,y+130);ctx.moveTo(mx,y+87);ctx.lineTo(mx+14,y+80);ctx.stroke();poly([[mx-16,y+137],[mx+16,y+137],[mx+11,y+150],[mx-11,y+150]],'#373737','#111',2)} // Light truss sits on the SOUTH audience edge, not behind the stage. const ty=y+h+depth-4; ctx.strokeStyle='#aab2b4';ctx.lineWidth=6;ctx.beginPath();ctx.moveTo(x+depth+8,ty);ctx.lineTo(x+w+depth-8,ty);ctx.moveTo(x+depth+10,ty-34);ctx.lineTo(x+depth+10,ty+20);ctx.moveTo(x+w+depth-10,ty-34);ctx.lineTo(x+w+depth-10,ty+20);ctx.stroke(); const lc=['#e64a38','#f1b83e','#3f84a5','#9766a3','#e64a38']; for(let i=0;i<5;i++){const lx=x+depth+36+i*(w-72)/4;ctx.fillStyle=lc[i];ctx.beginPath();ctx.arc(lx,ty,7,0,Math.PI*2);ctx.fill();ctx.strokeStyle='#222';ctx.lineWidth=2;ctx.stroke()} ctx.fillStyle='#f4e6be';ctx.font='1000 10px system-ui';ctx.textAlign='center';ctx.fillText('BACKYARD PRACTICE STAGE',x+w/2,y+49); ctx.restore(); } function drawYardB(h){ ctx.save(); // Open perimeter loop is shown only by subtle mowing, never by a fence or collision line. const l=h.lot;ctx.strokeStyle='rgba(255,255,255,.07)';ctx.lineWidth=44;ctx.strokeRect(l.x+48,l.y+48,l.w-96,l.h-96); // Hot tub. rr(1810,3072,132,88,18,'#6d665c','#2d2b29',4);rr(1823,3084,106,62,14,'#3f91a9','#d8d0be',4); ctx.fillStyle='rgba(255,255,255,.30)';for(let i=0;i<4;i++){ctx.beginPath();ctx.arc(1840+i*23,3113+(i%2)*7,5,0,Math.PI*2);ctx.fill()} // Beer pong. ctx.fillStyle='#256a53';ctx.fillRect(1078,3252,130,50);ctx.strokeStyle='#f0e9dc';ctx.lineWidth=3;ctx.strokeRect(1078,3252,130,50);ctx.beginPath();ctx.moveTo(1143,3252);ctx.lineTo(1143,3302);ctx.stroke(); ctx.fillStyle='#e64a38';for(let i=0;i<6;i++){ctx.beginPath();ctx.arc(1092+(i%3)*12,3267+Math.floor(i/3)*13,4,0,Math.PI*2);ctx.fill();ctx.beginPath();ctx.arc(1194-(i%3)*12,3267+Math.floor(i/3)*13,4,0,Math.PI*2);ctx.fill()} // Fire pit and seats. ctx.fillStyle='#4c4237';ctx.beginPath();ctx.arc(1276,3344,34,0,Math.PI*2);ctx.fill();ctx.strokeStyle='#9c8265';ctx.lineWidth=6;ctx.stroke();ctx.fillStyle='#e64a38';ctx.beginPath();ctx.arc(1276,3344,13,0,Math.PI*2);ctx.fill();ctx.fillStyle='#d7b64e';ctx.beginPath();ctx.arc(1276,3340,7,0,Math.PI*2);ctx.fill(); for(const [cx,cy,a] of [[1226,3320,-.4],[1325,3320,.4],[1226,3378,.3],[1325,3378,-.3]]){ctx.save();ctx.translate(cx,cy);ctx.rotate(a);ctx.fillStyle='#83684c';ctx.fillRect(-16,-9,32,18);ctx.restore()} // Garden beds and flowers. for(let i=0;i<2;i++){const gy=3318+i*48;ctx.fillStyle='#775033';ctx.fillRect(1450,gy,190,34);ctx.strokeStyle='#3b2d22';ctx.lineWidth=4;ctx.strokeRect(1450,gy,190,34);for(let j=0;j<8;j++){ctx.fillStyle=j%2?'#4d8d42':'#6aa556';ctx.beginPath();ctx.arc(1465+j*22,gy+17,6,0,Math.PI*2);ctx.fill()}} for(let i=0;i<12;i++)flower(1660+(i%6)*24,3315+Math.floor(i/6)*42,['#e64a38','#f1b83e','#9766a3'][i%3]); // Archery lane stays clear of the drivable perimeter. ctx.strokeStyle='rgba(239,229,190,.32)';ctx.lineWidth=3;ctx.setLineDash([10,9]);ctx.beginPath();ctx.moveTo(1745,3380);ctx.lineTo(1928,3380);ctx.stroke();ctx.setLineDash([]); ctx.fillStyle='#e7ddc7';ctx.beginPath();ctx.arc(1935,3380,34,0,Math.PI*2);ctx.fill();ctx.strokeStyle='#433c33';ctx.lineWidth=4;ctx.stroke(); for(const [r,c] of [[25,'#2b2b2b'],[18,'#e7ddc7'],[12,'#e64a38'],[6,'#f1b83e']]){ctx.fillStyle=c;ctx.beginPath();ctx.arc(1935,3380,r,0,Math.PI*2);ctx.fill()} ctx.fillStyle='#5a4936';ctx.fillRect(1929,3413,12,25); ctx.restore(); } drawR36B45BandHome=function(h){ drawBandStageB(h.stage||band.stage); drawBandHouseB(h); drawYardB(h); drawHomeParkedVehicle(h,'band'); }; const oldBlocked=homeBuildingBlocked; homeBuildingBlocked=function(x,y){ if(oldBlocked(x,y)) return true; const h=R36B45_HOMES&&R36B45_HOMES.band,s=h&&h.stage; if(!s)return false; return x>=s.x-20&&x<=s.x+s.w+55&&y>=s.y-36&&y<=s.y+s.h+58; }; })(); </script> <script> /* R36B48D — Approved isometric art-direction pass for the Band House hero property. */ (function(){ if(!window.R36B45_HOMES || !R36B45_HOMES.band) return; const band=R36B45_HOMES.band; band.heroVersion='R36B48D'; // Geometry is kept clear of the perimeter loop so the player can circle the full property. band.building={x:1434,y:3008,w:330,h:225}; band.door={x:1564,y:3198,w:58,h:48}; band.stage={x:1065,y:3010,w:250,h:168}; band.spawn={x:1325,y:2878,angle:-Math.PI/2}; function poly48(points,fill,stroke='#171514',lw=4){ ctx.beginPath();ctx.moveTo(points[0][0],points[0][1]); for(let i=1;i<points.length;i++)ctx.lineTo(points[i][0],points[i][1]); ctx.closePath();ctx.fillStyle=fill;ctx.fill(); if(stroke){ctx.strokeStyle=stroke;ctx.lineWidth=lw;ctx.stroke();} } function line48(points,color,lw=3,dash=[]){ ctx.save();ctx.strokeStyle=color;ctx.lineWidth=lw;ctx.setLineDash(dash);ctx.beginPath();ctx.moveTo(points[0][0],points[0][1]);for(let i=1;i<points.length;i++)ctx.lineTo(points[i][0],points[i][1]);ctx.stroke();ctx.restore(); } function shadow48(points,alpha=.28){poly48(points,'rgba(16,19,19,'+alpha+')',null,0)} function isoWindow48(cx,cy,w,h,skew,face){ let p; if(face==='east') p=[[cx,cy],[cx+w,cy-skew],[cx+w,cy+h-skew],[cx,cy+h]]; else p=[[cx,cy],[cx+w,cy+skew],[cx+w,cy+h+skew],[cx,cy+h]]; poly48(p,'#8fd0df','#34474d',3); const mx=(p[0][0]+p[1][0])/2,my=(p[0][1]+p[1][1])/2; line48([[mx,my+2],[mx,my+h-2]],'rgba(255,255,255,.78)',2); line48([[(p[0][0]+p[3][0])/2,(p[0][1]+p[3][1])/2],[(p[1][0]+p[2][0])/2,(p[1][1]+p[2][1])/2]],'rgba(255,255,255,.78)',2); } function flower48(x,y,c){ ctx.fillStyle='#315f2d';ctx.fillRect(x-1,y,2,9);ctx.fillStyle=c; for(let a=0;a<Math.PI*2;a+=Math.PI/2){ctx.beginPath();ctx.arc(x+Math.cos(a)*3.8,y+Math.sin(a)*3.8,2.8,0,Math.PI*2);ctx.fill();} ctx.fillStyle='#f1b83e';ctx.beginPath();ctx.arc(x,y,2,0,Math.PI*2);ctx.fill(); } function drawBandHouseIso48(h){ const x=h.building.x,y=h.building.y,w=h.building.w; // Isometric basis: south/front face slopes down-right; east face recedes up-right. const frontL=[x,y+112], frontR=[x+w,y+160], backR=[x+w+88,y+105], backL=[x+88,y+56]; const wallH=142; const frontLb=[frontL[0],frontL[1]+wallH],frontRb=[frontR[0],frontR[1]+wallH]; const backRb=[backR[0],backR[1]+wallH]; const ridgeL=[x+74,y-10],ridgeR=[x+w+18,y+38]; ctx.save(); // Northeast light produces one coherent southwest shadow for the complete building mass. shadow48([[frontL[0]-42,frontL[1]+42],[frontR[0]-42,frontR[1]+42],[backR[0]-42,backR[1]+wallH+42],[frontLb[0]-42,frontLb[1]+42]],.30); // Walls first, then roof. The front and east faces share the same isometric projection. poly48([frontL,frontR,frontRb,frontLb],'#d8bd91','#171514',5); poly48([frontR,backR,backRb,frontRb],'#b28762','#171514',5); // Large dominant roof planes, matching the supplied isometric house references. poly48([frontL,ridgeL,ridgeR,frontR],'#873f3d','#171514',5); poly48([ridgeL,backL,backR,ridgeR],'#55302f','#171514',5); // Eave/fascia emphasizes that the roof covers the whole structure. line48([frontL,frontR],'#241817',8); line48([ridgeL,ridgeR],'#241817',5); line48([frontR,backR],'#241817',7); // Roof shingles follow each plane direction rather than screen-horizontal lines. ctx.save(); ctx.beginPath();ctx.moveTo(frontL[0],frontL[1]);ctx.lineTo(ridgeL[0],ridgeL[1]);ctx.lineTo(ridgeR[0],ridgeR[1]);ctx.lineTo(frontR[0],frontR[1]);ctx.closePath();ctx.clip(); for(let i=1;i<6;i++) line48([[frontL[0]+i*52,frontL[1]+i*8],[ridgeL[0]+i*52,ridgeL[1]+i*8]],'rgba(255,255,255,.10)',2); for(let i=1;i<6;i++) line48([[frontL[0]+i*12,frontL[1]-i*18],[frontR[0]+i*12,frontR[1]-i*18]],'rgba(255,255,255,.10)',2); ctx.restore(); ctx.save(); ctx.beginPath();ctx.moveTo(ridgeL[0],ridgeL[1]);ctx.lineTo(backL[0],backL[1]);ctx.lineTo(backR[0],backR[1]);ctx.lineTo(ridgeR[0],ridgeR[1]);ctx.closePath();ctx.clip(); for(let i=1;i<5;i++) line48([[backL[0]+i*60,backL[1]+i*8],[ridgeL[0]+i*60,ridgeL[1]+i*8]],'rgba(255,255,255,.075)',2); ctx.restore(); // Chimney and its southwest shadow sit on the rear roof plane. shadow48([[x+w-24,y+36],[x+w+10,y+41],[x+w-8,y+90],[x+w-42,y+85]],.22); poly48([[x+w-2,y+15],[x+w+31,y+20],[x+w+31,y+69],[x+w-2,y+64]],'#614235','#171514',4); poly48([[x+w-8,y+10],[x+w+35,y+16],[x+w+29,y+25],[x+w-14,y+19]],'#2d2522','#171514',3); // Windows only appear on the vertical wall faces. isoWindow48(x+54,y+164,66,42,10,'front'); isoWindow48(x+213,y+187,66,42,10,'front'); isoWindow48(x+w+24,y+171,42,44,10,'east'); // Front door and porch are projected with the front face. const dx=x+142,dy=y+235; poly48([[dx,dy],[dx+60,dy+9],[dx+60,dy+67],[dx,dy+58]],'#38251f','#171514',4); ctx.fillStyle='#f1b83e';ctx.beginPath();ctx.arc(dx+49,dy+39,4,0,Math.PI*2);ctx.fill(); poly48([[dx-23,dy+62],[dx+84,dy+78],[dx+64,dy+94],[dx-43,dy+78]],'#9e7a55','#171514',3); poly48([[dx-16,dy+84],[dx+67,dy+96],[dx+52,dy+107],[dx-31,dy+95]],'#725b43','#171514',3); // Foundation garden follows the front wall angle. const cols=['#e64a38','#f1b83e','#9766a3','#f0e9dc']; for(let i=0;i<12;i++) flower48(x+22+i*26,y+270+i*4,cols[i%cols.length]); poly48([[x+58,y+302],[x+w-44,y+342],[x+w-64,y+368],[x+38,y+328]],'rgba(17,21,20,.84)',null,0); ctx.save();ctx.translate(x+w/2,y+334);ctx.rotate(Math.atan2(48,w));ctx.fillStyle='#f4e6be';ctx.font='1000 12px system-ui';ctx.textAlign='center';ctx.fillText('BAND HOUSE',0,0);ctx.restore(); ctx.restore(); } function drawBandStageIso48(s){ const x=s.x,y=s.y,w=s.w; const A=[x,y+66],B=[x+w,y+102],C=[x+w+50,y+72],D=[x+50,y+36],deckH=112; ctx.save(); shadow48([[A[0]-34,A[1]+34],[B[0]-34,B[1]+34],[B[0]+22,B[1]+deckH+48],[A[0]+16,A[1]+deckH+48]],.31); // Deck top, front fascia and east side use the same isometric basis as the house. poly48([A,B,C,D],'#343332','#111',5); poly48([A,B,[B[0],B[1]+deckH],[A[0],A[1]+deckH]],'#6e523b','#171514',4); poly48([B,C,[C[0],C[1]+deckH],[B[0],B[1]+deckH]],'#4b3b31','#171514',4); // Canopy roof at north/back edge, visibly raised above the deck. const ca=[x+22,y+34],cb=[x+w-14,y+68],cc=[x+w+26,y+44],cd=[x+62,y+10]; poly48([ca,cb,cc,cd],'#202124','#111',4); line48([[ca[0],ca[1]],[ca[0],A[1]+58]],'#8f999c',5); line48([[cb[0],cb[1]],[cb[0],B[1]+58]],'#8f999c',5); // Drum riser is an isometric platform centered on the deck. const rx=x+92,ry=y+92; poly48([[rx,ry],[rx+82,ry+12],[rx+101,ry],[rx+19,ry-12]],'#5b5b5b','#111',3); ctx.fillStyle='#c3c3c3';ctx.beginPath();ctx.arc(rx+50,ry+6,16,0,Math.PI*2);ctx.fill();ctx.strokeStyle='#111';ctx.stroke(); ctx.fillStyle='#363636';ctx.beginPath();ctx.arc(rx+27,ry-2,8,0,Math.PI*2);ctx.arc(rx+75,ry+5,8,0,Math.PI*2);ctx.fill(); // Speaker stacks stand on the visible front half of the deck. for(const q of [[x+22,y+105],[x+w-35,y+137]]){ poly48([[q[0],q[1]],[q[0]+28,q[1]+4],[q[0]+28,q[1]+57],[q[0],q[1]+53]],'#111','#555',3); ctx.fillStyle='#4d4d4d';ctx.beginPath();ctx.arc(q[0]+14,q[1]+19,7,0,Math.PI*2);ctx.arc(q[0]+14,q[1]+41,10,0,Math.PI*2);ctx.fill(); } // Two microphones and monitor wedges. for(const q of [[x+76,y+122],[x+w-80,y+147]]){ line48([[q[0],q[1]],[q[0],q[1]+44]],'#c4c7c8',3); line48([[q[0],q[1]+7],[q[0]+13,q[1]+1]],'#c4c7c8',3); poly48([[q[0]-14,q[1]+49],[q[0]+14,q[1]+53],[q[0]+9,q[1]+66],[q[0]-18,q[1]+62]],'#373737','#111',2); } // SOUTH-END lighting truss follows the lower/audience edge of the stage. const trA=[A[0]+12,A[1]+deckH+6],trB=[B[0]-12,B[1]+deckH+6]; line48([trA,trB],'#aab2b4',6); line48([[trA[0]+3,trA[1]-38],[trA[0]+3,trA[1]+19]],'#aab2b4',6); line48([[trB[0]-3,trB[1]-38],[trB[0]-3,trB[1]+19]],'#aab2b4',6); const lc=['#e64a38','#f1b83e','#3f84a5','#9766a3','#e64a38']; for(let i=0;i<5;i++){ const t=i/4,lx=trA[0]+(trB[0]-trA[0])*t,ly=trA[1]+(trB[1]-trA[1])*t; ctx.fillStyle=lc[i];ctx.beginPath();ctx.arc(lx,ly,7,0,Math.PI*2);ctx.fill();ctx.strokeStyle='#222';ctx.lineWidth=2;ctx.stroke(); } ctx.save();ctx.translate(x+w/2,y+82);ctx.rotate(Math.atan2(36,w));ctx.fillStyle='#f4e6be';ctx.font='1000 10px system-ui';ctx.textAlign='center';ctx.fillText('BACKYARD PRACTICE STAGE',0,0);ctx.restore(); ctx.restore(); } function drawBandYardIso48(h){ const l=h.lot;ctx.save(); // No collision border: only subtle mow lines define the drivable perimeter loop. ctx.strokeStyle='rgba(255,255,255,.055)';ctx.lineWidth=38;ctx.strokeRect(l.x+46,l.y+46,l.w-92,l.h-92); // Hot tub and southwest shadow. shadow48([[1810,3078],[1944,3078],[1910,3170],[1776,3170]],.20); ctx.beginPath();ctx.roundRect(1808,3070,138,92,20);ctx.fillStyle='#68645d';ctx.fill();ctx.strokeStyle='#2d2b29';ctx.lineWidth=4;ctx.stroke(); ctx.beginPath();ctx.roundRect(1822,3083,110,64,15);ctx.fillStyle='#3f91a9';ctx.fill();ctx.strokeStyle='#d8d0be';ctx.stroke(); ctx.fillStyle='rgba(255,255,255,.28)';for(let i=0;i<4;i++){ctx.beginPath();ctx.arc(1840+i*24,3114+(i%2)*7,5,0,Math.PI*2);ctx.fill();} // Beer pong table. shadow48([[1070,3260],[1202,3260],[1178,3318],[1046,3318]],.18); poly48([[1070,3250],[1200,3269],[1222,3255],[1092,3236]],'#276d55','#e8eee8',3); line48([[1146,3246],[1146,3276]],'#e8eee8',3); ctx.fillStyle='#e64a38';for(let i=0;i<6;i++){ctx.beginPath();ctx.arc(1094+(i%3)*11,3255+Math.floor(i/3)*10,4,0,Math.PI*2);ctx.fill();ctx.beginPath();ctx.arc(1198-(i%3)*11,3270+Math.floor(i/3)*10,4,0,Math.PI*2);ctx.fill();} // Fire pit and chairs. shadow48([[1222,3338],[1324,3338],[1286,3403],[1184,3403]],.17); ctx.fillStyle='#4c4237';ctx.beginPath();ctx.arc(1270,3360,34,0,Math.PI*2);ctx.fill();ctx.strokeStyle='#9c8265';ctx.lineWidth=6;ctx.stroke(); ctx.fillStyle='#e64a38';ctx.beginPath();ctx.arc(1270,3360,14,0,Math.PI*2);ctx.fill();ctx.fillStyle='#f1b83e';ctx.beginPath();ctx.arc(1270,3355,7,0,Math.PI*2);ctx.fill(); for(const [cx,cy,a] of [[1218,3333,-.35],[1322,3338,.35],[1215,3392,.35],[1320,3396,-.35]]){ctx.save();ctx.translate(cx,cy);ctx.rotate(a);ctx.fillStyle='#83684c';ctx.fillRect(-16,-9,32,18);ctx.restore();} // Garden beds and flowers. for(let i=0;i<2;i++){ const gy=3318+i*48;shadow48([[1450,gy+10],[1640,gy+10],[1622,gy+48],[1432,gy+48]],.14); poly48([[1450,gy],[1640,gy+28],[1660,gy+15],[1470,gy-13]],'#775033','#3b2d22',4); for(let j=0;j<8;j++){ctx.fillStyle=j%2?'#4d8d42':'#6aa556';ctx.beginPath();ctx.arc(1475+j*22,gy+8+j*3,6,0,Math.PI*2);ctx.fill();} } for(let i=0;i<14;i++)flower48(1660+(i%7)*23,3310+Math.floor(i/7)*43,['#e64a38','#f1b83e','#9766a3'][i%3]); // Archery target and clear lane. line48([[1738,3380],[1926,3407]],'rgba(239,229,190,.30)',3,[10,9]); shadow48([[1900,3378],[1968,3388],[1940,3460],[1872,3450]],.20); ctx.fillStyle='#e7ddc7';ctx.beginPath();ctx.arc(1940,3413,34,0,Math.PI*2);ctx.fill();ctx.strokeStyle='#433c33';ctx.lineWidth=4;ctx.stroke(); for(const [r,c] of [[25,'#2b2b2b'],[18,'#e7ddc7'],[12,'#e64a38'],[6,'#f1b83e']]){ctx.fillStyle=c;ctx.beginPath();ctx.arc(1940,3413,r,0,Math.PI*2);ctx.fill();} ctx.fillStyle='#5a4936';ctx.fillRect(1934,3445,12,26); ctx.restore(); } drawR36B45BandHome=function(h){ drawBandStageIso48(h.stage||band.stage); drawBandHouseIso48(h); drawBandYardIso48(h); drawHomeParkedVehicle(h,'band'); }; })(); </script> <script> /* R36B48D — Parcel-aligned Band House hero property refinement. */ (function(){ if(!window.R36B45_HOMES || !R36B45_HOMES.band) return; const band=R36B45_HOMES.band; band.heroVersion='R36B48D'; band.building={x:1450,y:3030,w:320,h:220}; band.door={x:1578,y:3208,w:60,h:48}; band.stage={x:1065,y:3025,w:260,h:175}; band.spawn={x:1320,y:2878,angle:-Math.PI/2}; function p48d(points,fill,stroke='#171514',lw=4){ ctx.beginPath();ctx.moveTo(points[0][0],points[0][1]); for(let i=1;i<points.length;i++)ctx.lineTo(points[i][0],points[i][1]); ctx.closePath();ctx.fillStyle=fill;ctx.fill(); if(stroke){ctx.strokeStyle=stroke;ctx.lineWidth=lw;ctx.stroke();} } function l48d(points,color,lw=3,dash=[]){ ctx.save();ctx.strokeStyle=color;ctx.lineWidth=lw;ctx.setLineDash(dash);ctx.beginPath();ctx.moveTo(points[0][0],points[0][1]); for(let i=1;i<points.length;i++)ctx.lineTo(points[i][0],points[i][1]);ctx.stroke();ctx.restore(); } function sh48d(x,y,w,h,ox=-28,oy=30,a=.25){ ctx.save();ctx.fillStyle='rgba(12,16,17,'+a+')';ctx.beginPath();ctx.roundRect(x+ox,y+oy,w,h,12);ctx.fill();ctx.restore(); } function win48d(x,y,w,h){ ctx.fillStyle='#92d4e2';ctx.fillRect(x,y,w,h);ctx.strokeStyle='#34474d';ctx.lineWidth=3;ctx.strokeRect(x,y,w,h); ctx.strokeStyle='rgba(255,255,255,.8)';ctx.lineWidth=2;ctx.beginPath();ctx.moveTo(x+w/2,y+2);ctx.lineTo(x+w/2,y+h-2);ctx.moveTo(x+2,y+h/2);ctx.lineTo(x+w-2,y+h/2);ctx.stroke(); } function flower48d(x,y,c){ ctx.fillStyle='#315f2d';ctx.fillRect(x-1,y,2,8);ctx.fillStyle=c; for(let a=0;a<Math.PI*2;a+=Math.PI/2){ctx.beginPath();ctx.arc(x+Math.cos(a)*3.4,y+Math.sin(a)*3.4,2.5,0,Math.PI*2);ctx.fill();} ctx.fillStyle='#f1b83e';ctx.beginPath();ctx.arc(x,y,1.8,0,Math.PI*2);ctx.fill(); } function drawParcelBorder48d(h){ const l=h.lot,gapX=h.roadCenterX||1320,gap=150; ctx.save();ctx.strokeStyle='#855d3d';ctx.lineWidth=9;ctx.lineCap='square'; // Top fence has a large open road entrance. Fence is visual only and never collision geometry. l48d([[l.x+14,l.y+14],[gapX-gap/2,l.y+14]],'#855d3d',9); l48d([[gapX+gap/2,l.y+14],[l.x+l.w-14,l.y+14]],'#855d3d',9); l48d([[l.x+14,l.y+14],[l.x+14,l.y+l.h-14],[l.x+l.w-14,l.y+l.h-14],[l.x+l.w-14,l.y+14]],'#855d3d',9); ctx.fillStyle='#b17a4f'; const posts=[]; for(let x=l.x+18;x<l.x+l.w-10;x+=55){if(x<gapX-gap/2-10||x>gapX+gap/2+10)posts.push([x,l.y+14],[x,l.y+l.h-14]);} for(let y=l.y+18;y<l.y+l.h-10;y+=55)posts.push([l.x+14,y],[l.x+l.w-14,y]); for(const [x,y] of posts)ctx.fillRect(x-4,y-8,8,16); ctx.restore(); } function drawHouse48d(h){ const x=h.building.x,y=h.building.y,w=h.building.w; // Axis-aligned footprint: front and side edges run parallel to parcel edges. sh48d(x,y+58,w+42,180,-30,34,.28); // Front wall and right wall. ctx.fillStyle='#dfc79d';ctx.fillRect(x,y+92,w,132);ctx.strokeStyle='#171514';ctx.lineWidth=5;ctx.strokeRect(x,y+92,w,132); p48d([[x+w,y+92],[x+w+42,y+68],[x+w+42,y+198],[x+w,y+224]],'#b68b68','#171514',5); // Dominant roof top, viewed from above, with ridge horizontal and footprint unrotated. p48d([[x-18,y+96],[x+52,y+24],[x+w-30,y+24],[x+w+42,y+68],[x+w,y+102],[x,y+102]],'#883f3e','#171514',5); p48d([[x+52,y+24],[x+105,y-18],[x+w+20,y+18],[x+w-30,y+24]],'#5a302f','#171514',4); l48d([[x-18,y+96],[x+w,y+102]],'#251817',8); l48d([[x+52,y+24],[x+w-30,y+24]],'#251817',5); // Roof texture runs parallel with the parcel, not diagonally across it. for(let yy=y+40;yy<y+91;yy+=14)l48d([[x+20,yy],[x+w-2,yy]],'rgba(255,255,255,.10)',2); for(let xx=x+38;xx<x+w-8;xx+=44)l48d([[xx,y+30],[xx-24,y+95]],'rgba(255,255,255,.08)',2); // Chimney. sh48d(x+w-50,y+3,38,58,-12,18,.18);ctx.fillStyle='#684538';ctx.fillRect(x+w-50,y-3,34,60);ctx.strokeStyle='#171514';ctx.lineWidth=4;ctx.strokeRect(x+w-50,y-3,34,60); // Vertical-wall windows only. win48d(x+42,y+132,68,45);win48d(x+205,y+132,68,45); p48d([[x+w+10,y+119],[x+w+35,y+104],[x+w+35,y+151],[x+w+10,y+166]],'#92d4e2','#34474d',3); // Door, porch, steps. ctx.fillStyle='#38251f';ctx.fillRect(x+132,y+164,58,60);ctx.strokeStyle='#171514';ctx.lineWidth=4;ctx.strokeRect(x+132,y+164,58,60); ctx.fillStyle='#f1b83e';ctx.beginPath();ctx.arc(x+178,y+195,4,0,Math.PI*2);ctx.fill(); ctx.fillStyle='#947455';ctx.fillRect(x+110,y+224,102,18);ctx.fillStyle='#725b43';ctx.fillRect(x+120,y+242,82,13); // Foundation flowers. const cols=['#e64a38','#f1b83e','#9766a3','#f0e9dc'];for(let i=0;i<13;i++)flower48d(x+15+i*23,y+238,cols[i%4]); ctx.fillStyle='rgba(17,21,20,.84)';ctx.fillRect(x+50,y+255,w-100,31);ctx.fillStyle='#f4e6be';ctx.font='1000 12px system-ui';ctx.textAlign='center';ctx.fillText('BAND HOUSE',x+w/2,y+276); } function drawStage48d(s){ const x=s.x,y=s.y,w=s.w,h=s.h; // Stage footprint is parallel to the parcel edges. sh48d(x,y,w+30,h+22,-28,28,.28); ctx.fillStyle='#5f4938';ctx.fillRect(x,y+58,w,h-58);ctx.strokeStyle='#171514';ctx.lineWidth=5;ctx.strokeRect(x,y+58,w,h-58); // Raised deck and canopy, all horizontal/vertical relative to yard. ctx.fillStyle='#333331';ctx.fillRect(x-8,y+50,w+16,24);ctx.strokeRect(x-8,y+50,w+16,24); p48d([[x-18,y+50],[x+25,y+8],[x+w-25,y+8],[x+w+18,y+50]],'#202124','#111',5); // Back posts and stage wall. l48d([[x+6,y+48],[x+6,y+145]],'#9aa2a4',5);l48d([[x+w-6,y+48],[x+w-6,y+145]],'#9aa2a4',5); ctx.fillStyle='#171717';ctx.fillRect(x+14,y+76,w-28,62); // Speakers. for(const q of [x+18,x+w-46]){ctx.fillStyle='#111';ctx.fillRect(q,y+92,28,62);ctx.strokeStyle='#555';ctx.strokeRect(q,y+92,28,62);ctx.fillStyle='#4d4d4d';ctx.beginPath();ctx.arc(q+14,y+110,7,0,Math.PI*2);ctx.arc(q+14,y+137,10,0,Math.PI*2);ctx.fill();} // Drum riser and kit. ctx.fillStyle='#555';ctx.fillRect(x+90,y+96,80,34);ctx.strokeStyle='#111';ctx.strokeRect(x+90,y+96,80,34);ctx.fillStyle='#c9c9c9';ctx.beginPath();ctx.arc(x+130,y+111,16,0,Math.PI*2);ctx.fill();ctx.stroke(); ctx.fillStyle='#363636';ctx.beginPath();ctx.arc(x+108,y+105,8,0,Math.PI*2);ctx.arc(x+151,y+105,8,0,Math.PI*2);ctx.fill(); // Mic stands and monitor wedges. for(const q of [x+72,x+w-72]){l48d([[q,y+102],[q,y+150]],'#c4c7c8',3);l48d([[q,y+108],[q+14,y+101]],'#c4c7c8',3);p48d([[q-14,y+148],[q+14,y+148],[q+9,y+162],[q-18,y+162]],'#373737','#111',2);} // South-end light truss exactly along the stage's south edge. const ty=y+h+8;l48d([[x+4,ty],[x+w-4,ty]],'#aab2b4',6);l48d([[x+7,ty-40],[x+7,ty+18]],'#aab2b4',6);l48d([[x+w-7,ty-40],[x+w-7,ty+18]],'#aab2b4',6); const lc=['#e64a38','#f1b83e','#3f84a5','#9766a3','#e64a38'];for(let i=0;i<5;i++){const lx=x+12+i*(w-24)/4;ctx.fillStyle=lc[i];ctx.beginPath();ctx.arc(lx,ty,7,0,Math.PI*2);ctx.fill();ctx.strokeStyle='#222';ctx.lineWidth=2;ctx.stroke();} ctx.fillStyle='#f4e6be';ctx.font='1000 10px system-ui';ctx.textAlign='center';ctx.fillText('BACKYARD PRACTICE STAGE',x+w/2,y+38); } function drawYard48d(h){ const l=h.lot;ctx.save(); drawParcelBorder48d(h); // Subtle open driving loop. This is visual only and keeps a wide path around house and stage. ctx.strokeStyle='rgba(238,233,205,.09)';ctx.lineWidth=34;ctx.strokeRect(l.x+62,l.y+62,l.w-124,l.h-124); // Separate hot-tub patio in the northeast corner, detached from house. sh48d(1804,2960,154,122,-24,26,.20);ctx.fillStyle='#a88d70';ctx.fillRect(1792,2948,166,130);ctx.strokeStyle='#5b4939';ctx.lineWidth=4;ctx.strokeRect(1792,2948,166,130); ctx.beginPath();ctx.roundRect(1810,2966,130,91,20);ctx.fillStyle='#66635d';ctx.fill();ctx.strokeStyle='#2d2b29';ctx.stroke();ctx.beginPath();ctx.roundRect(1824,2980,102,62,15);ctx.fillStyle='#3f91a9';ctx.fill();ctx.strokeStyle='#d8d0be';ctx.stroke();ctx.fillStyle='rgba(255,255,255,.28)';for(let i=0;i<4;i++){ctx.beginPath();ctx.arc(1842+i*22,3010+(i%2)*6,5,0,Math.PI*2);ctx.fill();} ctx.fillStyle='#4b3c30';ctx.fillRect(1798,3060,154,12); // Proper beer-pong table on its own clear pad. sh48d(1056,3260,180,92,-20,24,.16);ctx.fillStyle='rgba(185,164,122,.42)';ctx.fillRect(1046,3248,190,96); ctx.fillStyle='#286c56';ctx.fillRect(1070,3260,142,62);ctx.strokeStyle='#eef3ef';ctx.lineWidth=4;ctx.strokeRect(1070,3260,142,62);l48d([[1141,3262],[1141,3320]],'#eef3ef',3); ctx.fillStyle='#8a5d3c';ctx.fillRect(1081,3322,8,22);ctx.fillRect(1193,3322,8,22); const cups=[[1087,3276],[1100,3276],[1113,3276],[1093,3288],[1106,3288],[1099,3300],[1195,3276],[1182,3276],[1169,3276],[1189,3288],[1176,3288],[1183,3300]];ctx.fillStyle='#e64a38';for(const [cx,cy] of cups){ctx.beginPath();ctx.arc(cx,cy,4.5,0,Math.PI*2);ctx.fill();} // Fire pit and chairs remain grouped in the southwest hangout zone. sh48d(1210,3352,122,78,-20,18,.15);ctx.fillStyle='#4c4237';ctx.beginPath();ctx.arc(1270,3370,34,0,Math.PI*2);ctx.fill();ctx.strokeStyle='#9c8265';ctx.lineWidth=6;ctx.stroke();ctx.fillStyle='#e64a38';ctx.beginPath();ctx.arc(1270,3370,14,0,Math.PI*2);ctx.fill();ctx.fillStyle='#f1b83e';ctx.beginPath();ctx.arc(1270,3365,7,0,Math.PI*2);ctx.fill();for(const [cx,cy,a] of [[1218,3343,-.35],[1322,3348,.35],[1215,3402,.35],[1320,3406,-.35]]){ctx.save();ctx.translate(cx,cy);ctx.rotate(a);ctx.fillStyle='#83684c';ctx.fillRect(-16,-9,32,18);ctx.restore();} // Garden and flower beds along south face, leaving driving space behind them. for(let i=0;i<2;i++){const gy=3324+i*48;ctx.fillStyle='#775033';ctx.fillRect(1450,gy,200,33);ctx.strokeStyle='#3b2d22';ctx.lineWidth=4;ctx.strokeRect(1450,gy,200,33);for(let j=0;j<8;j++){ctx.fillStyle=j%2?'#4d8d42':'#6aa556';ctx.beginPath();ctx.arc(1470+j*24,gy+16,6,0,Math.PI*2);ctx.fill();}} for(let i=0;i<14;i++)flower48d(1680+(i%7)*22,3320+Math.floor(i/7)*40,['#e64a38','#f1b83e','#9766a3'][i%3]); // Archery lane remains clear on southeast edge. l48d([[1760,3400],[1910,3400]],'rgba(239,229,190,.30)',3,[10,9]);ctx.fillStyle='#e7ddc7';ctx.beginPath();ctx.arc(1940,3400,34,0,Math.PI*2);ctx.fill();ctx.strokeStyle='#433c33';ctx.lineWidth=4;ctx.stroke();for(const [r,c] of [[25,'#2b2b2b'],[18,'#e7ddc7'],[12,'#e64a38'],[6,'#f1b83e']]){ctx.fillStyle=c;ctx.beginPath();ctx.arc(1940,3400,r,0,Math.PI*2);ctx.fill();}ctx.fillStyle='#5a4936';ctx.fillRect(1934,3432,12,26); ctx.restore(); } drawR36B45BandHome=function(h){ drawStage48d(h.stage||band.stage); drawHouse48d(h); drawYard48d(h); drawHomeParkedVehicle(h,'band'); }; })(); </script> <script> /* R36B48E — True top-down Band House property rebuild. */ (function(){ if(!window.R36B45_HOMES || !R36B45_HOMES.band) return; const band=R36B45_HOMES.band; band.heroVersion='R36B48H'; // Spacious, parcel-aligned layout with a continuous drivable perimeter. band.building={x:1510,y:3025,w:300,h:220}; band.door={x:1632,y:3188,w:58,h:48}; band.stage={x:1080,y:3040,w:245,h:165}; band.spawn={x:1435,y:2895,angle:-Math.PI/2}; band.roadCenterX=1510; function rect(x,y,w,h,fill,stroke='#171514',lw=4){ ctx.fillStyle=fill;ctx.fillRect(x,y,w,h); if(stroke){ctx.strokeStyle=stroke;ctx.lineWidth=lw;ctx.strokeRect(x,y,w,h);} } function poly(points,fill,stroke='#171514',lw=4){ ctx.beginPath();ctx.moveTo(points[0][0],points[0][1]); for(let i=1;i<points.length;i++)ctx.lineTo(points[i][0],points[i][1]); ctx.closePath();ctx.fillStyle=fill;ctx.fill(); if(stroke){ctx.strokeStyle=stroke;ctx.lineWidth=lw;ctx.stroke();} } function line(points,color,lw=3,dash=[]){ ctx.save();ctx.strokeStyle=color;ctx.lineWidth=lw;ctx.setLineDash(dash); ctx.beginPath();ctx.moveTo(points[0][0],points[0][1]); for(let i=1;i<points.length;i++)ctx.lineTo(points[i][0],points[i][1]); ctx.stroke();ctx.restore(); } function softShadow(x,y,w,h,dx=-24,dy=26,a=.24,r=9){ ctx.save();ctx.fillStyle='rgba(15,18,18,'+a+')'; ctx.beginPath();ctx.roundRect(x+dx,y+dy,w,h,r);ctx.fill();ctx.restore(); } function flower(x,y,c){ ctx.fillStyle='#315f2d';ctx.fillRect(x-1,y,2,8);ctx.fillStyle=c; for(let a=0;a<Math.PI*2;a+=Math.PI/2){ctx.beginPath();ctx.arc(x+Math.cos(a)*3.2,y+Math.sin(a)*3.2,2.4,0,Math.PI*2);ctx.fill();} ctx.fillStyle='#f1b83e';ctx.beginPath();ctx.arc(x,y,1.8,0,Math.PI*2);ctx.fill(); } function windowSouth(x,y,w,h){ rect(x,y,w,h,'#91d3e2','#34474d',3); line([[x+w/2,y+2],[x+w/2,y+h-2]],'rgba(255,255,255,.8)',2); line([[x+2,y+h/2],[x+w-2,y+h/2]],'rgba(255,255,255,.8)',2); } function windowEast(x,y,w,h){ poly([[x,y+8],[x+w,y],[x+w,y+h-8],[x,y+h]],'#91d3e2','#34474d',3); line([[x+w/2,y+4],[x+w/2,y+h-4]],'rgba(255,255,255,.8)',2); } function drawFence(h){ const l=h.lot,gap=190,cx=h.roadCenterX||1510; ctx.save();ctx.strokeStyle='#855d3d';ctx.lineWidth=8;ctx.lineCap='square'; line([[l.x+12,l.y+12],[cx-gap/2,l.y+12]],'#855d3d',8); line([[cx+gap/2,l.y+12],[l.x+l.w-12,l.y+12]],'#855d3d',8); line([[l.x+12,l.y+12],[l.x+12,l.y+l.h-12],[l.x+l.w-12,l.y+l.h-12],[l.x+l.w-12,l.y+12]],'#855d3d',8); ctx.fillStyle='#b17a4f'; for(let x=l.x+18;x<l.x+l.w-10;x+=58){ if(x<cx-gap/2-10||x>cx+gap/2+10)ctx.fillRect(x-4,l.y+4,8,17); ctx.fillRect(x-4,l.y+l.h-20,8,17); } for(let y=l.y+22;y<l.y+l.h-16;y+=58){ctx.fillRect(l.x+4,y-8,8,17);ctx.fillRect(l.x+l.w-12,y-8,8,17);} ctx.restore(); } function drawHouse(h){ const x=h.building.x,y=h.building.y,w=h.building.w,hgt=h.building.h; // R36B48G: south-facing top-down oblique object. The roof is the dominant visible plane. // NE light (upper-right) casts the complete building shadow toward the SW (lower-left). softShadow(x+6,y+18,w+24,hgt-18,-30,30,.28,5); // Building base is seated directly on the grass. Only short south/east wall faces are visible. const wallTop=y+142; const southBottom=y+214; rect(x+12,wallTop,w-30,southBottom-wallTop,'#dfc79d','#171514',5); poly([[x+w-18,wallTop-8],[x+w+16,wallTop-25],[x+w+16,southBottom-19],[x+w-18,southBottom]],'#b68b68','#171514',5); // Large top roof plane occupies the position of Republic Square's sign/top feature. // It faces south, not the viewer: ridge toward north, eave toward south. const left=x-8,right=x+w+14,north=y+24,south=wallTop+4,ridgeY=y+58; poly([[left+46,north],[right-42,north],[right+4,ridgeY],[left,ridgeY]],'#4e2d2c','#171514',5); poly([[left,ridgeY],[right+4,ridgeY],[right-10,south],[left+16,south]],'#873f3d','#171514',5); line([[left,ridgeY],[right+4,ridgeY]],'#241817',5); line([[left+16,south],[right-10,south]],'#241817',8); // Roof texture follows the ground/parcel axes and reinforces the top-down plane. for(let yy=ridgeY+16;yy<south-7;yy+=17)line([[left+18,yy],[right-12,yy]],'rgba(255,255,255,.10)',2); for(let xx=left+50;xx<right-22;xx+=43)line([[xx,north+5],[xx+8,ridgeY-3]],'rgba(255,255,255,.075)',2); // Chimney is anchored to the roof plane, with its shadow also cast SW. softShadow(x+w-72,y+32,34,50,-12,14,.18,2); rect(x+w-72,y+24,34,50,'#684538','#171514',4); rect(x+w-77,y+20,44,10,'#2d2522','#171514',3); // Windows exist only on the short vertical wall faces. windowSouth(x+38,wallTop+13,64,38); windowSouth(x+192,wallTop+13,64,38); windowEast(x+w-8,wallTop+5,27,44); // South-facing entry and porch sit below the roof eave. rect(x+121,wallTop+10,58,62,'#38251f','#171514',4); ctx.fillStyle='#f1b83e';ctx.beginPath();ctx.arc(x+168,wallTop+41,4,0,Math.PI*2);ctx.fill(); rect(x+102,southBottom,96,15,'#947455','#171514',3); rect(x+112,southBottom+15,76,11,'#725b43','#171514',3); ctx.fillStyle='rgba(17,21,20,.84)';ctx.fillRect(x+55,southBottom+34,w-110,29); ctx.fillStyle='#f4e6be';ctx.font='1000 12px system-ui';ctx.textAlign='center';ctx.fillText('BAND HOUSE',x+w/2,southBottom+54); } function drawStage(s){ const x=s.x,y=s.y,w=s.w,h=s.h; // R36B48G: stage is built on the same south-facing top-down projection as the house. // The stage base sits on grass; roof/canopy dominates; only a short south fascia is visible. softShadow(x+3,y+18,w+18,h+18,-28,28,.27,5); const canopyNorth=y+10,canopySouth=y+98; const deckTop=y+100,deckBottom=y+151; // Short stage wall/deck face beneath the canopy. rect(x+8,deckTop,w-16,deckBottom-deckTop,'#6d523b','#171514',5); poly([[x+w-8,deckTop-7],[x+w+12,deckTop-18],[x+w+12,deckBottom-12],[x+w-8,deckBottom]],'#4d3a2c','#171514',4); // Dominant canopy top plane, facing south and parallel to parcel edges. poly([[x+32,canopyNorth],[x+w-32,canopyNorth],[x+w+10,y+42],[x-10,y+42]],'#202124','#111',5); poly([[x-10,y+42],[x+w+10,y+42],[x+w-3,canopySouth],[x+3,canopySouth]],'#303234','#111',5); line([[x-10,y+42],[x+w+10,y+42]],'#0f0f0f',5); line([[x+3,canopySouth],[x+w-3,canopySouth]],'#111',7); // Open performance deck below the roof eave. rect(x+14,y+66,w-28,42,'#171717','#343434',3); line([[x+10,y+40],[x+10,deckBottom]],'#9aa2a4',5); line([[x+w-10,y+40],[x+w-10,deckBottom]],'#9aa2a4',5); // Drum riser and kit centered beneath the canopy. rect(x+82,y+69,82,31,'#555','#111',3); ctx.fillStyle='#c9c9c9';ctx.beginPath();ctx.arc(x+123,y+84,14,0,Math.PI*2);ctx.fill();ctx.strokeStyle='#111';ctx.stroke(); ctx.fillStyle='#363636';ctx.beginPath();ctx.arc(x+103,y+75,7,0,Math.PI*2);ctx.arc(x+145,y+75,7,0,Math.PI*2);ctx.fill(); // Speakers, mic stands and monitor wedges all share the same ground alignment. for(const q of [x+17,x+w-45]){rect(q,y+61,28,48,'#111','#555',3);ctx.fillStyle='#4d4d4d';ctx.beginPath();ctx.arc(q+14,y+74,7,0,Math.PI*2);ctx.arc(q+14,y+95,9,0,Math.PI*2);ctx.fill();} for(const q of [x+68,x+w-68]){line([[q,y+78],[q,deckBottom-8]],'#c4c7c8',3);line([[q,y+84],[q+14,y+77]],'#c4c7c8',3);poly([[q-14,deckBottom-14],[q+14,deckBottom-14],[q+9,deckBottom-2],[q-18,deckBottom-2]],'#373737','#111',2);} // South-end light truss faces the yard/audience. const ty=y+h+7;line([[x+5,ty],[x+w-5,ty]],'#aab2b4',6);line([[x+8,ty-38],[x+8,ty+17]],'#aab2b4',6);line([[x+w-8,ty-38],[x+w-8,ty+17]],'#aab2b4',6); const lc=['#e64a38','#f1b83e','#3f84a5','#9766a3','#e64a38']; for(let i=0;i<5;i++){const lx=x+14+i*(w-28)/4;ctx.fillStyle=lc[i];ctx.beginPath();ctx.arc(lx,ty,7,0,Math.PI*2);ctx.fill();ctx.strokeStyle='#222';ctx.lineWidth=2;ctx.stroke();} ctx.fillStyle='#f4e6be';ctx.font='1000 10px system-ui';ctx.textAlign='center';ctx.fillText('BACKYARD PRACTICE STAGE',x+w/2,y+35); } function drawHotTub(){ // Detached patio area, not attached to house. softShadow(1810,2940,145,118,-22,24,.18,10); rect(1798,2928,166,132,'#a88d70','#5b4939',4); ctx.beginPath();ctx.roundRect(1814,2945,134,94,20);ctx.fillStyle='#66635d';ctx.fill();ctx.strokeStyle='#2d2b29';ctx.lineWidth=4;ctx.stroke(); ctx.beginPath();ctx.roundRect(1828,2959,106,65,15);ctx.fillStyle='#3f91a9';ctx.fill();ctx.strokeStyle='#d8d0be';ctx.stroke(); ctx.fillStyle='rgba(255,255,255,.28)';for(let i=0;i<4;i++){ctx.beginPath();ctx.arc(1846+i*23,2989+(i%2)*7,5,0,Math.PI*2);ctx.fill();} ctx.fillStyle='#4b3c30';ctx.fillRect(1805,3044,152,10); } function drawBeerPong(){ // Its own activity pad with recognizable cup triangles. rect(1080,3260,188,94,'rgba(185,164,122,.42)',null,0); softShadow(1102,3270,142,62,-15,18,.15,2); rect(1102,3270,142,62,'#286c56','#eef3ef',4); line([[1173,3272],[1173,3330]],'#eef3ef',3); ctx.fillStyle='#8a5d3c';ctx.fillRect(1114,3332,8,20);ctx.fillRect(1224,3332,8,20); const left=[[1119,3287],[1131,3287],[1143,3287],[1125,3299],[1137,3299],[1131,3311]]; const right=left.map(([cx,cy])=>[2346-cx,cy]); ctx.fillStyle='#e64a38';for(const [cx,cy] of left.concat(right)){ctx.beginPath();ctx.arc(cx,cy,4.5,0,Math.PI*2);ctx.fill();} } function drawFirePit(){ softShadow(1275,3355,112,78,-18,17,.15,5); ctx.fillStyle='#4c4237';ctx.beginPath();ctx.arc(1328,3372,34,0,Math.PI*2);ctx.fill();ctx.strokeStyle='#9c8265';ctx.lineWidth=6;ctx.stroke(); ctx.fillStyle='#e64a38';ctx.beginPath();ctx.arc(1328,3372,14,0,Math.PI*2);ctx.fill();ctx.fillStyle='#f1b83e';ctx.beginPath();ctx.arc(1328,3367,7,0,Math.PI*2);ctx.fill(); for(const [cx,cy,a] of [[1277,3348,-.3],[1380,3350,.3],[1278,3405,.3],[1379,3407,-.3]]){ctx.save();ctx.translate(cx,cy);ctx.rotate(a);ctx.fillStyle='#83684c';ctx.fillRect(-16,-9,32,18);ctx.restore();} } function drawGarden(){ // Garden and flowers are one coherent landscaped zone. const gx=1460,gy=3315; rect(gx-22,gy-18,300,118,'rgba(88,110,61,.24)',null,0); for(let i=0;i<2;i++){ const yy=gy+i*48;rect(gx,yy,190,34,'#775033','#3b2d22',4); for(let j=0;j<8;j++){ctx.fillStyle=j%2?'#4d8d42':'#6aa556';ctx.beginPath();ctx.arc(gx+20+j*22,yy+17,6,0,Math.PI*2);ctx.fill();} } const cols=['#e64a38','#f1b83e','#9766a3','#f0e9dc']; for(let i=0;i<16;i++)flower(gx+215+(i%4)*18,gy+2+Math.floor(i/4)*22,cols[i%4]); ctx.fillStyle='#f4e6be';ctx.font='900 10px system-ui';ctx.textAlign='center';ctx.fillText('GARDEN',gx+95,gy-6); } function drawArchery(){ // A readable lane: shooting line, bow rack, arrows, target and safety marker. const sx=1735,sy=3400,tx=1940,ty=3400; line([[sx,sy],[tx-42,ty]],'rgba(239,229,190,.42)',4,[12,9]); line([[sx,sy-34],[sx,sy+34]],'#f4e6be',5); ctx.fillStyle='#6f4b2f';ctx.fillRect(sx-42,sy-24,12,50);ctx.fillRect(sx-55,sy-27,38,6); // Bow silhouette and arrow bundle. ctx.strokeStyle='#3a251b';ctx.lineWidth=4;ctx.beginPath();ctx.arc(sx-28,sy,18,-Math.PI/2,Math.PI/2);ctx.stroke();line([[sx-28,sy-18],[sx-28,sy+18]],'#d9c7a2',2); for(let i=0;i<3;i++)line([[sx-3+i*5,sy-20],[sx-3+i*5,sy+20]],'#d9c7a2',2); ctx.fillStyle='#e7ddc7';ctx.beginPath();ctx.arc(tx,ty,34,0,Math.PI*2);ctx.fill();ctx.strokeStyle='#433c33';ctx.lineWidth=4;ctx.stroke(); for(const [r,c] of [[25,'#2b2b2b'],[18,'#e7ddc7'],[12,'#e64a38'],[6,'#f1b83e']]){ctx.fillStyle=c;ctx.beginPath();ctx.arc(tx,ty,r,0,Math.PI*2);ctx.fill();} ctx.fillStyle='#5a4936';ctx.fillRect(tx-6,ty+32,12,26); ctx.fillStyle='#f4e6be';ctx.font='900 10px system-ui';ctx.textAlign='center'; } function drawYard(h){ const l=h.lot;ctx.save(); drawFence(h); // Wide, open, drivable loop around entire property. Visual only, no collision. ctx.strokeStyle='rgba(238,233,205,.075)';ctx.lineWidth=38;ctx.strokeRect(l.x+68,l.y+68,l.w-136,l.h-136); drawHotTub();drawBeerPong();drawFirePit();drawGarden();drawArchery(); ctx.restore(); } // Prevent the legacy property-border drawer from duplicating the new Band fence. if(typeof drawR36B45PropertyBorder==='function'){ const oldBorder48e=drawR36B45PropertyBorder; drawR36B45PropertyBorder=function(h){if(h&&h.id==='band')return;return oldBorder48e(h);}; } drawR36B45BandHome=function(h){ drawStage(h.stage||band.stage); drawHouse(h); drawYard(h); drawHomeParkedVehicle(h,'band'); }; // Replace accumulated legacy collision wrappers with one clean definition. homeBuildingBlocked=function(x,y){ if(!R36B45_HOMES||typeof R36B45_HOMES!=='object')return false; for(const h of Object.values(R36B45_HOMES)){ if(!h||!h.building)continue; if(h.id==='band'){ const b=h.building,s=h.stage||band.stage; if(x>=b.x-24&&x<=b.x+b.w+30&&y>=b.y-20&&y<=b.y+b.h+40)return true; if(s&&x>=s.x-22&&x<=s.x+s.w+22&&y>=s.y-18&&y<=s.y+s.h+32)return true; }else if(x>=h.building.x-42&&x<=h.building.x+h.building.w+28&&y>=h.building.y-80&&y<=h.building.y+h.building.h+42)return true; } return false; }; })(); </script> <script> /* R36B48G — Band House facade, yard semantics, entrance and stage-lighting pass. */ (function(){ if(!window.R36B45_HOMES||!R36B45_HOMES.band)return; const band=R36B45_HOMES.band; band.heroVersion='R36B48H'; band.building={x:1490,y:3060,w:320,h:205}; band.door={x:1619,y:3192,w:56,h:56}; band.stage={x:1085,y:3155,w:255,h:178}; band.spawn={x:1510,y:2945,angle:-Math.PI/2}; band.roadCenterX=1510; function rect(x,y,w,h,fill,stroke='#171514',lw=4){ctx.fillStyle=fill;ctx.fillRect(x,y,w,h);if(stroke){ctx.strokeStyle=stroke;ctx.lineWidth=lw;ctx.strokeRect(x,y,w,h)}} function poly(p,fill,stroke='#171514',lw=4){ctx.beginPath();ctx.moveTo(p[0][0],p[0][1]);for(let i=1;i<p.length;i++)ctx.lineTo(p[i][0],p[i][1]);ctx.closePath();ctx.fillStyle=fill;ctx.fill();if(stroke){ctx.strokeStyle=stroke;ctx.lineWidth=lw;ctx.stroke()}} function line(p,color,lw=3,dash=[]){ctx.save();ctx.strokeStyle=color;ctx.lineWidth=lw;ctx.setLineDash(dash);ctx.beginPath();ctx.moveTo(p[0][0],p[0][1]);for(let i=1;i<p.length;i++)ctx.lineTo(p[i][0],p[i][1]);ctx.stroke();ctx.restore()} function shadowPoly(p,a=.24){ctx.save();ctx.translate(-28,30);poly(p,'rgba(14,18,18,'+a+')',null,0);ctx.restore()} function flower(x,y,c){ctx.fillStyle='#315f2d';ctx.fillRect(x-1,y,2,8);ctx.fillStyle=c;for(let a=0;a<Math.PI*2;a+=Math.PI/2){ctx.beginPath();ctx.arc(x+Math.cos(a)*3.3,y+Math.sin(a)*3.3,2.5,0,Math.PI*2);ctx.fill()}ctx.fillStyle='#f1b83e';ctx.beginPath();ctx.arc(x,y,1.8,0,Math.PI*2);ctx.fill()} function southWindow(x,y,w,h){rect(x,y,w,h,'#91d3e2','#34474d',3);line([[x+w/2,y+2],[x+w/2,y+h-2]],'rgba(255,255,255,.82)',2);line([[x+2,y+h/2],[x+w-2,y+h/2]],'rgba(255,255,255,.82)',2)} function eastWindow(x,y,w,h){poly([[x,y+8],[x+w,y],[x+w,y+h-8],[x,y+h]],'#91d3e2','#34474d',3);line([[x+w/2,y+4],[x+w/2,y+h-4]],'rgba(255,255,255,.82)',2)} function drawBandFence(h){ const l=h.lot,cx=h.roadCenterX||1510,gap=220; ctx.save();ctx.strokeStyle='#7d5639';ctx.lineWidth=8;ctx.lineCap='square'; line([[l.x+10,l.y+10],[cx-gap/2,l.y+10]],'#7d5639',8); line([[cx+gap/2,l.y+10],[l.x+l.w-10,l.y+10]],'#7d5639',8); line([[l.x+10,l.y+10],[l.x+10,l.y+l.h-10],[l.x+l.w-10,l.y+l.h-10],[l.x+l.w-10,l.y+10]],'#7d5639',8); ctx.fillStyle='#b17a4f'; for(let x=l.x+18;x<l.x+l.w-12;x+=58){if(x<cx-gap/2-8||x>cx+gap/2+8)ctx.fillRect(x-4,l.y+2,8,18);ctx.fillRect(x-4,l.y+l.h-20,8,18)} for(let y=l.y+22;y<l.y+l.h-16;y+=58){ctx.fillRect(l.x+2,y-8,8,17);ctx.fillRect(l.x+l.w-10,y-8,8,17)} ctx.restore(); } function drawHouseG(h){ const x=h.building.x,y=h.building.y,w=h.building.w; const wallTop=y+83,frontBottom=y+190,side=46; shadowPoly([[x-6,wallTop],[x+w+side,wallTop-28],[x+w+side,frontBottom-20],[x+w,frontBottom],[x,frontBottom]],.28); // South facade follows the same hard-edged pseudo-3D language as the city businesses. rect(x,wallTop,w,frontBottom-wallTop,'#dfc79d','#171514',5); poly([[x+w,wallTop],[x+w+side,wallTop-28],[x+w+side,frontBottom-25],[x+w,frontBottom]],'#b68b68','#171514',5); // Keep the approved dominant roof, with a sharper eave and east return. poly([[x-12,wallTop],[x+54,y+4],[x+w-42,y+4],[x+w+18,wallTop-18],[x+w,wallTop+3],[x,wallTop+3]],'#873f3d','#171514',5); poly([[x+w-42,y+4],[x+w+14,y-10],[x+w+side+12,wallTop-37],[x+w+18,wallTop-18]],'#4f2d2c','#171514',5); line([[x,wallTop+3],[x+w,wallTop+3]],'#231817',8); for(let xx=x+34;xx<x+w-30;xx+=42)line([[xx,y+18],[xx+24,wallTop-8]],'rgba(255,255,255,.08)',2); for(let yy=y+30;yy<wallTop-6;yy+=17)line([[x+34,yy],[x+w-18,yy]],'rgba(255,255,255,.09)',2); rect(x+w-65,y+7,34,48,'#684538','#171514',4);rect(x+w-70,y+3,44,10,'#2d2522','#171514',3); southWindow(x+34,wallTop+18,62,40);southWindow(x+w-103,wallTop+18,62,40);eastWindow(x+w+10,wallTop+11,27,46); rect(h.door.x,h.door.y,h.door.w,h.door.h,'#38251f','#171514',4);ctx.fillStyle='#f1b83e';ctx.beginPath();ctx.arc(h.door.x+h.door.w-10,h.door.y+h.door.h/2,4,0,Math.PI*2);ctx.fill(); rect(x+110,frontBottom,100,15,'#947455','#171514',3);rect(x+120,frontBottom+15,80,10,'#725b43','#171514',3); drawGuitarMailbox(x+235,frontBottom+34); } function drawGuitarMailbox(x,y){ ctx.save();ctx.fillStyle='#65452f';ctx.fillRect(x-3,y+13,6,42);ctx.fillStyle='#27211d';ctx.fillRect(x-18,y+48,36,7); // Guitar body doubles as the mailbox body; neck supports the flag. ctx.fillStyle='#a84b35';ctx.beginPath();ctx.arc(x,y,14,0,Math.PI*2);ctx.fill();ctx.beginPath();ctx.arc(x,y+16,18,0,Math.PI*2);ctx.fill();ctx.strokeStyle='#2b1d17';ctx.lineWidth=3;ctx.stroke(); ctx.fillStyle='#d8b46c';ctx.fillRect(x-4,y-30,8,31);ctx.fillStyle='#2b1d17';ctx.fillRect(x-7,y-34,14,7); ctx.fillStyle='#f4e6be';ctx.font='900 7px system-ui';ctx.textAlign='center';ctx.fillText('MAIL',x,y+18); ctx.strokeStyle='#e64a38';ctx.lineWidth=3;ctx.beginPath();ctx.moveTo(x+12,y-3);ctx.lineTo(x+24,y-17);ctx.stroke();ctx.fillStyle='#e64a38';ctx.fillRect(x+22,y-23,12,8);ctx.restore(); } function drawStageG(s){ const x=s.x,y=s.y,w=s.w,depth=38,deckTop=y+78,deckBottom=y+157; shadowPoly([[x-6,y+30],[x+w+depth,y+6],[x+w+depth,deckBottom-16],[x+w,deckBottom],[x,deckBottom]],.27); // Stage base/facade mirrors the city's pseudo-building facade angle. rect(x,deckTop,w,deckBottom-deckTop,'#6d523b','#171514',5); poly([[x+w,deckTop],[x+w+depth,deckTop-23],[x+w+depth,deckBottom-20],[x+w,deckBottom]],'#4d3a2c','#171514',5); // Canopy top, parallel to parcel edges and facing south. poly([[x-8,deckTop],[x+34,y+18],[x+w-30,y+18],[x+w+10,deckTop-12],[x+w,deckTop+3],[x,deckTop+3]],'#232426','#111',5); poly([[x+w-30,y+18],[x+w+10,y+8],[x+w+depth+7,deckTop-35],[x+w+10,deckTop-12]],'#111214','#111',4); rect(x+14,y+68,w-28,45,'#171717','#343434',3); // Truss and lights move to the north/top edge, with rods visually extending SW like their shadows. const ty=y+33;line([[x+12,ty],[x+w-12,ty]],'#aab2b4',6);line([[x+14,ty],[x-5,ty+39]],'#aab2b4',5);line([[x+w-14,ty],[x+w-33,ty+39]],'#aab2b4',5); const colors=['#e64a38','#f1b83e','#3f84a5','#9766a3','#e64a38']; for(let i=0;i<5;i++){const lx=x+25+i*(w-50)/4;ctx.fillStyle=colors[i];ctx.beginPath();ctx.arc(lx,ty+7,7,0,Math.PI*2);ctx.fill();ctx.strokeStyle='#222';ctx.lineWidth=2;ctx.stroke();line([[lx+2,ty+12],[lx-11,ty+32]],'rgba(15,18,18,.18)',4)} // Performance gear. rect(x+85,y+77,84,31,'#555','#111',3);ctx.fillStyle='#c9c9c9';ctx.beginPath();ctx.arc(x+127,y+92,14,0,Math.PI*2);ctx.fill();ctx.strokeStyle='#111';ctx.stroke(); for(const q of [x+18,x+w-46]){rect(q,y+73,28,48,'#111','#555',3);ctx.fillStyle='#4d4d4d';ctx.beginPath();ctx.arc(q+14,y+86,7,0,Math.PI*2);ctx.arc(q+14,y+107,9,0,Math.PI*2);ctx.fill()} for(const q of [x+70,x+w-70]){line([[q,y+90],[q,deckBottom-7]],'#c4c7c8',3);line([[q,y+96],[q+14,y+89]],'#c4c7c8',3);poly([[q-14,deckBottom-13],[q+14,deckBottom-13],[q+9,deckBottom-2],[q-18,deckBottom-2]],'#373737','#111',2)} ctx.fillStyle='#f4e6be';ctx.font='1000 10px system-ui';ctx.textAlign='center';ctx.fillText('BACKYARD PRACTICE STAGE',x+w/2,y+62); } function drawHotTubG(){ rect(1778,2898,172,138,'#a88d70','#5b4939',4);ctx.beginPath();ctx.roundRect(1793,2914,142,102,20);ctx.fillStyle='#66635d';ctx.fill();ctx.strokeStyle='#2d2b29';ctx.lineWidth=4;ctx.stroke();ctx.beginPath();ctx.roundRect(1808,2929,112,72,15);ctx.fillStyle='#3f91a9';ctx.fill();ctx.strokeStyle='#d8d0be';ctx.stroke();ctx.fillStyle='rgba(255,255,255,.28)';for(let i=0;i<4;i++){ctx.beginPath();ctx.arc(1827+i*24,2960+(i%2)*6,5,0,Math.PI*2);ctx.fill()} } function drawFirePitG(){const x=1640,y=3070;ctx.fillStyle='#4c4237';ctx.beginPath();ctx.arc(x,y,34,0,Math.PI*2);ctx.fill();ctx.strokeStyle='#9c8265';ctx.lineWidth=6;ctx.stroke();ctx.fillStyle='#e64a38';ctx.beginPath();ctx.arc(x,y,14,0,Math.PI*2);ctx.fill();ctx.fillStyle='#f1b83e';ctx.beginPath();ctx.arc(x,y-5,7,0,Math.PI*2);ctx.fill();for(const [cx,cy,a] of [[x-52,y-24,-.3],[x+52,y-22,.3],[x-52,y+36,.3],[x+52,y+36,-.3]]){ctx.save();ctx.translate(cx,cy);ctx.rotate(a);ctx.fillStyle='#83684c';ctx.fillRect(-16,-9,32,18);ctx.restore()}} function drawBeerPongG(){const x=1080,y=3360;rect(x-14,y-16,205,106,'rgba(185,164,122,.40)',null,0);rect(x,y,170,72,'#286c56','#eef3ef',4);line([[x+85,y+2],[x+85,y+70]],'#eef3ef',3);ctx.fillStyle='#8a5d3c';ctx.fillRect(x+13,y+72,9,21);ctx.fillRect(x+148,y+72,9,21);const cups=[[20,19],[33,19],[46,19],[26,32],[39,32],[33,45]];ctx.fillStyle='#e64a38';for(const [cx,cy] of cups){for(const mirror of [0,1]){const px=mirror?x+170-cx:x+cx;ctx.beginPath();ctx.arc(px,y+cy,4.5,0,Math.PI*2);ctx.fill()}}} function drawGardenFlowersG(){const gx=1060,gy=2905;rect(gx-18,gy-14,300,130,'rgba(88,110,61,.24)',null,0);for(let r=0;r<2;r++){rect(gx,gy+r*49,190,35,'#775033','#3b2d22',4);for(let j=0;j<8;j++){ctx.fillStyle=j%2?'#4d8d42':'#6aa556';ctx.beginPath();ctx.arc(gx+20+j*22,gy+r*49+18,6,0,Math.PI*2);ctx.fill()}}const c=['#e64a38','#f1b83e','#9766a3','#f0e9dc'];for(let i=0;i<20;i++)flower(gx+216+(i%5)*16,gy+4+Math.floor(i/5)*24,c[i%4]);ctx.fillStyle='#f4e6be';ctx.font='900 10px system-ui';ctx.textAlign='center';ctx.fillText('GARDEN + FLOWERS',gx+95,gy-4)} function drawArcheryG(){const sx=1710,sy=3400,tx=1950,ty=3400;rect(sx-58,sy-52,295,108,'rgba(135,112,72,.15)',null,0);line([[sx,sy],[tx-45,ty]],'rgba(239,229,190,.5)',4,[12,9]);line([[sx,sy-38],[sx,sy+38]],'#f4e6be',5);ctx.fillStyle='#6f4b2f';ctx.fillRect(sx-45,sy-29,12,58);ctx.fillRect(sx-58,sy-31,40,6);ctx.strokeStyle='#3a251b';ctx.lineWidth=4;ctx.beginPath();ctx.arc(sx-29,sy,20,-Math.PI/2,Math.PI/2);ctx.stroke();line([[sx-29,sy-20],[sx-29,sy+20]],'#d9c7a2',2);for(let i=0;i<4;i++)line([[sx-5+i*5,sy-23],[sx-5+i*5,sy+23]],'#d9c7a2',2);ctx.fillStyle='#e7ddc7';ctx.beginPath();ctx.arc(tx,ty,36,0,Math.PI*2);ctx.fill();ctx.strokeStyle='#433c33';ctx.lineWidth=4;ctx.stroke();for(const [r,c] of [[27,'#2b2b2b'],[20,'#e7ddc7'],[13,'#e64a38'],[6,'#f1b83e']]){ctx.fillStyle=c;ctx.beginPath();ctx.arc(tx,ty,r,0,Math.PI*2);ctx.fill()}ctx.fillStyle='#5a4936';ctx.fillRect(tx-6,ty+34,12,28);ctx.fillStyle='#f4e6be';ctx.font='900 10px system-ui';ctx.textAlign='center';} function drawInstruments(){ // Guitar, keyboard case and drum cases positioned as believable yard/stage props. ctx.save();ctx.translate(1372,3265);ctx.rotate(-.22);ctx.fillStyle='#8b4d2f';ctx.beginPath();ctx.arc(0,0,11,0,Math.PI*2);ctx.arc(0,13,15,0,Math.PI*2);ctx.fill();ctx.fillRect(-3,-31,6,31);ctx.fillStyle='#2b1d17';ctx.fillRect(-6,-36,12,7);ctx.restore(); rect(1420,3290,72,22,'#2b2c2e','#111',3);for(let i=0;i<8;i++){ctx.fillStyle=i%2?'#111':'#eee';ctx.fillRect(1428+i*7,3294,6,12)} ctx.fillStyle='#333';ctx.beginPath();ctx.arc(1345,3300,15,0,Math.PI*2);ctx.arc(1380,3304,12,0,Math.PI*2);ctx.fill();ctx.strokeStyle='#777';ctx.lineWidth=3;ctx.stroke(); } function drawYardG(h){drawBandFence(h);ctx.save();const l=h.lot;ctx.strokeStyle='rgba(238,233,205,.07)';ctx.lineWidth=44;ctx.strokeRect(l.x+72,l.y+72,l.w-144,l.h-144);drawGardenFlowersG();drawHotTubG();drawFirePitG();drawBeerPongG();drawArcheryG();drawInstruments();ctx.restore()} const oldGround=drawR36B45ResidentialGround; drawR36B45ResidentialGround=function(h){ if(!h||h.id!=='band')return oldGround(h); const l=h.lot;ctx.save();ctx.fillStyle=h.yard;ctx.fillRect(l.x,l.y,l.w,l.h);ctx.fillStyle='rgba(255,255,255,.028)';for(let i=0;i<9;i++)ctx.fillRect(l.x+28+i*101,l.y+30,45,l.h-60); // No second asphalt slab. Only the center line continues from the existing street to the entrance. ctx.strokeStyle='#d7b64e';ctx.lineWidth=4;ctx.setLineDash([25,20]);ctx.beginPath();ctx.moveTo(h.roadCenterX,h.road.y+10);ctx.lineTo(h.roadCenterX,l.y-8);ctx.stroke();ctx.setLineDash([]);ctx.restore(); }; drawR36B45BandHome=function(h){drawStageG(h.stage||band.stage);drawHouseG(h);drawYardG(h);drawHomeParkedVehicle(h,'band')}; homeBuildingBlocked=function(x,y){ if(!R36B45_HOMES||typeof R36B45_HOMES!=='object')return false; for(const h of Object.values(R36B45_HOMES)){ if(!h||!h.building)continue; if(h.id==='band'){ const b=h.building,s=h.stage||band.stage; if(x>=b.x-18&&x<=b.x+b.w+62&&y>=b.y-10&&y<=b.y+250)return true; if(s&&x>=s.x-18&&x<=s.x+s.w+50&&y>=s.y-8&&y<=s.y+s.h+26)return true; }else if(x>=h.building.x-42&&x<=h.building.x+h.building.w+28&&y>=h.building.y-80&&y<=h.building.y+h.building.h+42)return true; } return false; }; })(); </script> <script> /* R36B48H — South-facing top-down Band House, Red River entrance and semantic yard correction. */ (function(){ if(!window.R36B45_HOMES||!R36B45_HOMES.band)return; const band=R36B45_HOMES.band; band.heroVersion='R36B48H'; // Red River occupies x 1270–1440; use its true center for the home approach. band.roadCenterX=1355; band.road={x:1205,y:2600,w:300,h:190}; band.pullin={x:1205,y:2600,w:300,h:190}; band.spawn={x:1355,y:2875,angle:-Math.PI/2}; // Keep the house and stage parallel to the parcel, with their south façades facing down-map. band.building={x:1510,y:3055,w:330,h:205}; band.door={x:1643,y:3205,w:64,h:50}; band.stage={x:1065,y:3115,w:275,h:185}; if(Array.isArray(window.R36B45_HOME_ROADS)){ const others=R36B45_HOME_ROADS.filter(r=>r!==band.road&&r!==band.pullin&&!(r&&r.x===1360&&r.y===2600)); window.R36B45_HOME_ROADS=others.concat([band.road]); } function rect(x,y,w,h,fill,stroke='#171514',lw=4){ctx.fillStyle=fill;ctx.fillRect(x,y,w,h);if(stroke){ctx.strokeStyle=stroke;ctx.lineWidth=lw;ctx.strokeRect(x,y,w,h)}} function poly(points,fill,stroke='#171514',lw=4){ctx.beginPath();ctx.moveTo(points[0][0],points[0][1]);for(let i=1;i<points.length;i++)ctx.lineTo(points[i][0],points[i][1]);ctx.closePath();ctx.fillStyle=fill;ctx.fill();if(stroke){ctx.strokeStyle=stroke;ctx.lineWidth=lw;ctx.stroke()}} function line(points,color,lw=3,dash=[]){ctx.save();ctx.strokeStyle=color;ctx.lineWidth=lw;ctx.setLineDash(dash);ctx.beginPath();ctx.moveTo(points[0][0],points[0][1]);for(let i=1;i<points.length;i++)ctx.lineTo(points[i][0],points[i][1]);ctx.stroke();ctx.restore()} function shadow(points,a=.26){ctx.save();ctx.translate(-30,32);poly(points,'rgba(13,17,18,'+a+')',null,0);ctx.restore()} function flower(x,y,c){ctx.fillStyle='#315f2d';ctx.fillRect(x-1,y,2,8);ctx.fillStyle=c;for(let a=0;a<Math.PI*2;a+=Math.PI/2){ctx.beginPath();ctx.arc(x+Math.cos(a)*3.2,y+Math.sin(a)*3.2,2.4,0,Math.PI*2);ctx.fill()}ctx.fillStyle='#f1b83e';ctx.beginPath();ctx.arc(x,y,1.8,0,Math.PI*2);ctx.fill()} function windowFront(x,y,w,h){rect(x,y,w,h,'#91d3e2','#34474d',3);line([[x+w/2,y+2],[x+w/2,y+h-2]],'rgba(255,255,255,.8)',2);line([[x+2,y+h/2],[x+w-2,y+h/2]],'rgba(255,255,255,.8)',2)} function drawFenceH(h){ const l=h.lot,cx=h.roadCenterX,gap=230; ctx.save();ctx.strokeStyle='#80583a';ctx.lineWidth=8;ctx.lineCap='square'; line([[l.x+12,l.y+12],[cx-gap/2,l.y+12]],'#80583a',8); line([[cx+gap/2,l.y+12],[l.x+l.w-12,l.y+12]],'#80583a',8); line([[l.x+12,l.y+12],[l.x+12,l.y+l.h-12],[l.x+l.w-12,l.y+l.h-12],[l.x+l.w-12,l.y+12]],'#80583a',8); ctx.fillStyle='#b17a4f'; for(let x=l.x+18;x<l.x+l.w-10;x+=58){if(x<cx-gap/2-8||x>cx+gap/2+8)ctx.fillRect(x-4,l.y+4,8,17);ctx.fillRect(x-4,l.y+l.h-21,8,17)} for(let y=l.y+22;y<l.y+l.h-14;y+=58){ctx.fillRect(l.x+4,y-8,8,17);ctx.fillRect(l.x+l.w-12,y-8,8,17)} ctx.restore(); } function drawHouseH(h){ const x=h.building.x,y=h.building.y,w=h.building.w; const roofTop=y,roofBottom=y+132,frontTop=roofBottom-4,frontBottom=y+202; // The footprint is on the grass. Most visible area is roof; only a narrow south façade remains. shadow([[x+8,roofTop+12],[x+w-8,roofTop+12],[x+w+4,frontBottom],[x+4,frontBottom]],.29); poly([[x+8,roofTop+22],[x+54,roofTop],[x+w-52,roofTop],[x+w-8,roofTop+22],[x+w-20,roofBottom],[x+20,roofBottom]],'#843f3d','#171514',5); // South-facing wall, parallel to the yard edges and intentionally shallow. poly([[x+20,frontTop],[x+w-20,frontTop],[x+w-22,frontBottom],[x+22,frontBottom]],'#dfc79d','#171514',5); // A very narrow east return provides depth without turning the side toward the viewer. poly([[x+w-20,frontTop],[x+w+8,frontTop-12],[x+w+6,frontBottom-12],[x+w-22,frontBottom]],'#b68b68','#171514',4); line([[x+20,frontTop],[x+w-20,frontTop]],'#241817',7); for(let yy=roofTop+24;yy<roofBottom-8;yy+=15)line([[x+30,yy],[x+w-30,yy]],'rgba(255,255,255,.10)',2); for(let xx=x+42;xx<x+w-28;xx+=44)line([[xx,roofTop+10],[xx-18,roofBottom-8]],'rgba(255,255,255,.07)',2); // Chimney remains on the north roof plane. rect(x+w-74,roofTop+7,34,50,'#684538','#171514',4);rect(x+w-79,roofTop+3,44,9,'#2d2522','#171514',3); windowFront(x+50,frontTop+18,66,40);windowFront(x+w-116,frontTop+18,66,40); rect(h.door.x,h.door.y,h.door.w,h.door.h,'#38251f','#171514',4);ctx.fillStyle='#f1b83e';ctx.beginPath();ctx.arc(h.door.x+h.door.w-10,h.door.y+h.door.h/2,4,0,Math.PI*2);ctx.fill(); rect(x+118,frontBottom,94,13,'#927255','#171514',3);rect(x+128,frontBottom+13,74,9,'#725a43','#171514',2); } function drawStageH(s){ const x=s.x,y=s.y,w=s.w,roofBottom=y+104,frontTop=roofBottom-3,frontBottom=y+177; shadow([[x+4,y+8],[x+w-4,y+8],[x+w+5,frontBottom],[x+5,frontBottom]],.28); // Dominant canopy seen from above. poly([[x+8,y+20],[x+42,y],[x+w-40,y],[x+w-8,y+20],[x+w-18,roofBottom],[x+18,roofBottom]],'#242628','#111',5); // Narrow south-facing stage front. poly([[x+18,frontTop],[x+w-18,frontTop],[x+w-18,frontBottom],[x+18,frontBottom]],'#6c523b','#171514',5); rect(x+30,frontTop+8,w-60,38,'#171717','#3a3a3a',3); // Truss and lamps sit along the north/top edge beside the stage name. const ty=y+30;line([[x+22,ty],[x+w-22,ty]],'#aeb4b5',6);line([[x+24,ty],[x+8,ty+33]],'#aeb4b5',5);line([[x+w-24,ty],[x+w-40,ty+33]],'#aeb4b5',5); const colors=['#e64a38','#f1b83e','#3f84a5','#9766a3','#e64a38']; for(let i=0;i<5;i++){const lx=x+33+i*(w-66)/4;ctx.fillStyle=colors[i];ctx.beginPath();ctx.arc(lx,ty+6,7,0,Math.PI*2);ctx.fill();ctx.strokeStyle='#222';ctx.lineWidth=2;ctx.stroke();line([[lx,ty+12],[lx-13,ty+31]],'rgba(12,16,18,.22)',4)} ctx.fillStyle='#f4e6be';ctx.font='1000 10px system-ui';ctx.textAlign='center';ctx.fillText('BACKYARD PRACTICE STAGE',x+w/2,y+59); rect(x+91,frontTop+10,88,30,'#555','#111',3);ctx.fillStyle='#ccc';ctx.beginPath();ctx.arc(x+135,frontTop+25,14,0,Math.PI*2);ctx.fill();ctx.strokeStyle='#111';ctx.stroke(); for(const q of [x+30,x+w-58]){rect(q,frontTop+8,28,46,'#111','#555',3);ctx.fillStyle='#4d4d4d';ctx.beginPath();ctx.arc(q+14,frontTop+21,7,0,Math.PI*2);ctx.arc(q+14,frontTop+40,9,0,Math.PI*2);ctx.fill()} for(const q of [x+75,x+w-75]){line([[q,frontTop+21],[q,frontBottom-8]],'#c4c7c8',3);line([[q,frontTop+26],[q+13,frontTop+20]],'#c4c7c8',3)} } function drawGuitarMailboxH(){ // Mailbox is at the Red River entrance, not beside the house. const x=1450,y=2837;ctx.save();ctx.fillStyle='#65452f';ctx.fillRect(x-3,y+12,6,43);ctx.fillStyle='#27211d';ctx.fillRect(x-18,y+49,36,7); ctx.fillStyle='#a84b35';ctx.beginPath();ctx.arc(x,y,14,0,Math.PI*2);ctx.arc(x,y+16,18,0,Math.PI*2);ctx.fill();ctx.strokeStyle='#2b1d17';ctx.lineWidth=3;ctx.stroke(); ctx.fillStyle='#d8b46c';ctx.fillRect(x-4,y-30,8,31);ctx.fillStyle='#2b1d17';ctx.fillRect(x-7,y-35,14,7); ctx.fillStyle='#f4e6be';ctx.font='900 6px system-ui';ctx.textAlign='center';ctx.fillText('BAND',x,y+12);ctx.fillText('HOUSE',x,y+20); ctx.strokeStyle='#e64a38';ctx.lineWidth=3;ctx.beginPath();ctx.moveTo(x+12,y-2);ctx.lineTo(x+25,y-16);ctx.stroke();ctx.fillStyle='#e64a38';ctx.fillRect(x+22,y-23,13,8);ctx.restore(); } function drawGardenH(){ const gx=1038,gy=2868;rect(gx-14,gy-12,320,126,'rgba(84,108,59,.22)',null,0); for(let r=0;r<2;r++){rect(gx,gy+r*48,194,34,'#775033','#3b2d22',4);for(let j=0;j<8;j++){ctx.fillStyle=j%2?'#4d8d42':'#6aa556';ctx.beginPath();ctx.arc(gx+20+j*22,gy+r*48+17,6,0,Math.PI*2);ctx.fill()}} const c=['#e64a38','#f1b83e','#9766a3','#f0e9dc'];for(let i=0;i<24;i++)flower(gx+220+(i%6)*14,gy+2+Math.floor(i/6)*24,c[i%4]); ctx.fillStyle='#f4e6be';ctx.font='900 10px system-ui';ctx.textAlign='center';ctx.fillText('GARDEN + FLOWERS',gx+97,gy-4); } function drawHotTubH(){const x=1390,y=2880,w=129,h=102;rect(x,y,w,h,'#a88d70','#5b4939',4);ctx.beginPath();ctx.roundRect(x+11,y+11,w-22,h-22,15);ctx.fillStyle='#66635d';ctx.fill();ctx.strokeStyle='#2d2b29';ctx.lineWidth=4;ctx.stroke();ctx.beginPath();ctx.roundRect(x+22,y+22,w-44,h-44,11);ctx.fillStyle='#3f91a9';ctx.fill();ctx.strokeStyle='#d8d0be';ctx.stroke();ctx.fillStyle='rgba(255,255,255,.28)';for(let i=0;i<4;i++){ctx.beginPath();ctx.arc(x+37+i*18,y+49+(i%2)*5,4,0,Math.PI*2);ctx.fill()}} function drawFirePitH(){const x=1510,y=3110;ctx.fillStyle='#4c4237';ctx.beginPath();ctx.arc(x,y,34,0,Math.PI*2);ctx.fill();ctx.strokeStyle='#9c8265';ctx.lineWidth=6;ctx.stroke();ctx.fillStyle='#e64a38';ctx.beginPath();ctx.arc(x,y,14,0,Math.PI*2);ctx.fill();ctx.fillStyle='#f1b83e';ctx.beginPath();ctx.arc(x,y-5,7,0,Math.PI*2);ctx.fill();for(const [cx,cy,a] of [[x-52,y-24,-.3],[x+52,y-22,.3],[x-52,y+36,.3],[x+52,y+36,-.3]]){ctx.save();ctx.translate(cx,cy);ctx.rotate(a);ctx.fillStyle='#83684c';ctx.fillRect(-16,-9,32,18);ctx.restore()}} function drawBeerPongH(){const x=1080,y=3380;rect(x-12,y-14,205,102,'rgba(185,164,122,.34)',null,0);rect(x,y,170,70,'#286c56','#eef3ef',4);line([[x+85,y+2],[x+85,y+68]],'#eef3ef',3);ctx.fillStyle='#8a5d3c';ctx.fillRect(x+13,y+70,9,20);ctx.fillRect(x+148,y+70,9,20);const cups=[[20,18],[33,18],[46,18],[26,31],[39,31],[33,44]];ctx.fillStyle='#e64a38';for(const [cx,cy] of cups){for(const mirror of [0,1]){const px=mirror?x+170-cx:x+cx;ctx.beginPath();ctx.arc(px,y+cy,4.5,0,Math.PI*2);ctx.fill()}}} function drawArcheryH(){ // Long, unobstructed east-side lane with a clear shooter station and target. const sx=1662,sy=3388,tx=1960,ty=3388;rect(sx-58,sy-54,352,110,'rgba(135,112,72,.14)',null,0);line([[sx,sy],[tx-46,ty]],'rgba(239,229,190,.58)',4,[12,9]);line([[sx,sy-39],[sx,sy+39]],'#f4e6be',5); ctx.fillStyle='#6f4b2f';ctx.fillRect(sx-46,sy-29,12,58);ctx.fillRect(sx-59,sy-32,40,6);ctx.strokeStyle='#3a251b';ctx.lineWidth=4;ctx.beginPath();ctx.arc(sx-29,sy,20,-Math.PI/2,Math.PI/2);ctx.stroke();line([[sx-29,sy-20],[sx-29,sy+20]],'#d9c7a2',2);for(let i=0;i<4;i++)line([[sx-5+i*5,sy-23],[sx-5+i*5,sy+23]],'#d9c7a2',2); ctx.fillStyle='#e7ddc7';ctx.beginPath();ctx.arc(tx,ty,36,0,Math.PI*2);ctx.fill();ctx.strokeStyle='#433c33';ctx.lineWidth=4;ctx.stroke();for(const [r,c] of [[27,'#2b2b2b'],[20,'#e7ddc7'],[13,'#e64a38'],[6,'#f1b83e']]){ctx.fillStyle=c;ctx.beginPath();ctx.arc(tx,ty,r,0,Math.PI*2);ctx.fill()}ctx.fillStyle='#5a4936';ctx.fillRect(tx-6,ty+34,12,28);ctx.fillStyle='#f4e6be';ctx.font='900 10px system-ui';ctx.textAlign='center'; } function drawInstrumentsH(){ ctx.save();ctx.translate(1376,3275);ctx.rotate(-.18);ctx.fillStyle='#8b4d2f';ctx.beginPath();ctx.arc(0,0,11,0,Math.PI*2);ctx.arc(0,13,15,0,Math.PI*2);ctx.fill();ctx.fillRect(-3,-31,6,31);ctx.fillStyle='#2b1d17';ctx.fillRect(-6,-36,12,7);ctx.restore(); ctx.fillStyle='#333';ctx.beginPath();ctx.arc(1350,3304,15,0,Math.PI*2);ctx.arc(1384,3306,12,0,Math.PI*2);ctx.fill();ctx.strokeStyle='#777';ctx.lineWidth=3;ctx.stroke(); } function drawYardH(h){ drawFenceH(h);ctx.save();const l=h.lot; // Subtle visual loop only; it does not block the van. ctx.strokeStyle='rgba(238,233,205,.055)';ctx.lineWidth=42;ctx.strokeRect(l.x+70,l.y+70,l.w-140,l.h-140); drawGardenH();drawHotTubH();drawFirePitH();drawBeerPongH();drawArcheryH();drawInstrumentsH();drawGuitarMailboxH();ctx.restore(); } const previousGround=drawR36B45ResidentialGround; drawR36B45ResidentialGround=function(h){ if(!h||h.id!=='band')return previousGround(h); const l=h.lot;ctx.save();ctx.fillStyle=h.yard;ctx.fillRect(l.x,l.y,l.w,l.h);ctx.fillStyle='rgba(255,255,255,.026)';for(let i=0;i<9;i++)ctx.fillRect(l.x+28+i*101,l.y+30,45,l.h-60); // No discolored road overlay: only Red River's center line continues through the outside approach. ctx.strokeStyle='#d7b64e';ctx.lineWidth=4;ctx.setLineDash([25,20]);ctx.beginPath();ctx.moveTo(h.roadCenterX,h.road.y);ctx.lineTo(h.roadCenterX,l.y-8);ctx.stroke();ctx.setLineDash([]);ctx.restore(); }; // Yard first, then buildings, so nothing can accidentally draw over the house or stage. drawR36B45BandHome=function(h){drawYardH(h);drawStageH(h.stage||band.stage);drawHouseH(h);drawHomeParkedVehicle(h,'band')}; homeBuildingBlocked=function(x,y){ if(!R36B45_HOMES||typeof R36B45_HOMES!=='object')return false; for(const h of Object.values(R36B45_HOMES)){ if(!h||!h.building)continue; if(h.id==='band'){ const b=h.building,s=h.stage||band.stage; if(x>=b.x+8&&x<=b.x+b.w+12&&y>=b.y&&y<=b.y+232)return true; if(s&&x>=s.x+4&&x<=s.x+s.w+8&&y>=s.y&&y<=s.y+s.h+10)return true; }else if(x>=h.building.x-42&&x<=h.building.x+h.building.w+28&&y>=h.building.y-80&&y<=h.building.y+h.building.h+42)return true; } return false; }; // Export Band-property helpers for later layout passes. Earlier builds kept these scoped, // which caused the follow-up renderer to fail and left the map/UI partially drawn. window.drawYardH=drawYardH; window.drawFenceH=drawFenceH; window.drawGardenH=drawGardenH; window.drawHotTubH=drawHotTubH; window.drawFirePitH=drawFirePitH; window.drawBeerPongH=drawBeerPongH; window.drawArcheryH=drawArcheryH; window.drawInstrumentsH=drawInstrumentsH; window.drawGuitarMailboxH=drawGuitarMailboxH; window.drawStageH=drawStageH; window.drawHouseH=drawHouseH; })(); </script> <script> /* R36B48I — Band property relational layout: house east, stage west, shared activity rows. */ (function(){ const drawFenceH=window.drawFenceH; const drawGardenH=window.drawGardenH; const drawArcheryH=window.drawArcheryH; const drawInstrumentsH=window.drawInstrumentsH; const drawGuitarMailboxH=window.drawGuitarMailboxH; const drawHotTubH=window.drawHotTubH; const drawFirePitH=window.drawFirePitH; if(!window.R36B45_HOMES||!R36B45_HOMES.band)return; const band=R36B45_HOMES.band; band.heroVersion='R36B48I'; band.building={x:1710,y:2960,w:205,h:330}; band.door={x:1692,y:3090,w:34,h:64}; band.stage={x:1065,y:3025,w:310,h:190}; function rectI(x,y,w,h,fill,stroke='#171514',lw=4){ctx.fillStyle=fill;ctx.fillRect(x,y,w,h);if(stroke){ctx.strokeStyle=stroke;ctx.lineWidth=lw;ctx.strokeRect(x,y,w,h)}} function polyI(points,fill,stroke='#171514',lw=4){ctx.beginPath();ctx.moveTo(points[0][0],points[0][1]);for(let i=1;i<points.length;i++)ctx.lineTo(points[i][0],points[i][1]);ctx.closePath();ctx.fillStyle=fill;ctx.fill();if(stroke){ctx.strokeStyle=stroke;ctx.lineWidth=lw;ctx.stroke()}} function lineI(points,color,lw=3,dash=[]){ctx.save();ctx.strokeStyle=color;ctx.lineWidth=lw;ctx.setLineDash(dash);ctx.beginPath();ctx.moveTo(points[0][0],points[0][1]);for(let i=1;i<points.length;i++)ctx.lineTo(points[i][0],points[i][1]);ctx.stroke();ctx.restore()} function shadowI(points,a=.26){ctx.save();ctx.translate(-30,32);polyI(points,'rgba(13,17,18,'+a+')',null,0);ctx.restore()} function winI(x,y,w,h){rectI(x,y,w,h,'#91d3e2','#34474d',3);lineI([[x+w/2,y+2],[x+w/2,y+h-2]],'rgba(255,255,255,.8)',2);lineI([[x+2,y+h/2],[x+w-2,y+h/2]],'rgba(255,255,255,.8)',2)} function drawHouseI(h){ const x=h.building.x,y=h.building.y,w=h.building.w,hh=h.building.h; // Long north-south footprint along the east side. Roof dominates; narrow west facade faces the stage. shadowI([[x+8,y+6],[x+w-10,y+20],[x+w-8,y+hh-12],[x+6,y+hh-2]],.29); polyI([[x+28,y],[x+w-10,y+28],[x+w-10,y+hh-36],[x+28,y+hh],[x,y+hh-28],[x,y+30]],'#843f3d','#171514',5); for(let yy=y+34;yy<y+hh-36;yy+=18)lineI([[x+18,yy],[x+w-20,yy+10]],'rgba(255,255,255,.10)',2); // Narrow west-facing facade toward the stage. polyI([[x,y+30],[x+28,y],[x+28,y+hh],[x,y+hh-28]],'#dfc79d','#171514',5); // Short south return for depth. polyI([[x+28,y+hh],[x+w-10,y+hh-36],[x+w+12,y+hh-14],[x+18,y+hh+18]],'#b68b68','#171514',4); winI(x+5,y+72,22,54);winI(x+5,y+208,22,54); rectI(x-18,y+142,34,64,'#38251f','#171514',4);ctx.fillStyle='#f1b83e';ctx.beginPath();ctx.arc(x+8,y+174,4,0,Math.PI*2);ctx.fill(); rectI(x+58,y+hh-28,48,24,'#91d3e2','#34474d',3); rectI(x+w-58,y+28,32,48,'#684538','#171514',4);rectI(x+w-64,y+22,44,9,'#2d2522','#171514',3); ctx.fillStyle='#f4e6be';ctx.font='900 9px system-ui';ctx.textAlign='center';ctx.fillText('BAND HOUSE',x+12,y+hh/2+78); } function drawStageI(s){ const x=s.x,y=s.y,w=s.w,h=s.h; // Stage on west side faces east toward the house. shadowI([[x+6,y+6],[x+w-4,y+10],[x+w+8,y+h-4],[x+12,y+h]],.28); polyI([[x+24,y],[x+w-34,y],[x+w,y+26],[x+w,y+h-30],[x+w-30,y+h],[x+24,y+h]],'#242628','#111',5); polyI([[x+w-30,y+28],[x+w,y+26],[x+w,y+h-30],[x+w-30,y+h-8]],'#6c523b','#171514',5); rectI(x+34,y+32,w-78,h-66,'#171717','#3a3a3a',3); // East/top edge truss and lights facing house. const tx=x+w-42;lineI([[tx,y+24],[tx,y+h-24]],'#aeb4b5',6);lineI([[tx,y+26],[tx-28,y+10]],'#aeb4b5',5);lineI([[tx,y+h-26],[tx-28,y+h-10]],'#aeb4b5',5); const colors=['#e64a38','#f1b83e','#3f84a5','#9766a3','#e64a38']; for(let i=0;i<5;i++){const ly=y+35+i*(h-70)/4;ctx.fillStyle=colors[i];ctx.beginPath();ctx.arc(tx-6,ly,7,0,Math.PI*2);ctx.fill();ctx.strokeStyle='#222';ctx.lineWidth=2;ctx.stroke();lineI([[tx-12,ly],[tx-32,ly+13]],'rgba(12,16,18,.22)',4)} ctx.save();ctx.translate(x+44,y+h/2);ctx.rotate(-Math.PI/2);ctx.fillStyle='#f4e6be';ctx.font='1000 10px system-ui';ctx.textAlign='center';ctx.fillText('BACKYARD PRACTICE STAGE',0,0);ctx.restore(); rectI(x+116,y+65,78,34,'#555','#111',3);ctx.fillStyle='#ccc';ctx.beginPath();ctx.arc(x+155,y+82,14,0,Math.PI*2);ctx.fill();ctx.strokeStyle='#111';ctx.stroke(); for(const q of [y+52,y+h-82]){rectI(x+48,q,30,48,'#111','#555',3);ctx.fillStyle='#4d4d4d';ctx.beginPath();ctx.arc(x+63,q+15,7,0,Math.PI*2);ctx.arc(x+63,q+35,9,0,Math.PI*2);ctx.fill()} } function drawHotTubI(){const x=1848,y=2824,w=129,h=102;rectI(x,y,w,h,'#a88d70','#5b4939',4);ctx.beginPath();ctx.roundRect(x+9,y+9,w-18,h-18,15);ctx.fillStyle='#66635d';ctx.fill();ctx.strokeStyle='#2d2b29';ctx.lineWidth=4;ctx.stroke();ctx.beginPath();ctx.roundRect(x+18,y+18,w-36,h-36,11);ctx.fillStyle='#3f91a9';ctx.fill();ctx.strokeStyle='#d8d0be';ctx.stroke();ctx.fillStyle='rgba(255,255,255,.28)';for(let i=0;i<4;i++){ctx.beginPath();ctx.arc(x+31+i*18,y+51+(i%2)*4,4,0,Math.PI*2);ctx.fill()}} function drawFirePitI(){const x=1510,y=3110;ctx.fillStyle='#4c4237';ctx.beginPath();ctx.arc(x,y,34,0,Math.PI*2);ctx.fill();ctx.strokeStyle='#9c8265';ctx.lineWidth=6;ctx.stroke();ctx.fillStyle='#e64a38';ctx.beginPath();ctx.arc(x,y,14,0,Math.PI*2);ctx.fill();ctx.fillStyle='#f1b83e';ctx.beginPath();ctx.arc(x,y-5,7,0,Math.PI*2);ctx.fill();for(const [cx,cy,a] of [[x-52,y-24,-.3],[x+52,y-22,.3],[x-52,y+36,.3],[x+52,y+36,-.3]]){ctx.save();ctx.translate(cx,cy);ctx.rotate(a);ctx.fillStyle='#83684c';ctx.fillRect(-16,-9,32,18);ctx.restore()}} function drawBeerPongI(){const x=1055,y=3360;rectI(x-12,y-14,205,102,'rgba(185,164,122,.34)',null,0);rectI(x,y,170,70,'#286c56','#eef3ef',4);lineI([[x+85,y+2],[x+85,y+68]],'#eef3ef',3);ctx.fillStyle='#8a5d3c';ctx.fillRect(x+13,y+70,9,20);ctx.fillRect(x+148,y+70,9,20);const cups=[[20,18],[33,18],[46,18],[26,31],[39,31],[33,44]];ctx.fillStyle='#e64a38';for(const [cx,cy] of cups){for(const mirror of [0,1]){const px=mirror?x+170-cx:x+cx;ctx.beginPath();ctx.arc(px,y+cy,4.5,0,Math.PI*2);ctx.fill()}}} const oldYard=drawYardH; drawYardH=function(h){ drawFenceH(h);ctx.save();const l=h.lot;ctx.strokeStyle='rgba(238,233,205,.045)';ctx.lineWidth=42;ctx.strokeRect(l.x+70,l.y+70,l.w-140,l.h-140); drawGardenH();drawHotTubI();drawFirePitI();drawBeerPongI();drawArcheryH();drawInstrumentsH();drawGuitarMailboxH();ctx.restore(); }; drawR36B45BandHome=function(h){drawYardH(h);drawStageI(h.stage||band.stage);drawHouseI(h);drawHomeParkedVehicle(h,'band')}; homeBuildingBlocked=function(x,y){ if(!R36B45_HOMES||typeof R36B45_HOMES!=='object')return false; for(const h of Object.values(R36B45_HOMES)){ if(!h||!h.building)continue; if(h.id==='band'){const b=h.building,s=h.stage||band.stage;if(x>=b.x-25&&x<=b.x+b.w+20&&y>=b.y-8&&y<=b.y+b.h+25)return true;if(s&&x>=s.x-8&&x<=s.x+s.w+12&&y>=s.y-8&&y<=s.y+s.h+12)return true;} else if(x>=h.building.x-42&&x<=h.building.x+h.building.w+28&&y>=h.building.y-80&&y<=h.building.y+h.building.h+42)return true; } return false; }; })(); </script> <script> /* R36B48J — Band property alignment correction: centered east house, sideways stage, aligned activity row. */ (function(){ const drawFenceH=window.drawFenceH; const drawGardenH=window.drawGardenH; const drawArcheryH=window.drawArcheryH; const drawInstrumentsH=window.drawInstrumentsH; const drawGuitarMailboxH=window.drawGuitarMailboxH; const drawHotTubH=window.drawHotTubH; const drawFirePitH=window.drawFirePitH; if(!window.R36B45_HOMES||!R36B45_HOMES.band)return; const band=R36B45_HOMES.band; band.heroVersion='R36B48O'; // The house center sits halfway between the hot-tub row and archery row. band.building={x:1705,y:2978,w:220,h:325}; band.door={x:1687,y:3110,w:36,h:62}; // Sideways/north-south stage on the west side, opening east toward the house. band.stage={x:1080,y:2988,w:235,h:300}; function rj(x,y,w,h,fill,stroke='#171514',lw=4){ctx.fillStyle=fill;ctx.fillRect(x,y,w,h);if(stroke){ctx.strokeStyle=stroke;ctx.lineWidth=lw;ctx.strokeRect(x,y,w,h)}} function pj(p,fill,stroke='#171514',lw=4){ctx.beginPath();ctx.moveTo(p[0][0],p[0][1]);for(let i=1;i<p.length;i++)ctx.lineTo(p[i][0],p[i][1]);ctx.closePath();ctx.fillStyle=fill;ctx.fill();if(stroke){ctx.strokeStyle=stroke;ctx.lineWidth=lw;ctx.stroke()}} function lj(p,c,lw=3,d=[]){ctx.save();ctx.strokeStyle=c;ctx.lineWidth=lw;ctx.setLineDash(d);ctx.beginPath();ctx.moveTo(p[0][0],p[0][1]);for(let i=1;i<p.length;i++)ctx.lineTo(p[i][0],p[i][1]);ctx.stroke();ctx.restore()} function sj(p,a=.26){ctx.save();ctx.translate(-28,30);pj(p,'rgba(13,17,18,'+a+')',null,0);ctx.restore()} function wj(x,y,w,h){rj(x,y,w,h,'#91d3e2','#34474d',3);lj([[x+w/2,y+2],[x+w/2,y+h-2]],'rgba(255,255,255,.8)',2);lj([[x+2,y+h/2],[x+w-2,y+h/2]],'rgba(255,255,255,.8)',2)} function drawHouseJ(h){ const x=h.building.x,y=h.building.y,w=h.building.w,hh=h.building.h; sj([[x+12,y+6],[x+w-10,y+22],[x+w-8,y+hh-18],[x+8,y+hh-2]],.29); // Dominant roof plane, parallel to the east property edge. pj([[x+30,y],[x+w-12,y+28],[x+w-12,y+hh-38],[x+30,y+hh],[x,y+hh-28],[x,y+30]],'#843f3d','#171514',5); for(let yy=y+38;yy<y+hh-42;yy+=19)lj([[x+19,yy],[x+w-22,yy+10]],'rgba(255,255,255,.10)',2); // Narrow west facade facing the stage. pj([[x,y+30],[x+30,y],[x+30,y+hh],[x,y+hh-28]],'#dfc79d','#171514',5); // Small southern return only, keeping the top-down look. pj([[x+30,y+hh],[x+w-12,y+hh-38],[x+w+9,y+hh-16],[x+18,y+hh+16]],'#b68b68','#171514',4); wj(x+5,y+76,23,54);wj(x+5,y+211,23,54); rj(x-18,y+145,36,62,'#38251f','#171514',4);ctx.fillStyle='#f1b83e';ctx.beginPath();ctx.arc(x+9,y+176,4,0,Math.PI*2);ctx.fill(); rj(x+58,y+hh-27,50,23,'#91d3e2','#34474d',3); rj(x+w-60,y+30,33,47,'#684538','#171514',4);rj(x+w-66,y+23,45,9,'#2d2522','#171514',3); ctx.save();ctx.translate(x+12,y+hh/2+74);ctx.rotate(-Math.PI/2);ctx.fillStyle='#f4e6be';ctx.font='900 9px system-ui';ctx.textAlign='center';ctx.fillText('BAND HOUSE',0,0);ctx.restore(); } function drawStageJ(s){ const x=s.x,y=s.y,w=s.w,h=s.h; sj([[x+5,y+5],[x+w-5,y+10],[x+w+7,y+h-5],[x+10,y+h]],.28); // Tall north-south canopy/body: unmistakably sideways and facing east. pj([[x+22,y],[x+w-33,y],[x+w,y+27],[x+w,y+h-28],[x+w-32,y+h],[x+22,y+h]],'#242628','#111',5); pj([[x+w-32,y+28],[x+w,y+27],[x+w,y+h-28],[x+w-32,y+h-8]],'#6c523b','#171514',5); rj(x+34,y+33,w-76,h-66,'#171717','#3a3a3a',3); // Vertical truss on the east/open side aimed toward the house. const tx=x+w-40;lj([[tx,y+24],[tx,y+h-24]],'#aeb4b5',7);lj([[tx,y+28],[tx-27,y+11]],'#aeb4b5',5);lj([[tx,y+h-28],[tx-27,y+h-11]],'#aeb4b5',5); const cs=['#e64a38','#f1b83e','#3f84a5','#9766a3','#e64a38']; for(let i=0;i<5;i++){const ly=y+42+i*(h-84)/4;ctx.fillStyle=cs[i];ctx.beginPath();ctx.arc(tx-7,ly,7,0,Math.PI*2);ctx.fill();ctx.strokeStyle='#222';ctx.lineWidth=2;ctx.stroke();lj([[tx-14,ly],[tx-34,ly+13]],'rgba(12,16,18,.22)',4)} ctx.save();ctx.translate(x+43,y+h/2);ctx.rotate(-Math.PI/2);ctx.fillStyle='#f4e6be';ctx.font='1000 10px system-ui';ctx.textAlign='center';ctx.fillText('BACKYARD PRACTICE STAGE',0,0);ctx.restore(); rj(x+92,y+112,76,36,'#555','#111',3);ctx.fillStyle='#ccc';ctx.beginPath();ctx.arc(x+130,y+130,14,0,Math.PI*2);ctx.fill();ctx.strokeStyle='#111';ctx.stroke(); for(const q of [y+55,y+h-103]){rj(x+48,q,30,48,'#111','#555',3);ctx.fillStyle='#4d4d4d';ctx.beginPath();ctx.arc(x+63,q+15,7,0,Math.PI*2);ctx.arc(x+63,q+35,9,0,Math.PI*2);ctx.fill()} } function drawBeerPongJ(){ // Moved north and centered on the same activity row as the archery setup. const x=1092,y=3346; rj(x-12,y-14,205,102,'rgba(185,164,122,.34)',null,0);rj(x,y,170,70,'#286c56','#eef3ef',4);lj([[x+85,y+2],[x+85,y+68]],'#eef3ef',3);ctx.fillStyle='#8a5d3c';ctx.fillRect(x+13,y+70,9,20);ctx.fillRect(x+148,y+70,9,20); const cups=[[20,18],[33,18],[46,18],[26,31],[39,31],[33,44]];ctx.fillStyle='#e64a38';for(const [cx,cy] of cups){for(const m of [0,1]){const px=m?x+170-cx:x+cx;ctx.beginPath();ctx.arc(px,y+cy,4.5,0,Math.PI*2);ctx.fill()}} } drawYardH=function(h){ drawFenceH(h);ctx.save();const l=h.lot;ctx.strokeStyle='rgba(238,233,205,.045)';ctx.lineWidth=42;ctx.strokeRect(l.x+70,l.y+70,l.w-140,l.h-140); drawGardenH(); if(typeof drawHotTubI==='function')drawHotTubI();else if(typeof drawHotTubH==='function')drawHotTubH(); if(typeof drawFirePitI==='function')drawFirePitI();else if(typeof drawFirePitH==='function')drawFirePitH(); drawBeerPongJ();drawArcheryH();drawInstrumentsH();drawGuitarMailboxH();ctx.restore(); }; drawR36B45BandHome=function(h){drawYardH(h);drawStageJ(h.stage||band.stage);drawHouseJ(h);drawHomeParkedVehicle(h,'band')}; homeBuildingBlocked=function(x,y){ if(!R36B45_HOMES||typeof R36B45_HOMES!=='object')return false; for(const h of Object.values(R36B45_HOMES)){ if(!h||!h.building)continue; if(h.id==='band'){const b=h.building,s=h.stage||band.stage;if(x>=b.x-25&&x<=b.x+b.w+20&&y>=b.y-8&&y<=b.y+b.h+25)return true;if(s&&x>=s.x-8&&x<=s.x+s.w+12&&y>=s.y-8&&y<=s.y+s.h+12)return true;} else if(x>=h.building.x-42&&x<=h.building.x+h.building.w+28&&y>=h.building.y-80&&y<=h.building.y+h.building.h+42)return true; } return false; }; })(); </script> <style id="r36b48o-mobile-objective-center"> /* R36B48O — center the phone objective panel between left and right driving controls. */ @media (max-width:760px){ html body .objective.objectiveTop, html body.trainingWheelsActive .objective.objectiveTop, html.mobileFullscreen body .objective.objectiveTop, html.mobileFullscreen body.trainingWheelsActive .objective.objectiveTop{ left:50%!important;right:auto!important;top:auto!important; bottom:calc(env(safe-area-inset-bottom,0px) + 78px)!important; width:clamp(170px,calc(100vw - 238px),360px)!important; max-width:360px!important;min-width:170px!important; transform:translateX(-50%)!important; z-index:58!important; } } @media (max-width:760px) and (orientation:landscape){ html body .objective.objectiveTop, html body.trainingWheelsActive .objective.objectiveTop, html.mobileFullscreen body .objective.objectiveTop, html.mobileFullscreen body.trainingWheelsActive .objective.objectiveTop{ bottom:70px!important;width:clamp(260px,46vw,430px)!important;max-width:430px!important; } } </style> <script> /* R36B48P — exact Band hot-tub alignment and responsive objective HUD correction. */ (function(){ if(!window.R36B45_HOMES||!R36B45_HOMES.band)return; const band=R36B45_HOMES.band; band.heroVersion='R36B48S'; const drawFenceP=window.drawFenceH; const drawGardenP=window.drawGardenH; const drawArcheryP=window.drawArcheryH; const drawInstrumentsP=window.drawInstrumentsH; const drawMailboxP=window.drawGuitarMailboxH; function rp(x,y,w,h,fill,stroke='#171514',lw=4){ctx.fillStyle=fill;ctx.fillRect(x,y,w,h);if(stroke){ctx.strokeStyle=stroke;ctx.lineWidth=lw;ctx.strokeRect(x,y,w,h)}} function drawHotTubP(){ // Garden top inset: 2868 - 2790 = 78. House east inset: 2040 - (1705 + 220) = 115. // Match the 194px garden-bed width and preserve the hot-tub aspect ratio. const x=1731,y=2868,w=194,h=153; rp(x,y,w,h,'#a88d70','#5b4939',4); ctx.beginPath();ctx.roundRect(x+12,y+12,w-24,h-24,18);ctx.fillStyle='#66635d';ctx.fill();ctx.strokeStyle='#2d2b29';ctx.lineWidth=4;ctx.stroke(); ctx.beginPath();ctx.roundRect(x+27,y+27,w-54,h-54,14);ctx.fillStyle='#3f91a9';ctx.fill();ctx.strokeStyle='#d8d0be';ctx.lineWidth=4;ctx.stroke(); ctx.fillStyle='rgba(255,255,255,.28)';for(let i=0;i<5;i++){ctx.beginPath();ctx.arc(x+45+i*25,y+75+(i%2)*6,5,0,Math.PI*2);ctx.fill()} } function drawFirePitP(){if(typeof window.drawFirePitI==='function')window.drawFirePitI();else if(typeof window.drawFirePitH==='function')window.drawFirePitH()} function drawBeerPongP(){if(typeof window.drawBeerPongJ==='function')window.drawBeerPongJ();else if(typeof window.drawBeerPongH==='function')window.drawBeerPongH()} const priorYard=window.drawYardH||drawYardH; window.drawYardH=drawYardH=function(h){ if(typeof drawFenceP==='function')drawFenceP(h); ctx.save();const l=h.lot;ctx.strokeStyle='rgba(238,233,205,.045)';ctx.lineWidth=42;ctx.strokeRect(l.x+70,l.y+70,l.w-140,l.h-140); if(typeof drawGardenP==='function')drawGardenP(); drawHotTubP();drawFirePitP();drawBeerPongP(); if(typeof drawArcheryP==='function')drawArcheryP(); if(typeof drawInstrumentsP==='function')drawInstrumentsP(); if(typeof drawMailboxP==='function')drawMailboxP(); ctx.restore(); }; })(); </script> <style id="r36b48p-objective-layout"> /* Desktop remains top-left. Internal spacing is normalized on every platform. */ html body .objective.objectiveTop{ display:grid!important;grid-template-columns:1fr!important;align-content:start!important;row-gap:6px!important; padding:11px 14px!important;text-align:left!important;box-sizing:border-box!important; } html body .objective.objectiveTop > br{display:none!important} html body .objective.objectiveTop .trainingHeader{display:flex!important;align-items:center!important;justify-content:space-between!important;gap:10px!important;width:100%!important;margin:0!important} html body .objective.objectiveTop #objectiveTitle{display:block!important;margin:0!important;line-height:1.08!important} html body .objective.objectiveTop #objectiveText{display:block!important;margin:0!important;line-height:1.25!important} html body .objective.objectiveTop .trainingActions{display:flex!important;align-items:center!important;justify-content:flex-start!important;width:100%!important;margin:2px 0 0!important} html body .objective.objectiveTop .trainingGuide{margin:0!important;min-height:28px!important;padding:5px 10px!important} @media (min-width:761px){ html body .objective.objectiveTop,html body.trainingWheelsActive .objective.objectiveTop{left:10px!important;right:auto!important;top:10px!important;bottom:auto!important;width:365px!important;max-width:365px!important;transform:none!important} } /* Phones only: bottom-center, evenly centered in the clear space between steering and throttle controls. */ @media (max-width:760px){ html body .objective.objectiveTop,html body.trainingWheelsActive .objective.objectiveTop, html.mobileFullscreen body .objective.objectiveTop,html.mobileFullscreen body.trainingWheelsActive .objective.objectiveTop{ position:fixed!important;left:50%!important;right:auto!important;top:auto!important; bottom:calc(env(safe-area-inset-bottom,0px) + 14px)!important; width:clamp(182px,calc(100vw - 246px),340px)!important;max-width:340px!important;min-width:182px!important; min-height:92px!important;max-height:132px!important;overflow:auto!important; transform:translateX(-50%)!important;z-index:66!important;padding:9px 11px!important;row-gap:5px!important; } html body .objective.objectiveTop .trainingHeader{gap:6px!important} html body .objective.objectiveTop .trainingBadge,html body .objective.objectiveTop .trainingProgress{font-size:8px!important;line-height:1.05!important} html body .objective.objectiveTop #objectiveTitle{font-size:10px!important} html body .objective.objectiveTop #objectiveText{font-size:9px!important} html body .objective.objectiveTop .trainingGuide{font-size:8px!important;min-height:25px!important;padding:4px 8px!important} } @media (max-width:760px) and (orientation:landscape){ html body .objective.objectiveTop,html body.trainingWheelsActive .objective.objectiveTop, html.mobileFullscreen body .objective.objectiveTop,html.mobileFullscreen body.trainingWheelsActive .objective.objectiveTop{ bottom:calc(env(safe-area-inset-bottom,0px) + 12px)!important;width:clamp(320px,48vw,470px)!important;max-width:470px!important;min-height:82px!important;max-height:116px!important; } } </style> <style id="r36b48q-objective-final-center"> /* R36B48Q — desktop objective stays upper-left; phone objective is centered between driving controls at the bottom. */ @media (min-width:761px){ html body .objective.objectiveTop, html body.trainingWheelsActive .objective.objectiveTop{ left:10px!important;right:auto!important;top:10px!important;bottom:auto!important; width:365px!important;max-width:365px!important;transform:none!important; } } @media (max-width:760px){ html body .objective.objectiveTop, html body.trainingWheelsActive .objective.objectiveTop, html.mobileFullscreen body .objective.objectiveTop, html.mobileFullscreen body.trainingWheelsActive .objective.objectiveTop{ position:fixed!important;left:50%!important;right:auto!important;top:auto!important; bottom:calc(env(safe-area-inset-bottom,0px) + 10px)!important; width:clamp(176px,calc(100vw - 244px),340px)!important; max-width:340px!important;min-width:176px!important; transform:translateX(-50%)!important;z-index:58!important; padding:9px 11px!important;row-gap:5px!important; } html body .objective.objectiveTop .trainingHeader{gap:7px!important;align-items:center!important} html body .objective.objectiveTop .trainingBadge{max-width:58%!important;text-align:center!important;line-height:1.1!important} html body .objective.objectiveTop .trainingProgress{max-width:40%!important;text-align:center!important;line-height:1.1!important} html body .objective.objectiveTop #objectiveTitle{line-height:1.08!important} html body .objective.objectiveTop #objectiveText{line-height:1.22!important} html body .objective.objectiveTop .trainingActions{justify-content:center!important;margin-top:2px!important} } @media (max-width:760px) and (orientation:landscape){ html body .objective.objectiveTop, html body.trainingWheelsActive .objective.objectiveTop, html.mobileFullscreen body .objective.objectiveTop, html.mobileFullscreen body.trainingWheelsActive .objective.objectiveTop{ left:50%!important;bottom:8px!important; width:clamp(330px,calc(100vw - 470px),590px)!important; max-width:590px!important;min-width:330px!important; transform:translateX(-50%)!important; } } </style> <script> /* R36B48Q — exact Band-property visual cleanup requested after R36B48P. */ (function(){ if(!window.R36B45_HOMES||!R36B45_HOMES.band)return; const band=R36B45_HOMES.band; band.heroVersion='R36B48S'; function rectQ(x,y,w,h,fill,stroke='#171514',lw=4){ctx.fillStyle=fill;ctx.fillRect(x,y,w,h);if(stroke){ctx.strokeStyle=stroke;ctx.lineWidth=lw;ctx.strokeRect(x,y,w,h)}} function polyQ(p,fill,stroke='#171514',lw=4){ctx.beginPath();ctx.moveTo(p[0][0],p[0][1]);for(let i=1;i<p.length;i++)ctx.lineTo(p[i][0],p[i][1]);ctx.closePath();ctx.fillStyle=fill;ctx.fill();if(stroke){ctx.strokeStyle=stroke;ctx.lineWidth=lw;ctx.stroke()}} function lineQ(p,c,lw=3,d=[]){ctx.save();ctx.strokeStyle=c;ctx.lineWidth=lw;ctx.setLineDash(d);ctx.beginPath();ctx.moveTo(p[0][0],p[0][1]);for(let i=1;i<p.length;i++)ctx.lineTo(p[i][0],p[i][1]);ctx.stroke();ctx.restore()} function shadowQ(p,a=.28){ctx.save();ctx.translate(-28,30);polyQ(p,'rgba(13,17,18,'+a+')',null,0);ctx.restore()} function windowQ(x,y,w,h){rectQ(x,y,w,h,'#91d3e2','#34474d',3);lineQ([[x+w/2,y+2],[x+w/2,y+h-2]],'rgba(255,255,255,.8)',2);lineQ([[x+2,y+h/2],[x+w-2,y+h/2]],'rgba(255,255,255,.8)',2)} function drawHotTubQ(){ // Exactly the garden-bed width. Its vertical center matches the garden group. // East edge keeps the same fence inset as the back/east edge of the Band House. const x=1731,y=2880,w=194,h=102; rectQ(x,y,w,h,'#a88d70','#5b4939',4); ctx.beginPath();ctx.roundRect(x+10,y+10,w-20,h-20,16);ctx.fillStyle='#66635d';ctx.fill();ctx.strokeStyle='#2d2b29';ctx.lineWidth=4;ctx.stroke(); ctx.beginPath();ctx.roundRect(x+24,y+22,w-48,h-44,12);ctx.fillStyle='#3f91a9';ctx.fill();ctx.strokeStyle='#d8d0be';ctx.lineWidth=4;ctx.stroke(); ctx.fillStyle='rgba(255,255,255,.28)';for(let i=0;i<5;i++){ctx.beginPath();ctx.arc(x+43+i*27,y+52+(i%2)*5,4.5,0,Math.PI*2);ctx.fill()} } function drawHouseQ(h){ const x=h.building.x,y=h.building.y,w=h.building.w,hh=h.building.h; const footprint=[[x+12,y+8],[x+w-10,y+24],[x+w-7,y+hh-18],[x+8,y+hh-2]]; shadowQ(footprint,.29); // Dominant overhead roof plane. polyQ([[x+30,y],[x+w-12,y+28],[x+w-12,y+hh-38],[x+30,y+hh],[x,y+hh-28],[x,y+30]],'#843f3d','#171514',5); for(let yy=y+38;yy<y+hh-42;yy+=19)lineQ([[x+19,yy],[x+w-22,yy+10]],'rgba(255,255,255,.10)',2); // One narrow grounded facade facing the stage; no pink south-return wall. polyQ([[x,y+30],[x+30,y],[x+30,y+hh],[x,y+hh-28]],'#dfc79d','#171514',5); windowQ(x+5,y+76,23,54);windowQ(x+5,y+211,23,54); rectQ(x-18,y+145,36,62,'#38251f','#171514',4);ctx.fillStyle='#f1b83e';ctx.beginPath();ctx.arc(x+9,y+176,4,0,Math.PI*2);ctx.fill(); // Thin foundation line shows the full base resting on the grass. lineQ([[x+3,y+hh-27],[x+30,y+hh],[x+w-12,y+hh-38]],'#4b3a2d',8); // Overhead square chimney; no roof window. rectQ(x+w-66,y+31,39,39,'#684538','#171514',4);rectQ(x+w-71,y+26,49,9,'#2d2522','#171514',3); ctx.save();ctx.translate(x+12,y+hh/2+74);ctx.rotate(-Math.PI/2);ctx.fillStyle='#f4e6be';ctx.font='900 9px system-ui';ctx.textAlign='center';ctx.fillText('BAND HOUSE',0,0);ctx.restore(); } function drawStageQ(s){ const x=s.x,y=s.y,w=s.w,h=s.h; shadowQ([[x+5,y+5],[x+w-5,y+10],[x+w+7,y+h-5],[x+10,y+h]],.28); polyQ([[x+22,y],[x+w-33,y],[x+w,y+27],[x+w,y+h-28],[x+w-32,y+h],[x+22,y+h]],'#242628','#111',5); polyQ([[x+w-32,y+28],[x+w,y+27],[x+w,y+h-28],[x+w-32,y+h-8]],'#6c523b','#171514',5); rectQ(x+34,y+33,w-76,h-66,'#171717','#3a3a3a',3); const tx=x+w-40;lineQ([[tx,y+24],[tx,y+h-24]],'#aeb4b5',7);lineQ([[tx,y+28],[tx-27,y+11]],'#aeb4b5',5);lineQ([[tx,y+h-28],[tx-27,y+h-11]],'#aeb4b5',5); const cs=['#e64a38','#f1b83e','#3f84a5','#9766a3','#e64a38']; for(let i=0;i<5;i++){const ly=y+42+i*(h-84)/4;ctx.fillStyle=cs[i];ctx.beginPath();ctx.arc(tx-7,ly,7,0,Math.PI*2);ctx.fill();ctx.strokeStyle='#222';ctx.lineWidth=2;ctx.stroke();lineQ([[tx-14,ly],[tx-34,ly+13]],'rgba(12,16,18,.22)',4)} ctx.save();ctx.translate(x+43,y+h/2);ctx.rotate(-Math.PI/2);ctx.fillStyle='#f4e6be';ctx.font='1000 10px system-ui';ctx.textAlign='center';ctx.fillText('BACKYARD PRACTICE STAGE',0,0);ctx.restore(); // Recognizable drum kit facing east toward the house. No rectangle-with-circle placeholder. const dx=x+133,dy=y+h/2; ctx.fillStyle='#d8d8d8';ctx.strokeStyle='#111';ctx.lineWidth=3; ctx.beginPath();ctx.arc(dx+20,dy,18,0,Math.PI*2);ctx.fill();ctx.stroke(); for(const [cx,cy,r] of [[dx-7,dy-17,10],[dx-7,dy+17,10],[dx-31,dy,12]]){ctx.beginPath();ctx.arc(cx,cy,r,0,Math.PI*2);ctx.fill();ctx.stroke()} lineQ([[dx-23,dy-33],[dx-23,dy+33]],'#aaa',3);lineQ([[dx+4,dy-37],[dx+4,dy+37]],'#aaa',3); ctx.fillStyle='#d6b85b';for(const [cx,cy] of [[dx-24,dy-38],[dx+5,dy+38]]){ctx.beginPath();ctx.ellipse(cx,cy,14,5,0,0,Math.PI*2);ctx.fill();ctx.stroke()} // Keep the two speaker stacks only. for(const q of [y+55,y+h-103]){rectQ(x+48,q,30,48,'#111','#555',3);ctx.fillStyle='#4d4d4d';ctx.beginPath();ctx.arc(x+63,q+15,7,0,Math.PI*2);ctx.arc(x+63,q+35,9,0,Math.PI*2);ctx.fill()} } const fenceQ=window.drawFenceH, gardenQ=window.drawGardenH, archeryQ=window.drawArcheryH, instrumentsQ=window.drawInstrumentsH, mailboxQ=window.drawGuitarMailboxH; window.drawYardH=drawYardH=function(h){ if(typeof fenceQ==='function')fenceQ(h); ctx.save();const l=h.lot;ctx.strokeStyle='rgba(238,233,205,.045)';ctx.lineWidth=42;ctx.strokeRect(l.x+70,l.y+70,l.w-140,l.h-140); if(typeof gardenQ==='function')gardenQ(); drawHotTubQ(); if(typeof window.drawFirePitI==='function')window.drawFirePitI();else if(typeof window.drawFirePitH==='function')window.drawFirePitH(); if(typeof window.drawBeerPongJ==='function')window.drawBeerPongJ();else if(typeof window.drawBeerPongH==='function')window.drawBeerPongH(); if(typeof archeryQ==='function')archeryQ();if(typeof instrumentsQ==='function')instrumentsQ();if(typeof mailboxQ==='function')mailboxQ(); ctx.restore(); }; window.drawR36B45BandHome=drawR36B45BandHome=function(h){drawYardH(h);drawStageQ(h.stage||band.stage);drawHouseQ(h);drawHomeParkedVehicle(h,'band')}; })(); </script> <style id="r36b48r-objective-exact-gap"> /* R36B48R — desktop objective unchanged; phone objective fills the exact clear gap between driving controls. */ @media (min-width:761px){ html body .objective.objectiveTop, html body.trainingWheelsActive .objective.objectiveTop{ position:absolute!important;left:10px!important;right:auto!important;top:10px!important;bottom:auto!important; width:365px!important;max-width:365px!important;min-width:0!important;transform:none!important; } } @media (max-width:760px){ html body .objective.objectiveTop, html body.trainingWheelsActive .objective.objectiveTop, html.mobileFullscreen body .objective.objectiveTop, html.mobileFullscreen body.trainingWheelsActive .objective.objectiveTop{ position:fixed!important;left:118px!important;right:118px!important;top:auto!important; bottom:calc(env(safe-area-inset-bottom,0px) + 10px)!important; width:auto!important;max-width:none!important;min-width:0!important; transform:none!important;box-sizing:border-box!important;z-index:66!important; padding:10px 12px!important;row-gap:6px!important;text-align:left!important; } html body .objective.objectiveTop .trainingHeader{ display:grid!important;grid-template-columns:minmax(0,1fr) minmax(0,.62fr)!important; align-items:center!important;gap:8px!important;width:100%!important; } html body .objective.objectiveTop .trainingBadge, html body .objective.objectiveTop .trainingProgress{ max-width:none!important;width:100%!important;text-align:center!important;box-sizing:border-box!important; } html body .objective.objectiveTop #objectiveTitle, html body .objective.objectiveTop #objectiveText{width:100%!important;margin:0!important} html body .objective.objectiveTop .trainingActions{width:100%!important;justify-content:center!important;margin:2px 0 0!important} html body .objective.objectiveTop .trainingGuide{width:100%!important;box-sizing:border-box!important;text-align:center!important} } @media (max-width:760px) and (orientation:landscape){ html body .objective.objectiveTop, html body.trainingWheelsActive .objective.objectiveTop, html.mobileFullscreen body .objective.objectiveTop, html.mobileFullscreen body.trainingWheelsActive .objective.objectiveTop{ left:132px!important;right:132px!important;bottom:8px!important;width:auto!important;max-width:none!important;min-width:0!important; } } </style> <script> /* R36B48R — center the reduced hot tub vertically between the north fence and the Band House. */ (function(){ if(!window.R36B45_HOMES||!R36B45_HOMES.band)return; const band=R36B45_HOMES.band; band.heroVersion='R36B48S'; const fenceR=window.drawFenceH, gardenR=window.drawGardenH, archeryR=window.drawArcheryH, instrumentsR=window.drawInstrumentsH, mailboxR=window.drawGuitarMailboxH; function rr(x,y,w,h,fill,stroke='#171514',lw=4){ctx.fillStyle=fill;ctx.fillRect(x,y,w,h);if(stroke){ctx.strokeStyle=stroke;ctx.lineWidth=lw;ctx.strokeRect(x,y,w,h)}} function drawHotTubR(){ const lot=band.lot,b=band.building,w=194,h=102; // Same width as the garden. Centered in the north/south gap between north fence and house. const northInner=lot.y+18; const houseNorth=b.y; const y=Math.round(northInner+Math.max(0,(houseNorth-northInner-h)/2)); // Preserve the approved east-side alignment. const x=1731; rr(x,y,w,h,'#a88d70','#5b4939',4); ctx.beginPath();ctx.roundRect(x+10,y+10,w-20,h-20,16);ctx.fillStyle='#66635d';ctx.fill();ctx.strokeStyle='#2d2b29';ctx.lineWidth=4;ctx.stroke(); ctx.beginPath();ctx.roundRect(x+24,y+22,w-48,h-44,12);ctx.fillStyle='#3f91a9';ctx.fill();ctx.strokeStyle='#d8d0be';ctx.lineWidth=4;ctx.stroke(); ctx.fillStyle='rgba(255,255,255,.28)';for(let i=0;i<5;i++){ctx.beginPath();ctx.arc(x+43+i*27,y+52+(i%2)*5,4.5,0,Math.PI*2);ctx.fill()} } window.drawYardH=drawYardH=function(h){ if(typeof fenceR==='function')fenceR(h); ctx.save();const l=h.lot;ctx.strokeStyle='rgba(238,233,205,.045)';ctx.lineWidth=42;ctx.strokeRect(l.x+70,l.y+70,l.w-140,l.h-140); if(typeof gardenR==='function')gardenR(); drawHotTubR(); if(typeof window.drawFirePitI==='function')window.drawFirePitI();else if(typeof window.drawFirePitH==='function')window.drawFirePitH(); if(typeof window.drawBeerPongJ==='function')window.drawBeerPongJ();else if(typeof window.drawBeerPongH==='function')window.drawBeerPongH(); if(typeof archeryR==='function')archeryR();if(typeof instrumentsR==='function')instrumentsR();if(typeof mailboxR==='function')mailboxR(); ctx.restore(); }; })(); </script> <script> /* R36B48S — Band entry semantics, archery stand correction, beer-pong centering, and pseudo-3D drums. */ (function(){ if(!window.R36B45_HOMES||!R36B45_HOMES.band)return; const band=R36B45_HOMES.band; band.heroVersion='R36B48S'; function rsRect(x,y,w,h,fill,stroke='#171514',lw=4){ctx.fillStyle=fill;ctx.fillRect(x,y,w,h);if(stroke){ctx.strokeStyle=stroke;ctx.lineWidth=lw;ctx.strokeRect(x,y,w,h)}} function rsPoly(p,fill,stroke='#171514',lw=4){ctx.beginPath();ctx.moveTo(p[0][0],p[0][1]);for(let i=1;i<p.length;i++)ctx.lineTo(p[i][0],p[i][1]);ctx.closePath();ctx.fillStyle=fill;ctx.fill();if(stroke){ctx.strokeStyle=stroke;ctx.lineWidth=lw;ctx.stroke()}} function rsLine(p,c,lw=3,d=[]){ctx.save();ctx.strokeStyle=c;ctx.lineWidth=lw;ctx.setLineDash(d);ctx.beginPath();ctx.moveTo(p[0][0],p[0][1]);for(let i=1;i<p.length;i++)ctx.lineTo(p[i][0],p[i][1]);ctx.stroke();ctx.restore()} function rsShadow(p,a=.27){ctx.save();ctx.translate(-28,30);rsPoly(p,'rgba(13,17,18,'+a+')',null,0);ctx.restore()} function rsWindow(x,y,w,h){rsRect(x,y,w,h,'#91d3e2','#34474d',3);rsLine([[x+w/2,y+2],[x+w/2,y+h-2]],'rgba(255,255,255,.8)',2);rsLine([[x+2,y+h/2],[x+w-2,y+h/2]],'rgba(255,255,255,.8)',2)} function drawBandWelcomeMatS(h){ if(window.__vancertsSkipBandNorthArtifacts)return; const l=h.lot,cx=h.roadCenterX||1510; const x=cx-58,y=l.y+7,w=116,hh=38; // A low, drive-over mat centered in the open entrance. rsRect(x,y,w,hh,'#4c3529','#211915',4); ctx.fillStyle='#d8c49a';ctx.font='1000 11px system-ui';ctx.textAlign='center';ctx.textBaseline='middle';ctx.fillText('BAND HOUSE',cx,y+hh/2+1); for(let i=0;i<6;i++)rsLine([[x+10+i*18,y+7],[x+10+i*18,y+hh-7]],'rgba(255,255,255,.08)',2); } function drawGuitarMailboxS(h){ if(window.__vancertsSkipBandNorthArtifacts)return; // Keep the guitar-shaped mailbox beside the entrance, with no property-name text. const cx=h.roadCenterX||1510,x=cx+88,y=h.lot.y+39; ctx.save();ctx.fillStyle='#65452f';ctx.fillRect(x-3,y+12,6,43);ctx.fillStyle='#27211d';ctx.fillRect(x-18,y+49,36,7); ctx.fillStyle='#a84b35';ctx.beginPath();ctx.arc(x,y,14,0,Math.PI*2);ctx.arc(x,y+16,18,0,Math.PI*2);ctx.fill();ctx.strokeStyle='#2b1d17';ctx.lineWidth=3;ctx.stroke(); ctx.fillStyle='#d8b46c';ctx.fillRect(x-4,y-30,8,31);ctx.fillStyle='#2b1d17';ctx.fillRect(x-7,y-35,14,7); ctx.strokeStyle='#e64a38';ctx.lineWidth=3;ctx.beginPath();ctx.moveTo(x+12,y-2);ctx.lineTo(x+25,y-16);ctx.stroke();ctx.fillStyle='#e64a38';ctx.fillRect(x+22,y-23,13,8);ctx.restore(); } function drawHouseS(h){ const x=h.building.x,y=h.building.y,w=h.building.w,hh=h.building.h; rsShadow([[x+12,y+6],[x+w-10,y+22],[x+w-8,y+hh-18],[x+8,y+hh-2]],.29); // Approved dominant top-down roof. rsPoly([[x+30,y],[x+w-12,y+28],[x+w-12,y+hh-38],[x+30,y+hh],[x,y+hh-28],[x,y+30]],'#843f3d','#171514',5); for(let yy=y+38;yy<y+hh-42;yy+=19)rsLine([[x+19,yy],[x+w-22,yy+10]],'rgba(255,255,255,.10)',2); // Narrow west facade toward the stage. rsPoly([[x,y+30],[x+30,y],[x+30,y+hh],[x,y+hh-28]],'#dfc79d','#171514',5); rsWindow(x+5,y+76,23,54);rsWindow(x+5,y+211,23,54); // Top-down door leaf projects west toward the stage; knob sits on the stage-facing edge. const dy=y+145; rsRect(x-31,dy,31,62,'#38251f','#171514',4); rsLine([[x-1,dy+4],[x-1,dy+58]],'rgba(255,255,255,.10)',2); ctx.fillStyle='#f1b83e';ctx.beginPath();ctx.arc(x-24,dy+31,4,0,Math.PI*2);ctx.fill();ctx.strokeStyle='#171514';ctx.lineWidth=1.5;ctx.stroke(); // Foundation follows every visible base edge. rsLine([[x+2,y+hh-28],[x+30,y+hh],[x+w-12,y+hh-38]],'#4b3a2d',8); // Square overhead chimney. rsRect(x+w-62,y+29,38,38,'#684538','#171514',4);rsRect(x+w-67,y+24,48,9,'#2d2522','#171514',3); } function drawPseudoDrumsS(x,y){ ctx.save(); // Grounded kit shadow toward southwest. ctx.fillStyle='rgba(12,15,16,.28)';ctx.beginPath();ctx.ellipse(x-12,y+18,58,34,-.08,0,Math.PI*2);ctx.fill(); // Bass drum facing east toward the house. ctx.fillStyle='#d8d8d8';ctx.strokeStyle='#171514';ctx.lineWidth=3; ctx.beginPath();ctx.ellipse(x+17,y,22,30,0,0,Math.PI*2);ctx.fill();ctx.stroke(); ctx.fillStyle='#aeb4b5';ctx.beginPath();ctx.ellipse(x+13,y,13,21,0,0,Math.PI*2);ctx.fill();ctx.stroke(); // Toms use oblique ellipses and short shells. const drums=[[x-13,y-19,13,9,'#d5d5d5'],[x-14,y+18,13,9,'#c9c9c9'],[x-40,y+2,16,12,'#bfc3c4']]; for(const [cx,cy,rx,ry,c] of drums){ctx.fillStyle='#777';ctx.fillRect(cx-rx,cy,rx*2,10);ctx.fillStyle=c;ctx.beginPath();ctx.ellipse(cx,cy,rx,ry,0,0,Math.PI*2);ctx.fill();ctx.stroke()} // Snare and stool. ctx.fillStyle='#d5d5d5';ctx.beginPath();ctx.ellipse(x-35,y-24,12,7,0,0,Math.PI*2);ctx.fill();ctx.stroke(); ctx.fillStyle='#2e2e2e';ctx.beginPath();ctx.ellipse(x-54,y+1,10,6,0,0,Math.PI*2);ctx.fill(); // Cymbal stands and tilted cymbals, not flat circles. for(const [sx,sy,ang] of [[x-29,y-43,-.18],[x-21,y+43,.18]]){ rsLine([[sx,sy+4],[sx+4,y]],'#aeb4b5',3);rsLine([[sx-7,sy+18],[sx+4,sy+4],[sx+14,sy+17]],'#aeb4b5',2); ctx.save();ctx.translate(sx,sy);ctx.rotate(ang);ctx.fillStyle='#d6b85b';ctx.beginPath();ctx.ellipse(0,0,18,6,0,0,Math.PI*2);ctx.fill();ctx.strokeStyle='#7d6324';ctx.lineWidth=2;ctx.stroke();ctx.restore(); } ctx.restore(); } function drawStageS(s){ const x=s.x,y=s.y,w=s.w,h=s.h; rsShadow([[x+5,y+5],[x+w-5,y+10],[x+w+7,y+h-5],[x+10,y+h]],.28); rsPoly([[x+22,y],[x+w-33,y],[x+w,y+27],[x+w,y+h-28],[x+w-32,y+h],[x+22,y+h]],'#242628','#111',5); rsPoly([[x+w-32,y+28],[x+w,y+27],[x+w,y+h-28],[x+w-32,y+h-8]],'#6c523b','#171514',5); rsRect(x+34,y+33,w-76,h-66,'#171717','#3a3a3a',3); const tx=x+w-40;rsLine([[tx,y+24],[tx,y+h-24]],'#aeb4b5',7);rsLine([[tx,y+28],[tx-27,y+11]],'#aeb4b5',5);rsLine([[tx,y+h-28],[tx-27,y+h-11]],'#aeb4b5',5); const cs=['#e64a38','#f1b83e','#3f84a5','#9766a3','#e64a38']; for(let i=0;i<5;i++){const ly=y+42+i*(h-84)/4;ctx.fillStyle=cs[i];ctx.beginPath();ctx.arc(tx-7,ly,7,0,Math.PI*2);ctx.fill();ctx.strokeStyle='#222';ctx.lineWidth=2;ctx.stroke();rsLine([[tx-14,ly],[tx-34,ly+13]],'rgba(12,16,18,.22)',4)} ctx.save();ctx.translate(x+43,y+h/2);ctx.rotate(-Math.PI/2);ctx.fillStyle='#f4e6be';ctx.font='1000 10px system-ui';ctx.textAlign='center';ctx.fillText('BACKYARD PRACTICE STAGE',0,0);ctx.restore(); // One semantic pseudo-3D drum kit, facing east toward the house. drawPseudoDrumsS(x+133,y+h/2); for(const q of [y+55,y+h-103]){rsRect(x+48,q,30,48,'#111','#555',3);ctx.fillStyle='#4d4d4d';ctx.beginPath();ctx.arc(x+63,q+15,7,0,Math.PI*2);ctx.arc(x+63,q+35,9,0,Math.PI*2);ctx.fill()} } function drawBeerPongS(){ const s=band.stage,l=band.lot,w=170,h=70; // Centered in the vertical gap between the stage south edge and south fence. const x=Math.round(s.x+(s.w-w)/2), y=Math.round((s.y+s.h + (l.y+l.h-18) - h)/2); rsRect(x-12,y-14,205,102,'rgba(185,164,122,.34)',null,0);rsRect(x,y,w,h,'#286c56','#eef3ef',4);rsLine([[x+w/2,y+2],[x+w/2,y+h-2]],'#eef3ef',3); ctx.fillStyle='#8a5d3c';ctx.fillRect(x+13,y+h,9,20);ctx.fillRect(x+w-22,y+h,9,20); const cups=[[20,18],[33,18],[46,18],[26,31],[39,31],[33,44]];ctx.fillStyle='#e64a38';for(const [cx,cy] of cups){for(const m of [0,1]){const px=m?x+w-cx:x+cx;ctx.beginPath();ctx.arc(px,y+cy,4.5,0,Math.PI*2);ctx.fill()}} } function drawArcheryStandS(){ const sx=1662,sy=3388,tx=1960,ty=3388; rsRect(sx-58,sy-54,352,110,'rgba(135,112,72,.14)',null,0);rsLine([[sx,sy],[tx-46,ty]],'rgba(239,229,190,.58)',4,[12,9]);rsLine([[sx,sy-39],[sx,sy+39]],'#f4e6be',5); // Bow rack flipped so its feet/base extend south like the target's stand. ctx.fillStyle='#6f4b2f';ctx.fillRect(sx-46,sy-29,12,58);ctx.fillRect(sx-59,sy+25,40,6); ctx.strokeStyle='#3a251b';ctx.lineWidth=4;ctx.beginPath();ctx.arc(sx-29,sy,20,-Math.PI/2,Math.PI/2);ctx.stroke();rsLine([[sx-29,sy-20],[sx-29,sy+20]],'#d9c7a2',2); for(let i=0;i<4;i++)rsLine([[sx-5+i*5,sy-23],[sx-5+i*5,sy+23]],'#d9c7a2',2); // Matching downward feet/base. rsLine([[sx-42,sy+31],[sx-52,sy+55]],'#5a4936',5);rsLine([[sx-24,sy+31],[sx-14,sy+55]],'#5a4936',5);rsLine([[sx-56,sy+55],[sx-10,sy+55]],'#5a4936',5); ctx.fillStyle='#e7ddc7';ctx.beginPath();ctx.arc(tx,ty,36,0,Math.PI*2);ctx.fill();ctx.strokeStyle='#433c33';ctx.lineWidth=4;ctx.stroke();for(const [r,c] of [[27,'#2b2b2b'],[20,'#e7ddc7'],[13,'#e64a38'],[6,'#f1b83e']]){ctx.fillStyle=c;ctx.beginPath();ctx.arc(tx,ty,r,0,Math.PI*2);ctx.fill()}ctx.fillStyle='#5a4936';ctx.fillRect(tx-6,ty+34,12,28); ctx.fillStyle='#f4e6be';ctx.font='900 10px system-ui';ctx.textAlign='center'; } const fenceS=window.drawFenceH, gardenS=window.drawGardenH, instrumentsS=window.drawInstrumentsH; window.drawYardH=drawYardH=function(h){ if(typeof fenceS==='function')fenceS(h); ctx.save();const l=h.lot;ctx.strokeStyle='rgba(238,233,205,.045)';ctx.lineWidth=42;ctx.strokeRect(l.x+70,l.y+70,l.w-140,l.h-140); if(typeof gardenS==='function')gardenS(); // Preserve the corrected hot tub and fire pit from R36B48R. if(typeof window.drawHotTubR==='function')window.drawHotTubR(); else if(typeof window.drawHotTubH==='function')window.drawHotTubH(); if(typeof window.drawFirePitI==='function')window.drawFirePitI();else if(typeof window.drawFirePitH==='function')window.drawFirePitH(); if(!window.__vancertsSkipBeerPong)drawBeerPongS(); if(!window.__vancertsSkipArchery)drawArcheryStandS(); if(typeof instrumentsS==='function')instrumentsS(); drawBandWelcomeMatS(h);drawGuitarMailboxS(h); ctx.restore(); }; window.drawR36B45BandHome=drawR36B45BandHome=function(h){drawYardH(h);drawStageS(h.stage||band.stage);drawHouseS(h);drawHomeParkedVehicle(h,'band')}; })(); </script> <script> /* R36B48T — restore approved hot-tub position; embed the door in the cream facade; clean cymbals; center the bow stand. */ (function(){ if(!window.R36B45_HOMES||!R36B45_HOMES.band)return; const band=R36B45_HOMES.band; band.heroVersion='R36B48T'; function rsRect(x,y,w,h,fill,stroke='#171514',lw=4){ctx.fillStyle=fill;ctx.fillRect(x,y,w,h);if(stroke){ctx.strokeStyle=stroke;ctx.lineWidth=lw;ctx.strokeRect(x,y,w,h)}} function rsPoly(p,fill,stroke='#171514',lw=4){ctx.beginPath();ctx.moveTo(p[0][0],p[0][1]);for(let i=1;i<p.length;i++)ctx.lineTo(p[i][0],p[i][1]);ctx.closePath();ctx.fillStyle=fill;ctx.fill();if(stroke){ctx.strokeStyle=stroke;ctx.lineWidth=lw;ctx.stroke()}} function rsLine(p,c,lw=3,d=[]){ctx.save();ctx.strokeStyle=c;ctx.lineWidth=lw;ctx.setLineDash(d);ctx.beginPath();ctx.moveTo(p[0][0],p[0][1]);for(let i=1;i<p.length;i++)ctx.lineTo(p[i][0],p[i][1]);ctx.stroke();ctx.restore()} function rsShadow(p,a=.27){ctx.save();ctx.translate(-28,30);rsPoly(p,'rgba(13,17,18,'+a+')',null,0);ctx.restore()} function rsWindow(x,y,w,h){rsRect(x,y,w,h,'#91d3e2','#34474d',3);rsLine([[x+w/2,y+2],[x+w/2,y+h-2]],'rgba(255,255,255,.8)',2);rsLine([[x+2,y+h/2],[x+w-2,y+h/2]],'rgba(255,255,255,.8)',2)} function drawBandWelcomeMatS(h){ if(window.__vancertsSkipBandNorthArtifacts)return; const l=h.lot,cx=h.roadCenterX||1510; const x=cx-58,y=l.y+7,w=116,hh=38; // A low, drive-over mat centered in the open entrance. rsRect(x,y,w,hh,'#4c3529','#211915',4); ctx.fillStyle='#d8c49a';ctx.font='1000 11px system-ui';ctx.textAlign='center';ctx.textBaseline='middle';ctx.fillText('BAND HOUSE',cx,y+hh/2+1); for(let i=0;i<6;i++)rsLine([[x+10+i*18,y+7],[x+10+i*18,y+hh-7]],'rgba(255,255,255,.08)',2); } function drawGuitarMailboxS(h){ if(window.__vancertsSkipBandNorthArtifacts)return; // Keep the guitar-shaped mailbox beside the entrance, with no property-name text. const cx=h.roadCenterX||1510,x=cx+88,y=h.lot.y+39; ctx.save();ctx.fillStyle='#65452f';ctx.fillRect(x-3,y+12,6,43);ctx.fillStyle='#27211d';ctx.fillRect(x-18,y+49,36,7); ctx.fillStyle='#a84b35';ctx.beginPath();ctx.arc(x,y,14,0,Math.PI*2);ctx.arc(x,y+16,18,0,Math.PI*2);ctx.fill();ctx.strokeStyle='#2b1d17';ctx.lineWidth=3;ctx.stroke(); ctx.fillStyle='#d8b46c';ctx.fillRect(x-4,y-30,8,31);ctx.fillStyle='#2b1d17';ctx.fillRect(x-7,y-35,14,7); ctx.strokeStyle='#e64a38';ctx.lineWidth=3;ctx.beginPath();ctx.moveTo(x+12,y-2);ctx.lineTo(x+25,y-16);ctx.stroke();ctx.fillStyle='#e64a38';ctx.fillRect(x+22,y-23,13,8);ctx.restore(); } function drawHouseS(h){ const x=h.building.x,y=h.building.y,w=h.building.w,hh=h.building.h; rsShadow([[x+12,y+6],[x+w-10,y+22],[x+w-8,y+hh-18],[x+8,y+hh-2]],.29); // Preserve the approved dominant top-down roof. rsPoly([[x+30,y],[x+w-12,y+28],[x+w-12,y+hh-38],[x+30,y+hh],[x,y+hh-28],[x,y+30]],'#843f3d','#171514',5); for(let yy=y+38;yy<y+hh-42;yy+=19)rsLine([[x+19,yy],[x+w-22,yy+10]],'rgba(255,255,255,.10)',2); // Cream west facade faces the stage. Both windows and the door are embedded in this wall. rsPoly([[x,y+30],[x+30,y],[x+30,y+hh],[x,y+hh-28]],'#dfc79d','#171514',5); rsWindow(x+5,y+64,23,48); rsWindow(x+5,y+228,23,48); const dy=y+142; rsRect(x+4,dy,24,58,'#38251f','#171514',3); rsLine([[x+7,dy+4],[x+7,dy+54]],'rgba(255,255,255,.10)',2); // Knob sits on the west/stage-facing edge of the door. ctx.fillStyle='#f1b83e';ctx.beginPath();ctx.arc(x+8,dy+29,3.8,0,Math.PI*2);ctx.fill();ctx.strokeStyle='#171514';ctx.lineWidth=1.4;ctx.stroke(); // Foundation follows every visible base edge. rsLine([[x+2,y+hh-28],[x+30,y+hh],[x+w-12,y+hh-38]],'#4b3a2d',8); // Square overhead chimney remains unchanged. rsRect(x+w-62,y+29,38,38,'#684538','#171514',4);rsRect(x+w-67,y+24,48,9,'#2d2522','#171514',3); } function drawPseudoDrumsS(x,y){ ctx.save(); ctx.fillStyle='rgba(12,15,16,.28)';ctx.beginPath();ctx.ellipse(x-12,y+18,55,32,-.08,0,Math.PI*2);ctx.fill(); // Bass drum faces east toward the house. ctx.fillStyle='#d8d8d8';ctx.strokeStyle='#171514';ctx.lineWidth=3; ctx.beginPath();ctx.ellipse(x+17,y,22,30,0,0,Math.PI*2);ctx.fill();ctx.stroke(); ctx.fillStyle='#aeb4b5';ctx.beginPath();ctx.ellipse(x+13,y,13,21,0,0,Math.PI*2);ctx.fill();ctx.stroke(); const drums=[[x-13,y-18,13,9,'#d5d5d5'],[x-13,y+18,13,9,'#c9c9c9'],[x-39,y+2,15,11,'#bfc3c4']]; for(const [cx,cy,rx,ry,c] of drums){ctx.fillStyle='#777';ctx.fillRect(cx-rx,cy,rx*2,9);ctx.fillStyle=c;ctx.beginPath();ctx.ellipse(cx,cy,rx,ry,0,0,Math.PI*2);ctx.fill();ctx.stroke()} ctx.fillStyle='#d5d5d5';ctx.beginPath();ctx.ellipse(x-34,y-23,11,7,0,0,Math.PI*2);ctx.fill();ctx.stroke(); ctx.fillStyle='#2e2e2e';ctx.beginPath();ctx.ellipse(x-52,y+1,9,6,0,0,Math.PI*2);ctx.fill(); // Compact cymbal stands stay inside the kit silhouette and do not poke through drums. const cymbals=[[x-25,y-34,-.12],[x-23,y+34,.12]]; for(const [sx,sy,ang] of cymbals){ rsLine([[sx,sy+5],[sx+2,sy+20]],'#aeb4b5',2.5); rsLine([[sx-6,sy+21],[sx+2,sy+17],[sx+9,sy+22]],'#aeb4b5',2); ctx.save();ctx.translate(sx,sy);ctx.rotate(ang);ctx.fillStyle='#d6b85b';ctx.beginPath();ctx.ellipse(0,0,16,5,0,0,Math.PI*2);ctx.fill();ctx.strokeStyle='#7d6324';ctx.lineWidth=2;ctx.stroke();ctx.restore(); } ctx.restore(); } function drawStageS(s){ const x=s.x,y=s.y,w=s.w,h=s.h; rsShadow([[x+5,y+5],[x+w-5,y+10],[x+w+7,y+h-5],[x+10,y+h]],.28); rsPoly([[x+22,y],[x+w-33,y],[x+w,y+27],[x+w,y+h-28],[x+w-32,y+h],[x+22,y+h]],'#242628','#111',5); rsPoly([[x+w-32,y+28],[x+w,y+27],[x+w,y+h-28],[x+w-32,y+h-8]],'#6c523b','#171514',5); rsRect(x+34,y+33,w-76,h-66,'#171717','#3a3a3a',3); const tx=x+w-40;rsLine([[tx,y+24],[tx,y+h-24]],'#aeb4b5',7);rsLine([[tx,y+28],[tx-27,y+11]],'#aeb4b5',5);rsLine([[tx,y+h-28],[tx-27,y+h-11]],'#aeb4b5',5); const cs=['#e64a38','#f1b83e','#3f84a5','#9766a3','#e64a38']; for(let i=0;i<5;i++){const ly=y+42+i*(h-84)/4;ctx.fillStyle=cs[i];ctx.beginPath();ctx.arc(tx-7,ly,7,0,Math.PI*2);ctx.fill();ctx.strokeStyle='#222';ctx.lineWidth=2;ctx.stroke();rsLine([[tx-14,ly],[tx-34,ly+13]],'rgba(12,16,18,.22)',4)} ctx.save();ctx.translate(x+43,y+h/2);ctx.rotate(-Math.PI/2);ctx.fillStyle='#f4e6be';ctx.font='1000 10px system-ui';ctx.textAlign='center';ctx.fillText('BACKYARD PRACTICE STAGE',0,0);ctx.restore(); // One semantic pseudo-3D drum kit, facing east toward the house. drawPseudoDrumsS(x+133,y+h/2); for(const q of [y+55,y+h-103]){rsRect(x+48,q,30,48,'#111','#555',3);ctx.fillStyle='#4d4d4d';ctx.beginPath();ctx.arc(x+63,q+15,7,0,Math.PI*2);ctx.arc(x+63,q+35,9,0,Math.PI*2);ctx.fill()} } function drawBeerPongS(){ const s=band.stage,l=band.lot,w=170,h=70; // Centered in the vertical gap between the stage south edge and south fence. const x=Math.round(s.x+(s.w-w)/2), y=Math.round((s.y+s.h + (l.y+l.h-18) - h)/2); rsRect(x-12,y-14,205,102,'rgba(185,164,122,.34)',null,0);rsRect(x,y,w,h,'#286c56','#eef3ef',4);rsLine([[x+w/2,y+2],[x+w/2,y+h-2]],'#eef3ef',3); ctx.fillStyle='#8a5d3c';ctx.fillRect(x+13,y+h,9,20);ctx.fillRect(x+w-22,y+h,9,20); const cups=[[20,18],[33,18],[46,18],[26,31],[39,31],[33,44]];ctx.fillStyle='#e64a38';for(const [cx,cy] of cups){for(const m of [0,1]){const px=m?x+w-cx:x+cx;ctx.beginPath();ctx.arc(px,y+cy,4.5,0,Math.PI*2);ctx.fill()}} } function drawArcheryStandS(){ const sx=1662,sy=3388,tx=1960,ty=3388; rsRect(sx-58,sy-54,352,110,'rgba(135,112,72,.14)',null,0);rsLine([[sx,sy],[tx-46,ty]],'rgba(239,229,190,.58)',4,[12,9]);rsLine([[sx,sy-39],[sx,sy+39]],'#f4e6be',5); // Center the bow and its stand over one symmetrical base. ctx.fillStyle='#6f4b2f';ctx.fillRect(sx-5,sy-31,10,61); ctx.strokeStyle='#3a251b';ctx.lineWidth=4;ctx.beginPath();ctx.arc(sx-17,sy,20,-Math.PI/2,Math.PI/2);ctx.stroke();rsLine([[sx-17,sy-20],[sx-17,sy+20]],'#d9c7a2',2); for(let i=0;i<4;i++)rsLine([[sx+11+i*5,sy-23],[sx+11+i*5,sy+23]],'#d9c7a2',2); rsLine([[sx-5,sy+30],[sx-20,sy+54]],'#5a4936',5);rsLine([[sx+5,sy+30],[sx+20,sy+54]],'#5a4936',5);rsLine([[sx-25,sy+54],[sx+25,sy+54]],'#5a4936',5); ctx.fillStyle='#e7ddc7';ctx.beginPath();ctx.arc(tx,ty,36,0,Math.PI*2);ctx.fill();ctx.strokeStyle='#433c33';ctx.lineWidth=4;ctx.stroke();for(const [r,c] of [[27,'#2b2b2b'],[20,'#e7ddc7'],[13,'#e64a38'],[6,'#f1b83e']]){ctx.fillStyle=c;ctx.beginPath();ctx.arc(tx,ty,r,0,Math.PI*2);ctx.fill()}ctx.fillStyle='#5a4936';ctx.fillRect(tx-6,ty+34,12,28); ctx.fillStyle='#f4e6be';ctx.font='900 10px system-ui';ctx.textAlign='center'; } const fenceS=window.drawFenceH, gardenS=window.drawGardenH, instrumentsS=window.drawInstrumentsH; function drawHotTubT(){ const lot=band.lot,b=band.building,w=194,h=102; const northInner=lot.y+18,houseNorth=b.y; const y=Math.round(northInner+Math.max(0,(houseNorth-northInner-h)/2)); const x=1731; rsRect(x,y,w,h,'#a88d70','#5b4939',4); ctx.beginPath();ctx.roundRect(x+10,y+10,w-20,h-20,16);ctx.fillStyle='#66635d';ctx.fill();ctx.strokeStyle='#2d2b29';ctx.lineWidth=4;ctx.stroke(); ctx.beginPath();ctx.roundRect(x+24,y+22,w-48,h-44,12);ctx.fillStyle='#3f91a9';ctx.fill();ctx.strokeStyle='#d8d0be';ctx.lineWidth=4;ctx.stroke(); ctx.fillStyle='rgba(255,255,255,.28)';for(let i=0;i<5;i++){ctx.beginPath();ctx.arc(x+43+i*27,y+52+(i%2)*5,4.5,0,Math.PI*2);ctx.fill()} } window.drawYardH=drawYardH=function(h){ if(typeof fenceS==='function')fenceS(h); ctx.save();const l=h.lot;ctx.strokeStyle='rgba(238,233,205,.045)';ctx.lineWidth=42;ctx.strokeRect(l.x+70,l.y+70,l.w-140,l.h-140); if(typeof gardenS==='function')gardenS(); // Restore the approved R36B48R hot-tub coordinates exactly. drawHotTubT(); if(typeof window.drawFirePitI==='function')window.drawFirePitI();else if(typeof window.drawFirePitH==='function')window.drawFirePitH(); if(!window.__vancertsSkipBeerPong)drawBeerPongS();if(!window.__vancertsSkipArchery)drawArcheryStandS(); if(typeof instrumentsS==='function')instrumentsS(); drawBandWelcomeMatS(h);drawGuitarMailboxS(h); ctx.restore(); }; window.drawR36B45BandHome=drawR36B45BandHome=function(h){drawYardH(h);drawStageS(h.stage||band.stage);drawHouseS(h);drawHomeParkedVehicle(h,'band')}; })(); </script> <script> /* R36B48U — vertical outward-opening Band House door and ground-laid archery bow. */ (function(){ if(!window.R36B45_HOMES||!R36B45_HOMES.band)return; const band=R36B45_HOMES.band; band.heroVersion='R36B48U'; function rsRect(x,y,w,h,fill,stroke='#171514',lw=4){ctx.fillStyle=fill;ctx.fillRect(x,y,w,h);if(stroke){ctx.strokeStyle=stroke;ctx.lineWidth=lw;ctx.strokeRect(x,y,w,h)}} function rsPoly(p,fill,stroke='#171514',lw=4){ctx.beginPath();ctx.moveTo(p[0][0],p[0][1]);for(let i=1;i<p.length;i++)ctx.lineTo(p[i][0],p[i][1]);ctx.closePath();ctx.fillStyle=fill;ctx.fill();if(stroke){ctx.strokeStyle=stroke;ctx.lineWidth=lw;ctx.stroke()}} function rsLine(p,c,lw=3,d=[]){ctx.save();ctx.strokeStyle=c;ctx.lineWidth=lw;ctx.setLineDash(d);ctx.beginPath();ctx.moveTo(p[0][0],p[0][1]);for(let i=1;i<p.length;i++)ctx.lineTo(p[i][0],p[i][1]);ctx.stroke();ctx.restore()} function rsShadow(p,a=.27){ctx.save();ctx.translate(-28,30);rsPoly(p,'rgba(13,17,18,'+a+')',null,0);ctx.restore()} function rsWindow(x,y,w,h){rsRect(x,y,w,h,'#91d3e2','#34474d',3);rsLine([[x+w/2,y+2],[x+w/2,y+h-2]],'rgba(255,255,255,.8)',2);rsLine([[x+2,y+h/2],[x+w-2,y+h/2]],'rgba(255,255,255,.8)',2)} function drawBandWelcomeMatS(h){ if(window.__vancertsSkipBandNorthArtifacts)return; const l=h.lot,cx=h.roadCenterX||1510; const x=cx-58,y=l.y+7,w=116,hh=38; // A low, drive-over mat centered in the open entrance. rsRect(x,y,w,hh,'#4c3529','#211915',4); ctx.fillStyle='#d8c49a';ctx.font='1000 11px system-ui';ctx.textAlign='center';ctx.textBaseline='middle';ctx.fillText('BAND HOUSE',cx,y+hh/2+1); for(let i=0;i<6;i++)rsLine([[x+10+i*18,y+7],[x+10+i*18,y+hh-7]],'rgba(255,255,255,.08)',2); } function drawGuitarMailboxS(h){ if(window.__vancertsSkipBandNorthArtifacts)return; // Keep the guitar-shaped mailbox beside the entrance, with no property-name text. const cx=h.roadCenterX||1510,x=cx+88,y=h.lot.y+39; ctx.save();ctx.fillStyle='#65452f';ctx.fillRect(x-3,y+12,6,43);ctx.fillStyle='#27211d';ctx.fillRect(x-18,y+49,36,7); ctx.fillStyle='#a84b35';ctx.beginPath();ctx.arc(x,y,14,0,Math.PI*2);ctx.arc(x,y+16,18,0,Math.PI*2);ctx.fill();ctx.strokeStyle='#2b1d17';ctx.lineWidth=3;ctx.stroke(); ctx.fillStyle='#d8b46c';ctx.fillRect(x-4,y-30,8,31);ctx.fillStyle='#2b1d17';ctx.fillRect(x-7,y-35,14,7); ctx.strokeStyle='#e64a38';ctx.lineWidth=3;ctx.beginPath();ctx.moveTo(x+12,y-2);ctx.lineTo(x+25,y-16);ctx.stroke();ctx.fillStyle='#e64a38';ctx.fillRect(x+22,y-23,13,8);ctx.restore(); } function drawHouseS(h){ const x=h.building.x,y=h.building.y,w=h.building.w,hh=h.building.h; rsShadow([[x+12,y+6],[x+w-10,y+22],[x+w-8,y+hh-18],[x+8,y+hh-2]],.29); // Preserve the approved dominant top-down roof. rsPoly([[x+30,y],[x+w-12,y+28],[x+w-12,y+hh-38],[x+30,y+hh],[x,y+hh-28],[x,y+30]],'#843f3d','#171514',5); for(let yy=y+38;yy<y+hh-42;yy+=19)rsLine([[x+19,yy],[x+w-22,yy+10]],'rgba(255,255,255,.10)',2); // Cream west facade faces the stage. Both windows and the door are embedded in this wall. rsPoly([[x,y+30],[x+30,y],[x+30,y+hh],[x,y+hh-28]],'#dfc79d','#171514',5); rsWindow(x+5,y+64,23,48); rsWindow(x+5,y+228,23,48); const dy=y+142; // Vertical doorway in the cream facade between the windows. rsRect(x+5,dy,22,58,'#241a17','#171514',3); // Door leaf hinges to the facade and swings outward west toward the stage. rsPoly([[x+5,dy+3],[x-24,dy+12],[x-24,dy+52],[x+5,dy+55]],'#38251f','#171514',3); rsLine([[x+1,dy+7],[x-20,dy+15],[x-20,dy+49],[x+1,dy+52]],'rgba(255,255,255,.10)',2); // Knob on the free, stage-facing edge. ctx.fillStyle='#f1b83e';ctx.beginPath();ctx.arc(x-19,dy+32,3.8,0,Math.PI*2);ctx.fill();ctx.strokeStyle='#171514';ctx.lineWidth=1.4;ctx.stroke(); // Foundation follows every visible base edge. rsLine([[x+2,y+hh-28],[x+30,y+hh],[x+w-12,y+hh-38]],'#4b3a2d',8); // Square overhead chimney remains unchanged. rsRect(x+w-62,y+29,38,38,'#684538','#171514',4);rsRect(x+w-67,y+24,48,9,'#2d2522','#171514',3); } function drawPseudoDrumsS(x,y){ ctx.save(); ctx.fillStyle='rgba(12,15,16,.28)';ctx.beginPath();ctx.ellipse(x-12,y+18,55,32,-.08,0,Math.PI*2);ctx.fill(); // Bass drum faces east toward the house. ctx.fillStyle='#d8d8d8';ctx.strokeStyle='#171514';ctx.lineWidth=3; ctx.beginPath();ctx.ellipse(x+17,y,22,30,0,0,Math.PI*2);ctx.fill();ctx.stroke(); ctx.fillStyle='#aeb4b5';ctx.beginPath();ctx.ellipse(x+13,y,13,21,0,0,Math.PI*2);ctx.fill();ctx.stroke(); const drums=[[x-13,y-18,13,9,'#d5d5d5'],[x-13,y+18,13,9,'#c9c9c9'],[x-39,y+2,15,11,'#bfc3c4']]; for(const [cx,cy,rx,ry,c] of drums){ctx.fillStyle='#777';ctx.fillRect(cx-rx,cy,rx*2,9);ctx.fillStyle=c;ctx.beginPath();ctx.ellipse(cx,cy,rx,ry,0,0,Math.PI*2);ctx.fill();ctx.stroke()} ctx.fillStyle='#d5d5d5';ctx.beginPath();ctx.ellipse(x-34,y-23,11,7,0,0,Math.PI*2);ctx.fill();ctx.stroke(); ctx.fillStyle='#2e2e2e';ctx.beginPath();ctx.ellipse(x-52,y+1,9,6,0,0,Math.PI*2);ctx.fill(); // Compact cymbal stands stay inside the kit silhouette and do not poke through drums. const cymbals=[[x-25,y-34,-.12],[x-23,y+34,.12]]; for(const [sx,sy,ang] of cymbals){ rsLine([[sx,sy+5],[sx+2,sy+20]],'#aeb4b5',2.5); rsLine([[sx-6,sy+21],[sx+2,sy+17],[sx+9,sy+22]],'#aeb4b5',2); ctx.save();ctx.translate(sx,sy);ctx.rotate(ang);ctx.fillStyle='#d6b85b';ctx.beginPath();ctx.ellipse(0,0,16,5,0,0,Math.PI*2);ctx.fill();ctx.strokeStyle='#7d6324';ctx.lineWidth=2;ctx.stroke();ctx.restore(); } ctx.restore(); } function drawStageS(s){ const x=s.x,y=s.y,w=s.w,h=s.h; rsShadow([[x+5,y+5],[x+w-5,y+10],[x+w+7,y+h-5],[x+10,y+h]],.28); rsPoly([[x+22,y],[x+w-33,y],[x+w,y+27],[x+w,y+h-28],[x+w-32,y+h],[x+22,y+h]],'#242628','#111',5); rsPoly([[x+w-32,y+28],[x+w,y+27],[x+w,y+h-28],[x+w-32,y+h-8]],'#6c523b','#171514',5); rsRect(x+34,y+33,w-76,h-66,'#171717','#3a3a3a',3); const tx=x+w-40;rsLine([[tx,y+24],[tx,y+h-24]],'#aeb4b5',7);rsLine([[tx,y+28],[tx-27,y+11]],'#aeb4b5',5);rsLine([[tx,y+h-28],[tx-27,y+h-11]],'#aeb4b5',5); const cs=['#e64a38','#f1b83e','#3f84a5','#9766a3','#e64a38']; for(let i=0;i<5;i++){const ly=y+42+i*(h-84)/4;ctx.fillStyle=cs[i];ctx.beginPath();ctx.arc(tx-7,ly,7,0,Math.PI*2);ctx.fill();ctx.strokeStyle='#222';ctx.lineWidth=2;ctx.stroke();rsLine([[tx-14,ly],[tx-34,ly+13]],'rgba(12,16,18,.22)',4)} ctx.save();ctx.translate(x+43,y+h/2);ctx.rotate(-Math.PI/2);ctx.fillStyle='#f4e6be';ctx.font='1000 10px system-ui';ctx.textAlign='center';ctx.fillText('BACKYARD PRACTICE STAGE',0,0);ctx.restore(); // Paul Audio uses this same stage renderer, but intentionally has no drum kit. if(!window.__vancertsSkipStageDrums)drawPseudoDrumsS(x+133,y+h/2); for(const q of [y+55,y+h-103]){rsRect(x+48,q,30,48,'#111','#555',3);ctx.fillStyle='#4d4d4d';ctx.beginPath();ctx.arc(x+63,q+15,7,0,Math.PI*2);ctx.arc(x+63,q+35,9,0,Math.PI*2);ctx.fill()} } function drawBeerPongS(){ const s=band.stage,l=band.lot,w=170,h=70; // Centered in the vertical gap between the stage south edge and south fence. const x=Math.round(s.x+(s.w-w)/2), y=Math.round((s.y+s.h + (l.y+l.h-18) - h)/2); rsRect(x-12,y-14,205,102,'rgba(185,164,122,.34)',null,0);rsRect(x,y,w,h,'#286c56','#eef3ef',4);rsLine([[x+w/2,y+2],[x+w/2,y+h-2]],'#eef3ef',3); ctx.fillStyle='#8a5d3c';ctx.fillRect(x+13,y+h,9,20);ctx.fillRect(x+w-22,y+h,9,20); const cups=[[20,18],[33,18],[46,18],[26,31],[39,31],[33,44]];ctx.fillStyle='#e64a38';for(const [cx,cy] of cups){for(const m of [0,1]){const px=m?x+w-cx:x+cx;ctx.beginPath();ctx.arc(px,y+cy,4.5,0,Math.PI*2);ctx.fill()}} } function drawArcheryStandS(){ const sx=1662,sy=3388,tx=1960,ty=3388; const bowX=Math.round((sx+tx)/2); rsRect(sx-58,sy-54,352,110,'rgba(135,112,72,.14)',null,0); rsLine([[sx,sy],[tx-46,ty]],'rgba(239,229,190,.58)',4,[12,9]); // Arrow bundle stays at the firing line. rsLine([[sx,sy-39],[sx,sy+39]],'#f4e6be',5); for(let i=0;i<4;i++){ const ax=sx+11+i*5; rsLine([[ax,sy-23],[ax,sy+23]],'#d9c7a2',2); rsPoly([[ax-2,sy-23],[ax+2,sy-23],[ax,sy-29]],'#e7ddc7','#5a4936',1); } // Bow lies sideways on the grass halfway between arrows and target, on the same axis. ctx.save();ctx.translate(bowX,sy); ctx.strokeStyle='#6f4b2f';ctx.lineWidth=5;ctx.beginPath();ctx.arc(0,0,27,Math.PI*.18,Math.PI*1.82);ctx.stroke(); rsLine([[-22,-16],[22,16]],'#d9c7a2',2); ctx.restore(); // Target remains fixed. ctx.fillStyle='#e7ddc7';ctx.beginPath();ctx.arc(tx,ty,36,0,Math.PI*2);ctx.fill();ctx.strokeStyle='#433c33';ctx.lineWidth=4;ctx.stroke(); for(const [r,c] of [[27,'#2b2b2b'],[20,'#e7ddc7'],[13,'#e64a38'],[6,'#f1b83e']]){ctx.fillStyle=c;ctx.beginPath();ctx.arc(tx,ty,r,0,Math.PI*2);ctx.fill()} ctx.fillStyle='#5a4936';ctx.fillRect(tx-6,ty+34,12,28); ctx.fillStyle='#f4e6be';ctx.font='900 10px system-ui';ctx.textAlign='center'; } const fenceS=window.drawFenceH, gardenS=window.drawGardenH, instrumentsS=window.drawInstrumentsH; function drawHotTubT(){ const lot=band.lot,b=band.building,w=194,h=102; const northInner=lot.y+18,houseNorth=b.y; const y=Math.round(northInner+Math.max(0,(houseNorth-northInner-h)/2)); const x=1731; rsRect(x,y,w,h,'#a88d70','#5b4939',4); ctx.beginPath();ctx.roundRect(x+10,y+10,w-20,h-20,16);ctx.fillStyle='#66635d';ctx.fill();ctx.strokeStyle='#2d2b29';ctx.lineWidth=4;ctx.stroke(); ctx.beginPath();ctx.roundRect(x+24,y+22,w-48,h-44,12);ctx.fillStyle='#3f91a9';ctx.fill();ctx.strokeStyle='#d8d0be';ctx.lineWidth=4;ctx.stroke(); ctx.fillStyle='rgba(255,255,255,.28)';for(let i=0;i<5;i++){ctx.beginPath();ctx.arc(x+43+i*27,y+52+(i%2)*5,4.5,0,Math.PI*2);ctx.fill()} } window.drawYardH=drawYardH=function(h){ if(typeof fenceS==='function')fenceS(h); ctx.save();const l=h.lot;ctx.strokeStyle='rgba(238,233,205,.045)';ctx.lineWidth=42;ctx.strokeRect(l.x+70,l.y+70,l.w-140,l.h-140); if(typeof gardenS==='function')gardenS(); // Restore the approved R36B48R hot-tub coordinates exactly. drawHotTubT(); if(typeof window.drawFirePitI==='function')window.drawFirePitI();else if(typeof window.drawFirePitH==='function')window.drawFirePitH(); if(!window.__vancertsSkipBeerPong)drawBeerPongS();if(!window.__vancertsSkipArchery)drawArcheryStandS(); if(typeof instrumentsS==='function')instrumentsS(); drawBandWelcomeMatS(h);drawGuitarMailboxS(h); ctx.restore(); }; window.drawR36B45BandHome=drawR36B45BandHome=function(h){drawYardH(h);drawStageS(h.stage||band.stage);drawHouseS(h);drawHomeParkedVehicle(h,'band')}; })(); </script> <script> /* R36B48W — surgical redo: open Band doorway and simple half-circle ground bow. */ (function(){ if(!window.R36B45_HOMES||!R36B45_HOMES.band||typeof window.drawR36B45BandHome!=='function')return; const band=R36B45_HOMES.band; band.heroVersion='R36B48W'; const previousBandRenderer=window.drawR36B45BandHome; function line(points,color,width=3,dash=[]){ ctx.save();ctx.strokeStyle=color;ctx.lineWidth=width;ctx.setLineDash(dash);ctx.beginPath(); ctx.moveTo(points[0][0],points[0][1]);for(let i=1;i<points.length;i++)ctx.lineTo(points[i][0],points[i][1]); ctx.stroke();ctx.restore(); } function rect(x,y,w,h,fill,stroke=null,width=0){ ctx.fillStyle=fill;ctx.fillRect(x,y,w,h); if(stroke){ctx.strokeStyle=stroke;ctx.lineWidth=width;ctx.strokeRect(x,y,w,h)} } function windowPane(x,y,w,h){ rect(x,y,w,h,'#91d3e2','#34474d',3); line([[x+w/2,y+2],[x+w/2,y+h-2]],'rgba(255,255,255,.82)',2); line([[x+2,y+h/2],[x+w-2,y+h/2]],'rgba(255,255,255,.82)',2); } function repaintDoorOnFacade(){ const b=band.building,x=b.x,y=b.y,hh=b.h; // Repaint only the west cream facade, removing the detached grass door from R36B48U. ctx.save(); ctx.beginPath();ctx.moveTo(x,y+30);ctx.lineTo(x+30,y);ctx.lineTo(x+30,y+hh);ctx.lineTo(x,y+hh-28);ctx.closePath(); ctx.fillStyle='#dfc79d';ctx.fill();ctx.strokeStyle='#171514';ctx.lineWidth=5;ctx.stroke(); windowPane(x+5,y+64,23,48); windowPane(x+5,y+228,23,48); // Leave a clean open doorway in the cream facade between both windows. const dx=x+5,dy=y+142,dw=23,dh=58; rect(dx,dy,dw,dh,'#171514','#171514',3); // Add a shallow interior floor shadow so the opening reads as part of the house, not grass. ctx.fillStyle='rgba(111,78,55,.72)';ctx.fillRect(dx+4,dy+5,dw-8,dh-10); ctx.restore(); } function repaintArcheryBow(){ const sx=1662,sy=3388,tx=1960,ty=3388; // Clean only the former upright-stand/bow area. Preserve the target and all other yard placement. ctx.save(); rect(sx-70,sy-62,245,124,band.yard||'#668d52'); // Restore the arrows at their original location and redraw the firing guide. line([[sx,sy-39],[sx,sy+39]],'#f4e6be',5); for(let i=0;i<4;i++){ const ax=sx+11+i*6; line([[ax,sy-23],[ax,sy+23]],'#d9c7a2',2.3); ctx.fillStyle='#5b4936';ctx.beginPath();ctx.moveTo(ax,sy-27);ctx.lineTo(ax-3,sy-21);ctx.lineTo(ax+3,sy-21);ctx.closePath();ctx.fill(); } line([[sx+39,sy],[tx-46,ty]],'rgba(239,229,190,.58)',4,[12,9]); // A simple sideways bow: one half-circle curve with one straight rope/string line. const mid=(sx+tx)/2, left=mid-34, right=mid+34; ctx.strokeStyle='rgba(12,16,18,.20)';ctx.lineWidth=6;ctx.beginPath(); ctx.moveTo(left-2,sy+8);ctx.quadraticCurveTo(mid,sy-24,right+2,sy+8);ctx.stroke(); ctx.strokeStyle='#3a251b';ctx.lineWidth=5;ctx.beginPath(); ctx.moveTo(left,sy);ctx.quadraticCurveTo(mid,sy-30,right,sy);ctx.stroke(); line([[left,sy],[right,sy]],'#d9c7a2',2.4); ctx.restore(); } window.drawR36B45BandHome=drawR36B45BandHome=function(h){ previousBandRenderer(h); repaintDoorOnFacade(); if(!window.__vancertsSkipArchery)repaintArcheryBow(); }; })(); </script> <script> /* R36B49A — remove unintended archery cleanup overlay while preserving the finished parcel. */ (function(){ if(!window.R36B45_HOMES||!R36B45_HOMES.band||typeof window.drawR36B45BandHome!=='function')return; const band=R36B45_HOMES.band; band.heroVersion='R36B49A'; const previousBandRenderer=window.drawR36B45BandHome; function fillPoly(points,fill,stroke=null,width=0){ ctx.save();ctx.beginPath();ctx.moveTo(points[0][0],points[0][1]); for(let i=1;i<points.length;i++)ctx.lineTo(points[i][0],points[i][1]);ctx.closePath(); ctx.fillStyle=fill;ctx.fill();if(stroke){ctx.strokeStyle=stroke;ctx.lineWidth=width;ctx.stroke()}ctx.restore(); } function line(points,color,width=3,dash=[]){ ctx.save();ctx.strokeStyle=color;ctx.lineWidth=width;ctx.setLineDash(dash);ctx.beginPath(); ctx.moveTo(points[0][0],points[0][1]);for(let i=1;i<points.length;i++)ctx.lineTo(points[i][0],points[i][1]);ctx.stroke();ctx.restore(); } function cleanOpenDoorway(){ const b=band.building,x=b.x,y=b.y,hh=b.h,dy=y+142; ctx.save(); // Erase the old outward-swinging leaf and knob with the exact yard color. fillPoly([[x-29,dy-2],[x+4,dy-2],[x+4,dy+60],[x-29,dy+60]],band.yard||'#668d52'); // Rebuild the cream facade so the opening remains attached to the house. fillPoly([[x,y+30],[x+30,y],[x+30,y+hh],[x,y+hh-28]],'#dfc79d','#171514',5); // Restore both facade windows. const wp=(wx,wy,ww,wh)=>{ctx.fillStyle='#91d3e2';ctx.fillRect(wx,wy,ww,wh);ctx.strokeStyle='#34474d';ctx.lineWidth=3;ctx.strokeRect(wx,wy,ww,wh);line([[wx+ww/2,wy+2],[wx+ww/2,wy+wh-2]],'rgba(255,255,255,.82)',2);line([[wx+2,wy+wh/2],[wx+ww-2,wy+wh/2]],'rgba(255,255,255,.82)',2)}; wp(x+5,y+64,23,48);wp(x+5,y+228,23,48); // Open doorway only: no leaf and no knob. ctx.fillStyle='#171514';ctx.fillRect(x+5,dy,23,58); ctx.fillStyle='rgba(111,78,55,.72)';ctx.fillRect(x+9,dy+5,15,48); ctx.restore(); } function cleanArcheryLabelFragment(){ // R36B49A: no overlay, no fill rectangle, and no replacement background. // The source label draw is disabled above so the original grass remains untouched. } window.drawR36B45BandHome=drawR36B45BandHome=function(h){ previousBandRenderer(h); cleanOpenDoorway(); cleanArcheryLabelFragment(); }; })(); </script> <script> /* R36B49A — duplicate the finished Band parcel for VANCERTS HOUSE and PAUL • AUDIO HOUSE. */ (function(){ if(!window.R36B45_HOMES||!R36B45_HOMES.band||typeof window.drawR36B45BandHome!=='function')return; const template=R36B45_HOMES.band; const renderBandTemplate=window.drawR36B45BandHome; const originalGround=window.drawR36B45ResidentialGround||drawR36B45ResidentialGround; const originalVehicle=window.drawHomeParkedVehicle||drawHomeParkedVehicle; function shiftRect(r,dx,dy){return r?{x:r.x+dx,y:r.y+dy,w:r.w,h:r.h}:null} function configureNorthernHome(id,centerX,label,border,vehicleKind){ const h=R36B45_HOMES[id]||{}; const lot={x:centerX-template.lot.w/2,y:-1010,w:template.lot.w,h:template.lot.h}; const dx=lot.x-template.lot.x,dy=lot.y-template.lot.y; h.id=id;h.label=label;h.lot=lot;h.yard=template.yard;h.border=border; h.building=shiftRect(template.building,dx,dy); h.stage=shiftRect(template.stage,dx,dy); h.roadCenterX=centerX; // Northern homes open from their south edge into the matching city street. h.road={x:centerX-150,y:lot.y+lot.h,w:300,h:Math.max(0,-(lot.y+lot.h))}; h.pullin={x:centerX-245,y:lot.y+lot.h-128,w:490,h:118}; h.spawn={x:centerX,y:lot.y+lot.h-86,angle:-Math.PI/2}; h.door={x:h.building.x-4,y:h.building.y+142,w:42,h:58}; h.templateDx=dx;h.templateDy=dy;h.vehicleKind=vehicleKind;h.heroVersion='R36B49A'; R36B45_HOMES[id]=h; return h; } const owner=configureNorthernHome('owner',695,'VANCERTS HOUSE','wood','owner'); const audio=configureNorthernHome('audio',2015,'PAUL • AUDIO HOUSE','wood','audio'); // Keep road/collision data synced to the newly aligned Congress and Trinity entries. R36B45_HOME_ROADS=Object.values(R36B45_HOMES).flatMap(h=>[h.road,h.pullin]); window.R36B45_HOME_ROADS=R36B45_HOME_ROADS; function drawNorthHomeGround(h){ const l=h.lot,cx=h.roadCenterX; ctx.save(); ctx.fillStyle=h.yard;ctx.fillRect(l.x,l.y,l.w,l.h); ctx.fillStyle='rgba(255,255,255,.035)';for(let i=0;i<9;i++)ctx.fillRect(l.x+28+i*101,l.y+30,45,l.h-60); // No duplicate/discolored road surface: only the center line extends to the existing city road. ctx.strokeStyle='#d7b64e';ctx.lineWidth=4;ctx.setLineDash([25,20]);ctx.beginPath();ctx.moveTo(cx,l.y+l.h+8);ctx.lineTo(cx,-8);ctx.stroke();ctx.setLineDash([]); ctx.restore(); } window.drawR36B45ResidentialGround=drawR36B45ResidentialGround=function(h){ if(h&&(h.id==='owner'||h.id==='audio'))return drawNorthHomeGround(h); return originalGround(h); }; function drawFenceSegment(x1,y,x2,industrial){ ctx.save();ctx.strokeStyle=industrial?'#454c50':'#6b452c';ctx.lineWidth=industrial?8:10;ctx.beginPath();ctx.moveTo(x1,y);ctx.lineTo(x2,y);ctx.stroke(); ctx.fillStyle=industrial?'#9aa1a5':'#8c5c35';for(let x=x1+18;x<x2;x+=46)ctx.fillRect(x-3,y-6,6,18);ctx.restore(); } function drawSouthWelcome(h,label,industrial){ const l=h.lot,cx=h.roadCenterX,gap=230,y=l.y+l.h; ctx.save(); // The copied north mat/mailbox are suppressed at their source. Do not paint a cleanup tile here. // Redraw only the matching fence segment so no green rectangle overlaps the pool or hangs outside the parcel. drawFenceSegment(cx-gap/2,l.y,cx+gap/2,industrial); // Open the opposite/south side entry and redraw the two fence runs around it. ctx.fillStyle=h.yard;ctx.fillRect(cx-gap/2-10,y-18,gap+20,38); drawFenceSegment(l.x,y,cx-gap/2,industrial);drawFenceSegment(cx+gap/2,y,l.x+l.w,industrial); // Drive-over welcome mat just inside the property. const mw=industrial?206:176,mh=38,mx=cx-mw/2,my=y-mh-8; ctx.fillStyle=industrial?'#31383c':'#4c3529';ctx.fillRect(mx,my,mw,mh);ctx.strokeStyle='#211915';ctx.lineWidth=4;ctx.strokeRect(mx,my,mw,mh); ctx.fillStyle='#d8c49a';ctx.font='1000 11px system-ui';ctx.textAlign='center';ctx.textBaseline='middle';ctx.fillText(label,cx,my+mh/2+1); for(let i=0;i<8;i++){ctx.strokeStyle='rgba(255,255,255,.08)';ctx.lineWidth=2;ctx.beginPath();ctx.moveTo(mx+12+i*(mw-24)/7,my+7);ctx.lineTo(mx+12+i*(mw-24)/7,my+mh-7);ctx.stroke()} ctx.restore(); } function drawTemplateAt(h,kind,label){ const dx=h.templateDx,dy=h.templateDy; ctx.save();ctx.translate(dx,dy); const savedVehicle=window.drawHomeParkedVehicle; const savedSkip=window.__vancertsSkipBandNorthArtifacts; const savedArchery=window.__vancertsSkipArchery; const savedBeerPong=window.__vancertsSkipBeerPong; const savedStageDrums=window.__vancertsSkipStageDrums; window.__vancertsSkipBandNorthArtifacts=true; window.__vancertsSkipArchery=(kind==='owner'||kind==='audio'); window.__vancertsSkipBeerPong=(kind==='audio'); window.__vancertsSkipStageDrums=(kind==='audio'); window.drawHomeParkedVehicle=drawHomeParkedVehicle=function(){}; try{renderBandTemplate(template)}finally{ window.drawHomeParkedVehicle=drawHomeParkedVehicle=savedVehicle; window.__vancertsSkipBandNorthArtifacts=savedSkip; window.__vancertsSkipArchery=savedArchery; window.__vancertsSkipBeerPong=savedBeerPong; window.__vancertsSkipStageDrums=savedStageDrums; } ctx.restore(); drawSouthWelcome(h,label,h.border==='industrial'); originalVehicle(h,kind); } window.drawR36B45OwnerHome=drawR36B45OwnerHome=function(h){drawTemplateAt(h,'owner','VANCERTS HOUSE')}; window.drawR36B45FngineerHome=drawR36B45FngineerHome=function(h){drawTemplateAt(h,'audio','PAUL • AUDIO HOUSE')}; })(); </script> <script> /* R36B49C — VANCERTS HOUSE cleanup, parrot perch, Marco reward, protection, BBQ/fireworks party, and animated backyard band. */ (function(){ if(!window.R36B45_HOMES||!R36B45_HOMES.owner)return; const owner=R36B45_HOMES.owner; owner.heroVersion='R36B49N'; const previousOwner=window.drawR36B45OwnerHome||drawR36B45OwnerHome; const previousDrawVan=window.drawVan||drawVan; const previousUpdate=window.update||update; function marcoState(){ state.marco=Object.assign({unlocked:false,partySeen:false,partyEndsAt:0,shieldReadyAt:0},state.marco||{}); return state.marco; } function ownerShift(){ const b=R36B45_HOMES.band; return {dx:owner.lot.x-b.lot.x,dy:owner.lot.y-b.lot.y}; } function yardGrassPatch(x,y,w,h){ ctx.save(); ctx.fillStyle=owner.yard||'#668d52';ctx.fillRect(x,y,w,h); ctx.fillStyle='rgba(255,255,255,.026)'; for(let i=0;i<Math.ceil(w/50);i++)ctx.fillRect(x+i*50,y,24,h); ctx.restore(); } function fenceRun(x1,y,x2){ ctx.save();ctx.strokeStyle='#6b452c';ctx.lineWidth=10;ctx.beginPath();ctx.moveTo(x1,y);ctx.lineTo(x2,y);ctx.stroke(); ctx.fillStyle='#8c5c35';for(let x=x1+18;x<x2;x+=46)ctx.fillRect(x-3,y-6,6,18);ctx.restore(); } function drawParrot(x,y,s=1,flap=0){ ctx.save();ctx.translate(x,y);ctx.scale(s,s); ctx.fillStyle='rgba(12,17,12,.25)';ctx.beginPath();ctx.ellipse(-5,10,13,6,0,0,Math.PI*2);ctx.fill(); ctx.fillStyle='#2f8f45';ctx.beginPath();ctx.ellipse(0,0,9,13,-.2,0,Math.PI*2);ctx.fill(); ctx.fillStyle='#f0d64b';ctx.beginPath();ctx.arc(2,-10,7,0,Math.PI*2);ctx.fill(); ctx.fillStyle='#1a1a18';ctx.beginPath();ctx.arc(4,-11,1.5,0,Math.PI*2);ctx.fill(); ctx.fillStyle='#59412d';ctx.beginPath();ctx.moveTo(8,-9);ctx.lineTo(14,-6);ctx.lineTo(8,-4);ctx.closePath();ctx.fill(); ctx.strokeStyle='#175f2b';ctx.lineWidth=4;ctx.beginPath();ctx.moveTo(-4,-2);ctx.lineTo(-15-flap,4);ctx.moveTo(4,-1);ctx.lineTo(14+flap,2);ctx.stroke(); ctx.strokeStyle='#9b2b2b';ctx.lineWidth=3;ctx.beginPath();ctx.moveTo(-2,11);ctx.lineTo(-6,20);ctx.moveTo(3,11);ctx.lineTo(1,20);ctx.stroke(); ctx.restore(); } function drawParrotPerch(){ const sh=ownerShift(), band=R36B45_HOMES.band, s=band.stage; const x=s.x+sh.dx+Math.round(s.w/2)-22; const y=owner.lot.y+owner.lot.h-126; yardGrassPatch(x-115,y-70,230,105); ctx.save(); ctx.strokeStyle='#5c3922';ctx.lineWidth=9;ctx.beginPath();ctx.moveTo(x,y-16);ctx.lineTo(x,y+48);ctx.moveTo(x-72,y-16);ctx.lineTo(x+72,y-16);ctx.stroke(); ctx.strokeStyle='#392316';ctx.lineWidth=6;ctx.beginPath();ctx.moveTo(x,y+44);ctx.lineTo(x-32,y+68);ctx.moveTo(x,y+44);ctx.lineTo(x+32,y+68);ctx.moveTo(x-42,y+68);ctx.lineTo(x+42,y+68);ctx.stroke(); drawParrot(x-43,y-31,.9,0);drawParrot(x+5,y-31,.9,2);drawParrot(x+49,y-31,.9,-1); // R36B49N: perch is identified through its action circle, not a permanent label. ctx.restore(); } function drawOwnerMailboxAtEntrance(){ const l=owner.lot,cx=owner.roadCenterX||695,x=cx+112,y=l.y+l.h-74; ctx.save();ctx.fillStyle='#65452f';ctx.fillRect(x-3,y+9,6,45);ctx.fillStyle='#27211d';ctx.fillRect(x-18,y+49,36,7); ctx.fillStyle='#a84b35';ctx.beginPath();ctx.arc(x,y,14,0,Math.PI*2);ctx.arc(x,y+16,18,0,Math.PI*2);ctx.fill();ctx.strokeStyle='#2b1d17';ctx.lineWidth=3;ctx.stroke(); ctx.fillStyle='#d8b46c';ctx.fillRect(x-4,y-30,8,31);ctx.fillStyle='#2b1d17';ctx.fillRect(x-7,y-35,14,7); ctx.strokeStyle='#e64a38';ctx.lineWidth=3;ctx.beginPath();ctx.moveTo(x+12,y-2);ctx.lineTo(x+25,y-16);ctx.stroke();ctx.fillStyle='#e64a38';ctx.fillRect(x+22,y-23,13,8);ctx.restore(); } function cleanOwnerNorthArtifacts(){ const l=owner.lot,cx=owner.roadCenterX||695; // Remove the copied north BAND HOUSE mat and copied mailbox without a flat cleanup box. yardGrassPatch(cx-90,l.y-2,180,62); yardGrassPatch(cx+56,l.y+4,92,82); fenceRun(l.x,l.y,l.x+l.w); } function drawOwnerBarrelBBQPit(){ const l=owner.lot; // Permanent barrel-style BBQ pit centered between the north garden and hot tub. // It shares their north-fence inset and sits entirely inside the parcel. const x=l.x+l.w/2-54,y=l.y+58,w=108,h=54; ctx.save(); // Southwest ground shadow. ctx.fillStyle='rgba(15,18,15,.24)';ctx.beginPath();ctx.ellipse(x+w/2-10,y+h+20,w*.52,13,-.08,0,Math.PI*2);ctx.fill(); // Two sturdy legs. ctx.strokeStyle='#272522';ctx.lineWidth=8;ctx.lineCap='round'; ctx.beginPath();ctx.moveTo(x+24,y+h-2);ctx.lineTo(x+17,y+h+27);ctx.moveTo(x+w-24,y+h-2);ctx.lineTo(x+w-17,y+h+27);ctx.stroke(); ctx.lineWidth=5;ctx.beginPath();ctx.moveTo(x+8,y+h+27);ctx.lineTo(x+33,y+h+27);ctx.moveTo(x+w-33,y+h+27);ctx.lineTo(x+w-8,y+h+27);ctx.stroke(); // Barrel body lying on its side. ctx.fillStyle='#25282a';ctx.strokeStyle='#111';ctx.lineWidth=5; ctx.beginPath();ctx.roundRect(x,y,w,h,22);ctx.fill();ctx.stroke(); // Curved end cap and metal bands. ctx.fillStyle='#34393b';ctx.beginPath();ctx.ellipse(x+17,y+h/2,15,h*.40,0,0,Math.PI*2);ctx.fill();ctx.stroke(); ctx.strokeStyle='#646a6c';ctx.lineWidth=4; ctx.beginPath();ctx.moveTo(x+37,y+5);ctx.lineTo(x+37,y+h-5);ctx.moveTo(x+w-29,y+5);ctx.lineTo(x+w-29,y+h-5);ctx.stroke(); // Lid seam, handle and warm coals visible through the grill. ctx.strokeStyle='#989d9f';ctx.lineWidth=3;ctx.beginPath();ctx.moveTo(x+18,y+h/2);ctx.lineTo(x+w-8,y+h/2);ctx.stroke(); ctx.strokeStyle='#151515';ctx.lineWidth=6;ctx.beginPath();ctx.moveTo(x+w/2-15,y-3);ctx.lineTo(x+w/2-15,y-12);ctx.lineTo(x+w/2+15,y-12);ctx.lineTo(x+w/2+15,y-3);ctx.stroke(); ctx.fillStyle='#d9542f';for(let i=0;i<4;i++){ctx.beginPath();ctx.arc(x+48+i*13,y+h/2+7,4,0,Math.PI*2);ctx.fill()} // R36B49N: BBQ is identified through its action circle, not a permanent label. ctx.restore(); } function drawMarcoParty(){ const m=marcoState();if(!m.partyEndsAt||Date.now()>m.partyEndsAt)return; const l=owner.lot,t=performance.now()/1000,cx=l.x+l.w/2; // BBQ tables and grills. ctx.save();ctx.fillStyle='#6d482e';ctx.fillRect(l.x+420,l.y+180,190,28);ctx.fillRect(l.x+445,l.y+208,10,34);ctx.fillRect(l.x+575,l.y+208,10,34); ctx.fillStyle='#202221';ctx.beginPath();ctx.arc(l.x+390,l.y+210,24,0,Math.PI*2);ctx.fill();ctx.fillStyle='#e64a38';ctx.fillRect(l.x+372,l.y+205,36,6); ctx.fillStyle='#f4e6be';ctx.font='1000 12px system-ui';ctx.textAlign='center';ctx.fillText('CITY BBQ',l.x+515,l.y+172); // Venue representatives and bike community. const colors=['#e64a38','#f1b83e','#3f84a5','#9766a3','#6a9a53','#efefef','#d97835']; for(let i=0;i<places.filter(p=>placeVisible(p)).length;i++){ const a=i/Math.max(1,places.length)*Math.PI*2,x=cx+Math.cos(a)*245,y=l.y+365+Math.sin(a)*115; ctx.fillStyle=colors[i%colors.length];ctx.beginPath();ctx.arc(x,y,8,0,Math.PI*2);ctx.fill();ctx.fillStyle='#222';ctx.fillRect(x-4,y+7,8,13); } for(let i=0;i<10;i++){const x=l.x+100+i*72,y=l.y+605+(i%2)*18;ctx.fillStyle='#242424';ctx.beginPath();ctx.arc(x-8,y,7,0,Math.PI*2);ctx.arc(x+8,y,7,0,Math.PI*2);ctx.fill();ctx.strokeStyle=colors[i%colors.length];ctx.lineWidth=4;ctx.beginPath();ctx.moveTo(x-8,y);ctx.lineTo(x,y-12);ctx.lineTo(x+8,y);ctx.stroke()} // All career vans and the band van arrive. if(typeof drawUnifiedCareerVan==='function'){ drawUnifiedCareerVan(l.x+250,l.y+555,0,'classic');drawUnifiedCareerVan(l.x+345,l.y+555,0,'owner');drawUnifiedCareerVan(l.x+440,l.y+555,0,'paul');drawUnifiedCareerVan(l.x+535,l.y+555,0,'band'); } // Animated band on the backyard stage. const sh=ownerShift(),s=R36B45_HOMES.band.stage, sx=s.x+sh.dx,sy=s.y+sh.dy; const bob=Math.sin(t*7)*4; for(const [i,col] of [['guitar','#e64a38'],['singer','#f1b83e'],['bass','#3f84a5']].entries()){ const x=sx+90+i*52,y=sy+80+bob*(i%2?1:-1);ctx.fillStyle=col;ctx.beginPath();ctx.arc(x,y-18,8,0,Math.PI*2);ctx.fill();ctx.fillRect(x-6,y-10,12,25);ctx.strokeStyle='#eee';ctx.lineWidth=3;ctx.beginPath();ctx.moveTo(x,y);ctx.lineTo(x+18,y+8);ctx.stroke(); } // Fireworks over the parcel. for(let i=0;i<6;i++){const phase=t*1.4+i*1.7,life=phase%3,r=life*34,x=l.x+130+(i*157)%760,y=l.y+90+(i%2)*55;ctx.globalAlpha=Math.max(0,1-life/3);ctx.strokeStyle=colors[i%colors.length];ctx.lineWidth=3;for(let k=0;k<10;k++){const a=k*Math.PI/5;ctx.beginPath();ctx.moveTo(x+Math.cos(a)*r*.3,y+Math.sin(a)*r*.3);ctx.lineTo(x+Math.cos(a)*r,y+Math.sin(a)*r);ctx.stroke()}} ctx.globalAlpha=1;ctx.restore(); } function renderOwner49C(h){ previousOwner(h); // North copied mat/mailbox are now suppressed at their true source. // Cover the copied beer-pong area with matching grass before adding the parrot perch. const sh=ownerShift(),s=R36B45_HOMES.band.stage; yardGrassPatch(s.x+sh.dx-10,owner.lot.y+owner.lot.h-205,230,150); drawOwnerBarrelBBQPit();drawParrotPerch();drawOwnerMailboxAtEntrance();drawMarcoParty(); } window.drawR36B45OwnerHome=drawR36B45OwnerHome=renderOwner49C; function marcoUnlocked(){const m=marcoState();return m.unlocked&&m.enabled!==false&&state.career?.path==='owner'} function maybeUnlockMarco(){ const m=marcoState(); if(!m.unlocked&&Array.isArray(state.completed)&&order.every(id=>state.completed.includes(id))){ m.unlocked=true;m.enabled=true;m.partySeen=true;m.partyEndsAt=Date.now()+600000;m.shieldReadyAt=0; save(); setTimeout(()=>modal('<h2>MARCO JOINS VANCERTS!</h2><p>Every main Chapter 1 business is complete. Marco, the yellow-headed Amazon parrot, can now fly with the VANCERTS van and protect it from regular hazards.</p><p>A fireworks show and city BBQ are underway at VANCERTS HOUSE. Every VANCERTS van, the Band van, Austin bike riders, and venue representatives have arrived for the celebration.</p><div class="btns"><button class="green" onclick="closeModal()">JOIN THE PARTY</button></div>'),120); } } window.update=update=function(dt){previousUpdate(dt);maybeUnlockMarco()}; function drawMarcoFollower(){ if(!marcoUnlocked())return; const t=performance.now()/280,dist=46,side=Math.sin(t*.27)*12,x=van.x-Math.cos(van.angle)*dist+Math.cos(van.angle+Math.PI/2)*side,y=van.y-Math.sin(van.angle)*dist+Math.sin(van.angle+Math.PI/2)*side-18-Math.sin(t)*7; drawParrot(x,y,.8,Math.sin(t)*4); } window.drawVan=drawVan=function(){previousDrawVan();drawMarcoFollower()}; function shieldWrap(name){ const old=window[name];if(typeof old!=='function'||old.__marcoWrapped)return; const wrapped=function(){ const hit=old.apply(this,arguments);if(!hit||!marcoUnlocked())return hit; const m=marcoState(),now=Date.now();if(now<m.shieldReadyAt)return hit; m.shieldReadyAt=now+12000;save();toast('MARCO BLOCKED A ROAD HAZARD!');return false; };wrapped.__marcoWrapped=true;window[name]=wrapped;try{eval(name+'=wrapped')}catch(e){} } ['trafficHit','trashBallHit'].forEach(shieldWrap); })(); </script> <script> /* R36B49L — full residential access + $5,000 promotional van-wrap garage. */ (function(){ const WRAP_PRICE=5000; const WRAPS={ classic:{name:'CLASSIC GREEN + YELLOW',description:'Original VANCERTS work-van promotion wrap.'}, owner:{name:'WHITE FLAME + RED V',description:'Owner flame wrap with the red V on the rear.'}, paul:{name:'PLAIN WHITE VANCERTS',description:'Clean white community-production promotion wrap.'}, band:{name:'BLACK BAND FLAMES',description:'Black touring-band wrap with flame graphics.'} }; function careerDefaultWrap(){ const p=state.career&&state.career.path; if(p==='band')return 'band'; if(p==='team')return 'paul'; return state.career&&state.career.vancertsVanOwned?'classic':'owner'; } function wrapGarage(){ if(!state.vanWrapGarage||typeof state.vanWrapGarage!=='object')state.vanWrapGarage={owned:{},active:null}; if(!state.vanWrapGarage.owned||typeof state.vanWrapGarage.owned!=='object')state.vanWrapGarage.owned={}; const starter=careerDefaultWrap(); state.vanWrapGarage.owned[starter]=true; if(!WRAPS[state.vanWrapGarage.active]||!state.vanWrapGarage.owned[state.vanWrapGarage.active])state.vanWrapGarage.active=starter; return state.vanWrapGarage; } window.vancertsWrapGarage=wrapGarage; // Every residential parcel, entrance and connector is a valid driving surface. // Only the actual house and stage remain solid. Fences are visual and never collision geometry. const previousDriveSurfaces=window.driveSurfaces||driveSurfaces; window.driveSurfaces=driveSurfaces=function(){ const surfaces=(previousDriveSurfaces?previousDriveSurfaces():[]).slice(); if(window.R36B45_HOMES&&typeof R36B45_HOMES==='object'){ for(const h of Object.values(R36B45_HOMES)){ if(!h)continue; if(h.lot)surfaces.push({x:h.lot.x-24,y:h.lot.y-24,w:h.lot.w+48,h:h.lot.h+48}); if(h.road)surfaces.push({x:h.road.x-18,y:h.road.y-18,w:h.road.w+36,h:h.road.h+36}); if(h.pullin)surfaces.push({x:h.pullin.x-24,y:h.pullin.y-24,w:h.pullin.w+48,h:h.pullin.h+48}); } } return surfaces; }; window.homeBuildingBlocked=homeBuildingBlocked=function(x,y){ if(!window.R36B45_HOMES||typeof R36B45_HOMES!=='object')return false; for(const h of Object.values(R36B45_HOMES)){ if(!h)continue; const b=h.building,s=h.stage; if(b&&x>=b.x-18&&x<=b.x+b.w+18&&y>=b.y-18&&y<=b.y+b.h+24)return true; if(s&&x>=s.x-15&&x<=s.x+s.w+15&&y>=s.y-15&&y<=s.y+s.h+20)return true; } return false; }; window.openVanWrapShop=function(){ const garage=wrapGarage(); const cards=Object.entries(WRAPS).map(([id,w])=>{ const owned=!!garage.owned[id],active=garage.active===id; return `<div class="card"><h3>${w.name}</h3><p>${w.description}</p><p><b>PROMOTIONAL WRAP UPGRADE • $${WRAP_PRICE.toLocaleString()}</b></p><div class="btns">${owned?`<button class="${active?'green':''}" onclick="equipVanWrap('${id}')" ${active?'disabled':''}>${active?'CURRENT WRAP':'EQUIP WRAP'}</button>`:`<button class="green" onclick="buyVanWrap('${id}')" ${state.cash<WRAP_PRICE?'disabled':''}>BUY • $${WRAP_PRICE.toLocaleString()}</button>`}</div></div>`; }).join(''); modal(`<h2>VANCERTS VAN WRAP GARAGE</h2><p>Every wrap uses the same approved VANCERTS van chassis. Buy alternate promotional wraps for <b>$5,000 each</b>, then switch between any wraps you own.</p><div class="grid">${cards}</div><div class="btns"><button onclick="hqModal()">BACK TO GARAGE</button><button class="secondary" onclick="closeModal()">CLOSE</button></div>`); }; window.buyVanWrap=function(id){ if(!WRAPS[id])return toast('WRAP NOT FOUND'); const garage=wrapGarage(); if(garage.owned[id])return equipVanWrap(id); if(state.cash<WRAP_PRICE)return toast('NEED $5,000 FOR THIS VAN WRAP'); const paid=typeof debitCash==='function'?debitCash(WRAP_PRICE,'Advertising & promotion',WRAPS[id].name,{vendor:'VANCERTS WRAP GARAGE',businessPurpose:'Promotional vehicle branding and community visibility',taxTreatment:'Business advertising expense example'}):(state.cash-=WRAP_PRICE,true); if(!paid)return toast('NOT ENOUGH CASH'); garage.owned[id]=true;garage.active=id;save();hud();toast(`${WRAPS[id].name} PURCHASED + EQUIPPED`);openVanWrapShop(); }; window.equipVanWrap=function(id){ const garage=wrapGarage(); if(!WRAPS[id]||!garage.owned[id])return toast('BUY THIS WRAP FIRST'); garage.active=id;save();toast(`${WRAPS[id].name} EQUIPPED`);openVanWrapShop(); }; window.drawPlayerCareerVehicle=drawPlayerCareerVehicle=function(){ const garage=wrapGarage(); const career=state.career&&state.career.path; // Band Story hard rule: the player vehicle is the approved BLACK BAND FLAMES van. // This changes the renderer source directly; no masking or visual cover is used. if(career==='band'){ garage.owned.band=true; garage.active='band'; drawUnifiedCareerVan(van.x,van.y,van.angle,'band',{armored:!!state.vanUpgrades.armored,potatoGun:!!state.vanUpgrades.potatoGun}); return; } drawUnifiedCareerVan(van.x,van.y,van.angle,garage.active,{armored:!!state.vanUpgrades.armored,potatoGun:!!state.vanUpgrades.potatoGun}); }; const previousHqModal=window.hqModal||hqModal; window.hqModal=hqModal=function(){ previousHqModal(); setTimeout(()=>{ const box=document.querySelector('#modal .btns'); if(box&&!box.querySelector('[data-wrap-shop]')){ const button=document.createElement('button');button.dataset.wrapShop='1';button.className='green';button.textContent='VAN WRAP GARAGE • $5,000 EACH';button.onclick=openVanWrapShop;box.insertBefore(button,box.firstChild); } },0); }; wrapGarage(); })(); </script> <script> /* R36B49N — owner-yard action markers, city-facing spawn, and guided Chapter 1 bookkeeping. */ (function(){ const BUILD='R36B49N'; function ownerFeaturePoints(){ if(!window.R36B45_HOMES||!R36B45_HOMES.owner||!R36B45_HOMES.band)return null; const owner=R36B45_HOMES.owner,band=R36B45_HOMES.band,l=owner.lot; const sh={dx:owner.lot.x-band.lot.x,dy:owner.lot.y-band.lot.y}; const s=band.stage; return{ bbq:{x:l.x+l.w/2,y:l.y+58+27,label:'BARREL BBQ PIT'}, parrots:{x:s.x+sh.dx+Math.round(s.w/2)-22,y:l.y+l.h-142,label:'YELLOW-HEADED AMAZON PARROTS'} }; } function drawActionCircle(x,y){ ctx.save(); ctx.fillStyle='rgba(0,0,0,.28)';ctx.beginPath();ctx.arc(x+5,y+7,17,0,Math.PI*2);ctx.fill(); ctx.fillStyle='#f1b83e';ctx.strokeStyle='#f4e6be';ctx.lineWidth=4;ctx.beginPath();ctx.arc(x,y,15,0,Math.PI*2);ctx.fill();ctx.stroke(); ctx.fillStyle='#171514';ctx.font='1000 17px system-ui';ctx.textAlign='center';ctx.textBaseline='middle';ctx.fillText('!',x,y+1); ctx.restore(); } const previousOwnerDraw=window.drawR36B45OwnerHome||window.drawR36B45OwnerHome; if(typeof previousOwnerDraw==='function'){ window.drawR36B45OwnerHome=drawR36B45OwnerHome=function(h){ previousOwnerDraw(h); if(!h||h.id!=='owner')return; const f=ownerFeaturePoints();if(!f)return; drawActionCircle(f.bbq.x,f.bbq.y-31); drawActionCircle(f.parrots.x,f.parrots.y-24); }; } const previousNear=window.activeCareerHomeNear||activeCareerHomeNear; window.activeCareerHomeNear=activeCareerHomeNear=function(){ const f=ownerFeaturePoints(); if(f){ if(Math.hypot(van.x-f.bbq.x,van.y-f.bbq.y)<78)return{type:'yardFeature',feature:'bbq',interact:{x:f.bbq.x,y:f.bbq.y}}; if(Math.hypot(van.x-f.parrots.x,van.y-f.parrots.y)<82)return{type:'yardFeature',feature:'parrots',interact:{x:f.parrots.x,y:f.parrots.y}}; } return previousNear(); }; const previousInteract=window.interact||interact; window.interact=interact=function(){ if(near&&near.type==='yardFeature'){ if(near.feature==='bbq')return modal('<h2>VANCERTS HOUSE BARREL BBQ</h2><p>A side-barrel barbecue pit used for crew meals, community cookouts, and the first-mission celebration.</p><p class="small">Crew food is tracked separately from business entertainment and personal food. The Business app explains how each receipt is categorized.</p><div class="btns"><button onclick="closeModal()">BACK TO THE YARD</button></div>'); return modal('<h2>YELLOW-HEADED AMAZON PARROTS</h2><p>These parrots live at VANCERTS House. Marco joins the van after the first Training Wheels mission and can protect the van from a road hazard after his reward celebration.</p><div class="btns"><button onclick="closeModal()">BACK TO THE YARD</button></div>'); } return previousInteract(); }; const previousSpawn=window.spawnCareerAtHome||spawnCareerAtHome; window.spawnCareerAtHome=spawnCareerAtHome=function(path=state.career?.path,role=state.career?.teamRole){ previousSpawn(path,role); const id=careerHomeId(path),h=R36B45_HOMES&&R36B45_HOMES[id]; if(h){van.angle=id==='band'?-Math.PI/2:Math.PI/2;van.speed=0} }; function monthKey(){const d=austinGameDate(new Date());return `${d.getFullYear()}-${String(d.getMonth()+1).padStart(2,'0')}`} function taxTrainingState(){ state.taxTraining=Object.assign({enabled:true,userDisabled:false,guideVisits:0,lastMonth:'',unpaid:0},state.taxTraining||{}); return state.taxTraining; } function ensureMonthlyLivingCosts(){ const t=taxTrainingState(),key=monthKey(); if(!t.lastMonth){t.lastMonth=key;save();return} if(t.lastMonth===key)return; t.lastMonth=key; const rent=1000,bills=500,total=1500; if(Number(state.cash||0)>=total){ debitCash(rent,'Personal housing','Monthly rent',{vendor:'HOME RENT',businessPurpose:'Personal housing cost tracked for cash-flow education. Not treated as a VANCERTS business deduction.',deductiblePct:0,taxTreatment:'PERSONAL EXPENSE • Home rent is not a VANCERTS business deduction in this simulation.',paymentMethod:'PERSONAL FUNDS'}); debitCash(bills,'Personal living costs','Phone, food and utilities',{vendor:'HOUSEHOLD BILLS',businessPurpose:'Monthly personal phone, food and utility budget.',deductiblePct:0,taxTreatment:'PERSONAL EXPENSE • Personal food, household utilities and personal phone use are not business deductions.',paymentMethod:'PERSONAL FUNDS'}); toast('MONTHLY PERSONAL COSTS PAID • RENT $1,000 • BILLS $500'); }else{ t.unpaid=Number(t.unpaid||0)+total; if(typeof pushFinanceTransaction==='function')pushFinanceTransaction('estimate',total,'Personal living costs','Monthly rent and bills due',{vendor:'HOUSEHOLD',businessPurpose:'Personal monthly living costs awaiting payment.',deductiblePct:0,taxTreatment:'PERSONAL EXPENSE • Not a business deduction.'}); toast('MONTHLY PERSONAL COSTS NEED ATTENTION • $1,500 DUE'); } save();hud(); } function taxReviewCount(){const f=state.finance||{};return (f.transactions||[]).filter(tx=>String(tx.deductionStatus||'')==='REVIEW').length} function taxGuideHtml(){ const t=taxTrainingState(),on=t.enabled&¤tChapter()===1,review=taxReviewCount(); return `<div class="taxSchool"><h3>${on?'TRAINING ON • CHAPTER 1 BOOKKEEPING GUIDE':'BOOKKEEPING GUIDE'}</h3> <p><b>The game files routine receipts automatically.</b> Client payments go to income; business fuel is tracked under the actual-expense example; qualifying crew meals are shown at 50%; payroll and ordinary business costs are categorized as paid.</p> <p><b>“Needs attention” is not a missing receipt.</b> It means the tax treatment cannot honestly be decided from the receipt alone. Equipment can require expensing, depreciation, or capitalization, so it stays marked REVIEW with an explanation instead of being guessed.</p> <p><b>Personal monthly budget:</b> Rent $1,000 + phone, food and utilities $500. These are tracked for player cash flow and marked personal/non-deductible unless a future game system documents a legitimate business-use portion.</p> <p><b>Current review cards:</b> ${review}. Open each card’s tax-treatment text to see why it needs review. The game never invents a deduction merely to clear the warning.</p> <div class="btns"><button class="${on?'green':''}" onclick="toggleTaxTraining()">${on?'TURN TAX TRAINING OFF':'TURN TAX TRAINING ON'}</button><button onclick="openTaxTrainingWalkthrough(1)">START STEP-BY-STEP GUIDE</button></div></div>`; } window.toggleTaxTraining=function(){const t=taxTrainingState();t.enabled=!t.enabled;t.userDisabled=!t.enabled;save();openExpenseTracker()}; window.openTaxTrainingWalkthrough=function(step=1){ const steps=[ ['STEP 1 • INCOME','Deposits and final client payments are business income. The game creates separate payment receipts so the full amount earned is visible without counting the same payment twice.'], ['STEP 2 • ACTUAL EXPENSES','Fuel, repairs, payroll and paid business purchases reduce cash. They need a vendor, amount, date and business purpose. The game adds those fields automatically when the transaction happens.'], ['STEP 3 • MEALS','The first chapter uses a $20-per-person show-food example. Qualifying business meals are displayed as a 50% educational deduction estimate; personal meals remain personal.'], ['STEP 4 • EQUIPMENT REVIEW','Equipment receipts remain REVIEW because the correct treatment may be immediate expensing, depreciation or capitalization. The warning is teaching you to inspect the item rather than guess.'], ['STEP 5 • PERSONAL COSTS','Monthly rent is $1,000. Phone, food and utilities total $500. The game tracks the $1,500 monthly personal budget but does not place it in VANCERTS deductions.'], ['STEP 6 • MONTH-END CHECK','Confirm income, actual cash spending, review cards, debt and outstanding client invoices. Keep the receipt even when the amount is not deductible.'] ]; const i=Math.max(1,Math.min(steps.length,Number(step)||1)),s=steps[i-1]; modal(`<h2>${s[0]}</h2><p>${s[1]}</p><p class="small">Training can be turned off at any time from the Business app without changing receipts or story progress.</p><div class="btns">${i>1?`<button onclick="openTaxTrainingWalkthrough(${i-1})">BACK</button>`:''}${i<steps.length?`<button class="green" onclick="openTaxTrainingWalkthrough(${i+1})">NEXT STEP</button>`:`<button class="green" onclick="openExpenseTracker()">OPEN RECEIPTS</button>`}<button class="secondary" onclick="closeModal()">CLOSE</button></div>`); }; const previousOpenExpense=window.openExpenseTracker||openExpenseTracker; window.openExpenseTracker=openExpenseTracker=function(){ ensureMonthlyLivingCosts(); const t=taxTrainingState();t.guideVisits=Number(t.guideVisits||0)+1; if(currentChapter()===1&&!t.userDisabled)t.enabled=true; save(); modal(`<h2>BUSINESS • EXPENSE TRACKER & RECEIPTS</h2><div class="expenseActions"><button class="green" onclick="openComplianceApp()">BUSINESS COMPLIANCE • BMI</button><button onclick="openStaffManager()">TEAM & PAYROLL</button><button onclick="bankModal()">COMMUNITY BANK STATEMENT</button></div>${taxGuideHtml()}${taxSchoolHtml()}${financeStatementHtml()}<h3>RECEIPT & COST-CARD ARCHIVE</h3>${financeReceiptArchiveHtml(24)}<div class="btns"><button class="secondary" onclick="closeModal()">CLOSE TRACKER</button></div>`); if(t.enabled&¤tChapter()===1&&t.guideVisits===1)setTimeout(()=>toast('CHAPTER 1 TAX TRAINING ON • THE BUSINESS APP WILL EXPLAIN EACH CATEGORY'),120); }; let lastLivingCostCheck=0; const previousUpdate=window.update||update; window.update=update=function(dt){ const result=previousUpdate(dt); if(Date.now()-lastLivingCostCheck>5000){lastLivingCostCheck=Date.now();ensureMonthlyLivingCosts()} return result; }; taxTrainingState(); try{save()}catch(_){ } })(); </script> <script> /* R36B49S — Paul Audio uses owner-matching fence and source-level stage suppression. */ (function(){ if(window.R36B45_HOMES&&R36B45_HOMES.audio)R36B45_HOMES.audio.heroVersion='R36B49S'; })(); </script> <script> /* R36B50C — BAND STORY: BUILD YOUR DRAW. Source-level story systems only: no visual masks or cover layers. */ (function(){ const BAND_SHOW_GOALS=[ {crowd:25,revenue:200,label:'GET PEOPLE THERE'}, {crowd:45,revenue:350,label:'BRING THEM BACK'}, {crowd:70,revenue:550,label:'PROVE YOUR DRAW'} ]; const BAND_CHAPTERS=[ {n:1,title:'BUILD YOUR DRAW',text:'Run at least three Band House shows. Use Leftway, KAZI, direct promotion, donations, and merch to prove people will come specifically for your band.'}, {n:2,title:'GET OUT OF THE BACKYARD',text:'Your draw is real. Start pursuing Austin bookings and learn when hiring VANCERTS production is smarter than trying to do everything yourself.'}, {n:3,title:'BUILD THE TEAM',text:'Work repeatedly with VANCERTS, Paul / Audio, stagehands, Leftway, KAZI, and venue contacts. Reliability and relationships become part of the band\'s career.'}, {n:4,title:'MAKE IT SUSTAINABLE',text:'Turn guarantees, merch, travel, production, taxes, and crew costs into a band business that can survive beyond one good show.'}, {n:5,title:'GIVE BACK',text:'Return to the Band House for a major community show powered by the network you built: VANCERTS, Paul, Leftway, KAZI, and newer local bands.'} ]; const walletKey=p=>p==='band'?'band':p==='team'?'team':'owner'; function ensureCareerWallets(){ state.careerWallets=state.careerWallets&&typeof state.careerWallets==='object'?state.careerWallets:{}; const key=walletKey(state.career&&state.career.path); if(!Number.isFinite(Number(state.careerWallets[key])))state.careerWallets[key]=Number(state.cash)||1000; if(!Number.isFinite(Number(state.careerWallets.band)))state.careerWallets.band=1000; if(!Number.isFinite(Number(state.careerWallets.team)))state.careerWallets.team=1000; if(!Number.isFinite(Number(state.careerWallets.owner)))state.careerWallets.owner=key==='owner'?(Number(state.cash)||1000):1000; return state.careerWallets; } function bandStory(){ state.bandStory=state.bandStory&&typeof state.bandStory==='object'?state.bandStory:{}; const b=state.bandStory; if(typeof b.started!=='boolean')b.started=false; b.instrument=b.instrument||''; b.chapter=Math.max(1,Math.min(5,Number(b.chapter)||1)); b.homeShows=Math.max(0,Number(b.homeShows)||0); b.totalAttendance=Math.max(0,Number(b.totalAttendance)||0); b.totalDonations=Math.max(0,Number(b.totalDonations)||0); b.totalMerchSold=Math.max(0,Number(b.totalMerchSold)||0); b.totalMerchRevenue=Math.max(0,Number(b.totalMerchRevenue)||0); b.merchStock=Math.max(0,Number.isFinite(Number(b.merchStock))?Number(b.merchStock):10); b.vancertsHires=Math.max(0,Number(b.vancertsHires)||0); b.vancertsRelationship=Math.max(0,Number(b.vancertsRelationship)||0); b.kaziInterviews=Math.max(0,Number(b.kaziInterviews)||0); b.kaziAds=Math.max(0,Number(b.kaziAds)||0); b.campaign=b.campaign&&typeof b.campaign==='object'?b.campaign:{showNo:b.homeShows+1,flyers:false,social:false,kaziInterview:false,kaziAd:false,kaziBuys:[],vancerts:false}; if(!Array.isArray(b.campaign.kaziBuys))b.campaign.kaziBuys=[]; if(Number(b.campaign.showNo)!==b.homeShows+1)b.campaign={showNo:b.homeShows+1,flyers:false,social:false,kaziInterview:false,kaziAd:false,kaziBuys:[],vancerts:false}; return b; } function leftwayBandAssets(){ try{return leftwayState().projects||[]}catch(_){return []} } const KAZI_RATE_SHEET={ spot30:{label:'30-SECOND SINGLE SPOT',cost:50,impact:8,chance:.55,productionFee:false}, spot60:{label:'60-SECOND SINGLE SPOT',cost:100,impact:14,chance:.60,productionFee:false}, overnight:{label:'OVERNIGHT SPOT • MIDNIGHT–5AM',cost:50,impact:6,chance:.45,productionFee:false}, interview:{label:'PROMOTIONAL INTERVIEW • 10–15 MIN',cost:150,impact:18,chance:.70,productionFee:false}, lunch:{label:'LUNCH RUSH • 1 HOUR',cost:250,impact:22,chance:.72,productionFee:false}, banner:{label:'KAZI FM WEBSITE BANNER • 1 MONTH',cost:325,impact:16,chance:.65,productionFee:false}, community:{label:'COMMUNITY CALENDAR ANNOUNCEMENT',cost:0,impact:8,chance:.35,productionFee:false,review:true}, liveRemote:{label:'LIVE REMOTE • UP TO 3 HOURS',cost:2000,impact:60,chance:.90,productionFee:false}, pkg20x30:{label:'20 × :30 SPOT PACKAGE',cost:875,impact:42,chance:.80,productionFee:true}, pkg50x30:{label:'50 × :30 SPOT PACKAGE',cost:1375,impact:58,chance:.84,productionFee:true}, pkg100x30:{label:'100 × :30 SPOT PACKAGE',cost:1875,impact:74,chance:.88,productionFee:true}, pkg200x30:{label:'200 × :30 SPOT PACKAGE',cost:2875,impact:96,chance:.92,productionFee:true}, pkg20x60:{label:'20 × :60 SPOT PACKAGE',cost:1375,impact:56,chance:.82,productionFee:true}, pkg50x60:{label:'50 × :60 SPOT PACKAGE',cost:1875,impact:72,chance:.86,productionFee:true}, pkg100x60:{label:'100 × :60 SPOT PACKAGE',cost:2375,impact:90,chance:.90,productionFee:true}, pkg200x60:{label:'200 × :60 SPOT PACKAGE',cost:3375,impact:116,chance:.94,productionFee:true} }; function kaziVancertsConnected(){ if(state.career.path==='owner')return true; if(state.career.path==='band')return !!bandStory().campaign.vancerts; return !!state.activeJob; } function bandKaziSummary(){ const c=bandStory().campaign,connected=!!c.vancerts,buys=Array.isArray(c.kaziBuys)?c.kaziBuys:[]; let projectedImpact=0; for(const id of buys){const o=KAZI_RATE_SHEET[id];if(!o)continue;const chance=Math.min(1,o.chance*(connected?2:1));const outcome=connected?2:1;projectedImpact+=o.impact*chance*outcome} return {connected,buys,projectedImpact:Math.round(projectedImpact),chanceMultiplier:connected?2:1,outcomeMultiplier:connected?2:1}; } function resolveBandKaziCampaign(){ const c=bandStory().campaign,connected=!!c.vancerts,buys=Array.isArray(c.kaziBuys)?c.kaziBuys:[];let impact=0,successes=[]; for(const id of buys){const o=KAZI_RATE_SHEET[id];if(!o)continue;const chance=Math.min(1,o.chance*(connected?2:1));if(Math.random()<chance){impact+=o.impact*(connected?2:1);successes.push(o.label)}} return {impact:Math.round(impact),successes,connected}; } function bandCampaignMetrics(){ const b=bandStory(),c=b.campaign,projects=leftwayBandAssets(); const fans=Math.max(0,Number(state.career.bandFans)||0),followers=Math.max(0,Number(state.career.onlineFollowers)||0),quality=Math.max(0,Number(state.career.songQuality)||0); const catalog=Math.min(24,projects.length*4+quality*.35+followers*.05); const returning=Math.min(28,Math.round(fans*.18+b.homeShows*4)); const direct=(c.flyers?12:0)+(c.social?Math.min(18,8+followers*.04):0); const kazi=bandKaziSummary().projectedImpact; const production=c.vancerts?10:0; const score=Math.round(8+catalog+returning+direct+kazi+production); const projected=Math.max(8,Math.round(10+score*.85)); const merchRate=Math.min(.34,.10+score/420+(c.vancerts?.025:0)); const donationAvg=Math.min(9,4.25+quality*.06+(c.vancerts?.75:0)); return {score,projected,merchRate,donationAvg,catalog,returning,direct,kazi,production}; } function currentBandGoal(){ const b=bandStory();return BAND_SHOW_GOALS[Math.min(2,b.homeShows)] } function bandChapterOneComplete(){ const b=bandStory();return b.homeShows>=3&&(b.totalDonations>=700||b.totalMerchSold>=30) } function syncBandChapter(){ const b=bandStory(); if(bandChapterOneComplete()&&b.chapter<2)b.chapter=2; return b.chapter } function bandObjective(){ const b=bandStory(),ch=syncBandChapter(); if(ch===1){ const goal=currentBandGoal(),m=bandCampaignMetrics(); return {title:`BAND • HOME SHOW ${b.homeShows+1}`,text:`${goal.label}: target ${goal.crowd}+ people and $${goal.revenue}+ donations + merch. Current campaign projects about ${m.projected}. After at least 3 shows, reach $700 donations OR 30 merch sold to prove your draw.`} } if(ch===2)return {title:'BAND • GET OUT OF THE BACKYARD',text:'Your draw is proven. Visit the Band House story board, keep using Leftway + KAZI, and begin connecting your outside bookings to VANCERTS production.'}; const chapter=BAND_CHAPTERS[ch-1];return {title:`BAND • CHAPTER ${ch}`,text:chapter.text} } function bandSetupModal(){ const b=bandStory(),name=safeFinanceText(state.career.bandName||'THE BAND'); modal(`<h2>BAND STORY • BUILD YOUR DRAW</h2><div class="card"><h3>YOU ARE ALREADY A BAND.</h3><p>You start at the Band House in the existing <b>black flame Band Van</b> with <b>$1,000</b>. Name the band, choose your role, then turn your backyard stage into a real draw.</p><label><b>BAND NAME</b><input id="bandStoryName" maxlength="40" value="${name}" style="width:100%;padding:10px;margin-top:6px;font:inherit"></label><br><br><label><b>YOUR ROLE / INSTRUMENT</b><select id="bandStoryInstrument" style="width:100%;padding:10px;margin-top:6px;font:inherit"><option>VOCALS</option><option>GUITAR</option><option>BASS</option><option>DRUMS</option><option>KEYS</option></select></label></div><div class="card"><b>CHAPTER 1:</b> Run at least three shows at home. Use Leftway media, KAZI interviews + show ads, street/social promotion, donations and merch. Your results come from the campaign you actually build.</div><div class="btns"><button class="green" onclick="saveBandStorySetup()">START BAND STORY</button><button class="secondary" onclick="openStaffManager()">BACK</button></div>`); setTimeout(()=>{const s=document.getElementById('bandStoryInstrument');if(s&&b.instrument)s.value=b.instrument},0) } window.saveBandStorySetup=function(){ const b=bandStory(),name=String(document.getElementById('bandStoryName')?.value||'').trim().replace(/\s+/g,' ').slice(0,40),inst=String(document.getElementById('bandStoryInstrument')?.value||'VOCALS'); if(!name)return toast('ENTER A BAND NAME'); state.career.bandName=name; b.instrument=inst; b.started=true; state.career.path='band'; state.career.bandXp=Math.max(Number(state.career.bandXp)||0,b.homeShows); state.vanWrapGarage=state.vanWrapGarage&&typeof state.vanWrapGarage==='object'?state.vanWrapGarage:{owned:{},active:null}; state.vanWrapGarage.owned=state.vanWrapGarage.owned&&typeof state.vanWrapGarage.owned==='object'?state.vanWrapGarage.owned:{}; state.vanWrapGarage.owned.band=true; state.vanWrapGarage.active='band'; ensureCareerWallets().band=Number(state.cash)||1000; spawnCareerAtHome('band'); save(); hud(); openBandStory(); toast('BAND STORY STARTED • BLACK FLAME BAND VAN READY') }; window.openBandStory=function(){ const b=bandStory(),ch=syncBandChapter(),m=bandCampaignMetrics(),g=currentBandGoal(),assets=leftwayBandAssets().length; const chapter=BAND_CHAPTERS[ch-1]; modal(`<h2>🎸 ${safeFinanceText(state.career.bandName)} • BAND STORY</h2><div class="card"><h3>CHAPTER ${ch} • ${chapter.title}</h3><p>${chapter.text}</p><p><b>Role:</b> ${safeFinanceText(b.instrument||'CHOOSE ROLE')} • <b>Band cash:</b> $${rentalMoney(state.cash)} • <b>Black flame Band Van:</b> ACTIVE</p></div>${ch===1?`<div class="grid"><div class="card"><h3>HOME SHOWS</h3><b>${b.homeShows} completed</b><br>Total attendance: <b>${b.totalAttendance}</b><br>Donations: <b>$${rentalMoney(b.totalDonations)}</b><br>Merch sold: <b>${b.totalMerchSold}</b> ($${rentalMoney(b.totalMerchRevenue)})</div><div class="card"><h3>NEXT SHOW • ${g.label}</h3>Target crowd: <b>${g.crowd}+</b><br>Target donations + merch: <b>$${g.revenue}+</b><br>Current projection: <b>${m.projected}</b><br>Campaign strength: <b>${m.score}</b></div><div class="card"><h3>MEDIA + MARKETING</h3>Leftway assets: <b>${assets}</b><br>KAZI interviews: <b>${b.kaziInterviews}</b><br>KAZI ads: <b>${b.kaziAds}</b><br>Merch stock: <b>${b.merchStock}</b></div></div><div class="card"><h3>CHAPTER 1 PASS CONDITION</h3><p>Play <b>at least 3 Band House shows</b>, then prove demand with either <b>$700 total donations</b> OR <b>30 pieces of merch sold</b>. Marketing and media determine how quickly you can reach those numbers.</p><p class="${bandChapterOneComplete()?'good':'bad'}">${bandChapterOneComplete()?'DRAW PROVEN • CHAPTER 2 UNLOCKED':`CURRENT: $${rentalMoney(b.totalDonations)} donations • ${b.totalMerchSold} merch sold`}</p></div>`:`<div class="card"><h3>THE SHARED TEAM</h3><p>From here the band repeatedly intersects with <b>VANCERTS Owner</b>, <b>Paul / Audio</b>, stagehands, Leftway, KAZI and venue contacts. The same Austin network now supports larger bookings and touring progression.</p><p>VANCERTS relationship: <b>${b.vancertsRelationship}</b> • VANCERTS hires: <b>${b.vancertsHires}</b></p></div>`}<div class="btns">${ch===1?'<button class="green" onclick="bandHomeModal()">PLAN BAND HOUSE SHOW</button>':''}<button onclick="leftwayModal()">LEFTWAY STUDIOS</button><button onclick="kaziMarketingModal()">KAZI MARKETING</button><button class="secondary" onclick="closeModal()">BACK TO AUSTIN</button></div>`) }; window.bandDirectPromo=function(kind){ const b=bandStory(),c=b.campaign; const cfg=kind==='flyers'?{cost:50,key:'flyers',name:'STREET FLYERS'}:{cost:75,key:'social',name:'SOCIAL PROMO PUSH'}; if(c[cfg.key])return toast(`${cfg.name} ALREADY ACTIVE FOR THIS SHOW`); if(Number(state.cash)<cfg.cost)return toast('NOT ENOUGH BAND CASH'); if(typeof debitCash==='function')debitCash(cfg.cost,'Marketing',`${state.career.bandName} • ${cfg.name}`,{vendor:'Band Promotion',purpose:'Promote the next Band House show and grow the band audience.',deductiblePct:100,taxTreatment:'Ordinary promotional spending directly connected to the music activity may generally be a business expense.'});else state.cash-=cfg.cost; c[cfg.key]=true; ensureCareerWallets().band=state.cash; save(); hud(); bandHomeModal(); toast(`${cfg.name} ACTIVE`) }; window.bandRestockMerch=function(){ const b=bandStory(),cost=120;if(Number(state.cash)<cost)return toast('NOT ENOUGH BAND CASH'); if(typeof debitCash==='function')debitCash(cost,'Merchandise',`${state.career.bandName} • 20 PIECE MERCH RUN`,{vendor:'Band Merch',purpose:'Produce merchandise inventory for sale at band performances.',deductiblePct:100,taxTreatment:'Merch production is tracked as a business cost; inventory and cost-of-goods treatment can depend on the accounting method used.'});else state.cash-=cost; b.merchStock+=20;ensureCareerWallets().band=state.cash;save();hud();bandHomeModal();toast('20 PIECES OF MERCH ADDED') }; window.bandHireVancerts=function(){ const b=bandStory(),c=b.campaign,cost=300;if(b.homeShows<1)return toast('PLAY THE FIRST HOME SHOW BEFORE HIRING VANCERTS');if(c.vancerts)return toast('VANCERTS ALREADY BOOKED FOR THIS SHOW');if(Number(state.cash)<cost)return toast('NOT ENOUGH BAND CASH'); if(typeof debitCash==='function')debitCash(cost,'Production',`VANCERTS • BAND HOUSE PRODUCTION`,{vendor:'VANCERTS',purpose:'Hire production support for the next Band House performance.',deductiblePct:100,taxTreatment:'Production services directly connected to a performance may generally be an ordinary business expense.'});else state.cash-=cost; c.vancerts=true;b.vancertsHires+=1;b.vancertsRelationship+=5;const w=ensureCareerWallets();w.owner=(Number(w.owner)||0)+cost;w.band=state.cash;save();hud();bandHomeModal();toast('VANCERTS + TEAM BOOKED FOR THE HOME SHOW') }; window.bandHomeModal=function(){ if(state.career.path!=='band')return toast('BAND HOUSE SHOWS REQUIRE BAND STORY'); const b=bandStory(),m=bandCampaignMetrics(),g=currentBandGoal(),c=b.campaign,assets=leftwayBandAssets().length; modal(`<h2>BAND HOUSE • HOME SHOW ${b.homeShows+1}</h2><div class="card"><h3>${g.label}</h3><p>Build the campaign first. The crowd is calculated from your real band fans, Leftway media, KAZI promotion, direct marketing and production choices.</p><p><b>Projected crowd:</b> ${m.projected} • <b>Target:</b> ${g.crowd}+<br><b>Campaign strength:</b> ${m.score}<br><b>Leftway media assets:</b> ${assets}</p></div><div class="grid"><div class="card"><h3>DIRECT PROMOTION</h3><p>Street flyers: <b>${c.flyers?'ACTIVE':'OFF'}</b><br>Social push: <b>${c.social?'ACTIVE':'OFF'}</b></p><button onclick="bandDirectPromo('flyers')" ${c.flyers?'disabled':''}>STREET FLYERS • $50</button><button onclick="bandDirectPromo('social')" ${c.social?'disabled':''}>SOCIAL PUSH • $75</button></div><div class="card"><h3>KAZI</h3><p>Placements booked: <b>${Array.isArray(c.kaziBuys)?c.kaziBuys.length:0}</b><br>${c.vancerts?'<span class="good">VANCERTS 2× KAZI BOOST ACTIVE</span>':'Hire VANCERTS to double KAZI chance + outcome.'}</p><button onclick="kaziMarketingModal()">VIEW KAZI RATE SHEET</button></div><div class="card"><h3>VANCERTS TEAM</h3><p>${b.homeShows<1?'First prove you can put on one show yourself. After that the growing crowd can justify bringing in professional production.':c.vancerts?'VANCERTS Owner + production team are booked.':'Hire VANCERTS for PA / production support. This improves the show and starts the band-to-team relationship.'}</p><button onclick="bandHireVancerts()" ${b.homeShows<1||c.vancerts?'disabled':''}>HIRE VANCERTS • $300</button></div><div class="card"><h3>MERCH</h3><p>Stock: <b>${b.merchStock}</b> pieces<br>Sale price: <b>$20</b></p><button onclick="bandRestockMerch()">PRINT 20 • $120</button></div></div><div class="btns"><button class="green" onclick="playBandHomeShow()">PLAY HOME SHOW</button><button onclick="leftwayModal()">LEFTWAY MEDIA</button><button class="secondary" onclick="openBandStory()">STORY BOARD</button></div>`) }; window.playBandHomeShow=function(){ const b=bandStory(),m=bandCampaignMetrics(),g=currentBandGoal(),showNo=b.homeShows+1,kaziResult=resolveBandKaziCampaign(); const actualScore=Math.max(1,m.score-m.kazi+kaziResult.impact); const actualProjected=Math.max(8,Math.round(10+actualScore*.85)); const multiplier=[.91,.96,1.02][Math.min(2,b.homeShows)]; const attendance=Math.max(8,Math.round(actualProjected*multiplier)); const donations=Math.round(attendance*m.donationAvg); const merchDemand=Math.max(1,Math.round(attendance*m.merchRate)); const merchSold=Math.min(b.merchStock,merchDemand),merchRevenue=merchSold*20,total=donations+merchRevenue; b.homeShows+=1;b.totalAttendance+=attendance;b.totalDonations+=donations;b.totalMerchSold+=merchSold;b.totalMerchRevenue+=merchRevenue;b.merchStock-=merchSold; state.career.bandXp=Math.max(Number(state.career.bandXp)||0,b.homeShows); state.career.bandFans=Math.max(0,Number(state.career.bandFans)||0)+Math.max(4,Math.round(attendance*(.28+Math.min(.22,m.score/300)))); state.career.onlineFollowers=Math.max(0,Number(state.career.onlineFollowers)||0)+Math.max(2,Math.round(attendance*.14)); if(typeof creditCash==='function'){creditCash(donations,'Band Show Income',`${state.career.bandName} • Home Show ${showNo} donations`,{vendor:'Band House Audience',businessPurpose:'Audience donations collected at a Band House performance.',paymentMethod:'DONATIONS'});if(merchRevenue)creditCash(merchRevenue,'Merchandise Sales',`${state.career.bandName} • Home Show ${showNo} merch`,{vendor:'Band House Audience',businessPurpose:'Band merchandise sold at the performance.',paymentMethod:'MERCH SALES'});}else state.cash+=total; ensureCareerWallets().band=state.cash; const crowdPass=attendance>=g.crowd,revenuePass=total>=g.revenue; const usedVancerts=!!b.campaign.vancerts;if(usedVancerts)b.vancertsRelationship+=3; b.campaign={showNo:b.homeShows+1,flyers:false,social:false,kaziInterview:false,kaziAd:false,kaziBuys:[],vancerts:false}; const unlockedNow=bandChapterOneComplete();if(unlockedNow)b.chapter=Math.max(2,b.chapter); save();hud(); modal(`<h2>HOME SHOW ${showNo} COMPLETE</h2><div class="grid"><div class="card"><h3>CROWD</h3><b>${attendance}</b> people<br>Goal: ${g.crowd}+<br><span class="${crowdPass?'good':'bad'}">${crowdPass?'CROWD GOAL HIT':'CROWD GOAL MISSED'}</span></div><div class="card"><h3>DONATIONS</h3><b>$${rentalMoney(donations)}</b></div><div class="card"><h3>MERCH</h3><b>${merchSold}</b> sold<br><b>$${rentalMoney(merchRevenue)}</b> revenue</div><div class="card"><h3>SHOW INCOME</h3><b>$${rentalMoney(total)}</b><br>Goal: $${g.revenue}+<br><span class="${revenuePass?'good':'bad'}">${revenuePass?'INCOME GOAL HIT':'KEEP BUILDING THE CAMPAIGN'}</span></div></div>${usedVancerts?'<div class="card"><b>VANCERTS TEAM:</b> Production support improved the show and strengthened the band\'s working relationship with the crew.</div>':''}${unlockedNow?'<div class="card"><h3 class="good">YOU HAVE A DRAW.</h3><p>People are not just coming to a party anymore. They are coming to see your band. <b>Chapter 2 — Get Out of the Backyard</b> is unlocked, and VANCERTS becomes part of the band\'s larger-city production path.</p></div>':b.homeShows>=3?`<div class="card"><h3>AT LEAST THREE SHOWS COMPLETE</h3><p>Now prove sustainable demand: reach <b>$700 total donations</b> OR <b>30 merch sold</b>. Current totals: $${rentalMoney(b.totalDonations)} donations • ${b.totalMerchSold} merch.</p></div>`:''}<div class="btns"><button class="green" onclick="openBandStory()">BAND STORY</button><button onclick="bandHomeModal()">PLAN NEXT HOME SHOW</button><button class="secondary" onclick="closeModal()">BACK TO AUSTIN</button></div>`) }; window.kaziMarketingModal=function(){ const isBand=state.career.path==='band',connected=kaziVancertsConnected(); const partner=`<div class="card"><h3>VANCERTS × KAZI RELATIONSHIP</h3><p>${connected?'<span class="good"><b>ACTIVE:</b> VANCERTS is involved. KAZI campaign success chance and successful campaign outcome are both <b>2×</b> for this event.</span>':'Bring VANCERTS into the event to activate its station relationship: <b>2× promotional success chance + 2× successful outcome.</b>' }</p></div>`; const cards=Object.entries(KAZI_RATE_SHEET).map(([id,o])=>{const total=o.productionFee?` <small>(includes $125 production fee)</small>`:'';const chance=Math.round(Math.min(1,o.chance*(connected?2:1))*100);return `<div class="card"><h3>${o.label}</h3><p><b>Rate: $${rentalMoney(o.cost)}</b>${total}<br>Game campaign success chance: <b>${chance}%</b>${connected?' • successful effect 2×':''}${o.review?'<br><small>Community Calendar placement is subject to station review.</small>':''}</p><button onclick="${isBand?'bandKaziPurchase':'genericKaziPurchase'}('${id}')">${o.cost?`BOOK • $${rentalMoney(o.cost)}`:'SUBMIT FOR REVIEW • FREE'}</button></div>`}).join(''); if(isBand){const b=bandStory(),c=b.campaign,buys=Array.isArray(c.kaziBuys)?c.kaziBuys:[];modal(`<h2>KAZI 88.7 FM • BAND MARKETING</h2>${partner}<div class="card"><b>CURRENT HOME-SHOW CAMPAIGN:</b> ${buys.length} KAZI placement(s) booked. ${connected?'VANCERTS multiplier is active.':'Hire VANCERTS from the Band House show planner to double KAZI chance + outcome.'}</div><div class="grid">${cards}</div><div class="card"><small>KAZI prices are modeled from the provided KAZI 88.7 FM rate sheet. Game attendance/fan effects are simulation mechanics, not real-world advertising guarantees.</small></div><div class="btns"><button onclick="leftwayModal()">LEFTWAY STUDIOS</button><button class="secondary" onclick="bandHomeModal()">BACK TO HOME SHOW</button></div>`);return} state.kaziMarketing=state.kaziMarketing&&typeof state.kaziMarketing==='object'?state.kaziMarketing:{interviews:0,ads:0}; modal(`<h2>KAZI 88.7 FM • COMMUNITY MARKETING</h2>${partner}<div class="grid">${cards}</div><div class="card"><small>KAZI prices are modeled from the provided station rate sheet. Game audience effects are simulation mechanics, not real-world advertising guarantees.</small></div><div class="btns"><button class="secondary" onclick="closeModal()">BACK TO AUSTIN</button></div>`) }; window.bandKaziPurchase=function(id){ const o=KAZI_RATE_SHEET[id],b=bandStory(),c=b.campaign;if(!o)return;if(!Array.isArray(c.kaziBuys))c.kaziBuys=[]; if(c.kaziBuys.includes(id))return toast('THAT KAZI OPTION IS ALREADY ACTIVE FOR THIS SHOW'); if(Number(state.cash)<o.cost)return toast('NOT ENOUGH BAND CASH'); if(o.cost){if(typeof debitCash==='function')debitCash(o.cost,'Marketing',`KAZI 88.7 FM • ${o.label}`,{vendor:'KAZI 88.7 FM',purpose:'Promote the next Band House performance through KAZI.',deductiblePct:100,taxTreatment:'Advertising purchased to promote the music business may generally be an ordinary business expense.'});else state.cash-=o.cost} c.kaziBuys.push(id);c.kaziInterview=c.kaziInterview||id==='interview';c.kaziAd=c.kaziAd||id!=='interview';if(id==='interview')b.kaziInterviews+=1;else b.kaziAds+=1; ensureCareerWallets().band=state.cash;save();hud();kaziMarketingModal();toast(`${o.label} ACTIVE${c.vancerts?' • VANCERTS 2× BOOST':''}`) }; window.genericKaziPurchase=function(id){ const o=KAZI_RATE_SHEET[id];if(!o)return;if(!state.activeJob&&state.career.path!=='owner')return toast('BOOK A SHOW FIRST');if(Number(state.cash)<o.cost)return toast('NOT ENOUGH CASH'); if(o.cost){if(typeof debitCash==='function')debitCash(o.cost,'Marketing',`KAZI 88.7 FM • ${o.label}`,{vendor:'KAZI 88.7 FM',purpose:'Promote live-music activity through KAZI.',deductiblePct:100,taxTreatment:'Advertising directly connected to the business may generally be an ordinary business expense.'});else state.cash-=o.cost} const connected=kaziVancertsConnected(),chance=Math.min(1,o.chance*(connected?2:1)),success=Math.random()<chance,effect=success?Math.max(1,Math.round((o.impact/8)*(connected?2:1))):0; if(state.activeJob){state.activeJob.kaziPromo=true;const v=state.venues[state.activeJob.id];if(v&&effect)v.rateCars=Math.min((places.find(p=>p.id===state.activeJob.id)?.capacity||16),Math.max(Number(v.rateCars)||0,permanentCars(state.activeJob.id)+effect))} state.kaziMarketing=state.kaziMarketing||{interviews:0,ads:0};if(id==='interview')state.kaziMarketing.interviews+=1;else state.kaziMarketing.ads+=1;if(success)state.rep+=connected?4:2; ensureCareerWallets()[walletKey(state.career.path)]=state.cash;save();hud();kaziMarketingModal();toast(success?`KAZI CAMPAIGN HIT • ${connected?'VANCERTS 2× BOOST ACTIVE':'AUDIENCE MOMENTUM ADDED'}`:'KAZI CAMPAIGN RAN • LIMITED RESPONSE THIS TIME') }; window.bandKaziInterview=function(){return bandKaziPurchase('interview')}; window.bandKaziAd=function(){return bandKaziPurchase('spot60')}; window.genericKaziInterview=function(){return genericKaziPurchase('interview')}; window.genericKaziAd=function(){return genericKaziPurchase('spot60')}; const previousChooseCareer=chooseCareerPath; chooseCareerPath=function(path,role){ if(!['owner','team','band'].includes(path))return; const wallets=ensureCareerWallets(),from=walletKey(state.career&&state.career.path);wallets[from]=Number(state.cash)||0; if(path==='team'&&['stagehand','audio'].includes(role))state.career.teamRole=role; state.career.path=path;const to=walletKey(path);if(!Number.isFinite(Number(wallets[to])))wallets[to]=1000;state.cash=Number(wallets[to]); if(path==='band'){state.vanWrapGarage=state.vanWrapGarage&&typeof state.vanWrapGarage==='object'?state.vanWrapGarage:{owned:{},active:null};state.vanWrapGarage.owned=state.vanWrapGarage.owned&&typeof state.vanWrapGarage.owned==='object'?state.vanWrapGarage.owned:{};state.vanWrapGarage.owned.band=true;state.vanWrapGarage.active='band'} spawnCareerAtHome(path,role||state.career.teamRole);save();hud(); if(path==='band'){const b=bandStory();if(!b.started)return bandSetupModal();openBandStory();toast('BAND STORY ACTIVE • BLACK FLAME BAND VAN READY');return} openStaffManager();toast(path==='owner'?'OWNER STORY ACTIVE • OWNER CASH RESTORED':`${state.career.teamRole==='audio'?'AUDIO ENGINEER':'STAGEHAND'} STORY ACTIVE • $${rentalMoney(state.cash)} CAREER CASH`) }; window.chooseCareerPath=chooseCareerPath; const previousOpenCareerHome=openCareerHome; openCareerHome=function(homeId){if(homeId==='band'&&state.career.path==='band')return bandHomeModal();return previousOpenCareerHome(homeId)}; window.openCareerHome=openCareerHome; const previousGigModal=gigModal; const kaziPlace=places.find(p=>p.id==='kazi');if(kaziPlace)kaziPlace.openFromStart=true; gigModal=function(id){if(id==='kazi')return kaziMarketingModal();return previousGigModal(id)}; window.gigModal=gigModal; const previousHud=hud; hud=function(){const r=previousHud();if(state.career&&state.career.path==='band'){const o=bandObjective(),t=document.getElementById('objectiveTitle'),x=document.getElementById('objectiveText');if(t)t.textContent=o.title;if(x)x.textContent=o.text;const w=ensureCareerWallets();w.band=Number(state.cash)||0}return r}; window.hud=hud; // Add the Band Story board to the existing Team / Career panel without replacing the rest of that system. const previousOpenStaff=openStaffManager; openStaffManager=function(){previousOpenStaff();setTimeout(()=>{const modalEl=document.getElementById('modal');if(!modalEl)return;const cards=[...modalEl.querySelectorAll('.card')];const bandCard=cards.find(el=>el.textContent.includes('🎸 BAND'));if(bandCard&&!bandCard.querySelector('[data-band-story-board]')){const btn=document.createElement('button');btn.dataset.bandStoryBoard='1';btn.textContent='BAND STORY MISSIONS';btn.onclick=()=>{if(state.career.path!=='band')chooseCareerPath('band');else openBandStory()};bandCard.querySelector('.btns')?.appendChild(btn)}} ,0)}; window.openStaffManager=openStaffManager; ensureCareerWallets();bandStory(); try{hud()}catch(_){ } })(); </script> <style id="r36b52h-story-navigation-responsive-style"> /* R36B52H — portrait-safe QueueTube sizing and final story/GPS authority. */ #objective.r36b52hStoryAuthority{border-color:#f1b83e!important;box-shadow:5px 5px 0 #000!important;scroll-behavior:auto!important} #objective.r36b52hStoryAuthority #objectiveTitle{color:#f1b83e!important} #objective.r36b52hStoryAuthority #objectiveText{white-space:normal!important} #miniCanvas.r36b52hGpsActive{outline:2px solid rgba(230,74,56,.58)!important;outline-offset:-2px!important} /* Keep the direct QueueTube player inside every portrait or landscape viewport. */ #rotaryRadio.vcQueueTubeDirect{ box-sizing:border-box!important; max-width:calc(100vw - 12px)!important; max-height:calc(100dvh - 12px)!important; } #rotaryRadio.vcQueueTubeDirect #qtPlayerMount, #rotaryRadio.vcQueueTubeDirect .qt-player{box-sizing:border-box!important;width:100%!important;max-width:100%!important} @media (max-width:760px),(pointer:coarse){ #rotaryRadio.vcQueueTubeDirect{ width:calc(100vw - 12px)!important; max-width:calc(100vw - 12px)!important; max-height:calc(100dvh - max(12px,env(safe-area-inset-top)) - max(12px,env(safe-area-inset-bottom)))!important; overflow:hidden!important; } #rotaryRadio.vcQueueTubeDirect .qt-player{overflow:hidden!important} } @media (orientation:portrait) and (max-width:760px){ #rotaryRadio.vcQueueTubeDirect{ left:6px; right:auto; top:max(58px,calc(env(safe-area-inset-top) + 48px)); width:calc(100vw - 12px)!important; max-width:calc(100vw - 12px)!important; max-height:calc(100dvh - max(70px,calc(env(safe-area-inset-top) + 58px)) - max(8px,env(safe-area-inset-bottom)))!important; border-width:3px!important; border-radius:14px!important; } #rotaryRadio.vcQueueTubeDirect .vcQtDockHead{height:42px!important;padding:6px!important} #rotaryRadio.vcQueueTubeDirect .vcQtDockButton{height:29px!important;min-width:66px!important;padding:3px 7px!important;font-size:8px!important} #rotaryRadio.vcQueueTubeDirect .qt-body{padding:10px 148px 6px 8px!important} #rotaryRadio.vcQueueTubeDirect .qt-artist{font-size:10px!important} #rotaryRadio.vcQueueTubeDirect .qt-title{font-size:12px!important} #rotaryRadio.vcQueueTubeDirect .qt-event{font-size:7px!important;margin-top:2px!important} #rotaryRadio.vcQueueTubeDirect .qt-progress-row{margin-top:7px!important} #rotaryRadio.vcQueueTubeDirect .qt-progress{height:10px!important} #rotaryRadio.vcQueueTubeDirect .qt-time{font-size:7px!important} #rotaryRadio.vcQueueTubeDirect .qt-controls{gap:3px!important;padding:6px!important} #rotaryRadio.vcQueueTubeDirect .qt-controls button{height:29px!important;font-size:8px!important} #rotaryRadio.vcQueueTubeDirect .qt-controls .qt-play{font-size:12px!important} #rotaryRadio.vcQueueTubeDirect .qt-volume{grid-template-columns:29px minmax(0,1fr) 29px 34px!important;gap:5px!important;padding:0 7px 6px!important} #rotaryRadio.vcQueueTubeDirect .qt-volume button{height:29px!important} #rotaryRadio.vcQueueTubeDirect .qt-status-row{padding:6px 8px!important} #rotaryRadio.vcQueueTubeDirect .qt-status{font-size:7px!important;min-height:17px!important} #rotaryRadio.vcQueueTubeDirect .qt-queue{max-height:min(132px,22dvh)!important} } @media (orientation:portrait) and (max-width:390px){ #rotaryRadio.vcQueueTubeDirect .qt-body{padding-right:136px!important} #rotaryRadio.vcQueueTubeDirect .vcQtDockButton{min-width:59px!important;font-size:7px!important} #rotaryRadio.vcQueueTubeDirect .qt-controls button{padding:0 2px!important;font-size:7px!important} } </style> <script id="r36b52h-story-navigation-responsive"> (function(){ 'use strict'; const BUILD='R36B52P'; const RED='#e64a38', PAPER='#fff8e5', INK='#171514'; const $id=id=>document.getElementById(id); const previousTrainingMission=typeof window.currentTrainingMission==='function'?window.currentTrainingMission:null; const previousHud=typeof window.hud==='function'?window.hud:null; const previousDraw=typeof window.draw==='function'?window.draw:null; const previousMini=typeof window.drawMini==='function'?window.drawMini:null; let lastObjectiveSignature=''; function careerId(){ const path=state?.career?.path||'owner'; return path==='team'?(state.career?.teamRole==='audio'?'audio':'stagehand'):path; } function careerLabel(){ const id=careerId(); return id==='band'?'BAND':id==='audio'?'PAUL • AUDIO ENGINEER':id==='stagehand'?'STAGEHAND':'VANCERTS OWNER'; } function trainingData(chapter,index,total,title,text,focus='objective',actionLabel='SHOW EXACT STEP',action='',targetId='',homeId=''){ return{mode:'story',chapter,index,total,title,text,focus,actionLabel,action,targetId,homeId,key:`${chapter}-${index}-${title}-${targetId||homeId}`}; } function placeById(id){return Array.isArray(places)?places.find(p=>p&&p.id===id):null} function placeName(id){const p=placeById(id);return p?.name||p?.short||String(id||'NEXT DESTINATION').toUpperCase()} function unpaid(){try{return typeof unpaidTotal==='function'?Math.max(0,Number(unpaidTotal())||0):0}catch(_){return 0}} function chapter(){try{return typeof trainingStoryChapter==='function'?Number(trainingStoryChapter())||1:1}catch(_){return 1}} function currentTutorial(){try{return typeof window.__VANCERTS_R36B52A_TUTORIAL==='function'?window.__VANCERTS_R36B52A_TUTORIAL():null}catch(_){return null}} function sharedShowMission(){ const role=careerLabel(), ch=chapter(); const roleTotal=careerId()==='owner'?8:7; if(state?.passengerRide&&!state.activeJob){ const dest=typeof activePassengerDestination==='function'?activePassengerDestination():null; if(dest)return trainingData(ch,1,roleTotal,`${role} • PASSENGER DELIVERY`,`Drive to ${dest.name||'the passenger destination'} and interact near its loading area.`, 'drive','SHOW DESTINATION','',dest.id||''); } if(state?.pendingOffer){ const id=state.pendingOffer.id,p=placeById(id); const text=careerId()==='audio'?`Open EMAIL. Review ${p?.name||'the client'}'s requested mains, subs, microphones, monitors, cables, and stage needs. Confirm the work order and deposit before equipment pickup.`:`Open EMAIL on the Nookia. Review ${p?.name||'the client'}'s approved equipment list, then press COLLECT DEPOSIT & CONFIRM DATE.`; return trainingData(ch,careerId()==='owner'?5:3,roleTotal,`${role} • REVIEW THE CLIENT EMAIL`,text, 'email','OPEN EMAIL','openEmail()'); } if(state?.activeJob){ const id=state.activeJob.id,p=placeById(id),name=p?.name||'THE CLIENT'; if(state.activeJob.phase==='pickup'){ const roleText=careerId()==='audio'?'This is the first equipment stop: load the approved PA, microphones, monitors, and cables from the confirmed work order.':careerId()==='stagehand'?'Load every approved item on the manifest.':careerId()==='band'?'Load the approved production package for the show.':'Load the exact approved equipment manifest.'; return trainingData(ch,careerId()==='owner'?6:4,roleTotal,`${role} • PICK UP THE SHOW GEAR`,`The deposit is complete. Drive to GIG BAG ATX, enter the loading area, interact, and press LOAD APPROVED GEAR. ${roleText}`, 'drive','SHOW GIG BAG','', 'shop'); } const roleText=careerId()==='audio'?'Set the Tascam Model 24 on the rear shelf facing the stage, place mains, subs, and monitors, complete the signal path, line-check every input, and prepare soundcheck while the Stage Manager handles communication.':careerId()==='stagehand'?'Unload, place, cable, and secure every stage item in its correct position.':careerId()==='band'?'Arrive for load-in and complete the show setup.':'Complete load-in, stage setup, and the performance.'; return trainingData(ch,careerId()==='owner'?7:5,roleTotal,`${role} • GEAR LOADED — RETURN TO ${String(name).toUpperCase()}`,`The equipment is loaded. Drive from Gig Bag ATX to ${name}, enter the marked loading zone, interact, and complete the show. ${roleText}`, 'drive','SHOW CLIENT DESTINATION','',id); } const due=unpaid(); if(due>0){ return trainingData(ch,careerId()==='owner'?8:6,roleTotal,`${role} • COLLECT THE FINAL PAYMENT`,`The show is complete and $${Math.round(due)} is still owed. Open the Nookia, use CALL, choose the client, and collect the remaining balance.`, 'call','OPEN NOOKIA','openPhone()'); } return null; } function ownerFallback(){ const ch=chapter(); if(state?.story?.festivalActive){ const route=typeof FESTIVAL_ROUTE!=='undefined'?FESTIVAL_ROUTE:[],id=route[Number(state.story.festivalIndex)||0]; if(id)return trainingData(ch,5,6,id==='hq'?"VANCERTS OWNER • FINISH IT'S A VAN FEST":'VANCERTS OWNER • CONTINUE THE VAN FEST ROUTE',id==='hq'?'Return to BYOB Austin, interact, and complete the citywide finale.':`Drive to ${placeName(id)}, enter the loading zone, and complete the current festival show.`, 'drive','SHOW DESTINATION','',id); } if(state?.story?.secondFestivalActive){ const route=state.story.secondFestivalRoute||[],id=route[Number(state.story.secondFestivalIndex)||0]; if(id)return trainingData(ch,5,6,id==='hq'?'VANCERTS OWNER • FINISH VAN FEST II':'VANCERTS OWNER • CONTINUE VAN FEST II',id==='hq'?'Return to BYOB Austin and complete the finale.':`Drive to ${placeName(id)} and complete the current festival stop.`, 'drive','SHOW DESTINATION','',id); } const list=typeof order!=='undefined'&&Array.isArray(order)?order:(typeof ORDER!=='undefined'&&Array.isArray(ORDER)?ORDER:['fsg','blueowl','republic','hope','topnotch','leftway']); const next=list.find(id=>!state.completed?.includes(id)); if(next)return trainingData(ch,4,8,`VANCERTS OWNER • BOOK ${placeName(next).toUpperCase()}`,`Drive to ${placeName(next)}, enter the marked loading zone, stop, and interact to begin the next client request.`, 'drive','SHOW DESTINATION','',next); return null; } function teamFallback(){ const id=careerId(),role=careerLabel(); const xp=id==='audio'?Number(state.career?.audioXp||0):Number(state.career?.stagehandXp||0); if(!xp&&!state.completed?.includes('fsg'))return trainingData(1,2,7,`${role} • FIRST WORK ORDER — FSG`,id==='audio'?`Drive to FSG PRINTSHOP first, enter the marked loading zone, and interact. Paul must receive the client work order before Gig Bag can prepare the PA.`:`Drive to FSG PRINTSHOP, enter the marked loading zone, and interact to receive the first crew work order.`, 'drive','SHOW FSG','', 'fsg'); return null; } function bandFallback(){ const b=typeof bandStory==='function'?bandStory():(state.bandStory||{}),assets=typeof leftwayBandAssets==='function'?leftwayBandAssets():[],c=b.campaign||{}; if(!b.started)return trainingData(1,1,12,'BAND • START THE BAND STORY','Open the Band Story board, name the band, choose your instrument, and start the story.','objective','OPEN BAND STORY','openBandStory()','','band'); if(!assets.length)return trainingData(1,2,12,'BAND • CREATE YOUR FIRST LEFTWAY DEMO','Drive to LEFTWAY STUDIOS, enter the interaction area, and purchase DEMO RECORDING — $150.','drive','SHOW LEFTWAY','', 'leftway'); if(b.homeShows===0&&!c.flyers&&!c.social)return trainingData(1,3,12,'BAND • PROMOTE HOME SHOW 1','Return to BAND HOUSE, open the show planner, and purchase STREET FLYERS or SOCIAL PUSH.','drive','SHOW BAND HOUSE','', '', 'band'); if(b.homeShows===0&&(!Array.isArray(c.kaziBuys)||!c.kaziBuys.length))return trainingData(1,4,12,'BAND • USE KAZI PROMOTION','Open the KAZI rate sheet from the Band House planner and purchase an affordable promotion.','objective','OPEN KAZI','kaziMarketingModal()'); return null; } function normalizePriorMission(m){ if(!m)return null; const copy=Object.assign({mode:'story',chapter:chapter(),index:1,total:1,focus:'objective',actionLabel:'SHOW EXACT STEP',action:''},m); copy.title=String(copy.title||`${careerLabel()} • CURRENT STORY`); copy.text=String(copy.text||'Follow the current story objective.'); return copy; } function deriveMission(){ const tutorial=currentTutorial(); if(tutorial&&!tutorial.done&&typeof window.__VANCERTS_R36B52A_GUIDANCE==='function'){ try{const g=window.__VANCERTS_R36B52A_GUIDANCE();return{mode:'controls',chapter:0,index:Math.min(Number(tutorial.step||0)+1,6),total:6,title:g.title,text:g.text,focus:Number(tutorial.step||0)>=5?'drive':'controls',actionLabel:'SHOW EXACT STEP',action:'',key:`controls-${tutorial.step}`}}catch(_){} } const shared=sharedShowMission();if(shared)return shared; const role=careerId(); const roleMission=role==='owner'?ownerFallback():role==='band'?bandFallback():teamFallback(); if(roleMission)return roleMission; try{return normalizePriorMission(previousTrainingMission?previousTrainingMission():null)}catch(e){console.warn(BUILD+' prior mission',e)} return trainingData(chapter(),1,1,`${careerLabel()} • CONTINUE THE STORY`,'Follow the current objective and interact with the highlighted destination or Nookia app.'); } window.currentTrainingMission=currentTrainingMission=function(){return deriveMission()}; function placeTarget(id,label){ const p=placeById(id);if(!p)return null; const rect=p.interactionRect||p.setup||p.parking||null; return{id:p.id,label:label||p.name||p.short||id,x:p.interact?.x??p.x+p.w/2,y:p.interact?.y??p.y+p.h/2,rect,radius:92}; } function homeTarget(id,label){ const h=typeof R36B45_HOMES!=='undefined'&&R36B45_HOMES?R36B45_HOMES[id]:null;if(!h)return null; const rect=h.pullin||h.lot||null; return{id:`home-${id}`,label:label||h.label||id,x:h.door?h.door.x+h.door.w/2:(h.spawn?.x||0),y:h.door?h.door.y+h.door.h+20:(h.spawn?.y||0),rect,radius:105}; } function contains(r,x,y,pad=0){return !!r&&x>=r.x-pad&&x<=r.x+r.w+pad&&y>=r.y-pad&&y<=r.y+r.h+pad} function reached(t){ if(!t||typeof van==='undefined')return true; if(contains(t.rect,van.x,van.y,10))return true; return Math.hypot(van.x-t.x,van.y-t.y)<=Number(t.radius||92); } function textTarget(m){ const hay=`${m?.title||''} ${m?.text||''}`.toUpperCase(); const homes=[['BAND HOUSE','band'],['PAUL • AUDIO HOUSE','audio'],['AUDIO HOUSE','audio'],['VANCERTS HOUSE','owner'],['OWNER HOME','owner']]; for(const [name,id] of homes)if(hay.includes(name))return homeTarget(id,name); const aliases={shop:['GIG BAG ATX','GIG BAG'],hq:['BYOB AUSTIN','VANCERTS HQ','BYOB'],fsg:['FSG PRINTSHOP','FSG'],leftway:['LEFTWAY STUDIOS','LEFTWAY'],kazi:['KAZI 88.7 FM','KAZI'],worldliquor:['WORLD LIQUOR'],blueowl:['BLUE OWL'],republic:['REPUBLIC SQUARE'],hope:['HOPE OUTDOOR'],topnotch:['TOP NOTCH'],mama:['MAMA DEAREST'],juan:['JUAN IN A MILLION'],tascam:['TASCAM'],jbl:['JBL PRO']}; for(const [id,names] of Object.entries(aliases))if(names.some(n=>hay.includes(n)))return placeTarget(id,names[0]); if(Array.isArray(places))for(const p of [...places].sort((a,b)=>String(b.name||'').length-String(a.name||'').length)){const names=[p.name,p.short,p.abbr].filter(Boolean).map(v=>String(v).toUpperCase());if(names.some(n=>n.length>2&&hay.includes(n)))return placeTarget(p.id,p.name)} return null; } function destination(m=deriveMission()){ if(!m||m.mode==='controls'&&Number(m.index||0)<6)return null; let t=m.homeId?homeTarget(m.homeId):m.targetId?placeTarget(m.targetId):textTarget(m); return reached(t)?null:t; } function renderObjective(){ try{ if(!$id('splash')?.classList.contains('hidden'))return null; const m=deriveMission(),dest=destination(m); let text=String(m.text||''); text=text.replace(/faint blinking yellow line/gi,'red road arrows').replace(/faint yellow[^.]*route/gi,'red road arrows').replace(/gold road markers/gi,'red road arrows').replace(/gold arrow/gi,'red road arrows').replace(/Follow the route/gi,'Follow the red road arrows and the Nookia GPS line'); if(dest&&!/NOOKIA GPS/i.test(text))text+=` GPS: Follow the red road arrows and the red line on the Nookia map to ${dest.label}.`; const progress=m.mode==='controls'?`STEP ${Math.min(Number(m.index)||1,6)} / 6`:`CHAPTER ${Number(m.chapter)||1} • STEP ${Number(m.index)||1} / ${Number(m.total)||1}`; const signature=[careerId(),m.key||'',m.title,text,progress,dest?.id||''].join('|'); const obj=$id('objective'),titleEl=$id('objectiveTitle'),textEl=$id('objectiveText'),badge=$id('trainingBadge'),progressEl=$id('trainingProgress'),guide=$id('trainingGuide'); if(obj)obj.classList.add('r36b51eTraining','r36b52hStoryAuthority'); if(titleEl&&titleEl.textContent!==m.title)titleEl.textContent=m.title; if(textEl&&textEl.textContent!==text)textEl.textContent=text; if(badge)badge.textContent=state.training?.enabled===false?'MISSION GUIDE':'TRAINING WHEELS'; if(progressEl)progressEl.textContent=progress; if(guide){guide.textContent=m.actionLabel||'SHOW EXACT STEP';guide.onclick=function(){const fn=String(m.action||'').match(/^([A-Za-z_$][\w$]*)\s*\(\s*\)\s*;?$/);if(fn&&typeof window[fn[1]]==='function')window[fn[1]]();else if(typeof toast==='function')toast(text)}} const pt=$id('phoneObjectiveTitle'),px=$id('phoneObjectiveText');if(pt)pt.textContent=m.title;if(px)px.textContent=text; if(signature!==lastObjectiveSignature&&obj){obj.scrollTop=0;lastObjectiveSignature=signature} return{mission:m,destination:dest,signature}; }catch(e){console.error(BUILD+' objective',e);return null} } function camera(){ const scale=typeof cameraScale==='function'?cameraScale():1,zoom=typeof cameraZoomLevel==='function'?cameraZoomLevel():1,viewW=W/scale,viewH=H/scale; const full=typeof FULL_CITY_VIEW_BOUNDS!=='undefined'?FULL_CITY_VIEW_BOUNDS:{x:0,y:0,w:world.w,h:world.h},bird=typeof BIRD_EYE_VIEW_BOUNDS!=='undefined'?BIRD_EYE_VIEW_BOUNDS:full; return{scale,camX:zoom===4?full.x-(viewW-full.w)/2:zoom===5?bird.x-(viewW-bird.w)/2:van.x-viewW/2,camY:zoom===4?full.y-(viewH-full.h)/2:zoom===5?bird.y-(viewH-bird.h)/2:van.y-viewH/2}; } function gpsBuildLaneGraph(){ if(window.__VANCERTS_R36B52K_LANE_GRAPH)return window.__VANCERTS_R36B52K_LANE_GRAPH; const segments=[]; const edgePad=16; for(const r of roads){ if(r.w>r.h){ const minX=r.x+edgePad,maxX=r.x+r.w-edgePad; segments.push({axis:'x',fixed:r.y+r.h*.25,min:minX,max:maxX,dir:-1,dx:-1,dy:0}); segments.push({axis:'x',fixed:r.y+r.h*.75,min:minX,max:maxX,dir:1,dx:1,dy:0}); }else{ const minY=r.y+edgePad,maxY=r.y+r.h-edgePad; segments.push({axis:'y',fixed:r.x+r.w*.25,min:minY,max:maxY,dir:1,dx:0,dy:1}); segments.push({axis:'y',fixed:r.x+r.w*.75,min:minY,max:maxY,dir:-1,dx:0,dy:-1}); } } const nodes=[],adj=[],bySegment=[]; const addNode=(segmentIndex,x,y)=>{ const id=nodes.length; const s=segments[segmentIndex]; nodes.push({id,x,y,segmentIndex,dx:s.dx,dy:s.dy}); adj.push([]); return id; }; const addEdge=(a,b,turn=false)=>{ if(a===b)return; const A=nodes[a],B=nodes[b]; adj[a].push({to:b,cost:Math.hypot(B.x-A.x,B.y-A.y)+(turn?18:0),turn}); }; const spacing=68; segments.forEach((s,segmentIndex)=>{ const ids=[]; const start=s.dir>0?s.min:s.max,end=s.dir>0?s.max:s.min; const length=Math.abs(end-start); const count=Math.max(1,Math.ceil(length/spacing)); for(let i=0;i<=count;i++){ const q=i/count; const value=start+(end-start)*q; ids.push(addNode(segmentIndex,s.axis==='x'?value:s.fixed,s.axis==='y'?value:s.fixed)); } for(let i=0;i<ids.length-1;i++)addEdge(ids[i],ids[i+1],false); bySegment[segmentIndex]=ids; }); const nearestOnSegment=(segmentIndex,x,y)=>{ let best=-1,bestDistance=Infinity; for(const id of bySegment[segmentIndex]){ const n=nodes[id],d=Math.hypot(n.x-x,n.y-y); if(d<bestDistance){bestDistance=d;best=id} } return best; }; for(let hi=0;hi<segments.length;hi++){ const h=segments[hi]; if(h.axis!=='x')continue; for(let vi=0;vi<segments.length;vi++){ const v=segments[vi]; if(v.axis!=='y')continue; if(v.fixed<h.min||v.fixed>h.max||h.fixed<v.min||h.fixed>v.max)continue; const hNode=nearestOnSegment(hi,v.fixed,h.fixed); const vNode=nearestOnSegment(vi,v.fixed,h.fixed); if(hNode<0||vNode<0)continue; addEdge(hNode,vNode,true); addEdge(vNode,hNode,true); } } const graph={segments,nodes,adj}; window.__VANCERTS_R36B52K_LANE_GRAPH=graph; return graph; } function gpsRoutePath(t){ const graph=gpsBuildLaneGraph(); const heading=Number.isFinite(Number(van.angle))?Number(van.angle):0; const signature=[ t.id||t.label||'destination', Math.round(van.x/34), Math.round(van.y/34), Math.round(heading*8/Math.PI), Math.round(t.x/20), Math.round(t.y/20) ].join('|'); const cached=window.__VANCERTS_R36B52K_ROUTE_CACHE; if(cached&&cached.signature===signature)return cached.path; let start=-1,startScore=Infinity,end=-1,endScore=Infinity; const hx=Math.cos(heading),hy=Math.sin(heading); for(const n of graph.nodes){ const distanceFromVan=Math.hypot(n.x-van.x,n.y-van.y); const headingDot=n.dx*hx+n.dy*hy; const laneScore=distanceFromVan+(1-headingDot)*92; if(laneScore<startScore){startScore=laneScore;start=n.id} const distanceToTarget=Math.hypot(n.x-t.x,n.y-t.y); if(distanceToTarget<endScore){endScore=distanceToTarget;end=n.id} } if(start<0||end<0){ const fallback=[{x:van.x,y:van.y},{x:t.x,y:t.y}]; window.__VANCERTS_R36B52K_ROUTE_CACHE={signature,path:fallback}; return fallback; } const count=graph.nodes.length; const distance=new Float64Array(count); const previous=new Int32Array(count); const visited=new Uint8Array(count); for(let i=0;i<count;i++){distance[i]=Infinity;previous[i]=-1} distance[start]=0; for(let step=0;step<count;step++){ let u=-1,best=Infinity; for(let i=0;i<count;i++)if(!visited[i]&&distance[i]<best){best=distance[i];u=i} if(u<0||u===end)break; visited[u]=1; for(const edge of graph.adj[u]){ const next=distance[u]+edge.cost; if(next<distance[edge.to]){ distance[edge.to]=next; previous[edge.to]=u; } } } const ids=[]; if(Number.isFinite(distance[end])){ for(let at=end;at>=0;at=previous[at]){ ids.push(at); if(at===start)break; } ids.reverse(); } let path=ids.length?ids.map(id=>({x:graph.nodes[id].x,y:graph.nodes[id].y})):[]; if(path.length<2)path=[{x:van.x,y:van.y},{x:t.x,y:t.y}]; window.__VANCERTS_R36B52K_ROUTE_CACHE={signature,path}; return path; } function drawGpsLaneArrow(x,y,angle){ ctx.save(); ctx.translate(x,y); ctx.rotate(angle); ctx.fillStyle=RED; ctx.strokeStyle='rgba(23,21,20,.92)'; ctx.lineWidth=4; ctx.beginPath(); ctx.moveTo(12,0); ctx.lineTo(-8,-8); ctx.lineTo(-4,0); ctx.lineTo(-8,8); ctx.closePath(); ctx.stroke(); ctx.fill(); ctx.restore(); } function drawRoadArrows(){ const t=destination(); if(!t||typeof ctx==='undefined'||!Array.isArray(roads))return; const path=gpsRoutePath(t); const c=camera(); ctx.save(); ctx.scale(c.scale,c.scale); ctx.translate(-c.camX,-c.camY); ctx.globalAlpha=.98; ctx.lineCap='round'; ctx.lineJoin='round'; for(let i=0;i<path.length-1;i++){ const a=path[i],b=path[i+1]; const dx=b.x-a.x,dy=b.y-a.y,length=Math.hypot(dx,dy); if(length<2)continue; const angle=Math.atan2(dy,dx); const spacing=56; const first=Math.min(22,length*.5); let painted=false; for(let distanceAlong=first;distanceAlong<length;distanceAlong+=spacing){ const q=distanceAlong/length; drawGpsLaneArrow(a.x+dx*q,a.y+dy*q,angle); painted=true; } if(!painted)drawGpsLaneArrow((a.x+b.x)/2,(a.y+b.y)/2,angle); } const pulse=1+.14*Math.sin(performance.now()/180); ctx.strokeStyle=RED; ctx.fillStyle='rgba(230,74,56,.16)'; ctx.lineWidth=5; ctx.beginPath(); ctx.arc(t.x,t.y,25*pulse,0,Math.PI*2); ctx.fill(); ctx.stroke(); ctx.restore(); } function drawPhoneRoute(){ const t=destination(),canvas=$id('miniCanvas'),c=typeof miniCtx!=='undefined'?miniCtx:null;if(!canvas||!c)return; canvas.classList.toggle('r36b52hGpsActive',!!t);if(!t)return; const w=Number(canvas.width)||340,h=Number(canvas.height)||190,padX=11,padY=8,plotW=w-padX*2,plotH=h-padY*2; const map=(x,y)=>({x:padX+(x/world.w)*plotW,y:padY+(y/world.h)*plotH}); const a=map(van.x,van.y),b=map(t.x,t.y),routeAng=Math.atan2(b.y-a.y,b.x-a.x),vanAng=Number.isFinite(Number(van.angle))?Number(van.angle):0,sx=a.x+Math.cos(routeAng)*10,sy=a.y+Math.sin(routeAng)*10; c.save();c.lineCap='round';c.lineJoin='round';c.strokeStyle=INK;c.lineWidth=7;c.beginPath();c.moveTo(sx,sy);c.lineTo(b.x,b.y);c.stroke();c.strokeStyle=RED;c.lineWidth=4;c.beginPath();c.moveTo(sx,sy);c.lineTo(b.x,b.y);c.stroke(); c.translate(a.x,a.y);c.rotate(vanAng);c.fillStyle=RED;c.strokeStyle=PAPER;c.lineWidth=2;c.beginPath();c.moveTo(11,0);c.lineTo(-7,-6);c.lineTo(-3,0);c.lineTo(-7,6);c.closePath();c.fill();c.stroke();c.setTransform(1,0,0,1,0,0); const pulse=5+1.8*Math.sin(performance.now()/200);c.fillStyle=RED;c.strokeStyle=PAPER;c.lineWidth=2;c.beginPath();c.arc(b.x,b.y,pulse,0,Math.PI*2);c.fill();c.stroke();c.restore(); } function fitQueueTube(){ const shell=$id('rotaryRadio');if(!shell||!shell.classList.contains('vcQueueTubeDirect')||shell.classList.contains('hidden'))return; const vv=window.visualViewport,vw=Math.max(240,Math.floor(vv?.width||innerWidth)),vh=Math.max(320,Math.floor(vv?.height||innerHeight)),portrait=vh>=vw,margin=portrait?6:8; if(portrait)shell.style.setProperty('width',Math.max(228,vw-margin*2)+'px','important'); const r=shell.getBoundingClientRect(),maxX=Math.max(margin,vw-r.width-margin),maxY=Math.max(margin,vh-r.height-margin); let x=Number.parseFloat(shell.style.left),y=Number.parseFloat(shell.style.top);if(!Number.isFinite(x))x=r.left;if(!Number.isFinite(y))y=r.top; shell.style.setProperty('left',Math.min(maxX,Math.max(margin,x))+'px','important');shell.style.setProperty('top',Math.min(maxY,Math.max(margin,y))+'px','important');shell.style.setProperty('right','auto','important');shell.style.setProperty('bottom','auto','important');shell.style.setProperty('transform','none','important'); } if(previousHud)window.hud=hud=function(){const r=previousHud.apply(this,arguments);renderObjective();return r}; if(previousDraw)window.draw=draw=function(){const r=previousDraw.apply(this,arguments);try{drawRoadArrows()}catch(e){console.warn(BUILD+' road arrows',e)}return r}; if(previousMini)window.drawMini=drawMini=function(){const r=previousMini.apply(this,arguments);try{drawPhoneRoute()}catch(e){console.warn(BUILD+' phone route',e)}return r}; const existingOpen=window.openQueueTube; window.openQueueTube=function(){const r=typeof existingOpen==='function'?existingOpen.apply(this,arguments):window.queueTubePlayer?.open();requestAnimationFrame(()=>{fitQueueTube();setTimeout(fitQueueTube,80)});return r}; if(window.queueTubePlayer&&typeof window.queueTubePlayer.open==='function'){ const open=window.queueTubePlayer.open.bind(window.queueTubePlayer); window.queueTubePlayer.open=function(){const r=open();requestAnimationFrame(()=>{fitQueueTube();setTimeout(fitQueueTube,80)});return r}; } addEventListener('resize',()=>{requestAnimationFrame(()=>{fitQueueTube();renderObjective()})},{passive:true}); if(window.visualViewport){visualViewport.addEventListener('resize',()=>requestAnimationFrame(fitQueueTube),{passive:true});visualViewport.addEventListener('scroll',()=>requestAnimationFrame(fitQueueTube),{passive:true})} document.addEventListener('click',()=>setTimeout(renderObjective,0),true); document.addEventListener('pointerup',()=>setTimeout(renderObjective,0),true); setInterval(()=>{const m=deriveMission(),d=destination(m),sig=[careerId(),m.key||'',state?.activeJob?.phase||'',state?.activeJob?.id||'',state?.pendingOffer?.id||'',unpaid(),state?.shows||0,state?.completed?.length||0,d?.id||''].join('|');if(sig!==window.__R36B52H_LAST_STATE){window.__R36B52H_LAST_STATE=sig;renderObjective()}},400); setTimeout(()=>{renderObjective();fitQueueTube();try{if(typeof hud==='function')hud()}catch(_){}},350); window.__VANCERTS_R36B52H_MISSION=deriveMission; window.__VANCERTS_R36B52H_DESTINATION=destination; window.__VANCERTS_R36B52H_RENDER=renderObjective; console.info(BUILD,'single Nookia GPS line, live van heading, and lane-side road routing ready'); })(); </script> <script id="r36b52i-single-gps-heading-marker"> window.__VANCERTS_R36B52K__={build:'R36B52P',singlePhoneGps:true,vanHeadingTriangle:true}; </script> <style id="r36b52l-objective-phone-responsive-style"> /* R36B52L — concise next action, phone-only objective when Training is off, paused objective/now-playing ticker, and orientation-safe Nookia sizing. */ #objective.r36b52lConciseObjective{ width:clamp(270px,31vw,470px)!important; max-width:calc(100vw - 20px)!important; max-height:none!important; overflow:hidden!important; } #objective.r36b52lConciseObjective #objectiveTitle{ font-size:13px!important; line-height:1.08!important; } #objective.r36b52lConciseObjective #objectiveText{ display:block!important; margin-top:5px!important; font-size:11px!important; line-height:1.28!important; white-space:normal!important; } body.r36b52lTrainingOff #objective{ display:none!important; visibility:hidden!important; pointer-events:none!important; } /* The legacy ticker remains as a data source. R36B52L owns the visible ticker. */ #phone .phoneTickerStable{ display:block!important; position:absolute!important; left:4px!important; right:4px!important; bottom:4px!important; box-sizing:border-box!important; overflow:hidden!important; white-space:normal!important; animation:none!important; } #phone .phoneTickerStable > .tickerText{display:none!important} #phone .r36b52lPhoneCycle{ display:grid!important; grid-template-rows:12px minmax(0,1fr)!important; width:100%!important; height:100%!important; min-width:0!important; color:#10211e!important; background:#b8c994!important; overflow:hidden!important; } #phone .r36b52lCycleLabel{ display:block!important; overflow:hidden!important; color:#3f5444!important; font:1000 7px/11px monospace!important; letter-spacing:.08em!important; white-space:nowrap!important; } #phone .r36b52lCycleViewport{ display:block!important; width:100%!important; min-width:0!important; overflow:hidden!important; white-space:nowrap!important; } #phone .r36b52lCycleText{ display:inline-block!important; min-width:max-content!important; transform:translateX(0); will-change:transform; color:#10211e!important; font:1000 9px/15px monospace!important; white-space:nowrap!important; } /* Final orientation geometry. It applies only to touch/coarse devices. */ @media (max-width:760px),(pointer:coarse){ #objective.r36b52lConciseObjective{ left:8px!important; right:auto!important; bottom:max(8px,env(safe-area-inset-bottom))!important; width:min(440px,calc(100vw - 16px))!important; max-width:calc(100vw - 16px)!important; padding:7px!important; } #objective.r36b52lConciseObjective #objectiveTitle{font-size:10px!important} #objective.r36b52lConciseObjective #objectiveText{font-size:9px!important;line-height:1.22!important} #phone.vcStablePhone:not(.collapsed){ width:230px!important; height:auto!important; max-width:none!important; max-height:none!important; transform:scale(var(--r36b52l-phone-scale,1))!important; transform-origin:top left!important; } #phone.vcStablePhone:not(.collapsed) .phoneKeys{ grid-template-columns:repeat(4,minmax(0,1fr))!important; grid-template-rows:repeat(3,var(--r36b52l-app-height,45px))!important; gap:var(--r36b52l-app-gap,5px)!important; } #phone.vcStablePhone:not(.collapsed) .phoneKeys .phoneApp{ width:100%!important; height:var(--r36b52l-app-height,45px)!important; min-height:var(--r36b52l-app-height,45px)!important; max-height:var(--r36b52l-app-height,45px)!important; } } @media (pointer:coarse) and (orientation:portrait){ #phone.vcStablePhone:not(.collapsed){ --r36b52l-app-height:45px; --r36b52l-app-gap:5px; } #phone .phoneTickerStable{height:34px!important;line-height:15px!important} } @media (pointer:coarse) and (orientation:landscape){ #phone.vcStablePhone:not(.collapsed){ --r36b52l-app-height:31px; --r36b52l-app-gap:3px; } #phone .phoneTickerStable{height:22px!important;padding:1px 3px!important} #phone .r36b52lPhoneCycle{grid-template-rows:8px minmax(0,1fr)!important} #phone .r36b52lCycleLabel{font-size:6px!important;line-height:8px!important} #phone .r36b52lCycleText{font-size:7px!important;line-height:11px!important} } /* R36B52M — authoritative training visibility, mobile guide docking, and reset app. */ body.r36b52lTrainingOff #objective, body.r36b52lTrainingOff #objective.r36b52lConciseObjective{ display:none!important; visibility:hidden!important; opacity:0!important; pointer-events:none!important; } #phoneFullscreenApp.resetGameApp{ background:#e64a38!important; color:#fff!important; border-color:#fff8e5!important; } #phoneFullscreenApp.resetGameApp span{color:#fff!important} @media (max-width:760px),(pointer:coarse){ body:not(.r36b52lTrainingOff) #objective.r36b52lConciseObjective{ box-sizing:border-box!important; left:calc(var(--safe-left,0px) + 110px)!important; right:calc(var(--safe-right,0px) + 55px)!important; bottom:calc(var(--safe-bottom,0px) + 4px)!important; width:auto!important; max-width:none!important; max-height:72px!important; overflow:auto!important; margin:0!important; z-index:57!important; } } @media (pointer:coarse) and (orientation:landscape){ body:not(.r36b52lTrainingOff) #objective.r36b52lConciseObjective{ left:calc(var(--safe-left,0px) + 154px)!important; right:calc(var(--safe-right,0px) + 78px)!important; bottom:calc(var(--safe-bottom,0px) + 4px)!important; max-height:68px!important; } } </style> <script id="r36b52l-objective-phone-responsive-runtime"> (function(){ 'use strict'; const BUILD='R36B52M'; const $=id=>document.getElementById(id); let rendering=false; let lastMissionSignature=''; let cycleIndex=0; let cycleToken=0; let cycleTimer=0; let scrollFrame=0; function trainingOff(){return window.state?.training?.enabled===false} function mission(){ try{ if(typeof window.__VANCERTS_R36B52H_MISSION==='function')return window.__VANCERTS_R36B52H_MISSION(); if(typeof window.currentTrainingMission==='function')return window.currentTrainingMission(); }catch(_){ } return null; } function destination(m){ try{return typeof window.__VANCERTS_R36B52H_DESTINATION==='function'?window.__VANCERTS_R36B52H_DESTINATION(m):null}catch(_){return null} } function owed(){ try{return typeof window.unpaidTotal==='function'?Math.max(0,Number(window.unpaidTotal())||0):0}catch(_){return 0} } function cleanLabel(value){return String(value||'the next destination').replace(/^home-/i,'').replace(/\s+/g,' ').trim()} function firstActionSentence(value){ const cleaned=String(value||'') .replace(/\s*GPS\s*:[\s\S]*$/i,'') .replace(/Follow the red road arrows[^.]*\.?/gi,'') .replace(/Follow the route[^.]*\.?/gi,'') .replace(/\s+/g,' ').trim(); const sentences=cleaned.match(/[^.!?]+[.!?]?/g)||[]; const action=/\b(drive|open|enter|tap|press|collect|load|return|buy|choose|complete|interact|stop|use|start|name|purchase|play|deliver|review|build|unload|place|cable|secure|hold|turn|move|visit|confirm)\b/i; const selected=sentences.find(s=>action.test(s))||sentences[0]||'Continue to the next marked step.'; return selected.trim().replace(/[,:;]\s*(then|and then).*$/i,'.').replace(/\s*[.!?]*$/,'.'); } function nextAction(m,d){ if(!m)return{title:'NEXT STEP',text:'Continue to the next marked objective.'}; const stateRef=window.state||{}; const role=String(m.title||'NEXT STEP').split('•')[0].trim(); if(m.mode==='controls')return{title:'NEXT STEP',text:firstActionSentence(m.text)}; if(d){ const label=cleanLabel(d.label).toUpperCase(); return{title:`NEXT • ${label}`,text:`Drive to ${cleanLabel(d.label)}.`}; } if(stateRef.pendingOffer)return{title:'NEXT • OPEN EMAIL',text:'Open EMAIL and collect the deposit.'}; if(stateRef.activeJob?.phase==='pickup')return{title:'NEXT • LOAD THE GEAR',text:'Interact at Gig Bag ATX and load the approved gear.'}; if(stateRef.activeJob)return{title:'NEXT • START THE SHOW',text:'Stop in the marked loading zone and interact.'}; if(owed()>0)return{title:'NEXT • FINAL PAYMENT',text:'Open CALL and collect the remaining balance.'}; if(stateRef.passengerRide)return{title:'NEXT • COMPLETE DELIVERY',text:'Stop in the marked loading area and interact.'}; if(m.targetId||m.homeId)return{title:`NEXT • ${role||'INTERACT'}`,text:'Stop in the marked interaction area and interact.'}; const actionLabel=String(m.actionLabel||'').replace(/^SHOW\s+/i,'').trim(); if(actionLabel&&!/EXACT STEP|DESTINATION/i.test(actionLabel))return{title:`NEXT • ${actionLabel}`,text:firstActionSentence(m.text)}; return{title:'NEXT STEP',text:firstActionSentence(m.text)}; } function currentObjective(){const m=mission(),d=destination(m),next=nextAction(m,d);return{m,d,next,signature:[m?.key||'',d?.id||'',next.title,next.text,trainingOff()].join('|')}} function renderConcise(){ if(rendering||!$('splash')?.classList.contains('hidden'))return; rendering=true; try{ const info=currentObjective(); const body=document.body; const off=trainingOff(); body.classList.toggle('r36b52lTrainingOff',off); const box=$('objective'),title=$('objectiveTitle'),text=$('objectiveText'); if(box){ box.classList.add('r36b52lConciseObjective'); if(off){ box.hidden=true; box.setAttribute('aria-hidden','true'); box.style.setProperty('display','none','important'); }else{ box.hidden=false; box.setAttribute('aria-hidden','false'); box.style.removeProperty('display'); box.style.removeProperty('visibility'); box.style.removeProperty('opacity'); } } if(title&&title.textContent!==info.next.title)title.textContent=info.next.title; if(text&&text.textContent!==info.next.text)text.textContent=info.next.text; if(info.signature!==lastMissionSignature){ lastMissionSignature=info.signature; cycleIndex=0; scheduleCycle(30); } }finally{rendering=false} } function nowPlaying(){ const artist=String($('qtArtist')?.textContent||'').trim(); const title=String($('qtTitle')?.textContent||'').trim(); if(artist&&title&&!/loading|unavailable/i.test(`${artist} ${title}`))return`${artist} — ${title}`; try{ const raw=String(typeof window.phoneNowPlayingStatus==='function'?window.phoneNowPlayingStatus():'').trim(); if(raw&&!/COMMUNITY RADIO READY$/i.test(raw))return raw.replace(/^NOW PLAYING\s*[•:-]?\s*/i,''); }catch(_){ } return'QueueTube ready'; } function installCycle(){ const host=document.querySelector('#phone .phoneTickerStable'); if(!host)return null; let cycle=host.querySelector('.r36b52lPhoneCycle'); if(!cycle){ cycle=document.createElement('div'); cycle.className='r36b52lPhoneCycle'; cycle.innerHTML='<b class="r36b52lCycleLabel"></b><div class="r36b52lCycleViewport"><span class="r36b52lCycleText"></span></div>'; host.appendChild(cycle); } return{host,cycle,label:cycle.querySelector('.r36b52lCycleLabel'),viewport:cycle.querySelector('.r36b52lCycleViewport'),text:cycle.querySelector('.r36b52lCycleText')}; } function cancelMotion(){ cycleToken++; clearTimeout(cycleTimer); cancelAnimationFrame(scrollFrame); } function animateScroll(ui,token){ if(!ui||token!==cycleToken)return; ui.text.style.transform='translateX(0px)'; const distance=Math.max(0,ui.text.scrollWidth-ui.viewport.clientWidth); const holdStart=1700,travel=distance?Math.min(5200,Math.max(2500,distance*22)):0,holdEnd=1700; if(!distance){cycleTimer=setTimeout(nextCycle,4600);return} cycleTimer=setTimeout(()=>{ const start=performance.now(); const move=now=>{ if(token!==cycleToken)return; const p=Math.min(1,(now-start)/travel); const eased=p<.5?2*p*p:1-Math.pow(-2*p+2,2)/2; ui.text.style.transform=`translateX(${-distance*eased}px)`; if(p<1)scrollFrame=requestAnimationFrame(move); else cycleTimer=setTimeout(nextCycle,holdEnd); }; scrollFrame=requestAnimationFrame(move); },holdStart); } function nextCycle(){cycleIndex++;showCycle()} function scheduleCycle(delay=0){cancelMotion();cycleTimer=setTimeout(showCycle,delay)} function showCycle(){ const ui=installCycle();if(!ui)return; cancelMotion(); const token=cycleToken; const info=currentObjective(); const items=trainingOff() ?[{label:'OBJECTIVE',text:`${info.next.title.replace(/^NEXT\s*[•:-]?\s*/i,'')}: ${info.next.text}`},{label:'NOW PLAYING',text:nowPlaying()}] :[{label:'NOW PLAYING',text:nowPlaying()}]; const item=items[Math.abs(cycleIndex)%items.length]; ui.label.textContent=item.label; ui.text.textContent=item.text; ui.host.setAttribute('aria-label',`${item.label}: ${item.text}`); requestAnimationFrame(()=>animateScroll(ui,token)); } function fitPhone(){ const phone=$('phone'); if(!phone||phone.classList.contains('collapsed')||!matchMedia('(pointer:coarse)').matches)return; const vv=window.visualViewport; const vw=Math.max(240,Number(vv?.width)||innerWidth),vh=Math.max(260,Number(vv?.height)||innerHeight); const portrait=vh>=vw; phone.style.setProperty('--r36b52l-app-height',portrait?'45px':'31px'); phone.style.setProperty('--r36b52l-app-gap',portrait?'5px':'3px'); phone.style.setProperty('--r36b52l-phone-scale','1'); const baseW=Math.max(1,phone.offsetWidth||230),baseH=Math.max(1,phone.offsetHeight||430); const availableW=Math.max(170,vw-12),availableH=Math.max(190,vh-12); const scale=Math.min(1,availableW/baseW,availableH/baseH); phone.style.setProperty('--r36b52l-phone-scale',String(Math.max(.55,scale))); requestAnimationFrame(()=>{ const rect=phone.getBoundingClientRect(),margin=6; let x=rect.left,y=rect.top; if(rect.right>vw-margin)x-=rect.right-(vw-margin); if(rect.bottom>vh-margin)y-=rect.bottom-(vh-margin); x=Math.max(margin,x);y=Math.max(margin,y); phone.style.setProperty('left',`${x}px`,'important'); phone.style.setProperty('top',`${y}px`,'important'); phone.style.setProperty('right','auto','important'); phone.style.setProperty('bottom','auto','important'); }); } function installResetGameApp(){ const button=$('phoneFullscreenApp'); if(!button)return; button.removeAttribute('onclick'); button.classList.remove('active'); button.classList.add('resetGameApp'); button.innerHTML='<span>×</span>RESET GAME'; button.setAttribute('aria-label','Reset game'); button.setAttribute('title','Reset game'); button.onclick=event=>{ event.preventDefault(); event.stopPropagation(); if(typeof window.openResetPrompt==='function')window.openResetPrompt(); else if(window.confirm('Are you sure you want to reset the game? This erases this save and restarts the story.')){ if(typeof window.resetGame==='function')window.resetGame(); } }; } const priorHud=typeof window.hud==='function'?window.hud:null; if(priorHud)window.hud=hud=function(){const result=priorHud.apply(this,arguments);renderConcise();return result}; const objective=$('objective'); if(objective){ const observer=new MutationObserver(()=>{if(!rendering)queueMicrotask(renderConcise)}); observer.observe(objective,{subtree:true,childList:true,characterData:true}); } const phone=$('phone'); if(phone){ const observer=new MutationObserver(()=>{renderConcise();if(trainingOff())scheduleCycle(20)}); observer.observe(phone,{attributes:true,attributeFilter:['class']}); } document.addEventListener('click',()=>setTimeout(()=>{installResetGameApp();renderConcise();showCycle();fitPhone()},1),true); document.addEventListener('pointerup',()=>setTimeout(()=>{renderConcise();fitPhone()},1),true); addEventListener('resize',()=>requestAnimationFrame(()=>{installResetGameApp();fitPhone();renderConcise();showCycle()}),{passive:true}); addEventListener('orientationchange',()=>setTimeout(()=>{installResetGameApp();fitPhone();renderConcise();showCycle()},180),{passive:true}); if(window.visualViewport)visualViewport.addEventListener('resize',()=>requestAnimationFrame(()=>{fitPhone();showCycle()}),{passive:true}); setInterval(()=>{ renderConcise(); const song=`${$('qtArtist')?.textContent||''}|${$('qtTitle')?.textContent||''}`; if(song!==window.__R36B52L_LAST_SONG){window.__R36B52L_LAST_SONG=song;scheduleCycle(20)} },700); setTimeout(()=>{installResetGameApp();renderConcise();installCycle();showCycle();fitPhone()},350); window.__VANCERTS_R36B52L_RENDER=renderConcise; window.__VANCERTS_R36B52L_FIT_PHONE=fitPhone; window.__VANCERTS_R36B52M__={build:BUILD,trainingOffHidesWorldObjective:true,phoneObjectiveWhenOpen:true,centeredMobileGuide:true,resetGameAppWithConfirmation:true,responsivePhoneApps:true}; console.info(BUILD,'training-off phone objective, centered mobile guide, reset app, and responsive Nookia ready'); })(); </script> <style id="r36b52o-stable-collapsed-phone"> /* R36B52O — CSS-only collapsed Nookia alignment. No observers, timers, or runtime hooks. */ #phone.phone.collapsed, html.mobileFullscreen #phone.phone.collapsed{ width:68px!important; height:54px!important; min-width:68px!important; min-height:54px!important; max-width:68px!important; max-height:54px!important; padding:5px!important; border-radius:14px!important; box-sizing:border-box!important; overflow:visible!important; transform:none!important; } #phone.phone.collapsed > .phoneTop, html.mobileFullscreen #phone.phone.collapsed > .phoneTop{ position:relative!important; display:grid!important; grid-template-columns:minmax(0,1fr) 29px!important; align-items:center!important; justify-content:stretch!important; gap:3px!important; width:100%!important; height:100%!important; min-height:0!important; margin:0!important; padding:0!important; overflow:hidden!important; box-sizing:border-box!important; } #phone.phone.collapsed .phoneZoomDial, #phone.phone.collapsed .phoneZoomDialLabel, #phone.phone.collapsed .zoomChoices, #phone.phone.collapsed .zoomHelp{ display:none!important; visibility:hidden!important; pointer-events:none!important; } #phone.phone.collapsed .phoneBrand{ display:grid!important; place-items:center!important; align-self:stretch!important; justify-self:stretch!important; width:100%!important; min-width:0!important; height:100%!important; min-height:0!important; margin:0!important; padding:0!important; overflow:hidden!important; font-size:0!important; line-height:1!important; box-sizing:border-box!important; } #phone.phone.collapsed .phoneBrand:after{ content:'▣'!important; display:block!important; margin:0!important; color:#e7f4f5!important; font:1000 21px/1 system-ui!important; transform:none!important; } #phone.phone.collapsed .phoneCollapse, html.mobileFullscreen #phone.phone.collapsed .phoneCollapse{ position:static!important; inset:auto!important; align-self:stretch!important; justify-self:end!important; width:29px!important; height:100%!important; min-width:29px!important; min-height:0!important; max-width:29px!important; max-height:none!important; margin:0!important; padding:0!important; border-width:2px!important; border-radius:7px!important; box-sizing:border-box!important; line-height:1!important; font-size:16px!important; transform:none!important; pointer-events:auto!important; touch-action:manipulation!important; } @media(max-width:760px),(pointer:coarse){ #phone.phone.collapsed, html.mobileFullscreen #phone.phone.collapsed{ width:72px!important; height:56px!important; min-width:72px!important; min-height:56px!important; max-width:72px!important; max-height:56px!important; padding:5px!important; } #phone.phone.collapsed > .phoneTop, html.mobileFullscreen #phone.phone.collapsed > .phoneTop{ grid-template-columns:minmax(0,1fr) 31px!important; gap:4px!important; } #phone.phone.collapsed .phoneCollapse, html.mobileFullscreen #phone.phone.collapsed .phoneCollapse{ width:31px!important; min-width:31px!important; max-width:31px!important; font-size:17px!important; } #phone.phone.collapsed .phoneBrand:after{font-size:22px!important} } </style>