1// BEGIN QR GENERATOR 2var PortalQR=(()=>{var g=(n,t)=>()=>{try{return t||n((t={exports:{}}).exports,t),t.exports}catch(e){throw t=0,e}};var _t=g((Sn,Lt)=>{Lt.exports=function(){return typeof Promise=="function"&&Promise.prototype&&Promise.prototype.then}});var I=g(P=>{var st,Le=[0,26,44,70,100,134,172,196,242,292,346,404,466,532,581,655,733,815,901,991,1085,1156,1258,1364,1474,1588,1706,1828,1921,2051,2185,2323,2465,2611,2761,2876,3034,3196,3362,3532,3706];P.getSymbolSize=function(t){if(!t)throw new Error('"version" cannot be null or undefined');if(t<1||t>40)throw new Error('"version" should be in range from 1 to 40');return t*4+17};P.getSymbolTotalCodewords=function(t){return Le[t]};P.getBCHDigit=function(n){let t=0;for(;n!==0;)t++,n>>>=1;return t};P.setToSJISFunction=function(t){if(typeof t!="function")throw new Error('"toSJISFunc" is not a valid function.');st=t};P.isKanjiModeEnabled=function(){return typeof st<"u"};P.toSJIS=function(t){return st(t)}});var j=g(m=>{m.L={bit:1};m.M={bit:0};m.Q={bit:3};m.H={bit:2};function _e(n){if(typeof n!="string")throw new Error("Param is not a string");switch(n.toLowerCase()){case"l":case"low":return m.L;case"m":case"medium":return m.M;case"q":case"quartile":return m.Q;case"h":case"high":return m.H;default:throw new Error("Unknown EC Level: "+n)}}m.isValid=function(t){return t&&typeof t.bit<"u"&&t.bit>=0&&t.bit<4};m.from=function(t,e){if(m.isValid(t))return t;try{return _e(t)}catch{return e}}});var qt=g((Rn,Ut)=>{function xt(){this.buffer=[],this.length=0}xt.prototype={get:function(n){let t=Math.floor(n/8);return(this.buffer[t]>>>7-n%8&1)===1},put:function(n,t){for(let e=0;e<t;e++)this.putBit((n>>>t-e-1&1)===1)},getLengthInBits:function(){return this.length},putBit:function(n){let t=Math.floor(this.length/8);this.buffer.length<=t&&this.buffer.push(0),n&&(this.buffer[t]|=128>>>this.length%8),this.length++}};Ut.exports=xt});var Ft=g((Ln,Dt)=>{function k(n){if(!n||n<1)throw new Error("BitMatrix size must be defined and greater than 0");this.size=n,this.data=new Uint8Array(n*n),this.reservedBit=new Uint8Array(n*n)}k.prototype.set=function(n,t,e,r){let o=n*this.size+t;this.data[o]=e,r&&(this.reservedBit[o]=!0)};k.prototype.get=function(n,t){return this.data[n*this.size+t]};k.prototype.xor=function(n,t,e){this.data[n*this.size+t]^=e};k.prototype.isReserved=function(n,t){return this.reservedBit[n*this.size+t]};Dt.exports=k});var kt=g(G=>{var xe=I().getSymbolSize;G.getRowColCoords=function(t){if(t===1)return[];let e=Math.floor(t/7)+2,r=xe(t),o=r===145?26:Math.ceil((r-13)/(2*e-2))*2,i=[r-7];for(let s=1;s<e-1;s++)i[s]=i[s-1]-o;return i.push(6),i.reverse()};G.getPositions=function(t){let e=[],r=G.getRowColCoords(t),o=r.length;for(let i=0;i<o;i++)for(let s=0;s<o;s++)i===0&&s===0||i===0&&s===o-1||i===o-1&&s===0||e.push([r[i],r[s]]);return e}});var Ht=g(Vt=>{var Ue=I().getSymbolSize,zt=7;Vt.getPositions=function(t){let e=Ue(t);return[[0,0],[e-zt,0],[0,e-zt]]}});var Kt=g(d=>{d.Patterns={PATTERN000:0,PATTERN001:1,PATTERN010:2,PATTERN011:3,PATTERN100:4,PATTERN101:5,PATTERN110:6,PATTERN111:7};var b={N1:3,N2:3,N3:40,N4:10};d.isValid=function(t){return t!=null&&t!==""&&!isNaN(t)&&t>=0&&t<=7};d.from=function(t){return d.isValid(t)?parseInt(t,10):void 0};d.getPenaltyN1=function(t){let e=t.size,r=0,o=0,i=0,s=null,u=null;for(let c=0;c<e;c++){o=i=0,s=u=null;for(let l=0;l<e;l++){let a=t.get(c,l);a===s?o++:(o>=5&&(r+=b.N1+(o-5)),s=a,o=1),a=t.get(l,c),a===u?i++:(i>=5&&(r+=b.N1+(i-5)),u=a,i=1)}o>=5&&(r+=b.N1+(o-5)),i>=5&&(r+=b.N1+(i-5))}return r};d.getPenaltyN2=function(t){let e=t.size,r=0;for(let o=0;o<e-1;o++)for(let i=0;i<e-1;i++){let s=t.get(o,i)+t.get(o,i+1)+t.get(o+1,i)+t.get(o+1,i+1);(s===4||s===0)&&r++}return r*b.N2};d.getPenaltyN3=function(t){let e=t.size,r=0,o=0,i=0;for(let s=0;s<e;s++){o=i=0;for(let u=0;u<e;u++)o=o<<1&2047|t.get(s,u),u>=10&&(o===1488||o===93)&&r++,i=i<<1&2047|t.get(u,s),u>=10&&(i===1488||i===93)&&r++}return r*b.N3};d.getPenaltyN4=function(t){let e=0,r=t.data.length;for(let i=0;i<r;i++)e+=t.data[i];return Math.abs(Math.ceil(e*100/r/5)-10)*b.N4};function qe(n,t,e){switch(n){case d.Patterns.PATTERN000:return(t+e)%2===0;case d.Patterns.PATTERN001:return t%2===0;case d.Patterns.PATTERN010:return e%3===0;case d.Patterns.PATTERN011:return(t+e)%3===0;case d.Patterns.PATTERN100:return(Math.floor(t/2)+Math.floor(e/3))%2===0;case d.Patterns.PATTERN101:return t*e%2+t*e%3===0;case d.Patterns.PATTERN110:return(t*e%2+t*e%3)%2===0;case d.Patterns.PATTERN111:return(t*e%3+(t+e)%2)%2===0;default:throw new Error("bad maskPattern:"+n)}}d.applyMask=function(t,e){let r=e.size;
2for(let o=0;o<r;o++)for(let i=0;i<r;i++)e.isReserved(i,o)||e.xor(i,o,qe(t,i,o))};d.getBestMask=function(t,e){let r=Object.keys(d.Patterns).length,o=0,i=1/0;for(let s=0;s<r;s++){e(s),d.applyMask(s,t);let u=d.getPenaltyN1(t)+d.getPenaltyN2(t)+d.getPenaltyN3(t)+d.getPenaltyN4(t);d.applyMask(s,t),u<i&&(i=u,o=s)}return o}});var ct=g(ut=>{var N=j(),Q=[1,1,1,1,1,1,1,1,1,1,2,2,1,2,2,4,1,2,4,4,2,4,4,4,2,4,6,5,2,4,6,6,2,5,8,8,4,5,8,8,4,5,8,11,4,8,10,11,4,9,12,16,4,9,16,16,6,10,12,18,6,10,17,16,6,11,16,19,6,13,18,21,7,14,21,25,8,16,20,25,8,17,23,25,9,17,23,34,9,18,25,30,10,20,27,32,12,21,29,35,12,23,34,37,12,25,34,40,13,26,35,42,14,28,38,45,15,29,40,48,16,31,43,51,17,33,45,54,18,35,48,57,19,37,51,60,19,38,53,63,20,40,56,66,21,43,59,70,22,45,62,74,24,47,65,77,25,49,68,81],$=[7,10,13,17,10,16,22,28,15,26,36,44,20,36,52,64,26,48,72,88,36,64,96,112,40,72,108,130,48,88,132,156,60,110,160,192,72,130,192,224,80,150,224,264,96,176,260,308,104,198,288,352,120,216,320,384,132,240,360,432,144,280,408,480,168,308,448,532,180,338,504,588,196,364,546,650,224,416,600,700,224,442,644,750,252,476,690,816,270,504,750,900,300,560,810,960,312,588,870,1050,336,644,952,1110,360,700,1020,1200,390,728,1050,1260,420,784,1140,1350,450,812,1200,1440,480,868,1290,1530,510,924,1350,1620,540,980,1440,1710,570,1036,1530,1800,570,1064,1590,1890,600,1120,1680,1980,630,1204,1770,2100,660,1260,1860,2220,720,1316,1950,2310,750,1372,2040,2430];ut.getBlocksCount=function(t,e){switch(e){case N.L:return Q[(t-1)*4+0];case N.M:return Q[(t-1)*4+1];case N.Q:return Q[(t-1)*4+2];case N.H:return Q[(t-1)*4+3];default:return}};ut.getTotalCodewordsCount=function(t,e){switch(e){case N.L:return $[(t-1)*4+0];case N.M:return $[(t-1)*4+1];case N.Q:return $[(t-1)*4+2];case N.H:return $[(t-1)*4+3];default:return}}});var Jt=g(Z=>{var z=new Uint8Array(512),W=new Uint8Array(256);(function(){let t=1;for(let e=0;e<255;e++)z[e]=t,W[t]=e,t<<=1,t&256&&(t^=285);for(let e=255;e<512;e++)z[e]=z[e-255]})();Z.log=function(t){if(t<1)throw new Error("log("+t+")");return W[t]};Z.exp=function(t){return z[t]};Z.mul=function(t,e){return t===0||e===0?0:z[W[t]+W[e]]}});var Yt=g(V=>{var lt=Jt();V.mul=function(t,e){let r=new Uint8Array(t.length+e.length-1);for(let o=0;o<t.length;o++)for(let i=0;i<e.length;i++)r[o+i]^=lt.mul(t[o],e[i]);return r};V.mod=function(t,e){let r=new Uint8Array(t);for(;r.length-e.length>=0;){let o=r[0];for(let s=0;s<e.length;s++)r[s]^=lt.mul(e[s],o);let i=0;for(;i<r.length&&r[i]===0;)i++;r=r.slice(i)}return r};V.generateECPolynomial=function(t){let e=new Uint8Array([1]);for(let r=0;r<t;r++)e=V.mul(e,new Uint8Array([1,lt.exp(r)]));return e}});var Gt=g((kn,jt)=>{var Ot=Yt();function at(n){this.genPoly=void 0,this.degree=n,this.degree&&this.initialize(this.degree)}at.prototype.initialize=function(t){this.degree=t,this.genPoly=Ot.generateECPolynomial(this.degree)};at.prototype.encode=function(t){if(!this.genPoly)throw new Error("Encoder not initialized");let e=new Uint8Array(t.length+this.degree);e.set(t);let r=Ot.mod(e,this.genPoly),o=this.degree-r.length;if(o>0){let i=new Uint8Array(this.degree);return i.set(r,o),i}return r};jt.exports=at});var ft=g(Qt=>{Qt.isValid=function(t){return!isNaN(t)&&t>=1&&t<=40}});var gt=g(B=>{var $t="[0-9]+",De="[A-Z $%*+\\-./:]+",H="(?:[u3000-u303F]|[u3040-u309F]|[u30A0-u30FF]|[uFF00-uFFEF]|[u4E00-u9FAF]|[u2605-u2606]|[u2190-u2195]|u203B|[u2010u2015u2018u2019u2025u2026u201Cu201Du2225u2260]|[u0391-u0451]|[u00A7u00A8u00B1u00B4u00D7u00F7])+";H=H.replace(/u/g,"\\u");var Fe="(?:(?![A-Z0-9 $%*+\\-./:]|"+H+`)(?:.|[\r 3]))+`;B.KANJI=new RegExp(H,"g");B.BYTE_KANJI=new RegExp("[^A-Z0-9 $%*+\\-./:]+","g");B.BYTE=new RegExp(Fe,"g");B.NUMERIC=new RegExp($t,"g");B.ALPHANUMERIC=new RegExp(De,"g");var ke=new RegExp("^"+H+"$"),ze=new RegExp("^"+$t+"$"),Ve=new RegExp("^[A-Z0-9 $%*+\\-./:]+$");B.testKanji=function(t){return ke.test(t)};B.testNumeric=function(t){return ze.test(t)};B.testAlphanumeric=function(t){return Ve.test(t)}});var M=g(p=>{var He=ft(),dt=gt();p.NUMERIC={id:"Numeric",bit:1,ccBits:[10,12,14]};p.ALPHANUMERIC={id:"Alphanumeric",bit:2,ccBits:[9,11,13]};p.BYTE={id:"Byte",bit:4,ccBits:[8,16,16]};p.KANJI={id:"Kanji",bit:8,ccBits:[8,10,12]};p.MIXED={bit:-1};p.getCharCountIndicator=function(t,e){if(!t.ccBits)throw new Error("Invalid mode: "+t);if(!He.isValid(e))throw new Error("Invalid version: "+e);return e>=1&&e<10?t.ccBits[0]:e<27?t.ccBits[1]:t.ccBits[2]};p.getBestModeForData=function(t){return dt.testNumeric(t)?p.NUMERIC:dt.testAlphanumeric(t)?p.ALPHANUMERIC:dt.testKanji(t)?p.KANJI:p.BYTE};p.toString=function(t){if(t&&t.id)return t.id;throw new Error("Invalid mode")};p.isValid=function(t){return t&&t.bit&&t.ccBits};
3function Ke(n){if(typeof n!="string")throw new Error("Param is not a string");switch(n.toLowerCase()){case"numeric":return p.NUMERIC;case"alphanumeric":return p.ALPHANUMERIC;case"kanji":return p.KANJI;case"byte":return p.BYTE;default:throw new Error("Unknown mode: "+n)}}p.from=function(t,e){if(p.isValid(t))return t;try{return Ke(t)}catch{return e}}});var te=g(R=>{var X=I(),Je=ct(),Wt=j(),S=M(),ht=ft(),Xt=7973,Zt=X.getBCHDigit(Xt);function Ye(n,t,e){for(let r=1;r<=40;r++)if(t<=R.getCapacity(r,e,n))return r}function vt(n,t){return S.getCharCountIndicator(n,t)+4}function Oe(n,t){let e=0;return n.forEach(function(r){let o=vt(r.mode,t);e+=o+r.getBitsLength()}),e}function je(n,t){for(let e=1;e<=40;e++)if(Oe(n,e)<=R.getCapacity(e,t,S.MIXED))return e}R.from=function(t,e){return ht.isValid(t)?parseInt(t,10):e};R.getCapacity=function(t,e,r){if(!ht.isValid(t))throw new Error("Invalid QR Code version");typeof r>"u"&&(r=S.BYTE);let o=X.getSymbolTotalCodewords(t),i=Je.getTotalCodewordsCount(t,e),s=(o-i)*8;if(r===S.MIXED)return s;let u=s-vt(r,t);switch(r){case S.NUMERIC:return Math.floor(u/10*3);case S.ALPHANUMERIC:return Math.floor(u/11*2);case S.KANJI:return Math.floor(u/13);case S.BYTE:default:return Math.floor(u/8)}};R.getBestVersionForData=function(t,e){let r,o=Wt.from(e,Wt.M);if(Array.isArray(t)){if(t.length>1)return je(t,o);if(t.length===0)return 1;r=t[0]}else r=t;return Ye(r.mode,r.getLength(),o)};R.getEncodedBits=function(t){if(!ht.isValid(t)||t<7)throw new Error("Invalid QR Code version");let e=t<<12;for(;X.getBCHDigit(e)-Zt>=0;)e^=Xt<<X.getBCHDigit(e)-Zt;return t<<12|e}});var oe=g(re=>{var pt=I(),ne=1335,Ge=21522,ee=pt.getBCHDigit(ne);re.getEncodedBits=function(t,e){let r=t.bit<<3|e,o=r<<10;for(;pt.getBCHDigit(o)-ee>=0;)o^=ne<<pt.getBCHDigit(o)-ee;return(r<<10|o)^Ge}});var se=g((Yn,ie)=>{var Qe=M();function x(n){this.mode=Qe.NUMERIC,this.data=n.toString()}x.getBitsLength=function(t){return 10*Math.floor(t/3)+(t%3?t%3*3+1:0)};x.prototype.getLength=function(){return this.data.length};x.prototype.getBitsLength=function(){return x.getBitsLength(this.data.length)};x.prototype.write=function(t){let e,r,o;for(e=0;e+3<=this.data.length;e+=3)r=this.data.substr(e,3),o=parseInt(r,10),t.put(o,10);let i=this.data.length-e;i>0&&(r=this.data.substr(e),o=parseInt(r,10),t.put(o,i*3+1))};ie.exports=x});var ce=g((On,ue)=>{var $e=M(),wt=["0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"," ","$","%","*","+","-",".","/",":"];function U(n){this.mode=$e.ALPHANUMERIC,this.data=n}U.getBitsLength=function(t){return 11*Math.floor(t/2)+6*(t%2)};U.prototype.getLength=function(){return this.data.length};U.prototype.getBitsLength=function(){return U.getBitsLength(this.data.length)};U.prototype.write=function(t){let e;for(e=0;e+2<=this.data.length;e+=2){let r=wt.indexOf(this.data[e])*45;r+=wt.indexOf(this.data[e+1]),t.put(r,11)}this.data.length%2&&t.put(wt.indexOf(this.data[e]),6)};ue.exports=U});var ae=g((jn,le)=>{var We=M();function q(n){this.mode=We.BYTE,typeof n=="string"?this.data=new TextEncoder().encode(n):this.data=new Uint8Array(n)}q.getBitsLength=function(t){return t*8};q.prototype.getLength=function(){return this.data.length};q.prototype.getBitsLength=function(){return q.getBitsLength(this.data.length)};q.prototype.write=function(n){for(let t=0,e=this.data.length;t<e;t++)n.put(this.data[t],8)};le.exports=q});var ge=g((Gn,fe)=>{var Ze=M(),Xe=I();function D(n){this.mode=Ze.KANJI,this.data=n}D.getBitsLength=function(t){return t*13};D.prototype.getLength=function(){return this.data.length};D.prototype.getBitsLength=function(){return D.getBitsLength(this.data.length)};D.prototype.write=function(n){let t;for(t=0;t<this.data.length;t++){let e=Xe.toSJIS(this.data[t]);if(e>=33088&&e<=40956)e-=33088;else if(e>=57408&&e<=60351)e-=49472;else throw new Error("Invalid SJIS character: "+this.data[t]+` 4Make sure your charset is UTF-8`);e=(e>>>8&255)*192+(e&255),n.put(e,13)}};fe.exports=D});var de=g((Qn,mt)=>{"use strict";var K={single_source_shortest_paths:function(n,t,e){var r={},o={};o[t]=0;var i=K.PriorityQueue.make();i.push(t,0);for(var s,u,c,l,a,w,h,y,A;!i.empty();){s=i.pop(),u=s.value,l=s.cost,a=n[u]||{};for(c in a)a.hasOwnProperty(c)&&(w=a[c],h=l+w,y=o[c],A=typeof o[c]>"u",(A||y>h)&&(o[c]=h,i.push(c,h),r[c]=u))}if(typeof e<"u"&&typeof o[e]>"u"){var T=["Could not find a path from ",t," to ",e,"."].join("");throw new Error(T)}return r},extract_shortest_path_from_predecessor_list:function(n,t){for(var e=[],r=t,o;r;)e.push(r),o=n[r],r=n[r];return e.reverse(),e},find_path:function(n,t,e){var r=K.single_source_shortest_paths(n,t,e);return K.extract_shortest_path_from_predecessor_list(r,e)},PriorityQueue:{make:function(n){var t=K.PriorityQueue,e={},r;n=n||{};for(r in t)t.hasOwnProperty(r)&&(e[r]=t[r]);return e.queue=[],e.sorter=n.sorter||t.default_sorter,e},default_sorter:function(n,t){return n.cost-t.cost},push:function(n,t){var e={value:n,cost:t};this.queue.push(e),this.queue.sort(this.sorter)},pop:function(){return this.queue.shift()},empty:function(){return this.queue.length===0}}};typeof mt<"u"&&(mt.exports=K)});var Be=g(F=>{var f=M(),we=se(),me=ce(),ye=ae(),Ee=ge(),J=gt(),v=I(),ve=de();function he(n){return unescape(encodeURIComponent(n)).length}function Y(n,t,e){let r=[],o;for(;(o=n.exec(e))!==null;)r.push({data:o[0],index:o.index,mode:t,length:o[0].length});return r}function Ce(n){let t=Y(J.NUMERIC,f.NUMERIC,n),e=Y(J.ALPHANUMERIC,f.ALPHANUMERIC,n),r,o;return v.isKanjiModeEnabled()?(r=Y(J.BYTE,f.BYTE,n),o=Y(J.KANJI,f.KANJI,n)):(r=Y(J.BYTE_KANJI,f.BYTE,n),o=[]),t.concat(e,r,o).sort(function(s,u){return s.index-u.index}).map(function(s){return{data:s.data,mode:s.mode,length:s.length}})}function yt(n,t){switch(t){case f.NUMERIC:return we.getBitsLength(n);case f.ALPHANUMERIC:return me.getBitsLength(n);case f.KANJI:return Ee.getBitsLength(n);case f.BYTE:return ye.getBitsLength(n)}}function tn(n){return n.reduce(function(t,e){let r=t.length-1>=0?t[t.length-1]:null;return r&&r.mode===e.mode?(t[t.length-1].data+=e.data,t):(t.push(e),t)},[])}function en(n){let t=[];for(let e=0;e<n.length;e++){let r=n[e];switch(r.mode){case f.NUMERIC:t.push([r,{data:r.data,mode:f.ALPHANUMERIC,length:r.length},{data:r.data,mode:f.BYTE,length:r.length}]);break;case f.ALPHANUMERIC:t.push([r,{data:r.data,mode:f.BYTE,length:r.length}]);break;case f.KANJI:t.push([r,{data:r.data,mode:f.BYTE,length:he(r.data)}]);break;case f.BYTE:t.push([{data:r.data,mode:f.BYTE,length:he(r.data)}])}}return t}function nn(n,t){let e={},r={start:{}},o=["start"];for(let i=0;i<n.length;i++){let s=n[i],u=[];for(let c=0;c<s.length;c++){let l=s[c],a=""+i+c;
vendor: 4,097 bytes, lines 4-8
4u.push(a),e[a]={node:l,lastCount:0},r[a]={};for(let w=0;w<o.length;w++){let h=o[w];e[h]&&e[h].node.mode===l.mode?(r[h][a]=yt(e[h].lastCount+l.length,l.mode)-yt(e[h].lastCount,l.mode),e[h].lastCount+=l.length):(e[h]&&(e[h].lastCount=l.length),r[h][a]=yt(l.length,l.mode)+4+f.getCharCountIndicator(l.mode,t))}}o=u}for(let i=0;i<o.length;i++)r[o[i]].end=0;return{map:r,table:e}}function pe(n,t){let e,r=f.getBestModeForData(n);if(e=f.from(t,r),e!==f.BYTE&&e.bit<r.bit)throw new Error('"'+n+'" cannot be encoded with mode '+f.toString(e)+`. 5 Suggested mode is: `+f.toString(r));switch(e===f.KANJI&&!v.isKanjiModeEnabled()&&(e=f.BYTE),e){case f.NUMERIC:return new we(n);case f.ALPHANUMERIC:return new me(n);case f.KANJI:return new Ee(n);case f.BYTE:return new ye(n)}}F.fromArray=function(t){return t.reduce(function(e,r){return typeof r=="string"?e.push(pe(r,null)):r.data&&e.push(pe(r.data,r.mode)),e},[])};F.fromString=function(t,e){let r=Ce(t,v.isKanjiModeEnabled()),o=en(r),i=nn(o,e),s=ve.find_path(i.map,"start","end"),u=[];for(let c=1;c<s.length-1;c++)u.push(i.table[s[c]].node);return F.fromArray(tn(u))};F.rawSplit=function(t){return F.fromArray(Ce(t,v.isKanjiModeEnabled()))}});var Te=g(Ae=>{var et=I(),Et=j(),rn=qt(),on=Ft(),sn=kt(),un=Ht(),At=Kt(),Tt=ct(),cn=Gt(),tt=te(),ln=oe(),an=M(),Ct=Be();function fn(n,t){let e=n.size,r=un.getPositions(t);for(let o=0;o<r.length;o++){let i=r[o][0],s=r[o][1];for(let u=-1;u<=7;u++)if(!(i+u<=-1||e<=i+u))for(let c=-1;c<=7;c++)s+c<=-1||e<=s+c||(u>=0&&u<=6&&(c===0||c===6)||c>=0&&c<=6&&(u===0||u===6)||u>=2&&u<=4&&c>=2&&c<=4?n.set(i+u,s+c,!0,!0):n.set(i+u,s+c,!1,!0))}}function gn(n){let t=n.size;for(let e=8;e<t-8;e++){let r=e%2===0;n.set(e,6,r,!0),n.set(6,e,r,!0)}}function dn(n,t){let e=sn.getPositions(t);for(let r=0;r<e.length;r++){let o=e[r][0],i=e[r][1];for(let s=-2;s<=2;s++)for(let u=-2;u<=2;u++)s===-2||s===2||u===-2||u===2||s===0&&u===0?n.set(o+s,i+u,!0,!0):n.set(o+s,i+u,!1,!0)}}function hn(n,t){let e=n.size,r=tt.getEncodedBits(t),o,i,s;for(let u=0;u<18;u++)o=Math.floor(u/3),i=u%3+e-8-3,s=(r>>u&1)===1,n.set(o,i,s,!0),n.set(i,o,s,!0)}function Bt(n,t,e){let r=n.size,o=ln.getEncodedBits(t,e),i,s;for(i=0;i<15;i++)s=(o>>i&1)===1,i<6?n.set(i,8,s,!0):i<8?n.set(i+1,8,s,!0):n.set(r-15+i,8,s,!0),i<8?n.set(8,r-i-1,s,!0):i<9?n.set(8,15-i-1+1,s,!0):n.set(8,15-i-1,s,!0);n.set(r-8,8,1,!0)}function pn(n,t){let e=n.size,r=-1,o=e-1,i=7,s=0;for(let u=e-1;u>0;u-=2)for(u===6&&u--;;){for(let c=0;c<2;c++)if(!n.isReserved(o,u-c)){let l=!1;s<t.length&&(l=(t[s]>>>i&1)===1),n.set(o,u-c,l),i--,i===-1&&(s++,i=7)}if(o+=r,o<0||e<=o){o-=r,r=-r;break}}}function wn(n,t,e){let r=new rn;e.forEach(function(c){r.put(c.mode.bit,4),r.put(c.getLength(),an.getCharCountIndicator(c.mode,n)),c.write(r)});let o=et.getSymbolTotalCodewords(n),i=Tt.getTotalCodewordsCount(n,t),s=(o-i)*8;for(r.getLengthInBits()+4<=s&&r.put(0,4);r.getLengthInBits()%8!==0;)r.putBit(0);let u=(s-r.getLengthInBits())/8;for(let c=0;c<u;c++)r.put(c%2?17:236,8);return mn(r,n,t)}function mn(n,t,e){let r=et.getSymbolTotalCodewords(t),o=Tt.getTotalCodewordsCount(t,e),i=r-o,s=Tt.getBlocksCount(t,e),u=r%s,c=s-u,l=Math.floor(r/s),a=Math.floor(i/s),w=a+1,h=l-a,y=new cn(h),A=0,T=new Array(s),bt=new Array(s),rt=0,Re=new Uint8Array(n.buffer);for(let _=0;_<s;_++){let it=_<c?a:w;T[_]=Re.slice(A,A+it),bt[_]=y.encode(T[_]),A+=it,rt=Math.max(rt,it)}let ot=new Uint8Array(r),Rt=0,E,C;for(E=0;E<rt;E++)for(C=0;C<s;C++)E<T[C].length&&(ot[Rt++]=T[C][E]);for(E=0;E<h;E++)for(C=0;C<s;C++)ot[Rt++]=bt[C][E];return ot}function yn(n,t,e,r){let o;if(Array.isArray(n))o=Ct.fromArray(n);else if(typeof n=="string"){let l=t;if(!l){let a=Ct.rawSplit(n);l=tt.getBestVersionForData(a,e)}o=Ct.fromString(n,l||40)}else throw new Error("Invalid data");let i=tt.getBestVersionForData(o,e);if(!i)throw new Error("The amount of data is too big to be stored in a QR Code");if(!t)t=i;else if(t<i)throw new Error(` 6The chosen QR Code version cannot contain this amount of data. 7Minimum version required to store current data is: `+i+`. 8`);let s=wn(t,e,o),u=et.getSymbolSize(t),c=new on(u);return fn(c,t),gn(c),dn(c,t),Bt(c,e,0),t>
8=7&&hn(c,t),pn(c,s),isNaN(r)&&(r=At.getBestMask(c,Bt.bind(null,c,e))),At.applyMask(r,c),Bt(c,e,r),{modules:c,version:t,errorCorrectionLevel:e,maskPattern:r,segments:o}}Ae.create=function(t,e){if(typeof t>"u"||t==="")throw new Error("No input text");let r=Et.M,o,i;return typeof e<"u"&&(r=Et.from(e.errorCorrectionLevel,Et.M),o=tt.from(e.version),i=At.from(e.maskPattern),e.toSJISFunc&&et.setToSJISFunction(e.toSJISFunc)),yn(t,o,r,i)}});var It=g(L=>{function Ie(n){if(typeof n=="number"&&(n=n.toString()),typeof n!="string")throw new Error("Color should be defined as hex string");let t=n.slice().replace("#","").split("");if(t.length<3||t.length===5||t.length>8)throw new Error("Invalid hex color: "+n);(t.length===3||t.length===4)&&(t=Array.prototype.concat.apply([],t.map(function(r){return[r,r]}))),t.length===6&&t.push("F","F");let e=parseInt(t.join(""),16);return{r:e>>24&255,g:e>>16&255,b:e>>8&255,a:e&255,hex:"#"+t.slice(0,6).join("")}}L.getOptions=function(t){t||(t={}),t.color||(t.color={});let e=typeof t.margin>"u"||t.margin===null||t.margin<0?4:t.margin,r=t.width&&t.width>=21?t.width:void 0,o=t.scale||4;
8return{width:r,scale:r?4:o,margin:e,color:{dark:Ie(t.color.dark||"#000000ff"),light:Ie(t.color.light||"#ffffffff")},type:t.type,rendererOpts:t.rendererOpts||{}}};L.getScale=function(t,e){return e.width&&e.width>=t+e.margin*2?e.width/(t+e.margin*2):e.scale};L.getImageWidth=function(t,e){let r=L.getScale(t,e);return Math.floor((t+e.margin*2)*r)};L.qrToImageData=function(t,e,r){let o=e.modules.size,i=e.modules.data,s=L.getScale(o,r),u=Math.floor((o+r.margin*2)*s),c=r.margin*s,l=[r.color.light,r.color.dark];for(let a=0;a<u;a++)for(let w=0;w<u;w++){let h=(a*u+w)*4,y=r.color.light;if(a>=c&&w>=c&&a<u-c&&w<u-c){let A=Math.floor((a-c)/s),T=Math.floor((w-c)/s);y=l[i[A*o+T]?1:0]}t[h++]=y.r,t[h++]=y.g,t[h++]=y.b,t[h]=y.a}}});var Ne=g(nt=>{var Nt=It();function En(n,t,e){n.clearRect(0,0,t.width,t.height),t.style||(t.style={}),t.height=e,t.width=e,t.style.height=e+"px",t.style.width=e+"px"}function Cn(){try{return document.createElement("canvas")}catch{throw new Error("You need to specify a canvas element")}}nt.render=function(t,e,r){let o=r,i=e;typeof o>"u"&&(!e||!e.getContext)&&(o=e,e=void 0),e||(i=Cn()),o=Nt.getOptions(o);let s=Nt.getImageWidth(t.modules.size,o),u=i.getContext("2d"),c=u.createImageData(s,s);return Nt.qrToImageData(c.data,t,o),En(u,i,s),u.putImageData(c,0,0),i};nt.renderToDataURL=function(t,e,r){let o=r;typeof o>"u"&&(!e||!e.getContext)&&(o=e,e=void 0),o||(o={});let i=nt.render(t,e,o),s=o.type||"image/png",u=o.rendererOpts||{};return i.toDataURL(s,u.quality)}});var Pe=g(Se=>{var Bn=It();function Me(n,t){let e=n.a/255,r=t+'="'+n.hex+'"';return e<1?r+" "+t+'-opacity="'+e.toFixed(2).slice(1)+'"':r}function Mt(n,t,e){let r=n+t;return typeof e<"u"&&(r+=" "+e),r}function An(n,t,e){let r="",o=0,i=!1,s=0;for(let u=0;u<n.length;u++){let c=Math.floor(u%t),l=Math.floor(u/t);!c&&!i&&(i=!0),n[u]?(s++,u>0&&c>0&&n[u-1]||(r+=i?Mt("M",c+e,.5+l+e):Mt("m",o,0),o=0,i=!1),c+1<t&&n[u+1]||(r+=Mt("h",s),s=0)):o++}return r}Se.render=function(t,e,r){let o=Bn.getOptions(e),i=t.modules.size,s=t.modules.data,u=i+o.margin*2,c=o.color.light.a?"<path "+Me(o.color.light,"fill")+' d="M0 0h'+u+"v"+u+'H0z"/>':"",l="<path "+Me(o.color.dark,"stroke")+' d="'+An(s,i,o.margin)+'"/>',a='viewBox="0 0 '+u+" "+u+'"',h='<svg xmlns="http://www.w3.org/2000/svg" '+(o.width?'width="'+o.width+'" height="'+o.width+'" ':"")+a+' shape-rendering="crispEdges">'+c+l+`</svg> 9`;return typeof r=="function"&&r(null,h),h}});var Nn=g(O=>{var Tn=_t(),St=Te(),be=Ne(),In=Pe();function Pt(n,t,e,r,o){let i=[].slice.call(arguments,1),s=i.length,u=typeof i[s-1]=="function";if(!u&&!Tn())throw new Error("Callback required as last argument");if(u){if(s<2)throw new Error("Too few arguments provided");s===2?(o=e,e=t,t=r=void 0):s===3&&(t.getContext&&typeof o>"u"?(o=r,r=void 0):(o=r,r=e,e=t,t=void 0))}else{if(s<1)throw new Error("Too few arguments provided");return s===1?(e=t,t=r=void 0):s===2&&!t.getContext&&(r=e,e=t,t=void 0),new Promise(function(c,l){try{let a=St.create(e,r);c(n(a,t,r))}catch(a){l(a)}})}try{let c=St.create(e,r);o(null,n(c,t,r))}catch(c){o(c)}}O.create=St.create;O.toCanvas=Pt.bind(null,be.render);O.toDataURL=Pt.bind(null,be.renderToDataURL);O.toString=Pt.bind(null,function(n,t,e){return In.render(n,e)})});return Nn();})(); 10 11// END QR GENERATOR 12// BEGIN CONTACT RENDERER 13const contactIcons={"Instagram": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c3ZnIGlkPSJpbnN0YWdyYW0iIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDI1NiAyNTYuMDIiPjxwYXRoIGQ9Ik0yNTUuMjMsNzUuMjNjLS42Mi0xMy42Mi0yLjc5LTIyLjkzLTUuOTUtMzEuMDctMy4yMS04LjU0LTguMjUtMTYuMjgtMTQuNzYtMjIuNjctNi4zOS02LjUxLTE0LjEzLTExLjU1LTIyLjY3LTE0Ljc3LTguMTQtMy4xNi0xNy40NS01LjMyLTMxLjA3LTUuOTQtMTMuNjUtLjYyLTE4LjAxLS43Ny01Mi43Ny0uNzdzLTM5LjEyLjE1LTUyLjc3Ljc3Yy0xMy42Mi42Mi0yMi45MywyLjc5LTMxLjA3LDUuOTUtOC41NSwzLjIyLTE2LjI4LDguMjUtMjIuNjcsMTQuNzctNi41MSw2LjM5LTExLjU1LDE0LjEyLTE0Ljc3LDIyLjY3LTMuMTYsOC4xNC01LjMyLDE3LjQ1LTUuOTQsMzEuMDctLjYzLDEzLjY1LS43NywxOC4wMS0uNzcsNTIuNzhzLjE1LDM5LjEyLjc3LDUyLjc4Yy42MiwxMy42MiwyLjc5LDIyLjkzLDUuOTUsMzEuMDcsMy4yMSw4LjU0LDguMjUsMTYuMjgsMTQuNzYsMjIuNjcsNi4zOSw2LjUxLDE0LjEzLDExLjU1LDIyLjY3LDE0Ljc2LDguMTQsMy4xNiwxNy40NSw1LjMzL
13DMxLjA3LDUuOTUsMTMuNjUuNjIsMTguMDEuNzcsNTIuNzcuNzdzMzkuMTItLjE0LDUyLjc3LS43N2MxMy42Mi0uNjIsMjIuOTMtMi43OSwzMS4wNy01Ljk1LDE3LjE5LTYuNjQsMzAuNzgtMjAuMjQsMzcuNDQtMzcuNDQsMy4xNi04LjE0LDUuMzMtMTcuNDUsNS45NS0zMS4wNy42Mi0xMy42NS43Ny0xOC4wMS43Ny01Mi43OHMtLjE1LTM5LjEzLS43Ny01Mi43OVpNMjMyLjE5LDE3OS43M2MtLjU3LDEyLjQ4LTIuNjUsMTkuMjYtNC40MSwyMy43Ni00LjMxLDExLjE2LTEzLjEzLDE5Ljk5LTI0LjI5LDI0LjI5LTQuNTEsMS43NS0xMS4yOSwzLjg0LTIzLjc2LDQuNDEtMTMuNS42MS0xNy41NC43NS01MS43Mi43NXMtMzguMjMtLjEzLTUxLjcyLS43NWMtMTIuNDgtLjU3LTE5LjI2LTIuNjUtMjMuNzYtNC40MS01LjU2LTIuMDYtMTAuNTktNS4zMi0xNC43MS05LjU4LTQuMjUtNC4xMy03LjUyLTkuMTUtOS41OC0xNC43MS0xLjc1LTQuNTEtMy44NC0xMS4yOS00LjQxLTIzLjc2LS42MS0xMy41LS43NS0xNy41NC0uNzUtNTEuNzJzLjEzLTM4LjIyLjc1LTUxLjcyYy41NS0xMi40OSwyLjYzLTE5LjI2LDQuMzgtMjMuNzcsMi4wNi01LjU2LDUuMzMtMTAuNiw5LjU4LTE0LjcyLDQuMTMtNC4yNSw5LjE2LTcuNTIsMTQuNzItOS41OCw0LjUxLTEuNzUsMTEuMjktMy44NCwyMy43Ni00LjQxLDEzLjUtLjYxLDE3LjU0LS43NCw1MS43Mi0uNzRoMGMzNC4xOCwwLDM4LjIyLjEzLDUxLjcyLjc1LDEyLjQ4LjU3LDE5LjI2LDIuNjUsMjMuNzYsNC40MSw1LjU2LDIuMDYsMTAuNTksNS4zMiwxNC43MSw5LjU4LDQuMjUsNC4xMyw3LjUyLDkuMTYsOS41OCwxNC43MiwxLjc1LDQuNTEsMy44NCwxMS4yOSw0LjQxLDIzLjc2LjYxLDEzLjUuNzUsMTcuNTQuNzUsNTEuNzJzLS4xMiwzOC4yMi0uNzMsNTEuNzJaIiBmaWxsPSIjZmZmIiBzdHJva2Utd2lkdGg9IjAiLz48cGF0aCBkPSJNMTI3Ljk5LDYyLjI4Yy0zNi4zLDAtNjUuNzIsMjkuNDMtNjUuNzIsNjUuNzJzMjkuNDMsNjUuNzMsNjUuNzIsNjUuNzMsNjUuNzMtMjkuNDMsNjUuNzMtNjUuNzMtMjkuNDMtNjUuNzItNjUuNzMtNjUuNzJaTTEyNy45OSwxNzAuNjdjLTIzLjU2LDAtNDIuNjYtMTkuMS00Mi42Ni00Mi42N3MxOS4xLTQyLjY3LDQyLjY3LTQyLjY3LDQyLjY3LDE5LjEsNDIuNjcsNDIuNjctMTkuMTEsNDIuNjctNDIuNjgsNDIuNjdaIiBmaWxsPSIjZmZmIiBzdHJva2Utd2lkdGg9IjAiLz48cGF0aCBkPSJNMjExLjY4LDU5LjY4YzAsOC40OC02Ljg4LDE1LjM2LTE1LjM2LDE1LjM2cy0xNS4zNi02Ljg4LTE1LjM2LTE1LjM2LDYuODgtMTUuMzYsMTUuMzYtMTUuMzYsMTUuMzYsNi44OCwxNS4zNiwxNS4zNloiIGZpbGw9IiNmZmYiIHN0cm9rZS13aWR0aD0iMCIvPjwvc3ZnPg==", "YouTube": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c3ZnIGlkPSJZb3VUdWJlIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzNjUuNzEgMjU2Ij48cGF0aCBkPSJNMzU4LjA3LDM5Ljk4Yy00LjIxLTE1LjczLTE2LjYtMjguMTMtMzIuMzMtMzIuMzNDMjk3LjIyLDAsMTgyLjg2LDAsMTgyLjg2LDBjMCwwLTExNC4zNiwwLTE0Mi44OCw3LjY0QzI0LjI0LDExLjg1LDExLjg1LDI0LjI0LDcuNjQsMzkuOTgsMCw2OC40OSwwLDEyOCwwLDEyOGMwLDAsMCw1OS41MSw3LjY0LDg4LjAyLDQuMjEsMTUuNzMsMTYuNiwyOC4xMywzMi4zMywzMi4zMywyOC41Miw3LjY0LDE0Mi44OCw3LjY0LDE0Mi44OCw3LjY0LDAsMCwxMTQuMzYsMCwxNDIuODgtNy42NCwxNS43My00LjIxLDI4LjEzLTE2LjYsMzIuMzMtMzIuMzMsNy42NC0yOC41Miw3LjY0LTg4LjAyLDcuNjQtODguMDIsMCwwLDAtNTkuNTEtNy42NC04OC4wMlpNMTQ2LjI5LDE4Mi44NnYtMTA5LjcxbDk1LjAxLDU0Ljg2LTk1LjAxLDU0Ljg2WiIgZmlsbD0iI2ZmZiIgc3Ryb2tlLXdpZHRoPSIwIi8+PC9zdmc+", "Facebook": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c3ZnIGlkPSJGYWNlYm9vayIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgMTI5LjMyIDI1NiI+PHBhdGggZD0iTTQuMTMsMTM2LjM1aDI4LjA2djExNS41M2MwLDIuMjgsMS44NSw0LjEzLDQuMTMsNC4xM2g0Ny41OGMyLjI4LDAsNC4xMy0xLjg1LDQuMTMtNC4xM3YtMTE0Ljk4aDMyLjI2YzIuMSwwLDMuODYtMS41Nyw0LjEtMy42Nmw0LjktNDIuNTNjLjEzLTEuMTctLjI0LTIuMzQtMS4wMi0zLjIyLS43OC0uODgtMS45MS0xLjM4LTMuMDgtMS4zOGgtMzcuMTZ2LTI2LjY2YzAtOC4wNCw0LjMzLTEyLjExLDEyLjg2LTEyLjExaDI0LjNjMi4yOCwwLDQuMTMtMS44NSw0LjEzLTQuMTNWNC4xNmMwLTIuMjgtMS44NS00LjEzLTQuMTMtNC4xM2gtMzMuNDhjLS4yNC0uMDEtLjc2LS4wMy0xLjUzLS4wMy01LjgxLDAtMjYsMS4xNC00MS45NSwxNS44Mi0xNy42NywxNi4yNi0xNS4yMiwzNS43My0xNC42MywzOS4xMXYzMS4xOEg0LjEzYy0yLjI4LDAtNC4xMywxLjg1LTQuMTMsNC4xM3Y0MS45OWMwLDIuMjgsMS44NSw0LjEzLDQuMTMsNC4xM1oiIGZpbGw9IiNmZmYiIHN0cm9rZS13aWR0aD0iMCIvPjwvc3ZnPg==", "TikTok": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c3ZnIGlkPSJ0aWt0b2siIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDIyMS44OCAyNTYiPjxwYXRoIGQ9Ik0xOTQuMjUsNTQuNzVjLTEuNzMtLjg5LTMuNDEtMS44Ny01LjA0LTIuOTMtNC43NC0zLjEzLTkuMDktNi44My0xMi45NC0xMS05LjY1LTExLjA0LTEzLjI2LTIyLjI1LTE0LjU5LTMwLjA5aC4wNWMtMS4xMS02LjUxLS42NS0xMC43Mi0uNTgtMTAuNzJoLTQzLjk3djE3MC4wMWMwLDIuMjgsMCw0LjU0LS4xLDYuNzcsMCwuMjgtLjAzLjUzLS4wNC44MywwLC4xMiwwLC4yNS0uMDMuMzh2LjFjLS45NCwxMi4zOS03Ljk4LDIzLjQ5LTE4Ljc4LDI5LjYzLTUuNTQsMy4xNS0xMS44MSw0LjgxLTE4LjE5LDQuOC0yMC40OCwwLTM3LjA5LTE2LjctMzcuMDktMzcuMzNzMTYuNi0zNy4zMywzNy4wOS0zNy4zM2MzLjg4LDAsNy43My42MSwxMS40MiwxLjgxbC4wNS00NC43N2MtMjIuNjMtMi45Mi00NS40NSwzLjc1LTYyLjkzLDE4LjQxLTcuNTgsNi41OC0xMy45NSwxNC40NC0xOC44MywyMy4yMS0xLjg2LDMuMi04Ljg2LDE2LjA2LTkuNzEsMzYuOTMtLjUzLDExLjg0LDMuMDIsMjQuMTIsNC43MiwyOS4xOXYuMTFjMS4wNywyLjk5LDUuMiwxMy4xOCwxMS45NCwyMS43Nyw1LjQzLDYuODksMTEuODUsMTIuOTUsMTkuMDQsMTcuOTd2LS4xMWwuMTEuMTFjMjEuMjgsMTQuNDYsNDQuODgsMTMuNTEsNDQuODgsMTMuNTEsNC4wOS0uMTcsMTcuNzcsMCwzMy4zMS03LjM2LDE3LjI0LTguMTYsMjcuMDUtMjAuMzMsMjcuMDUtMjAuMzMsNi4yNy03LjI3LDExLjI1LT
13E1LjU1LDE0Ljc0LTI0LjQ5LDMuOTgtMTAuNDYsNS4zMS0yMyw1LjMxLTI4LjAxdi05MC4xOWMuNTMuMzIsNy42NCw1LjAyLDcuNjQsNS4wMiwwLDAsMTAuMjMsNi41NiwyNi4yLDEwLjgzLDExLjQ2LDMuMDQsMjYuODksMy42OCwyNi44OSwzLjY4di00My42NWMtNS40MS41OS0xNi4zOS0xLjEyLTI3LjYzLTYuNzJaIiBmaWxsPSIjZmZmIiBzdHJva2Utd2lkdGg9IjAiLz48L3N2Zz4=", "X": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDI4My4yMiAyNTYiPjxnIGlkPSJ4IiBpbWFnZS1yZW5kZXJpbmc9Im9wdGltaXplUXVhbGl0eSIgc2hhcGUtcmVuZGVyaW5nPSJnZW9tZXRyaWNQcmVjaXNpb24iIHRleHQtcmVuZGVyaW5nPSJnZW9tZXRyaWNQcmVjaXNpb24iPjxwYXRoIGQ9Ik0yMjMuMDUsMGg0My40M2wtOTQuODgsMTA4LjQ0LDExMS42MiwxNDcuNTZoLTg3LjRsLTY4LjQ1LTg5LjUtNzguMzIsODkuNUg1LjU5bDEwMS40OC0xMTUuOTlMMCwwaDg5LjYxbDYxLjg3LDgxLjhMMjIzLjA1LDBaTTIwNy44MSwyMzBoMjQuMDdMNzYuNTQsMjQuNjNoLTI1LjgybDE1Ny4wOSwyMDUuMzdoMFoiIGZpbGw9IiNmZmYiIHN0cm9rZS13aWR0aD0iMCIvPjwvZz48L3N2Zz4=", "WhatsApp": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyBpZD0id2EiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmVyc2lvbj0iMS4xIiB2aWV3Qm94PSIwIDAgMjU2IDI1NiI+CiAgPGRlZnM+CiAgICA8c3R5bGU+CiAgICAgIC5jbHMtMSB7CiAgICAgICAgZmlsbDogI2ZmZjsKICAgICAgICBzdHJva2Utd2lkdGg6IDBweDsKICAgICAgfQogICAgPC9zdHlsZT4KICA8L2RlZnM+CiAgPHBhdGggY2xhc3M9ImNscy0xIiBkPSJNMTMwLjMsMEM2MS40LDAsNS42LDU1LjgsNS42LDEyNC43czYuNSw0NS42LDE3LjksNjQuNEwxLDI1Nmw2OS0yMi4xYzE3LjksOS45LDM4LjQsMTUuNSw2MC4zLDE1LjUsNjguOSwwLDEyNC43LTU1LjgsMTI0LjctMTI0LjdTMTk5LjIsMCwxMzAuMywwWk0xMzAuMywyMjguNWMtMjEuMSwwLTQwLjctNi4zLTU3LjEtMTcuMmwtMzkuOSwxMi44LDEzLTM4LjVjLTEyLjQtMTcuMS0xOS44LTM4LjEtMTkuOC02MC45LDAtNTcuMiw0Ni42LTEwMy44LDEwMy44LTEwMy44czEwMy44LDQ2LjYsMTAzLjgsMTAzLjgtNDYuNiwxMDMuOC0xMDMuOCwxMDMuOFpNMTg4LjgsMTUzYy0zLjEtMS43LTE4LjUtMTAtMjEuNC0xMS4yLTIuOS0xLjItNS0xLjgtNy4yLDEuMy0yLjIsMy4xLTguNiwxMC0xMC41LDEyLjEtMS45LDIuMS0zLjgsMi4yLTYuOS41LTMuMS0xLjctMTMuMy01LjUtMjUtMTYuOC05LjEtOC44LTE1LjEtMTkuNS0xNi45LTIyLjctMS43LTMuMywwLTQuOSwxLjYtNi40LDEuNS0xLjQsMy4zLTMuNiw1LTUuNCwxLjctMS44LDIuMi0zLjEsMy40LTUuMiwxLjEtMi4xLjctNCwwLTUuNi0uNy0xLjYtNi41LTE3LjUtOC45LTI0LTIuNC02LjUtNS4xLTUuNS03LTUuNi0xLjksMC00LS40LTYuMS0uNS0yLjEsMC01LjYuNi04LjYsMy43LTMsMy4xLTExLjUsMTAuNS0xMi4xLDI2LjEtLjYsMTUuNywxMC4zLDMxLjIsMTEuOCwzMy40LDEuNSwyLjIsMjAuNywzNi4xLDUyLjYsNTAuMSwzMS45LDE0LDMyLjEsOS43LDM3LjksOS40LDUuOS0uMywxOS4xLTcsMjIuMS0xNC4zLDIuOS03LjMsMy4yLTEzLjcsMi40LTE1LjEtLjctMS40LTIuOC0yLjItNi0zLjlaIi8+Cjwvc3ZnPg==", "Signal": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c3ZnIGlkPSJzaWduYWwiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDI1NiAyNTYiPjxwYXRoIGQ9Ik0xMjguMDEsMjRjLTU3LjQ0LjAyLTEwMy45OSw0Ni42Mi0xMDMuOTUsMTA0LjAzLDAsMTkuNTgsNS41MiwzOC43MywxNS45NCw1NS4yOWwtMTAsNDIuNjYsNDIuNjctMTBjNDguNjEsMzAuNiwxMTIuODIsMTYuMDIsMTQzLjQzLTMyLjU4LDMwLjYxLTQ4LjYsMTYuMDItMTEyLjgtMzIuNTktMTQzLjQtMTYuNjEtMTAuNDgtMzUuODYtMTYuMDItNTUuNS0xNmgwWk02OC42MSwyMjcuNzdsLTE3LjE5LDQsMi43MywxMS42OSwxMi42NS0yLjk0YzkuNTgsNS4yMywxOS44MSw5LjE5LDMwLjQyLDExLjc5bDIuODgtMTEuNjRjLTExLjA0LTIuNzUtMjEuNjMtNy4xMi0zMS40LTEyLjk4bC0uMDguMDhoMFpNMTIuNjEsMjAxLjc4bDExLjY5LDIuNzEsNC0xNy4xOWMtNS44My05Ljc5LTEwLjE5LTIwLjQyLTEyLjktMzEuNDhsLTExLjY1LDIuODdjMi42LDEwLjYsNi41OCwyMC44MywxMS43OSwzMC40MWwtMi45NCwxMi42N2gwWk00MC43NywyMzQuMTlsLTI0Ljc3LDUuNzksNS43Ny0yNC43Ny0xMS42OS0yLjczLTUuNzcsMjQuNzdjLTEuNTIsNi40NiwyLjUsMTIuOTIsOC45NCwxNC40MiwxLjc5LjQyLDMuNjcuNDIsNS40OCwwbDI0Ljc1LTUuNjktMi43MS0xMS43OWgwWk0xMTAuNjMsMTMuMjljMTEuNTItMS43MywyMy4yMy0xLjczLDM0Ljc1LDBsMS43OS0xMS44NWMtMTIuNzEtMS45Mi0yNS42NS0xLjkyLTM4LjM2LDBsMS44MSwxMS44NWgwWk0yMzcuNjIsNjEuODNsLTEwLjI3LDYuMTdjNi4wMiw5Ljk4LDEwLjUsMjAuODEsMTMuMjksMzIuMTJsMTEuNjUtMi44N2MtMy4wOC0xMi40OC04LjAyLTI0LjQxLTE0LjY3LTM1LjQxaDBaTTM0LjYzLDU5LjJjNi45Mi05LjM3LDE1LjIxLTE3LjY3LDI0LjU5LTI0LjU4bC03LjIxLTkuNjdjLTEwLjMxLDcuNi0xOS40NCwxNi43My0yNy4wNCwyNy4wNGw5LjY3LDcuMjFoMFpNMTk2LjgxLDM0LjYyYzkuMzgsNi45MiwxNy42NywxNS4yMSwyNC41OSwyNC41OGw5LjY3LTcuMjFjLTcuNi0xMC4zMS0xNi43My0xOS40NC0yNy4wNC0yNy4wNGwtNy4yMSw5LjY3aDBaTTIyMS4zOSwxOTYuOGMtNi45Miw5LjM3LTE1LjIxLDE3LjY0LTI0LjU5LDI0LjU2bDcuMTMsOS42N2MxMC4zMy03LjYsMTkuNDgtMTYuNzMsMjcuMTMtMjcuMDRsLTkuNjctNy4xOWgwWk0xNDUuMzksMjQyLjY5Yy0xMS41MiwxLjczLTIzLjIzLDEuNzMtMzQuNzUsMGwtMS43OSwx
13MS44N2MxMi43MSwxLjkyLDI1LjY1LDEuOTIsMzguMzYsMGwtMS44MS0xMS44N2gwWk0yNTIuMjcsMTU4LjcybC0xMS42NS0yLjg3Yy0yLjc5LDExLjMzLTcuMjcsMjIuMTYtMTMuMjksMzIuMTZsMTAuMjcsNi4xOWM2LjY3LTExLjAyLDExLjYxLTIzLDE0LjY3LTM1LjQ4aDBaTTI0NC4wMiwxMjcuOTljMCw1LjgxLS40NCwxMS42Mi0xLjMxLDE3LjM3bDExLjg2LDEuODFjMS45Mi0xMi43MSwxLjkyLTI1LjY0LDAtMzguMzVsLTExLjg2LDEuNzljLjg4LDUuNzUsMS4zMSwxMS41NiwxLjMxLDE3LjM3aDBaTTE5NC4xOCwyMzcuNThsLTYuMTctMTAuMjdjLTkuOTgsNi4wMi0yMC44MSwxMC41LTMyLjEzLDEzLjI5bDIuODgsMTEuNjRjMTIuNDgtMy4wOCwyNC40Mi04LjAyLDM1LjQyLTE0LjY3aDBaTTEyLDEyNy45OWMwLTUuODEuNDQtMTEuNjIsMS4yOS0xNy4zN2wtMTEuODYtMS43OWMtMS45MiwxMi43MS0xLjkyLDI1LjY0LDAsMzguMzVsMTEuODYtMS44MWMtLjg1LTUuNzUtMS4yOS0xMS41Ni0xLjI5LTE3LjM3aDBaTTE4LjQsNjEuODNjLTYuNjUsMTEuMDItMTEuNTgsMjIuOTYtMTQuNjcsMzUuNDNsMTEuNjUsMi44N2MyLjc5LTExLjMzLDcuMjctMjIuMTYsMTMuMjktMzIuMTZsLTEwLjI3LTYuMTVoMFpNMTU4LjcyLDMuNzNsLTIuODgsMTEuNjRjMTEuMzMsMi43OSwyMi4xNyw3LjI3LDMyLjE3LDEzLjI5bDYuMTktMTAuMjdjLTExLTYuNjUtMjIuOTgtMTEuNTgtMzUuNDgtMTQuNjdoMFpNOTcuMjgsMy43M2wyLjg4LDExLjY0Yy0xMS4zMywyLjc5LTIyLjE3LDcuMjctMzIuMTcsMTMuMjlsLTYuMTctMTAuMjdjMTEuMDQtNi42NSwyMi45OC0xMS41OCwzNS40Ni0xNC42N2gwWiIgZmlsbD0iI2ZmZiIgc3Ryb2tlLXdpZHRoPSIwIi8+PC9zdmc+", "InstagramTile": "data:image/jpeg;base64,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"}; 14const contactEscape=value=>String(value??'').replace(/[&<>"']/g,c=>({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c])); 15function contactIcon(type,featured=false){ 16 const image=contactIcons[featured&&type==='Instagram'?'InstagramTile':type]; 17 if(image)return `<img src="${image}" alt="" aria-hidden="true">`; 18 if(type==='Text')return `<svg viewBox="0 0 24 24" fill="${featured?'currentColor':'none'}" stroke="${featured?'none':'currentColor'}" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3C6.48 3 2 6.58 2 11c0 2.2 1.1 4.2 2.9 5.65L3.5 21l5.1-2.45c1.06.3 2.2.45 3.4.45 5.52 0 10-3.58 10-8s-4.48-8-10-8Z"/></svg>`; 19 const shapes={Text:'<path d="M4 4h16v12H9l-5 4z"/>',Call:'<path d="M5 3l4 4-2 3c2 4 3 5 7 7l3-2 4 4c-2 5-7 3-12-2S0 5 5 3z"/>',Email:'<rect x="3" y="5" width="18" height="14" rx="2"/><path d="m3 5 9 8 9-8"/>',Website:'<circle cx="12" cy="12" r="9"/><ellipse cx="12" cy="12" rx="4" ry="9"/><path d="M3 12h18M5 6h14M5 18h14"/>'}; 20 return `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" aria-hidden="true">${shapes[type]||shapes.Website}</svg>`; 21} 22function renderContactMarkup(profile){ 23 const reviews=profile.links.filter(l=>['write','read'].includes(l.googleReviewAction)); 24 const links=profile.links.filter(l=>!l.googleReviewAction),featured=['primary','secondary'].flatMap(role=>links.filter(l=>l.status===role)); 25 const subtitle=l=>['Instagram','Facebook','YouTube','TikTok','X'].includes(l.type)?'@'+l.value.replace(/^@/,''):l.value; 26 const top=`<div class="contact-featured">${featured.map(l=>`<a class="contact-feature" href="${contactEscape(l.url)}" target="_blank" rel="noopener noreferrer"><span class="contact-feature-icon ${['Text','Call'].includes(l.type)?'contact-green':''}">
26${contactIcon(l.type,true)}</span><span class="contact-feature-copy"><strong>${contactEscape(l.type)}</strong><span>${contactEscape(subtitle(l))}</span></span></a>`).join('')}</div>`; 27 const shop=profile.shop?renderLocationMarkup(profile.shop):''; 28 const footer=links.filter(l=>l.isInFooter); 29 const rows=Array.from({length:Math.ceil(footer.length/5)},(_,i)=>footer.slice(i*5,i*5+5)); 30 const bottom=`<div class="contact-socials">${rows.map(row=>`<div class="contact-social-row">${row.map(l=>`<a href="${contactEscape(l.url)}" aria-label="${contactEscape(l.type)}" title="${contactEscape(l.type)}" target="_blank" rel="noopener noreferrer">${contactIcon(l.type)}</a>`).join('')}</div>`).join('')}</div>`; 31 const googleReviewIcon='<img class="google-review-logo" src="data:image/png;base64,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" alt="" aria-hidden="true">'; 32 const reviewButtons=reviews.length?`<section class="contact-reviews" aria-label="Google Reviews">${['write','read'].map(action=>{const link=reviews.find(l=>l.googleReviewAction===action);return link?`<a class="${action==='write'?'google-review-write':'google-review-read'}" href="${contactEscape(link.url)}" target="_blank" rel="noopener noreferrer">${action==='write'?googleReviewIcon:''}<span>${action==='write'?'Leave a Google review':'Read reviews on Google'}</span>${action==='read'?' <span aria-hidden="true">â</span>':''}</a>`:'';}).join('')}</section>`:''; 33 return top+shop+bottom+reviewButtons+(!featured.length&&!footer.length&&!reviews.length&&!profile.shop?'<p class="empty-state">No contact information has been shared yet.</p>':''); 34} 35 36function renderLocationMarkup(s,{label='Tattoo studio',query=[s.title,s.address].filter(
36Boolean).join(' '),showTitle=true}={}) { 37 const url=`https://maps.apple.com/?q=${encodeURIComponent(query)}`; 38 let map=''; 39 if(Number.isFinite(s.latitude)&&Number.isFinite(s.longitude)&&Math.abs(s.latitude)<85&&Math.abs(s.longitude)<=180){ 40 const src=contactMapURL(s); 41 map=`<div class="contact-map-image"><img src="${contactEscape(src)}" alt="Satellite map of ${contactEscape(s.title)}" loading="eager" fetchpriority="high" decoding="async"><span class="contact-map-pin" aria-hidden="true"></span></div>`; 42 } 43 return `<section class="contact-shop"><div class="contact-map-wrap"><a class="contact-map" data-map-query="${contactEscape(query)}" href="${contactEscape(url)}" target="_blank" rel="noopener noreferrer" aria-label="Open ${contactEscape(s.title)} in Maps"><div class="contact-shop-header"><span>${contactEscape(label)}</span><span>${contactEscape(s.title)}</span></div>${map}</a>${map?'<details class="contact-map-credit"><summary aria-label="Map credits">i</summary><div>Powered by Esri · Esri, Maxar, Earthstar Geographics, and the GIS User Community</div></details>':''}</div>${showTitle?`<h2>${contactEscape(s.title)}</h2>`:''}<p>${contactEscape(s.address)}</p></section>`; 44} 45 46function contactMapURL(s){ 47 if(!s||!Number.isFinite(s.latitude)||!Number.isFinite(s.longitude)||Math.abs(s.latitude)>
47=85||Math.abs(s.longitude)>180)return null; 48 const x=s.longitude*20037508.34/180,y=Math.log(Math.tan((90+s.latitude)*Math.PI/360))*20037508.34/Math.PI; 49 return 'https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/export?'+new URLSearchParams({bbox:[x-300,y-150,x+300,y+150].join(','),bboxSR:'3857',imageSR:'3857',size:'900,450',format:'jpg',f:'image'}); 50} 51// END CONTACT RENDERER 52// Choose the destination app without changing the embedded map provider. 53function updateMapDestination(event){ 54 const link=event.target.closest?.('a[data-map-query]'); 55 if(!link)return; 56 const apple=/iPhone|iPad|iPod|Macintosh|Mac OS X/i.test(navigator.userAgent)&&!/Android/i.test(navigator.userAgent); 57 const query=encodeURIComponent(link.dataset.mapQuery); 58 link.href=apple?`https://maps.apple.com/?q=${query}`:`https://www.google.com/maps/search/?api=1&query=${query}`; 59} 60for(const event of ['pointerdown','click','auxclick','contextmenu'])document.addEventListener(event,updateMapDestination,true); 61// BEGIN PLACEMENT OPTIONS 62const placementOptions={"Torso (Front)":["Chest","Chest (Left)","Chest (Right)","Sternum","Breast","Underbreast","Clavicle (Left)","Clavicle (Right)","Stomach","Abdomen (Upper)","Abdomen (Lower)","Navel","Groin","Side / Flank","Ribs","Ribs (Left)","Ribs (Right)","Hip (Left)","Hip (Right)"],"Torso (Back)":["Ribs","Ribs (Left)","Ribs (Right)","Hip (Left)","Hip (Right)","Back","Back (Upper)","Back (Middle)","Back (Lower)","Spine","Shoulder Blade (Left)","Shoulder Blade (Right)","Buttocks","Buttocks (Left)","Buttocks (Right)"],"Arm (Left)":["Sleeve (Quarter)","Sleeve (Half)","Sleeve (Full)","Forearm","Forearm (Inner)","Forearm (Outer)","Elbow","Elbow (Inner)","Elbow (Outer)","Bicep","Bicep (Inner)","Bicep (Outer)","Shoulder","Upper Arm","Tricep / Back of Upper Arm","Armpit","Wrist (Inner)","Wrist (Outer)"],"Arm (Right)":["Sleeve (Quarter)","Sleeve (Half)","Sleeve (Full)","Forearm","Forearm (Inner)","Forearm (Outer)","Elbow","Elbow (Inner)","Elbow (Outer)","Bicep","Bicep (Inner)","Bicep (Outer)","Shoulder","Upper Arm","Tricep / Back of Upper Arm","Armpit","Wrist (Inner)","Wrist (Outer)"],"Hand (Left)":["Wrist (Inner)","Wrist (Outer)","Palm (Back)","Palm","Side of Hand","Fingers","Side of Finger","Fingertips","Knuckles","Thumb","Index Finger","Middle Finger","Ring Finger","Pinky Finger"],"Hand (Right)":["Wrist (Inner)","Wrist (Outer)","Palm (Back)","Palm","Side of Hand","Fingers","Side of Finger","Fingertips","Knuckles","Thumb","Index Finger","Middle Finger","Ring Finger","Pinky Finger"],"Leg (Left)":["Thigh","Thigh (Front)","Thigh (Upper)","Thigh (Lower)","Thigh (Inner)","Thigh (Outer)","Thigh (Rear)","Knee (Front)","Knee (Back)","Shin","Calf","Calf (Inner)","Calf (Outer)","Full Leg / Sleeve"],"Leg (Right)":["Thigh","Thigh (Front)","Thigh (Upper)","Thigh (Lower)","Thigh (Inner)","Thigh (Outer)","Thigh (Rear)","Knee (Front)","Knee (Back)","Shin","Calf","Calf (Inner)","Calf (Outer)","Full Leg / Sleeve"],"Foot (Left)":["Ankle (Inner)","Ankle (Outer)","Bridge (Top)","Foot (Inner Side)","Foot (Outer Side)","Heel","Achilles / Back of Ankle","Sole (Bottom)","Toe(s)"],"Foot (Right)":["Ankle (Inner)","Ankle (Outer)","Bridge (Top)","Foot (Inner Side)","Foot (Outer Side)","Heel","Achilles / Back of Ankle","Sole (Bottom)","Toe(s)"],"Face":["Mouth (Inner)","Mouth (Outer)","Forehead","Nose","Jawline","Chin","Under Chin","Cheek (Left)","Cheek (Right)","Temple (Left)","Temple (Right)"],"Head":["Ear (Left)","Ear (Right)","Behind Ear (Left)","Behind Ear (Right)","Scalp","Scalp (Crown)","Scalp (Back)","Scalp (Side)"],"Neck":["Neck (Throat)","Neck (Back)","Neck (Left)","Neck (Right)"]}; 63// END PLACEMENT OPTIONS 64const app=document.querySelector('#app'),dialog=document.querySelector('#detail'),detail=document.querySelector('#dialog-content'); 65const escape=value=>String(value??'').replace(/[&<>"']/g,c=>({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c])); 66const money=value=>new Intl.NumberFormat('en-US',{style:'currency',currency:'USD',maximumFractionDigits:2}).format(value); 67const labels={event:'Events',flash:'Flash',portfolio:'Portfolio',contact:'Contact',book:'Book'}; 68let fullProfileRequest; 69const bookingWeekdays=new Set(); 70const tabPanels=new Map(); 71let profile,activeTab,selectedDay,displayMonth,selectedFlash=null,bookingView='calendar'; 72const path=decodeURIComponent(location.pathname).split('/').filter(
72Boolean); 73const artistUsername=path[0]; 74const demo=artistUsername==='demo' && ['localhost','127.0.0.1'].includes(location.hostname); 75function dateLabel(value,options={dateStyle:'full'}) {return new Intl.DateTimeFormat('en-US',{timeZone:profile.timezone,...options}).format(new Date(value));} 76function dayKey(value) {return new Intl.DateTimeFormat('en-CA',{timeZone:profile.timezone,year:'numeric',month:'2-digit',day:'2-digit'}).format(new Date(value));} 77let dialogScrollCleanup=()=>{}; 78let dialogPageLock=null; 79function lockDialogPage(){ 80 // Keep the document in normal flow: repeatedly fixing the body can strand 81 // Safari's touch scrolling after a scrollable dialog followed by a short one. 82 if(!dialogPageLock)dialogPageLock={x:window.scrollX,y:window.scrollY}; 83} 84function unlockDialogPage(){ 85 if(dialog.open||!dialogPageLock)return; 86 const saved=dialogPageLock;dialogPageLock=null; 87 window.scrollTo({left:saved.x,top:saved.y,behavior:'instant'}); 88} 89// Contain gestures only inside the open dialog, never lock the page itself. 90let dialogTouchY=null; 91dialog.addEventListener('touchstart',event=>{dialogTouchY=event.touches.length===1?event.touches[0].clientY:null;},{passive:true}); 92dialog.addEventListener('touchmove',event=>{ 93 if(!dialog.open||dialogTouchY===null||event.touches.length!==1)return; 94 const y=event.touches[0].clientY,delta=dialogTouchY-y;dialogTouchY=y; 95 if(dialog.scrollHeight<=dialog.clientHeight+1||(delta<0&&dialog.scrollTop<=0)||(delta>0&&dialog.scrollTop+dialog.clientHeight>=dialog.scrollHeight-1))event.preventDefault(); 96},{passive:false}); 97dialog.addEventListener('touchend',()=>{dialogTouchY=null;},{passive:true}); 98dialog.addEventListener('touchcancel',()=>{dialogTouchY=null;},{passive:true}); 99dialog.addEventListener('close',unlockDialogPage); 100function showDialog(markup){dialogScrollCleanup();detail.innerHTML=markup;if(!dialog.open){lockDialogPage();try{dialog.showModal();}catch(error){unlockDialogPage();throw error;}}dialog.scrollTop=0;const heading=detail.querySelector('#dialog-title');if(heading){heading.tabIndex=-1;heading.focus({preventScroll:true});}} 101function closeDialogFromPointer(){ 102 // Restore scrolling now, without waiting for the queued close event. 103 dialog.close();unlockDialogPage();dialogScrollCleanup(); 104 requestAnimationFrame(()=>{if(!dialog.open&&document.activeElement instanceof HTMLElement)document.activeElement.blur();}); 105} 106dialog.addEventListener('cancel',event=>{event.preventDefault();closeDialogFromPointer();}); 107new MutationObserver(()=>{if(!dialog.open)unlockDialogPage();}).observe(dialog,{attributes:true,attributeFilter:['open']}); 108window.addEventListener('pageshow',()=>{if(!dialog.open)unlockDialogPage();}); 109document.querySelector('.close').onclick=closeDialogFromPointer; 110dialog.addEventListener('click',event=>{if(event.target===dialog){const r=dialog.getBoundingClientRect();if(event.clientX<r.left||event.clientX>r.right||event.clientY<r.top||event.clientY>r.bottom)closeDialogFromPointer();}}); 111async function api(url,options){const response=await fetch(url,options);let result;try{result=await response.json();}catch{throw new Error('The portal could not be reached. Please try again.');}if(!response.ok)throw new Error(result.message||'Please try again.');return result;} 112// Analytics contain only event categories and public design IDs, never form contents. 113const trackedAnalytics=new Set(); 114function trackAnalytics(type,target='',onceKey=''){ 115 if(demo||window.tattSafePreview||!profile||navigator.webdriver)return; 116 if(onceKey&&trackedAnalytics.has(onceKey))return; 117 if(onceKey)trackedAnalytics.add(onceKey); 118 try { 119 const body=JSON.stringify({id:crypto.randomUUID(),type,target}); 120 fetch(`/api/profiles/${encodeURIComponent(profile.username.toLowerCase())}/analytics`,{ 121 method:'POST',headers:{'content-type':'application/json'},body,keepalive:true 122 }).catch(()=>{}); 123 }catch{} // Tracking must never interrupt navigation or booking. 124} 125document.addEventListener('click',event=>{ 126 const link=event.target.closest?.('a');if(!link)return; 127 let type; 128 if(link.matches('.contact-feature'))type=link.querySelector('strong')?.textContent; 129 else if(link.closest('.contact-socials'))type=link.getAttribute('aria-label'); 130 else if(link.matches('.contact-map')||link.closest('.contact-shop'))type='Directions'; 131 else if(link.closest('.contact-reviews'))type='Google review'; 132 if(type)trackAnalytics('contact',type); 133}); 134function profileEventID(hash){ 135 const match=/^#event\/([a-zA-Z0-9_-]{1,180})$/.exec(hash); 136 return match?match[1]:null; 137} 138function eventArtistMarkup(artist,eventID){ 139 const photo=artist.image?`<img class="event-artist-avatar" src="${escape(artist.image)}" alt="" loading="lazy">`:`<span class="event-artist-avatar event-artist-initial" aria-hidden="true">${escape((artist.name||artist.username||'?').slice(0,1).toUpperCase())}</span>`;
140 const destination=artist.isGuest?artist.websiteURL:artist.portalURL?`${artist.portalURL}#portfolio`:null; 141 const avatar=destination?`<a class="event-artist-photo-link" href="${escape(destination)}" ${artist.isGuest?'target="_blank" rel="noopener noreferrer"':''} aria-label="View ${escape(artist.name)}âs ${artist.isGuest?'profile':'portfolio'}">${photo}</a>`:photo; 142 return `<div class="event-artist-card">${avatar}<strong>${escape(artist.name)}</strong><span>@${escape(artist.username)}</span></div>`; 143} 144async function load(){ 145 try { 146 if(artistUsername==='events'&&path.length===2){await loadEventPage(path[1]);return;} 147 if(!artistUsername){app.innerHTML='<div class="message"><h1>Your artist. Your next tattoo.</h1><p>Open the profile link shared by your artist to view their work and request a date.</p></div>';return;} 148 if(path.length!==1||!/^[a-z0-9][a-z0-9_.-]{2,39}$/i.test(artistUsername))throw new Error('This artist link is not valid. Please check the link your artist shared.'); 149 const initial=document.querySelector('#initial-profile'); 150 profile=demo?demoProfile():initial?JSON.parse(initial.textContent):await api(`/api/profiles/${encodeURIComponent(artistUsername.toLowerCase())}`); 151 document.title=`${profile.name||profile.username} | Tattoo Artist${[profile.shop?.city,profile.shop?.state].filter(Boolean).length?' in '+[profile.shop.city,profile.shop.state].filter(Boolean).join(', '):''} | TattSafe`; 152 const hash=profileEventID(location.hash)?'event':location.hash.slice(1);activeTab=profile.tabs.includes(hash)?hash:(profile.tabs.includes(profile.defaultTab)?profile.defaultTab:(profile.tabs.includes('portfolio')?'portfolio':profile.tabs[0])); 153 trackAnalytics('visit','','visit'); 154 installPortalShare();renderProfile();registerAgentTools();if(activeTab==='book')refreshVisibleAvailability(); 155 // Let the initial view paint and its visible images start first. 156 setTimeout(warmProfileTabs,600); 157 }catch(error){app.innerHTML=`<div class="message"><h1>Profile unavailable</h1><p>${escape(error.message)}</p><button class="secondary" id="retry">Try again</button></div>`;document.querySelector('#retry').onclick=load;} 158 finally{app.setAttribute('aria-busy','false');} 159} 160function renderProfile(){ 161 const tabOrder=['flash','portfolio','event','contact','book']; 162 profile.tabs.sort((a,b)=>tabOrder.indexOf(a)-tabOrder.indexOf(b)); 163 tabPanels.clear(); 164 app.innerHTML=`${demo?'<div class="preview-note">Local preview · Example availability. Booking requests are disabled here.</div>':''}${profile.banner?`<div class="profile-banner"><img src="${escape(profile.banner)}" alt="" fetchpriority="high"></div>`:''}<section class="identity">${profile.image?`<img class="avatar" src="${escape(profile.image)}" alt="${escape(profile.name)}">`:`<div class="avatar empty" aria-hidden="true">${escape((profile.name||profile.username)[0]?.toUpperCase())}</div>`}<div><h1>${escape(profile.name||profile.username)}</h1><p class="username">@${escape(profile.username)}</p>${profile.shop?`<p class="artist-location">${escape([profile.shop.title,[profile.shop.city,profile.shop.state].filter(Boolean).join(', ')].filter(Boolean).join(' · '))}</p>`:''}${profile.bio?`<p class="bio">${escape(profile.bio)}</p>`:''}</div></section><nav class="tabs" role="tablist" aria-label="Artist profile">${profile.tabs.map(tab=>`<button role="tab" id="tab-${tab}" aria-controls="panel-${tab}" aria-selected="${tab===activeTab}" tabindex="${tab===activeTab?0:-1}" data-tab="${tab}">${labels[tab]}</button>`).join('')}</nav><div id="content"></div>`; 165 const avatar=document.querySelector('.avatar'),identityCopy=document.querySelector('.identity>div:last-child'); 166 const sizeAvatar=()=>{const width=avatar.getBoundingClientRect().width;avatar.style.height=`${Math.max(width*1.25,Math.min(identityCopy.scrollHeight,width*1.5))}px`;}; 167 new ResizeObserver(sizeAvatar).observe(identityCopy);sizeAvatar(); 168 document.querySelectorAll('[data-tab]').forEach(button=>{button.onclick=()=>selectTab(button.dataset.tab);button.onkeydown=event=>{if(!['ArrowLeft','ArrowRight','Home','End'].includes(event.key))return;event.preventDefault();const i=profile.tabs.indexOf(activeTab),next=event.key==='Home'?0:event.key==='End'?profile.tabs.length-1:(i+(event.key==='ArrowRight'?1:-1)+profile.tabs.length)%profile.tabs.length;selectTab(profile.tabs[next]);document.querySelector(`#tab-${activeTab}`).focus();};}); 169 renderTab(); 170} 171let availabilityRequest; 172async function refreshAvailability(){ 173 if(demo)return; 174 if(availabilityRequest)return availabilityRequest; 175 availabilityRequest=(async()=>{ 176 const latest=await api(`/api/profiles/${encodeURIComponent(artistUsername.toLowerCase())}/availability`,{cache:'no-store'}); 177 const changed=JSON.stringify(profile.slots)!==JSON.stringify(latest.slots)||profile.timezone!==latest.timezone; 178 profile.slots=latest.slots;profile.timezone=latest.timezone; 179 if(changed){ 180 if(!profile.slots.some(slot=>dayKey(slot.start)===selectedDay)){selectedDay=profile.slots.length?dayKey(profile.slots[0].start):null;displayMonth=selectedDay?.slice(0,7);} 181 const panel=tabPanels.get('book');if(panel?.dataset.ready==='true')renderBooking(panel); 182 const calendar=detail.querySelector('#flash-calendar');
182if(dialog.open&&calendar)renderBooking(calendar,true); 183 } 184 })(); 185 try{await availabilityRequest;}finally{availabilityRequest=null;} 186} 187async function refreshVisibleAvailability(){ 188 if(!profile||document.visibilityState==='hidden'||(activeTab!=='book'&&!dialog.open))return; 189 try{await refreshAvailability();document.querySelector('#availability-error')?.remove();} 190 catch{ 191 const panel=tabPanels.get('book'); 192 if(panel&&!panel.querySelector('#availability-error'))panel.insertAdjacentHTML('afterbegin','<p class="note" id="availability-error" role="status">Unable to refresh availability. Reconnecting⦠Dates will be checked again before you book.</p>'); 193 } 194} 195window.addEventListener('pageshow',refreshVisibleAvailability); 196window.addEventListener('focus',refreshVisibleAvailability); 197document.addEventListener('visibilitychange',refreshVisibleAvailability); 198setInterval(refreshVisibleAvailability,30000); 199function selectTab(tab){if(tab==='event'){const panel=tabPanels.get('event');if(panel?.dataset.eventID){delete panel.dataset.ready;delete panel.dataset.loading;panel.dataset.request=String(Number(panel.dataset.request||0)+1);}}activeTab=tab;selectedFlash=null;history.replaceState(null,'',`#${tab}`);document.querySelectorAll('[data-tab]').forEach(b=>{b.setAttribute('aria-selected',String(b.dataset.tab===tab));b.tabIndex=b.dataset.tab===tab?0:-1;});renderTab().then(()=>{if(tab==='book')refreshVisibleAvailability();});} 200async function renderTab(){ 201 const tab=activeTab,container=document.querySelector('#content'); 202 if(!tab){container.innerHTML='<p class="empty-state">This artist hasnât shared any sections yet.</p>';return;} 203 let content=tabPanels.get(tab); 204 if(!content){ 205 content=document.createElement('section'); 206 content.id=`panel-${tab}`; 207 content.setAttribute('role','tabpanel'); 208 content.setAttribute('aria-labelledby',`tab-${tab}`); 209 content.tabIndex=0; 210 container.append(content); 211 tabPanels.set(tab,content); 212 } 213 for(const [name,panel] of tabPanels)panel.hidden=name!==tab; 214 // Keep loaded image elements mounted when another tab is shown. 215 if(content.dataset.ready==='true'||content.dataset.loading==='true')return; 216 if(profile.deferred && !(profile.loadedTabs||['contact']).includes(tab)) { 217 content.dataset.loading='true'; 218 content.innerHTML='<p class="message" role="status">Loading this sectionâ¦</p>'; 219 try { 220 fullProfileRequest??=api(`/api/profiles/${encodeURIComponent(artistUsername.toLowerCase())}`); 221 profile=await fullProfileRequest; 222 registerAgentTools(); 223 } catch(error) { 224 fullProfileRequest=null; 225 content.innerHTML=`<p class="message">${escape(error.message)}</p><button class="secondary">Try again</button>`; 226 content.querySelector('button').onclick=()=>renderTab(); 227 return; 228 } finally { 229 delete content.dataset.loading; 230 } 231 } 232 if(tab==='event'){await renderProfileEvents(content);return;} 233 if(tab==='flash')renderFlash(content); 234 if(tab==='portfolio')renderPortfolio(content); 235 if(tab==='contact')renderContact(content); 236 if(tab==='book')renderBooking(content); 237 content.dataset.ready='true'; 238} 239 240// Warm only the first gallery page, with bounded image requests so the visible tab wins. 241async function warmProfileTabs(){ 242 try{ 243 if(profile.deferred){ 244 fullProfileRequest??=api(`/api/profiles/${encodeURIComponent(artistUsername.toLowerCase())}`); 245 profile=await fullProfileRequest; 246 registerAgentTools(); 247 } 248 const tabs=activeTab==='portfolio'?['portfolio','flash']:['flash','portfolio']; 249 const groups={flash:(profile.flash||[]).slice(0,12).map(item=>item.preview||item.image),portfolio:(profile.portfolio||[]).slice(0,12).map(item=>item.preview||item.image),event:(profile.events||[]).slice(0,12).map(item=>item.coverImage),contact:[contactMapURL(profile.shop)]}; 250 const order=[activeTab,...['event','contact',...tabs].filter(tab=>tab!==activeTab)]; 251 const urls=[...new Set(Array.from({length:12},(_,i)=>order.map(tab=>groups[tab]?.[i])).flat().filter(Boolean))]; 252 let next=0; 253 await Promise.all(Array.from({length:4},async()=>{ 254 while(next<urls.length){ 255 const url=urls[next++]; 256 await new Promise(resolve=>{const image=new Image();const timer=setTimeout(resolve,10000);image.onload=image.onerror=()=>{clearTimeout(timer);resolve();};image.fetchPriority='low';image.src=url;}); 257 } 258 })); 259 }catch{fullProfileRequest=null;} // A tab can retry normally if background loading fails. 260} 261// Append pages rather than rebuilding existing images; retain a keyboard-accessible fallback. 262function paginateGallery(content,items,markup,bind){ 263 content.galleryObserver?.disconnect(); 264 const grid=content.querySelector('.grid'); 265 if(!grid)return; 266 let count=Math.min(12,items.length); 267 bind(); 268 if(count===items.length)return; 269 const more=document.createElement('button'); 270 more.type='button';more.className='secondary gallery-more';more.textContent='Load more'; 271 grid.after(more); 272 const append=()=>{ 273 const end=Math.min(count+12,items.length); 274 grid.insertAdjacentHTML('beforeend',items.slice(count,end).map((item,index)=>markup(item,count+index)).join('')); 275 count=end;bind(); 276 if(count===items.length){content.galleryObserver?.disconnect();more.remove();} 277 }; 278 more.onclick=append; 279 if('IntersectionObserver' in window){ 280 content.galleryObserver=new IntersectionObserver(entries=>{ 281 if(entries.some(entry=>entry.isIntersecting)&&!content.hidden)append(); 282 },{rootMargin:'400px'}); 283 content.galleryObserver.observe(more); 284 } 285} 286function collapseFlashStyles(target){ 287 document.querySelectorAll('.flash-style-filter[open]').forEach(menu=>{ 288 if(!menu.contains(target))menu.open=false; 289 }); 290} 291document.addEventListener('pointerdown',event=>collapseFlashStyles(event.target),true); 292document.addEventListener('keydown',event=>{ 293 if(event.key==='Escape')document.querySelectorAll('.flash-style-filter[open]').forEach(menu=>{menu.open=false;menu.querySelector('summary')?.focus();}); 294}); 295function filteredFlashItems(flash,styles){ 296 return flash.filter(item=>!styles.size||(item.styles||[]).some(style=>styles.has(style))); 297} 298function renderFlash(content,sort='preferred',selectedStyles=new Set(),filtersOpen=false){ 299 const styles=[...new Set(profile.flash.flatMap(item=>item.styles||[]))].sort((a,b)=>a.localeCompare(b)); 300 const items=filteredFlashItems(profile.flash,selectedStyles); 301 if(sort==='low')items.sort((a,b)=>a.total-b.total); 302 if(sort==='high')items.sort((a,b)=>b.total-a.total); 303 if(sort==='title')items.sort((a,b)=>a.title.localeCompare(b.title)); 304 content.galleryObserver?.disconnect(); 305 const flashCard=(flash,i)=>`<button class="card" data-flash="${i}" aria-label="${escape(flash.title||'Flash')} · ${escape(money(flash.total))}">${(flash.preview||flash.image)?`<img src="${escape(flash.preview||flash.image)}" alt="${escape(flash.title)}" loading="lazy">`:'<div class="art-empty">Image unavailable</div>'}<div class="card-body"><span class="price">${money(flash.total)}</span></div></button>`; 306 const markup=`${profile.flash.length?`<div class="flash-controls">${styles.length?`<details class="flash-style-filter" ${filtersOpen?'open':''}><summary><span>Styles: ${selectedStyles.size?`${selectedStyles.size} selected`:'All'}</span></summary><div class="flash-style-options"><button type="button" id="clear-flash-styles" aria-pressed="${!selectedStyles.size}">All Styles</button>${styles.map((style,i)=>`<button type="button" data-flash-style="${i}" aria-pressed="${selectedStyles.has(style)}">${escape(style)}</button>`).join('')}</div></details>`:''}<label class="flash-sort-control"><span class="flash-sort-label">Sort:</span><select id="flash-sort" aria-label="Sort flash"><option value="preferred">Artist Preferred</option><option value="title">Title AâZ</option><option value="low">Price: Low to High</option><option value="high">Price: High to Low</option></select></label></div>${!items.length?'<p class="empty-state">No designs match these styles. Choose another style or All Styles.</p>':''}
306<div class="grid flash-grid">${items.slice(0,12).map(flashCard).join('')}</div>`:'<p class="empty-state">No flash is available right now. Check back for new designs.</p>'}`; 307 const controls=content.querySelector('.flash-controls'); 308 if(controls){ 309 // Keep the tapped controls mounted so Safari cannot move focus to the page 310 // or close the menu while the filtered gallery is being refreshed. 311 const updated=document.createElement('div');updated.innerHTML=markup; 312 updated.querySelector('.flash-controls')?.remove(); 313 for(const child of [...content.children])if(child!==controls)child.remove(); 314 content.append(...updated.childNodes); 315 const menu=controls.querySelector('.flash-style-filter'); 316 if(menu){menu.open=filtersOpen;menu.querySelector('summary span').textContent=`Styles: ${selectedStyles.size?`${selectedStyles.size} selected`:'All'}`;} 317 controls.querySelectorAll('[data-flash-style]').forEach(button=>button.setAttribute('aria-pressed',String(selectedStyles.has(styles[Number(button.dataset.flashStyle)])))); 318 controls.querySelector('#clear-flash-styles')?.setAttribute('aria-pressed',String(!selectedStyles.size)); 319 }else content.innerHTML=markup; 320 paginateGallery(content,items,flashCard,()=>content.querySelectorAll('[data-flash]').forEach(b=>b.onclick=()=>flashDetail(items[Number(b.dataset.flash)]))); 321 const picker=content.querySelector('#flash-sort');if(picker){picker.value=sort;picker.onchange=()=>renderFlash(content,picker.value,selectedStyles,content.querySelector('.flash-style-filter')?.open);} 322 content.querySelectorAll('[data-flash-style]').forEach(button=>button.onclick=()=>{ 323 const style=styles[Number(button.dataset.flashStyle)],next=new Set(selectedStyles); 324 if(next.has(style))next.delete(style);else next.add(style); 325 renderFlash(content,sort,next,true); 326 content.querySelector(`[data-flash-style="${button.dataset.flashStyle}"]`)?.focus({preventScroll:true}); 327 }); 328 const clear=content.querySelector('#clear-flash-styles');if(clear)clear.onclick=()=>renderFlash(content,sort,new Set(),true); 329 330} 331function flashDetail(flash){ 332 trackAnalytics('flash_view',flash.id,`flash:${flash.id}`); 333 showDialog(`${flash.image?`<img class="detail-image" src="${escape(flash.image)}" alt="${escape(flash.title)}">`:''}<h2 id="dialog-title">${escape(flash.title||'Flash')}</h2>${flash.detail?.trim()?`<p class="detail-copy">${escape(flash.detail.trim())}</p>`:''}<div class="flash-price-breakdown" aria-label="Price breakdown"><div class="flash-price-row"><span aria-hidden="true"></span><span>Deposit <small>Due after approval</small></span><strong>${money(flash.deposit)}</strong></div><div class="flash-price-row"><span aria-hidden="true">+</span><span>Remaining balance <small>Due when your tattoo is finished</small></span><strong>${money((Math.round(flash.total*100)-Math.round(flash.deposit*100))/100)}</strong></div><div class="flash-price-row flash-price-total"><span aria-hidden="true">=</span><span>Total price</span><strong>${money(flash.total)}</strong></div></div><p class="note">Your deposit counts toward the total price.</p>${flashPlacementSummary(flash)}<p class="note">Send a request to your artist. Your appointment is confirmed after they respond. No payment is collected here.</p>${profile.slots.length?'<button class="primary full" id="choose-flash-date">Choose a date</button>':'<p class="empty-state">No availability posted right now.</p>'}`); 334 installFlashScrollHint(); 335 const choose=document.querySelector('#choose-flash-date');
335if(choose)choose.onclick=()=>{selectedFlash=flash;showDialog('<h2 id="dialog-title">Choose a date</h2><p class="meta">'+escape(flash.title)+'</p><div id="flash-calendar"></div>');renderBooking(document.querySelector('#flash-calendar'),true);}; 336} 337function renderPortfolio(content){content.galleryObserver?.disconnect();const photoCard=(item,i)=>`<button class="card" data-photo="${i}" aria-label="View tattoo ${i+1}">${(item.preview||item.image)?`<img src="${escape(item.preview||item.image)}" alt="${escape(item.styles.join(', ')||'Tattoo portfolio')}" loading="lazy">`:'<span class="art-empty">Image unavailable</span>'}</button>`;content.innerHTML=`${profile.portfolio.length?`<div class="grid portfolio-grid">${profile.portfolio.slice(0,12).map(photoCard).join('')}</div>`:'<p class="empty-state">No portfolio images have been shared yet.</p>'}`;paginateGallery(content,profile.portfolio,photoCard,()=>content.querySelectorAll('[data-photo]').forEach(b=>b.onclick=()=>{const item=profile.portfolio[Number(b.dataset.photo)];showPortfolioPhoto(item);}));} 338function showPortfolioPhoto(item){ 339 const photos=profile.portfolio?.includes(item)?profile.portfolio:[item]; 340 let index=Math.max(0,photos.indexOf(item)),touch=null,pinching=false; 341 const warmed=new Set(); 342 showDialog(`<section class="portfolio-lightbox"><h2 id="dialog-title">Portfolio</h2><div class="photo-viewer" aria-busy="true"><div class="photo-status" role="status"><span class="photo-spinner" aria-hidden="true"></span><span>Loading photoâ¦</span></div><img class="detail-image" alt="Tattoo portfolio" draggable="false" hidden><button class="secondary photo-retry" hidden>Try again</button></div><nav class="photo-navigation" aria-label="Portfolio photos"${photos.length<2?' hidden':''}><button class="secondary photo-previous" aria-label="Previous photo">â¹</button><span class="photo-counter" role="status" aria-live="polite" aria-atomic="true"></span><button class="secondary photo-next" aria-label="Next photo">âº</button></nav><p class="photo-swipe-hint meta"${photos.length<2?' hidden':''}>Swipe left or right to browse</p><div class="meta photo-styles"></div></section>`); 343 const root=detail.querySelector('.portfolio-lightbox'),viewer=root.querySelector('.photo-viewer'),photo=viewer.querySelector('img'),status=viewer.querySelector('.photo-status'),retry=viewer.querySelector('button'); 344 const previous=root.querySelector('.photo-previous'),next=root.querySelector('.photo-next'),counter=root.querySelector('.photo-counter'),styles=root.querySelector('.photo-styles'); 345 const load=()=>{ 346 const selected=photos[index]; 347 viewer.setAttribute('aria-busy','true');photo.hidden=true;retry.hidden=true;status.hidden=false; 348 counter.textContent=`${index+1} of ${photos.length}`;previous.disabled=index===0;next.disabled=index===photos.length-1; 349 photo.alt=`Tattoo portfolio photo ${index+1} of ${photos.length}`; 350 styles.innerHTML=(selected.styles||[]).map(style=>`<div>${escape(style)}</div>`).join(''); 351 status.innerHTML='<span class="photo-spinner" aria-hidden="true"></span><span>Loading photoâ¦</span>'; 352 photo.onload=()=>{viewer.setAttribute('aria-busy','false');status.hidden=true;photo.hidden=false;}; 353 photo.onerror=()=>{viewer.setAttribute('aria-busy','false');status.textContent='This photo couldnât load. Please try again.';retry.hidden=false;}; 354 const url=selected.image||selected.preview; 355 if(url){photo.src=url;}else{photo.removeAttribute('src');photo.onerror();retry.hidden=true;status.textContent='Photo unavailable.';} 356 for(const neighbor of [photos[index-1],photos[index+1]]){const src=neighbor?.image||neighbor?.preview;if(src&&!warmed.has(src)){warmed.add(src);const image=new Image();image.decoding='async';image.src=src;}} 357 }; 358 const navigate=delta=>{const target=index+delta;if(target<0||target>=photos.length)return;index=target;load();trackAnalytics('portfolio_view',photos[index].id,`portfolio:${photos[index].id}`);}; 359 previous.onclick=()=>navigate(-1);next.onclick=()=>navigate(1);retry.onclick=load; 360 root.addEventListener('keydown',event=>{if(event.key==='ArrowLeft'||event.key==='ArrowRight'){event.preventDefault();navigate(event.key==='ArrowLeft'?-1:1);}}); 361 viewer.addEventListener('touchstart',event=>{if(event.touches.length!==1){touch=null;pinching=true;return;}if(!pinching){const t=event.touches[0];touch={x:t.clientX,y:t.clientY};}},{passive:true}); 362 viewer.addEventListener('touchend',event=>{if(event.touches.length)return;const start=touch;touch=null;const ignore=pinching;pinching=false;if(ignore||!start||event.changedTouches.length!==1||(window.visualVie
362wport?.scale||1)>1.05)return;const t=event.changedTouches[0],dx=t.clientX-start.x,dy=t.clientY-start.y;if(Math.abs(dx)>=55&&Math.abs(dx)>Math.abs(dy)*1.5)navigate(dx<0?1:-1);},{passive:true}); 363 viewer.addEventListener('touchcancel',()=>{touch=null;pinching=false;},{passive:true}); 364 trackAnalytics('portfolio_view',item.id,`portfolio:${item.id}`);load(); 365} 366 367function renderContact(content){content.innerHTML=renderContactMarkup(profile);} 368 369function matchesBookingWeekday(date,weekdays){ 370 return weekdays.size===0||weekdays.has(new Date(`${date}T12:00:00Z`).getUTCDay()); 371} 372function renderBooking(content,compact=false){ 373 if(!profile.slots.length){content.innerHTML='<p class="empty-state">No availability posted. Check back for new dates.</p>';return;} 374 selectedDay??=dayKey(profile.slots[0].start);displayMonth??=selectedDay.slice(0,7); 375 const [year,month]=displayMonth.split('-').map(Number),first=new Date(Date.UTC(year,month-1,1)),count=new Date(Date.UTC(year,month,0)).getUTCDate(); 376 const dates=new Set(profile.slots.map(s=>dayKey(s.start))),selected=profile.slots.filter(s=>dayKey(s.start)===selectedDay); 377 const monthTitle=new Intl.DateTimeFormat('en-US',{month:'long',year:'numeric',timeZone:'UTC'}).format(first); 378 const switcher=compact?'':`<div class="booking-switch" role="tablist" aria-label="Availability view"><button role="tab" data-booking-view="calendar" aria-selected="${bookingView==='calendar'}">Calendar</button><button role="tab" data-booking-view="list" aria-selected="${bookingView==='list'}">List</button></div>`; 379 const calendarView=`<div class="booking-layout"><div class="calendar"><div class="calendar-header"><button id="prev-month" aria-label="Previous month">â¹</button><strong>${monthTitle}</strong><button id="next-month" aria-label="Next month">âº</button></div><div class="days">${['Sun','Mon','Tue','Wed','Thu','Fri','Sat'].map(d=>`<span class="day-name" aria-hidden="true">${d}</span>`).join('')}${'<span></span>'.repeat(first.getUTCDay())}${Array.from({length:count},(_,i)=>{const date=`${displayMonth}-${String(i+1).padStart(2,'0')}`,available=dates.has(date);return `<button class="day ${available?'available':''} ${date===selectedDay?'selected':''}" ${available?'':'disabled'} data-day="${date}" aria-pressed="${date===selectedDay}" aria-label="${monthTitle} ${i+1}${available?', available':''}"><span class="day-number">${i+1}</span></button>`;}).join('')}</div></div><div class="slots"><h3>${dateLabel(`${selectedDay}T12:00:00Z`,{weekday:'long',year:'numeric',month:'long',day:'numeric',timeZone:'UTC'})}</h3>${selected.map((slot,i)=>`<button class="slot" data-slot="${i}"><span>${dateLabel(slot.start,{hour:'numeric',minute:'2-digit'})}â${dateLabel(slot.end,{hour:'numeric',minute:'2-digit'})}</span><span>Request â</span></button>`).join('')||'<p class="note">Select an available day.</p>'}</div></div>`; 380 const weekdayNames=['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday']; 381 const filteredDates=[...dates].filter(date=>matchesBookingWeekday(date,bookingWeekdays)); 382 const weekdayPicker=`<div class="weekday-filter" role="group" aria-label="Filter availability by weekday">${weekdayNames.map((name,i)=>`<button type="button" data-weekday="${i}" aria-label="${name}" aria-pressed="${bookingWeekdays.has(i)}"><span class="weekday-label">${name.slice(0,3)}</span></button>`).join('')}</div>`; 383 const listView=`${weekdayPicker}<div class="booking-list">${filteredDates.map(date=>`<section><h3>${dateLabel(`${date}T12:00:00Z`,{weekday:'long',year:'numeric',month:'long',day:'numeric',timeZone:'UTC'})}</h3>${profile.slots.map((slot,i)=>dayKey(slot.start)===date?`<button class="slot" data-all-slot="${i}"><span>${dateLabel(slot.start,{hour:'numeric',minute:'2-digit'})}â${dateLabel(slot.end,{hour:'numeric',minute:'2-digit'})}</span><span>Request â</span></button>`:'').join('')}</section>`).join('')||`<p class="empty-state">No availability on the selected weekdays. Choose other days or deselect them to show all dates.</p>`}</div>`; 384 content.innerHTML=`${switcher}${compact||bookingView==='calendar'?calendarView:listView}`; 385 content.querySelectorAll('[data-weekday]').forEach(button=>button.onclick=()=>{ 386 const day=Number(button.dataset.weekday);
387 if(bookingWeekdays.has(day))bookingWeekdays.delete(day);else bookingWeekdays.add(day); 388 renderBooking(content,compact); 389 content.querySelector(`[data-weekday="${day}"]`)?.focus({preventScroll:true}); 390 }); 391 const shift=delta=>{const next=new Date(Date.UTC(year,month-1+delta,1));displayMonth=`${next.getUTCFullYear()}-${String(next.getUTCMonth()+1).padStart(2,'0')}`;const candidate=[...dates].find(d=>d.startsWith(displayMonth));selectedDay=candidate||`${displayMonth}-01`;renderBooking(content,compact);}; 392 const minimum=dayKey(new Date()).slice(0,7),maximum=dayKey(profile.slots.at(-1).start).slice(0,7); 393 const previous=content.querySelector('#prev-month'),next=content.querySelector('#next-month');if(previous&&next){previous.disabled=displayMonth<=minimum;next.disabled=displayMonth>=maximum;previous.onclick=()=>shift(-1);next.onclick=()=>shift(1);} 394 content.querySelectorAll('[data-booking-view]').forEach(b=>b.onclick=()=>{bookingView=b.dataset.bookingView;renderBooking(content,compact);}); 395 content.querySelectorAll('[data-day]').forEach(b=>b.onclick=()=>{selectedDay=b.dataset.day;renderBooking(content,compact);}); 396 content.querySelectorAll('[data-slot]').forEach(b=>b.onclick=()=>bookingForm(selected[Number(b.dataset.slot)],selectedFlash)); 397 content.querySelectorAll('[data-all-slot]').forEach(b=>b.onclick=()=>bookingForm(profile.slots[Number(b.dataset.allSlot)],selectedFlash)); 398} 399async function bookingImage(file){ 400 if(!file.type.startsWith('image/'))throw new Error('Choose an image file.'); 401 const bitmap=await createImageBitmap(file),scale=Math.min(1,900/Math.max(bitmap.width,bitmap.height)),canvas=document.createElement('canvas'); 402 canvas.width=Math.round(bitmap.width*scale);canvas.height=Math.round(bitmap.height*scale);canvas.getContext('2d').drawImage(bitmap,0,0,canvas.width,canvas.height);bitmap.close(); 403 for(const quality of [.78,.68,.58,.48,.38]){const blob=await new Promise(resolve=>canvas.toBlob(resolve,'image/jpeg',quality));if(blob&&blob.size<=90000)return await new Promise((resolve,reject)=>{const reader=new FileReader();reader.onload=()=>resolve(reader.result);reader.onerror=reject;reader.readAsDataURL(blob);});} 404 throw new Error('One of the images is too large. Try a smaller image.'); 405} 406function formatBookingPhone(value){ 407 const raw=String(value??''); 408 const digits=raw.replace(/\D/g,''); 409 // Leave international numbers and extensions intact. 410 if(/[a-z#]/i.test(raw)||(raw.trim().startsWith('+')&&!raw.trim().startsWith('+1'))||digits.length>11||(digits.length===11&&!digits.startsWith('1')))return raw; 411 const country=digits.startsWith('1')&&(raw.trim().startsWith('+1')||digits.length===11); 412 const local=country?digits.slice(1):digits; 413 const formatted=local.length<=3?local:local.length<=6?`(${local.slice(0,3)}) ${local.slice(3)}`:`(${local.slice(0,3)}) ${local.slice(3,6)}-${local.slice(6)}`; 414 return (country?'+1 ':'')+formatted; 415} 416function formatBookingPhoneInput(input){ 417 const raw=input.value,position=input.selectionStart??raw.length; 418 const count=raw.slice(0,position).replace(/\D/g,'').length; 419 const formatted=formatBookingPhone(raw); 420 if(formatted===raw)return; 421 input.value=formatted; 422 let cursor=0,seen=0; 423 while(cursor<formatted.length&&seen<count){if(/\d/.test(formatted[cursor]))seen++;cursor++;} 424 if(position===raw.length)cursor=formatted.length; 425 input.setSelectionRange(cursor,cursor); 426} 427function bookingSocial(social, platform){ 428 if(!social)return {socialPlatform:null,socialURL:null}; 429 const hosts={Instagram:['instagram.com'],TikTok:['tiktok.com'],Facebook:['facebook.com'],X:['x.com','twitter.com']}; 430 const label=Object.keys(hosts).find(p=>p.toLowerCase()===String(platform||'').toLowerCase()); 431 if(platform&&!label)throw new Error('Choose Instagram, TikTok, Facebook, or X.'); 432 if(!label)return {socialPlatform:null,socialURL:null}; // Older clients did not provide a platform. 433 let url; 434 if(/^https?:\/\//i.test(social)){ 435 try{url=new URL(social);}catch{throw new Error('Enter a valid social profile link.');} 436 const host=url.hostname.toLowerCase(); 437 if(url.username||url.password||!hosts[label].some(h=>host===h||host==='www.'+h||host==='m.'+h))throw new Error('The social link must match the selected platform.'); 438 url.protocol='https:'; 439 if(url.pathname==='/')throw new Error('Enter your profile link, not just the platform website.'); 440 }else{ 441 const handle=social.replace(/^@/,''); 442 if(!/^[a-zA-Z0-9_.-]+$/.test(handle))throw new Error('Enter a social username or full profile link.'); 443 url=new URL('https://'+hosts[label][0]+'/'+(label==='TikTok'?'@':'')+encodeURIComponent(handle)); 444 } 445 return {socialPlatform:label,socialURL:url.href}; 446} 447 448function setupBookingSocialFields(form,usernameField){ 449 const platform=form.elements.socialPlatform,username=form.elements.social; 450 const update=()=>{ 451 const visible=Boolean(platform.value); 452 usernameField.hidden=!visible; 453 username.disabled=!visible; 454 }; 455 platform.addEventListener('change',update); 456 update(); 457} 458 459async function bookingForm(slot,flash,values={}){ 460 if(!demo){ 461 showDialog('<h2 id="dialog-title">Checking availabilityâ¦</h2><p class="note" role="status">Confirming this date is still available.</p>'); 462 try{ 463 await refreshAvailability(); 464 if(!profile.slots.some(current=>current.id===slot.id)){ 465 showDialog('<h2 id="dialog-title">Date no longer available</h2><p>This time has been removed. Please choose another date.</p>');return; 466 } 467 }catch{showDialog('<h2 id="dialog-title">Couldnât check availability</h2><p>Please close this window and try again when youâre connected.</p>');return;} 468 if(!dialog.open)return; 469 } 470 471 const requestId=values.requestId||crypto.randomUUID(); 472 trackAnalytics('booking_start','',`booking:${requestId}`); 473 showDialog(`<h2 id="dialog-title">${flash?'Request this flash':'Tell us about your tattoo'}</h2><p class="meta">${escape(dateLabel(slot.start))} · ${escape(dateLabel(slot.start,{hour:'numeric',minute:'2-digit'}))}${flash?`<br>${escape(flash.title)} · ${money(flash.total)}`:''}</p><form id="booking-form"><label class="form-field">Your name<input name="name" autocomplete="name" maxlength="100" required value="${escape(values.name)}"></label><div class="form-grid"><label class="form-field">Email<input name="email" type="email" autocomplete="email" maxlength="254" value="${escape(values.email)}"></label><label class="form-field">Phone<input name="phone" type="tel" inputmode="tel" placeholder="(417) 986-6110" autocomplete="tel" maxlength="40" value="${escape(values.phone)}"></label></div><div class="booking-social-fields"><label class="form-field">Social platform<select name="socialPlatform"><option value="">Choose platform</option>${['Instagram','TikTok','Facebook','X'].map(p=>`<option value="${p}" ${values.socialPlatform===p?'selected':''}>${p}</option>`).join('')}</select></label><label class="form-field" id="social-username-field" hidden>Username<input name="social" disabled maxlength="100" autocapitalize="none" autocorrect="off" spellcheck="false" autocomplete="username" placeholder="@yourname" value="${escape(values.social)}"></label></div><p class="note">Add at least one contact method so your artist can reply.</p>${!flash?`<label class="form-field">Your tattoo idea<textarea name="idea" required maxlength="3000">${escape(values.idea)}</textarea></label>`:''}<div class="form-grid"><label class="form-field">Placement region<select name="placementRegion" required><option value="">Choose region</option>${Object.keys(placementOptions).filter(region=>!flash||!flash.placements.length||flash.placements.includes('Anywhere')||flash.placements.includes(region)).map(region=>`<option value="${escape(region)}" ${values.placementRegion===region?'selected':''}>${escape(region)}</option>`).join('')}</select></label><label class="form-field" id="placement-area-field" hidden>Placement area<select name="placementArea"><option value="">General</option></select></label><label class="form-field">Approximate size (optional)<input name="size" maxlength="100" placeholder="e.g. 3 à 4 inches" value="${escape(values.size)}"></label></div><label class="trap" aria-hidden="true">Website<input name="website" tabindex="-1" autocomplete="off"></label>
473<p id="form-error" class="error" role="alert"></p><p class="note">Your contact information and request will be shared with ${escape(profile.name||profile.username)}. This is a request, not a confirmed appointment.</p><button class="primary full" type="submit">Review request</button></form>`); 474 const booking=document.querySelector('#booking-form'),region=booking.elements.placementRegion,area=booking.elements.placementArea; 475 setupBookingSocialFields(booking,document.querySelector('#social-username-field')); 476 const updateArea=(selected='')=>{ 477 document.querySelector('#placement-area-field').hidden=!region.value; 478 const restricted=flash?.placementAreas && Object.hasOwn(flash.placementAreas,region.value); 479 area.required=Boolean(restricted); 480 area.innerHTML=(restricted?'<option value="">Choose area</option>':'<option value="">General</option>')+(restricted?flash.placementAreas[region.value]:(placementOptions[region.value]||[])).map(value=>`<option value="${escape(value)}" ${value===selected?'selected':''}>${escape(value)}</option>`).join(''); 481 }; 482 region.onchange=()=>updateArea();updateArea(values.placementArea); 483 const trap=document.querySelector('.trap');trap.insertAdjacentHTML('beforebegin',`${flash?`<label class="form-field">Notes / requests (optional)<textarea name="idea" maxlength="3000" placeholder="Tell your artist where you want this design and how it should fit near existing tattoos, scars, or other features.">${escape(values.idea)}</textarea></label>`:''}<label class="form-field">${flash?'Placement / reference photos (optional)':'Reference images (optional)'}<input name="images" type="file" accept="image/*" multiple><span class="meta">${flash?'Upload a photo of the body area showing where you want the design, including nearby tattoos or scars. ':''}Up to 3 images.${values.images?.length?` ${values.images.length} currently attached.`:''}</span></label>`); 484 const phoneInput=document.querySelector('#booking-form').elements.phone; 485 phoneInput.value=formatBookingPhone(phoneInput.value); 486 phoneInput.addEventListener('input',()=>formatBookingPhoneInput(phoneInput)); 487 phoneInput.addEventListener('change',()=>formatBookingPhoneInput(phoneInput)); 488 document.querySelector('#booking-form').onsubmit=async event=>{event.preventDefault();const form=event.currentTarget,error=document.querySelector('#form-error'),v=Object.fromEntries(new FormData(form));v.social=v.social||'';if(v.social.trim()&&!v.socialPlatform){error.textContent='Choose the social platform for your username or link.';return;}v.placement=v.placementRegion+(v.placementArea?' - '+v.placementArea:'');if(!v.email.trim()&&!v.phone.trim()&&!v.social.trim()){error.textContent='Add an email, phone number, or social handle.';return;}const files=[...form.elements.images.files];if(files.length>3){error.textContent='Attach up to 3 images.';return;}try{Object.assign(v,bookingSocial(v.social.trim(),v.socialPlatform));v.images=files.length?await Promise.all(files.map(bookingImage)):(values.images||[]);reviewBooking(slot,flash,{...v,requestId,slotId:slot.id,flashId:flash?.id??null});}catch(reason){error.textContent=reason.message||'The images could not be prepared.';}}; 489} 490function reviewBooking(slot,flash,values){ 491 showDialog(`<h2 id="dialog-title">Review your request</h2><dl class="review"><dt>Artist</dt><dd>${escape(profile.name||profile.username)}</dd><dt>Requested appointment</dt><dd>${escape(dateLabel(slot.start))}<br>${escape(dateLabel(slot.start,{hour:'numeric',minute:'2-digit'}))}</dd><dt>Your details</dt><dd>${escape(values.name)}<br>${[values.email,values.phone].filter(Boolean).map(escape).join('<br>')}${values.social?`<br>${values.socialURL?`<a href="${escape(values.socialURL)}" target="_blank" rel="noopener noreferrer">${escape(values.socialPlatform+': '+values.social)}</a>`:escape(values.social)}`:''}</dd><dt>${flash?'Flash':'Tattoo idea'}</dt><dd>${escape(flash?.title||values.idea)}</dd>${flash&&values.idea?.trim()?`<dt>Notes / requests</dt><dd style="white-space:pre-wrap">${escape(values.idea)}</dd>`:''}<dt>Placement and size</dt><dd>${escape(values.placement)}${values.size?` · ${escape(values.size)}`:''}</dd></dl><p class="note">Your artist will contact you after reviewing your request. No payment is collected here.</p><p id="send-error" class="error" role="alert"></p><div class="form-actions"><button class="secondary" id="edit-request">Edit</button><button class="primary" id="send-request" ${demo?'disabled':''}>${demo?'Preview only':'Send request'}</button></div>`); 492 if(values.images?.length)document.querySelector('.review').insertAdjacentHTML('afterend',`<div class="request-images">${values.images.map((image,index)=>`<img src="${image}" alt="Reference image ${index+1}">`).join('')}</div>`); 493 document.querySelector('#edit-request').onclick=()=>bookingForm(slot,flash,values); 494 document.querySelector('#send-request').onclick=async event=>{const button=event.currentTarget;button.disabled=true;button.textContent='Sendingâ¦';document.querySelector('#edit-request').disabled=true;try{await api(`/api/profiles/${encodeURIComponent(profile.username.toLowerCase())}/requests`,{method:'POST',headers:{'content-type':'application/json'},body:JSON.stringify(values)});showDialog(`<div class="success-mark" aria-hidden="true">â</div><h2 id="dialog-title">Request sent</h2><p class="detail-copy">${escape(profile.name||profile.username)} will review your request and contact you using the details you provided.
494</p><p class="note">Your appointment is not confirmed yet.</p><button class="primary full" id="done">Done</button>`);document.querySelector('#done').onclick=closeDialogFromPointer;}catch(error){document.querySelector('#send-error').textContent=error.message;button.disabled=false;button.textContent='Try again';document.querySelector('#edit-request').disabled=false;}}; 495} 496function demoProfile(){const start=new Date();start.setDate(start.getDate()+2);start.setHours(10,0,0,0);return {username:'yourusername',name:'Your artist profile',bio:'Your profile bio, portfolio, flash, and public contact details will appear here just as they do in TattSafe.',tabs:['flash','portfolio','contact','book'],image:null,banner:null,timezone:'America/Chicago',links:[],shop:null,portfolio:[],flash:[],slots:Array.from({length:8},(_,i)=>{const time=start.getTime()+i*86400000;return {id:`preview~${time}`,start:new Date(time).toISOString(),end:new Date(time+7200000).toISOString()};})};} 497let agentToolsRegistered=false; 498function registerAgentTools(){ 499 if(profile.deferred)return; 500 if(agentToolsRegistered||!document.modelContext?.registerTool)return; 501 agentToolsRegistered=true; 502 const lifecycle=new AbortController();window.addEventListener('pagehide',()=>lifecycle.abort(),{once:true}); 503 const tools=[{name:'read_artist_booking_options',description:'Read this artistâs public booking dates and flash options.',inputSchema:{type:'object',properties:{},additionalProperties:false},annotations:{readOnlyHint:true,untrustedContentHint:true},execute:()=>({username:profile.username,timezone:profile.timezone,slots:profile.slots,flash:profile.flash.map(({id,title,placements})=>({id,title,placements}))})},{name:'start_tattoo_booking_request',description:'Open the tattoo request form for a current slot. This does not submit a request; the client reviews and sends it in the page.',inputSchema:{type:'object',properties:{slotId:{type:'string'},flashId:{type:'string'}},required:['slotId'],additionalProperties:false},annotations:{readOnlyHint:false,untrustedContentHint:true},execute:input=>{const slot=profile.slots.find(s=>s.id===input?.slotId),flash=input?.flashId?profile.flash.find(f=>f.id===input.flashId):null;if(!slot||input?.flashId&&!flash||!flash&&!profile.tabs.includes('book'))throw new Error('Choose an available booking option.');bookingForm(slot,flash);return {opened:true,submitted:false};}}]; 504 for(const tool of tools){try{Promise.resolve(document.modelContext.registerTool(tool,{signal:lifecycle.signal})).catch(()=>{});}catch{}} 505} 506// BEGIN CONFIRMATION RETURN NAVIGATION 507function confirmationPortalDestination(token,href){ 508 const destination=new URL(href,location.href); 509 if(!/^[a-f0-9]{64}$/.test(token)||destination.origin!==location.origin)return href; 510 let reference=token; 511 try { 512 reference=crypto.randomUUID(); 513 sessionStorage.setItem('tattsafe.confirmationReturn.'+reference,token); 514 } catch { reference=token; } 515 // The usual URL holds only a tab-local reference. Storage-restricted browsers 516 // keep the capability in the fragment, never in a server request or referrer. 517 destination.hash='appointment-return='+reference; 518 return destination.href; 519} 520function confirmationReturnToken(){ 521 const reference=new URLSearchParams(location.hash.slice(1)).get('appointment-return'); 522 if(!reference)return null; 523 if(/^[a-f0-9]{64}$/.test(reference))return reference; 524 if(!/^[a-f0-9-]{36}$/.test(reference))return null; 525 try { 526 const token=sessionStorage.getItem('tattsafe.confirmationReturn.'+reference); 527 return /^[a-f0-9]{64}$/.test(token||'')?token:null; 528 } catch { return null; } 529} 530function showConfirmationReturn(){ 531 const token=confirmationReturnToken(); 532 if(!token)return; 533 const bar=document.querySelector('.topbar'); 534 if(!bar||bar.querySelector('.confirmation-return'))return; 535 const link=document.createElement('a'); 536 link.className='confirmation-return'; 537 link.href='/confirmation#'+token; 538 link.textContent='â¹ Back to appointment'; 539 bar.prepend(link); 540 bar.classList.add('has-confirmation-return'); 541} 542// END CONFIRMATION RETURN NAVIGATION 543async function loadConfirmation(){ 544 document.title='Your appointment · TattSafe';
545 const target=document.querySelector('#app'); 546 const token=location.hash.slice(1); 547 let generation=0; 548 const render=async()=>{ 549 const requestGeneration=++generation; 550 target.setAttribute('aria-busy','true'); 551 try { 552 const result=await api('/api/confirmation',{method:'POST',headers:{'content-type':'application/json'},body:JSON.stringify({token})}); 553 if(requestGeneration!==generation)return; 554 target.innerHTML=result.markup; 555 const artistLink=target.querySelector('a.confirmation-artist'); 556 if(artistLink)artistLink.href=confirmationPortalDestination(token,artistLink.href); 557 } catch(error){if(requestGeneration!==generation)return;target.innerHTML='<div class="message"><h1>Confirmation unavailable</h1><p></p><button class="secondary">Try again</button></div>';target.querySelector('p').textContent=error.message;target.querySelector('button').onclick=render;} 558 target.setAttribute('aria-busy','false'); 559 }; 560 await render(); 561 // Re-check after returning from a payment app; never retain a stale page from the back/forward cache. 562 window.addEventListener('pageshow',event=>{if(event.persisted)render();}); 563 document.addEventListener('visibilitychange',()=>{if(document.visibilityState==='visible')render();}); 564} 565if(location.pathname==='/confirmation')loadConfirmation();else {showConfirmationReturn();load();} 566 567// Placement summaries are display-only; booking retains the artist's exact allowed sides. 568function flashPlacementLabels(placements=[]){ 569 const allowed=new Set(placements); 570 if(!allowed.size||allowed.has('Anywhere'))return ['Anywhere']; 571 const labels=[]; 572 for(const region of allowed){ 573 const match=/^(Arm|Leg|Hand|Foot) \((Left|Right)\)$/.exec(region); 574 let label=region; 575 if(match){ 576 const part=match[1]; 577 label=allowed.has(part+' (Left)')&&allowed.has(part+' (Right)')?'Either '+part.toLowerCase():match[2]+' '+part.toLowerCase(); 578 }else if(region==='Torso (Front)')label='Front torso'; 579 else if(region==='Torso (Back)')label='Back'; 580 if(!labels.includes(label))labels.push(label); 581 } 582 return labels; 583} 584function flashPlacementSummary(flash){ 585 return `<section class="flash-placement-summary">${flash.width&&flash.height?`<h3>Tattoo size</h3><p>${escape(flash.width)} Ã ${escape(flash.height)} inches</p>`:''}<h3>Where can this design go?</h3><ul class="flash-placement-chips">${flashPlacementLabels(flash.placements).map(label=>`<li>${escape(label)}</li>`).join('')}</ul><p class="note">Choose your preferred placement when booking.</p></section>`; 586} 587 588let flashScrollHintDismissed=false; 589function installFlashScrollHint(){ 590 try{flashScrollHintDismissed ||= localStorage.getItem('flashScrollHintDismissed')==='true';}catch{} 591 if(flashScrollHintDismissed)return; 592 const hint=document.createElement('button'); 593 hint.type='button';hint.className='flash-scroll-hint';hint.textContent='More details below â'; 594 hint.setAttribute('aria-label','Scroll down for more tattoo details'); 595 dialog.append(hint); 596 const startingScroll=dialog.scrollTop; 597 const dismissHint=()=>{ 598 flashScrollHintDismissed=true; 599 try{localStorage.setItem('flashScrollHintDismissed','true');}catch{} 600 dialogScrollCleanup(); 601 }; 602 const update=()=>{ 603 const atBottom=dialog.scrollHeight-dialog.clientHeight-dialog.scrollTop<=8; 604 hint.classList.toggle('is-hidden',atBottom);hint.disabled=atBottom; 605 hint.setAttribute('aria-hidden',String(atBottom)); 606 }; 607 const onScroll=()=>{if(Math.abs(dialog.scrollTop-startingScroll)>1)dismissHint();}; 608 hint.onclick=()=>{ 609 dismissHint(); 610 dialog.scrollBy({top:Math.max(120,dialog.clientHeight*.65),behavior:matchMedia('(prefers-reduced-motion: reduce)').matches?'auto':'smooth'}); 611 }; 612 dialog.addEventListener('scroll',onScroll,{passive:true}); 613 detail.addEventListener('load',update,true); 614 const observer=new ResizeObserver(update);observer.observe(detail);observer.observe(dialog); 615 dialogScrollCleanup=()=>{observer.disconnect();dialog.removeEventListener('scroll',onScroll);detail.removeEventListener('load',update,true);hint.remove();dialogScrollCleanup=()=>{};}; 616 update(); 617} 618dialog.addEventListener('close',()=>{if(!dialog.open)dialogScrollCleanup();}); 619 620 621let portalInstallPrompt=null; 622let portalInstalled=false; 623const portalIsStandalone=()=>portalInstalled||matchMedia('(display-mode: standalone)').matches||navigator.standalone===true; 624window.addEventListener('beforeinstallprompt',event=>{ 625 event.preventDefault();portalInstallPrompt=event; 626 const button=document.querySelector('.portal-install-guide #install-portal');if(button&&!portalIsStandalone())button.hidden=false; 627}); 628window.addEventListener('appinstalled',()=>{ 629 portalInstalled=true;portalInstallPrompt=null; 630 const button=document.querySelector('#install-portal');if(button)button.hidden=true;
631 const status=document.querySelector('#portal-share-status');if(status)status.textContent='Added to your Home Screen.'; 632}); 633async function addPortalToHomeScreen(button,status){ 634 if(portalIsStandalone()){button.hidden=true;return;} 635 if(portalInstallPrompt){ 636 const prompt=portalInstallPrompt;portalInstallPrompt=null;button.disabled=true; 637 try{ 638 await prompt.prompt();const choice=await prompt.userChoice; 639 status.textContent=choice.outcome==='accepted'?'Installation requested. Check your Home Screen.':'You can add this portal later from your browser menu.'; 640 }catch{status.textContent='Open your browser menu and choose Add to Home screen or Install app.';} 641 finally{button.disabled=false;} 642 return; 643 } 644 const apple=/iPhone|iPad|iPod/.test(navigator.userAgent)||(navigator.platform==='MacIntel'&&navigator.maxTouchPoints>1); 645 const android=/Android/i.test(navigator.userAgent); 646 status.textContent=apple?'In Safari, tap the browserâs Share button, then More or View More if needed, and Add to Home Screen. Keep Open as Web App enabled if shown, then tap Add. If you opened this link inside another app, open it in Safari first.':android?'Open your browserâs menu (â®), then choose Add to Home screen or Install app and confirm. If you opened this link inside another app, open it in Chrome first.':'Open your browserâs menu and look for Install app or Add to Home Screen. This option depends on your browser.'; 647 status.scrollIntoView({block:'nearest',behavior:'smooth'}); 648} 649 650function showPortalInstallGuide(){ 651 const apple=/iPhone|iPad|iPod/.test(navigator.userAgent)||(navigator.platform==='MacIntel'&&navigator.maxTouchPoints>1); 652 const android=/Android/i.test(navigator.userAgent); 653 const iosSteps=`<li>Open this portal in <strong>Safari</strong>. From Instagram or another app, use its menu to open the page in your browser.</li><li>Tap Safariâs <strong>Share</strong> button <svg class="install-share-symbol" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" role="img" aria-label="square with an upward arrow"><path d="M12 15V3m-4 4 4-4 4 4M8 10H5v11h14V10h-3"/></svg>. If you donât see it, open the <strong>More (â¦)</strong> menu and look for <strong>Share</strong>. The menu may be at the bottom right; its location can vary on iPhone and iPad.</li><li>Choose <strong>Add to Home Screen</strong>. Tap <strong>More</strong> or <strong>View More</strong> first if needed.</li><li>Keep <strong>Open as Web App</strong> on if shown, then tap <strong>Add</strong>.</li>`; 654 const androidSteps=`<li>Open this portal in <strong>Chrome</strong> or <strong>Samsung Internet</strong>. If youâre inside another app, open the link in your browser first.</li><li>Tap the browserâs <strong>menu</strong> (â® or â°).</li><li>Choose <strong>Add to Home screen</strong> or <strong>Install app</strong>.</li><li>Confirm <strong>Install</strong> or <strong>Add</strong>, then look for the artistâs icon on your Home Screen.</li>`; 655 const card=(title,steps)=>`<section class="install-guide-card"><h3>${title}</h3><ol>${steps}</ol></section>`; 656 // Reuse the already loaded profile photo; generating the install icon requires a separate server round trip. 657 const icon=document.querySelector('.identity .avatar')?.currentSrc||profile.image||'/apple-touch-icon.png'; 658 showDialog(`<div class="portal-install-guide"><button class="install-back" id="install-back" aria-label="Back to QR actions"><svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m15 5-7 7 7 7"/></svg></button><div class="install-preview"><img src="${escape(icon)}" width="100" height="100" loading="eager" fetchpriority="high" alt="${escape(profile.username)} Home Screen icon"><p>${escape(profile.username)}</p></div><p class="install-eyebrow">YOUR ARTIST, ON YOUR HOME SCREEN</p><h2 id="dialog-title">Install your artistâs app</h2><p class="install-intro">Keep this portal one tap away. Itâs free to add, with no app store download.</p><button class="primary full" id="install-portal"${!portalInstallPrompt||portalIsStandalone()?' hidden':''}>Install Your Artistâs App</button>
658<p id="portal-share-status" role="status"></p>${apple?card('Install on iPhone or iPad',iosSteps):android?card('Install on Android',androidSteps):card('Install on iPhone or iPad',iosSteps)+card('Install on Android',androidSteps)}<section class="install-guide-card install-explainer"><h3>What gets added?</h3><p>A shortcut to this artistâs live portal, with their photo and username. Supported browsers open it in its own app window.</p><ul><li>One-tap access to your artist</li><li>The latest portfolio, flash, and booking options your artist shares</li><li>Updates appear automatically when you open the portal</li></ul><p class="meta">An internet connection is required.</p></section><p class="install-footer">Already added? Open the artistâs icon from your Home Screen.</p></div>`); 659 const button=detail.querySelector('#install-portal'),status=detail.querySelector('#portal-share-status'); 660 button.onclick=()=>addPortalToHomeScreen(button,status); 661 detail.querySelector('#install-back').onclick=showPortalShare; 662 detail.querySelector('.install-preview img').onerror=function(){this.onerror=null;this.src='/apple-touch-icon.png';}; 663} 664 665function installPortalShare(){ 666 const header=document.querySelector('.topbar'); 667 if(!header||document.querySelector('#share-artist'))return; 668 const button=document.createElement('button'); 669 button.id='share-artist';button.className='portal-share-button';button.setAttribute('aria-label','Share this artist'); 670 button.innerHTML='<svg width="23" height="23" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" aria-hidden="true"><rect x="3" y="3" width="6" height="6" rx=".5"/><rect x="15" y="3" width="6" height="6" rx=".5"/><rect x="3" y="15" width="6" height="6" rx=".5"/><path d="M15 13v4h4v4h2M13 21h2M21 13v2M12 3v3M3 12h3m6-3v3h4"/></svg>'; 671 button.onclick=showPortalShare;header.append(button); 672} 673async function showPortalShare(){ 674 // Share only the public profile, never an appointment token or return reference. 675 const url=new URL('/'+encodeURIComponent(profile.username.toLowerCase()),location.origin).href; 676 showDialog(`<div class="portal-share-sheet">${profile.image?`<img class="share-avatar" src="${escape(profile.image)}" alt="">`:''}<h3 id="dialog-title">${escape(profile.name||profile.username)}</h3><p class="meta">@${escape(profile.username)}</p><div id="portal-qr"><p>Loading QR codeâ¦</p></div><a class="share-url" href="${escape(url)}">${escape(url)}</a><p>Scan to view this artistâs portal</p><button class="primary full" id="share-portal-link">Share link</button><button class="primary full" id="copy-portal-link">Copy link</button><button class="primary full" id="install-portal"${portalIsStandalone()?' hidden':''}>Install Your Artistâs App</button><p id="portal-share-status" role="status"></p></div>`); 677 const status=detail.querySelector('#portal-share-status'); 678 const installButton=detail.querySelector('#install-portal'); 679 installButton.onclick=showPortalInstallGuide; 680 const copy=async()=>{try{await navigator.clipboard.writeText(url);status.textContent='Link copied';}catch{status.textContent='Touch and hold the link beneath the QR code to copy it.';}}; 681 detail.querySelector('#copy-portal-link').onclick=copy; 682 detail.querySelector('#share-portal-link').onclick=async()=>{ 683 if(!navigator.share){await copy();return;} 684 try{await navigator.share({title:profile.username,url});} 685 catch(error){if(error.name!=='AbortError')status.textContent='Couldnât share. Try Copy link instead.';} 686 }; 687 const container=detail.querySelector('#portal-qr'); 688 try{ 689 const QR=PortalQR; 690 const canvas=document.createElement('canvas'); 691 await QR.toCanvas(canvas,url,{width:320,margin:4,errorCorrectionLevel:'M',color:{dark:'#000000',light:'#ffffff'}}); 692 canvas.style.removeProperty('width');canvas.style.removeProperty('height'); 693 canvas.setAttribute('role','img');canvas.setAttribute('aria-label','QR code for the artist portal');container.replaceChildren(canvas); 694 }catch{container.textContent='QR code unavailable. You can still share or copy the portal link.';} 695} 696 697function eventCards(events){ 698 return events.length?events.map(event=>`<a class="event-summary" href="#event/${encodeURIComponent(event.id)}" data-event-id="${escape(event.id)}">${event.coverImage?`<img class="event-summary-banner" src="${escape(event.coverImage)}" alt="" loading="lazy">`:''}<div class="event-summary-details"><div><h2>${escape(event.name)}</h2><p class="event-summary-date">
698${escape(new Date(event.startsAt).toLocaleString([], {timeZone:event.timezone||'UTC',dateStyle:'medium',timeStyle:'short'}))}</p><p class="event-summary-location">${escape(event.location)}</p></div><span class="event-summary-chevron" aria-hidden="true">âº</span></div></a>`).join(''):'<p class="empty-state">No public events yet.</p>'; 699} 700async function renderProfileEvents(content){ 701 const id=profileEventID(location.hash); 702 content.dataset.eventID=id||''; 703 const request=String(Number(content.dataset.request||0)+1);content.dataset.request=request; 704 if(!id){ 705 content.innerHTML=eventCards(profile.events||[]);content.dataset.ready='true'; 706 content.querySelectorAll('[data-event-id]').forEach(link=>link.onclick=event=>{ 707 if(event.metaKey||event.ctrlKey||event.shiftKey||event.altKey)return; 708 event.preventDefault();history.pushState(null,'',link.getAttribute('href')); 709 delete content.dataset.ready;renderProfileEvents(content); 710 }); 711 return; 712 } 713 content.dataset.loading='true';content.innerHTML='<p class="message" role="status">Loading eventâ¦</p>'; 714 try{ 715 const event=await api(`/api/events/${encodeURIComponent(id)}`); 716 if(content.dataset.request!==request)return; 717 renderEventContent(event,content,true);content.dataset.ready='true'; 718 }catch(error){ 719 if(content.dataset.request!==request)return; 720 content.innerHTML=`<p class="message">${escape(error.message)}</p><button class="secondary">Try again</button>`; 721 content.querySelector('button').onclick=()=>renderProfileEvents(content); 722 }finally{if(content.dataset.request===request)delete content.dataset.loading;} 723} 724window.addEventListener('popstate',()=>{ 725 if(!profile)return; 726 const tab=profileEventID(location.hash)?'event':location.hash.slice(1); 727 if(!profile.tabs.includes(tab))return; 728 activeTab=tab; 729 const panel=tabPanels.get('event');if(tab==='event'&&panel&&(panel.dataset.eventID||'')!==(profileEventID(location.hash)||'')){delete panel.dataset.ready;delete panel.dataset.loading;panel.dataset.request=String(Number(panel.dataset.request||0)+1);} 730 document.querySelectorAll('[data-tab]').forEach(b=>{b.setAttribute('aria-selected',String(b.dataset.tab===tab));b.tabIndex=b.dataset.tab===tab?0:-1;}); 731 renderTab(); 732}); 733async function loadEventPage(id){ 734 const initial=document.querySelector('#initial-event'); 735 const event=initial?JSON.parse(initial.textContent):await api(`/api/events/${encodeURIComponent(id)}`); 736 const host=event.artists.find(a=>a.isOrganizer&&a.portalURL)||event.artists.find(a=>a.portalURL); 737 if(host){location.replace(`${host.portalURL}#event/${encodeURIComponent(id)}`);return;} 738 document.title=`${event.name} · TattSafe`;app.setAttribute('aria-busy','false'); 739 renderEventContent(event,app,false); 740} 741function eventLocationMarkup(event){ 742 const a=event.address||{}; 743 const address=[a.street,a.city,[a.region,a.postalCode].filter(Boolean).join(' '),a.country].filter(Boolean).join(', '); 744 const query=address||event.location||(Number.isFinite(a.latitude)&&Number.isFinite(a.longitude)?`${a.latitude},${a.longitude}`:''); 745 if(!query)return ''; 746 const title=a.venueName||event.venueName||(event.location&&event.location!==address?event.location:'Open in Maps'); 747 return renderLocationMarkup({title,address:address||event.location||'',latitude:a.latitude,longitude:a.longitude},{label:'Tattoo Shop',query,showTitle:false}); 748} 749function eventFlashPrice(flash){ 750 return flash.isGuestSheet&&flash.maximumPriceCents!==flash.minimumPriceCents?`${money(flash.minimumPriceCents/100)} â ${money(flash.maximumPriceCents/100)}`:money(flash.priceCents/100); 751} 752function eventFlashDetailsMarkup(flash,event){ 753 if(flash.isGuestSheet){ 754 const artist=event.artists.find(a=>a.id===flash.artistID); 755 return `<section class="event-flash-detail"><h2 id="dialog-title">${escape(flash.title)}</h2><img class="event-flash-large" src="${escape(flash.image)}" alt="${escape(flash.title)}"><h3>${escape(eventFlashPrice(flash))}</h3><p>Prices vary by design. Confirm your design and final price with the guest artist at the event.</p>${artist?`<div class="event-artists">
755${eventArtistMarkup(artist,event.id)}</div>`:''}</section>`; 756 } 757 758 const eligible=event.artists.filter(a=>(!a.isGuest||flash.individualDesign===true)&&(flash.eligibleArtistIDs||[flash.artistID]).includes(a.id)); 759 const original=Number.isSafeInteger(flash.originalPriceCents)?money(flash.originalPriceCents/100):'Not provided'; 760 const discount=Number.isSafeInteger(flash.discountBasisPoints)?`${(flash.discountBasisPoints/100).toLocaleString(undefined,{maximumFractionDigits:2})}% off`:'Not provided'; 761 const availability=eligible.length===1?'This design can be tattooed by the artist below.':eligible.length>1?'This design can be tattooed by any of the artists below.':'Ask the event organizer which artist can tattoo this design.'; 762 return `<section class="event-flash-detail"><h2 id="dialog-title">${escape(flash.title)}</h2>${flash.image?`<img class="event-flash-large" src="${escape(flash.image)}" alt="${escape(flash.title)}">`:'<p class="empty-state">Image unavailable</p>'}<dl class="event-flash-pricing"><div><dt>Original price</dt><dd>${escape(original)}</dd></div><div><dt>Discount</dt><dd>${escape(discount)}</dd></div><div class="event-flash-total"><dt>Event total</dt><dd>${escape(money(flash.priceCents/100))}</dd></div></dl>${flash.detail?`<p>${escape(flash.detail)}</p>`:''}${flash.individualDesign?`<dl class="event-flash-pricing"><div><dt>Minimum size</dt><dd>${flash.width&&flash.height?`${escape(flash.width)} à ${escape(flash.height)} in`:'Discuss with artist'}</dd></div><div><dt>Duration</dt><dd>${escape(flash.duration)} hours</dd></div><div><dt>Deposit</dt><dd>${escape(money(flash.deposit))}</dd></div><div><dt>Quantity</dt><dd>${flash.count===-1?'Unlimited':escape(flash.count)}</dd></div></dl>`:''}<h3>Who can tattoo this?</h3><p>${escape(availability)}</p><div class="event-artists">${eligible.map(a=>eventArtistMarkup(a,event.id)).join('')}</div><p class="note">Check in at the event to join the queue. Viewing a design does not reserve it.</p></section>`; 763} 764function showEventFlash(flash,event){showDialog(eventFlashDetailsMarkup(flash,event));} 765function renderEventContent(event,target,embedded){ 766 target.innerHTML=`<article class="event-page">${embedded?'<a class="event-back-link" href="#event" aria-label="Back to events"><svg viewBox="0 0 24 24" width="24" height="24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m15 5-7 7 7 7"/></svg></a>':''}<header class="event-hero">${event.coverImage?`<img class="event-cover" src="${escape(event.coverImage)}" alt="${escape(event.name)}">`:""}${embedded?'':'<a href="/">TattSafe Events</a>'}<p class="event-kicker">Tattoo Flash Event</p><h1>${escape(event.name)}</h1><div class="event-dates"><p class="event-date"><strong>Start</strong><span>${escape(new Date(event.startsAt).toLocaleString([], {timeZone:event.timezone||'UTC',dateStyle:'full',timeStyle:'short'}).replace(/\s+(?=[AP]M\b)/g,'\u00a0'))}</span></p><p class="event-date"><strong>End</strong><span>${escape(new Date(event.endsAt).toLocaleString([], {timeZone:event.timezone||'UTC',dateStyle:'full',timeStyle:'short'}).replace(/\s+(?=[AP]M\b)/g,'\u00a0'))}</span></p></div>${eventLocationMarkup(event)}<p class="event-description">${escape(event.details)}</p>${event.admission?`<p class="event-admission">${escape(event.admission)}</p>`:''}<p class="event-walkin">Check in at the event. This page does not reserve a place in the queue.</p></header><section class="event-section"><h2>Meet the Artists</h2><div class="event-artists">${event.artists.map(a=>eventArtistMarkup(a,event.id)).join('')}</div></section>${event.showFlash===false?'':`<section class="event-section"><div class="event-section-heading"><h2>Event Flash</h2><label>Artist <select id="event-artist"><option value="">All Artists</option>${event.artists.map(a=>`<option value="${escape(a.id)}">${escape(a.name)}</option>`).join('')}</select></label><label>Sort <select id="event-sort"><option value="title">Title AâZ</option><option value="low">Price: Low to High</option><option value="high">Price: High to Low</option></select></label></div><div id="event-flash" class="grid"></div></section>`}${event.activities.length?`<section class="event-section"><h2>What Else Is Happening</h2><div class="event-activities">${event.activities.map(a=>`<article>${(a.images??(a.image?[a.image]:[])).length?`<div class="event-vendor-gallery">${(a.images??[a.image]).map(src=>`<img class="event-vendor-image" src="${escape(src)}" alt="${escape(a.name)}" loading="lazy">`).join('')}</div>`:""}<p class="event-kicker">${escape(a.kind)}${a.time?` · ${escape(a.time)}`:''}</p><h3>${escape(a.name)}</h3><p>${escape(a.details)}</p><div class="event-links">${a.links.map(l=>`<a href="${escape(l.url)}" target="_blank" rel="noopener noreferrer">${escape(l.label)} â</a>`).join('')}</div></article>`).join('')}</div></section>`:''}</article>`; 767 target.querySelector('.event-back-link')?.addEventListener('click',event=>{ 768 if(event.metaKey||event.ctrlKey||event.shiftKey||event.altKey)return; 769 event.preventDefault();selectTab('event'); 770 }); 771 const render=()=>{ 772 const artist=target.querySelector('#event-artist').value,sort=target.querySelector('#event-sort').value; 773 const items=event.flash.filter(f=>!artist||f.artistID===artist).sort((a,b)=>sort==='low'?a.priceCents-b.priceCents:sort==='high'?b.priceCents-a.priceCents:a.title.localeCompare(b.title)); 774 target.querySelector('#event-flash').innerHTML=items.length?items.map(f=>`<button type="button" class="card event-flash-card" data-event-flash="${escape(f.id)}" aria-label="View ${escape(f.title)} details">${f.image?`<img src="${escape(f.image)}" alt="${escape(f.title)}" loading="lazy">`:'<div class="art-empty">Image unavailable</div>'}<div><h3>${escape(f.title)}</h3><p>
774${escape(eventFlashPrice(f))}</p><p>${escape(event.artists.find(a=>a.id===f.artistID)?.name||'')}</p></div></button>`).join(''):'<p class="empty-state">No event flash has been shared yet.</p>'; 775 target.querySelectorAll('[data-event-flash]').forEach(button=>button.onclick=()=>{ 776 const flash=items.find(f=>f.id===button.dataset.eventFlash); 777 if(flash)showEventFlash(flash,event); 778 }); 779 }; 780 if(event.showFlash!==false){target.querySelector('#event-artist').onchange=render;target.querySelector('#event-sort').onchange=render;render();} 781}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.