2026-09-23 12:27:35 -04:00
const B = globalThis , nt = B . ShadowRoot && ( B . ShadyCSS === void 0 || B . ShadyCSS . nativeShadow ) && "adoptedStyleSheets" in Document . prototype && "replace" in CSSStyleSheet . prototype , st = /* @__PURE__ */ Symbol (), lt = /* @__PURE__ */ new WeakMap ();
2026-09-20 14:19:39 -04:00
let zt = class {
constructor ( t , e , n ) {
2026-09-23 12:27:35 -04:00
if ( this . _$cssResult$ = ! 0 , n !== st ) throw Error ( "CSSResult is not constructable. Use `unsafeCSS` or `css` instead." );
2026-09-20 14:19:39 -04:00
this . cssText = t , this . t = e ;
2026-09-20 10:08:38 -04:00
}
get styleSheet () {
2026-09-20 14:19:39 -04:00
let t = this . o ;
const e = this . t ;
2026-09-20 18:39:11 -04:00
if ( nt && t === void 0 ) {
2026-09-20 14:19:39 -04:00
const n = e !== void 0 && e . length === 1 ;
2026-09-20 18:39:11 -04:00
n && ( t = lt . get ( e )), t === void 0 && (( this . o = t = new CSSStyleSheet ()). replaceSync ( this . cssText ), n && lt . set ( e , t ));
2026-09-20 10:08:38 -04:00
}
2026-09-20 14:19:39 -04:00
return t ;
2026-09-20 10:08:38 -04:00
}
toString () {
return this . cssText ;
}
};
2026-09-23 12:27:35 -04:00
const v = ( s ) => new zt ( typeof s == "string" ? s : s + "" , void 0 , st ), Pt = ( s , ... t ) => {
2026-09-20 19:17:52 -04:00
const e = s . length === 1 ? s [ 0 ] : t . reduce (( n , i , r ) => n + (( o ) => {
2026-09-20 13:54:14 -04:00
if ( o . _$cssResult$ === ! 0 ) return o . cssText ;
if ( typeof o == "number" ) return o ;
throw Error ( "Value passed to 'css' function must be a 'css' function result: " + o + ". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security." );
2026-09-20 19:17:52 -04:00
})( i ) + s [ r + 1 ], s [ 0 ]);
2026-09-23 12:27:35 -04:00
return new zt ( e , s , st );
}, Ft = ( s , t ) => {
2026-09-20 19:17:52 -04:00
if ( nt ) s . adoptedStyleSheets = t . map (( e ) => e instanceof CSSStyleSheet ? e : e . styleSheet );
2026-09-20 14:19:39 -04:00
else for ( const e of t ) {
2026-09-20 19:17:52 -04:00
const n = document . createElement ( "style" ), i = B . litNonce ;
i !== void 0 && n . setAttribute ( "nonce" , i ), n . textContent = e . cssText , s . appendChild ( n );
2026-09-20 10:08:38 -04:00
}
2026-09-20 19:17:52 -04:00
}, ct = nt ? ( s ) => s : ( s ) => s instanceof CSSStyleSheet ? (( t ) => {
2026-09-20 14:19:39 -04:00
let e = "" ;
for ( const n of t . cssRules ) e += n . cssText ;
2026-09-20 19:17:52 -04:00
return v ( e );
})( s ) : s ;
2026-09-23 12:27:35 -04:00
const { is : Qt , defineProperty : Wt , getOwnPropertyDescriptor : Zt , getOwnPropertyNames : Gt , getOwnPropertySymbols : Vt , getPrototypeOf : Kt } = Object , W = globalThis , dt = W . trustedTypes , Jt = dt ? dt . emptyScript : "" , Xt = W . reactiveElementPolyfillSupport , I = ( s , t ) => s , et = { toAttribute ( s , t ) {
2026-09-20 14:19:39 -04:00
switch ( t ) {
2026-09-20 10:08:38 -04:00
case Boolean :
2026-09-23 12:27:35 -04:00
s = s ? Jt : null ;
2026-09-20 10:08:38 -04:00
break ;
case Object :
case Array :
2026-09-20 19:17:52 -04:00
s = s == null ? s : JSON . stringify ( s );
2026-09-20 10:08:38 -04:00
}
2026-09-20 19:17:52 -04:00
return s ;
}, fromAttribute ( s , t ) {
let e = s ;
2026-09-20 14:19:39 -04:00
switch ( t ) {
2026-09-20 10:08:38 -04:00
case Boolean :
2026-09-20 19:17:52 -04:00
e = s !== null ;
2026-09-20 10:08:38 -04:00
break ;
case Number :
2026-09-20 19:17:52 -04:00
e = s === null ? null : Number ( s );
2026-09-20 10:08:38 -04:00
break ;
case Object :
case Array :
try {
2026-09-20 19:17:52 -04:00
e = JSON . parse ( s );
2026-09-20 10:08:38 -04:00
} catch {
2026-09-20 14:19:39 -04:00
e = null ;
2026-09-20 10:08:38 -04:00
}
}
2026-09-20 14:19:39 -04:00
return e ;
2026-09-23 12:27:35 -04:00
} }, It = ( s , t ) => ! Qt ( s , t ), pt = { attribute : ! 0 , type : String , converter : et , reflect : ! 1 , useDefault : ! 1 , hasChanged : It };
2026-09-20 18:39:11 -04:00
Symbol . metadata ??= /* @__PURE__ */ Symbol ( "metadata" ), W . litPropertyMetadata ??= /* @__PURE__ */ new WeakMap ();
2026-09-20 19:17:52 -04:00
let E = class extends HTMLElement {
2026-09-20 14:19:39 -04:00
static addInitializer ( t ) {
this . _$Ei (), ( this . l ??= []). push ( t );
2026-09-20 10:08:38 -04:00
}
static get observedAttributes () {
return this . finalize (), this . _$Eh && [... this . _$Eh . keys ()];
}
2026-09-20 18:39:11 -04:00
static createProperty ( t , e = pt ) {
2026-09-20 14:19:39 -04:00
if ( e . state && ( e . attribute = ! 1 ), this . _$Ei (), this . prototype . hasOwnProperty ( t ) && (( e = Object . create ( e )). wrapped = ! 0 ), this . elementProperties . set ( t , e ), ! e . noAccessor ) {
2026-09-20 19:17:52 -04:00
const n = /* @__PURE__ */ Symbol (), i = this . getPropertyDescriptor ( t , n , e );
2026-09-23 12:27:35 -04:00
i !== void 0 && Wt ( this . prototype , t , i );
2026-09-20 10:08:38 -04:00
}
}
2026-09-20 14:19:39 -04:00
static getPropertyDescriptor ( t , e , n ) {
2026-09-23 12:27:35 -04:00
const { get : i , set : r } = Zt ( this . prototype , t ) ?? { get () {
2026-09-20 14:19:39 -04:00
return this [ e ];
2026-09-20 13:54:14 -04:00
}, set ( o ) {
2026-09-20 14:19:39 -04:00
this [ e ] = o ;
2026-09-20 10:08:38 -04:00
} };
2026-09-20 19:17:52 -04:00
return { get : i , set ( o ) {
const l = i ? . call ( this );
2026-09-20 14:19:39 -04:00
r ? . call ( this , o ), this . requestUpdate ( t , l , n );
2026-09-20 10:08:38 -04:00
}, configurable : ! 0 , enumerable : ! 0 };
}
2026-09-20 14:19:39 -04:00
static getPropertyOptions ( t ) {
2026-09-20 18:39:11 -04:00
return this . elementProperties . get ( t ) ?? pt ;
2026-09-20 10:08:38 -04:00
}
static _$Ei () {
2026-09-20 18:39:11 -04:00
if ( this . hasOwnProperty ( I ( "elementProperties" ))) return ;
2026-09-23 12:27:35 -04:00
const t = Kt ( this );
2026-09-20 14:19:39 -04:00
t . finalize (), t . l !== void 0 && ( this . l = [... t . l ]), this . elementProperties = new Map ( t . elementProperties );
2026-09-20 10:08:38 -04:00
}
static finalize () {
2026-09-20 18:39:11 -04:00
if ( this . hasOwnProperty ( I ( "finalized" ))) return ;
if ( this . finalized = ! 0 , this . _$Ei (), this . hasOwnProperty ( I ( "properties" ))) {
2026-09-23 12:27:35 -04:00
const e = this . properties , n = [... Gt ( e ), ... Vt ( e )];
2026-09-20 19:17:52 -04:00
for ( const i of n ) this . createProperty ( i , e [ i ]);
2026-09-20 10:08:38 -04:00
}
2026-09-20 14:19:39 -04:00
const t = this [ Symbol . metadata ];
if ( t !== null ) {
const e = litPropertyMetadata . get ( t );
2026-09-20 19:17:52 -04:00
if ( e !== void 0 ) for ( const [ n , i ] of e ) this . elementProperties . set ( n , i );
2026-09-20 10:08:38 -04:00
}
this . _$Eh = /* @__PURE__ */ new Map ();
2026-09-20 14:19:39 -04:00
for ( const [ e , n ] of this . elementProperties ) {
2026-09-20 19:17:52 -04:00
const i = this . _$Eu ( e , n );
i !== void 0 && this . _$Eh . set ( i , e );
2026-09-20 10:08:38 -04:00
}
this . elementStyles = this . finalizeStyles ( this . styles );
}
2026-09-20 14:19:39 -04:00
static finalizeStyles ( t ) {
const e = [];
if ( Array . isArray ( t )) {
const n = new Set ( t . flat ( 1 / 0 ). reverse ());
2026-09-20 19:17:52 -04:00
for ( const i of n ) e . unshift ( ct ( i ));
} else t !== void 0 && e . push ( ct ( t ));
2026-09-20 14:19:39 -04:00
return e ;
2026-09-20 10:08:38 -04:00
}
2026-09-20 14:19:39 -04:00
static _$Eu ( t , e ) {
const n = e . attribute ;
return n === ! 1 ? void 0 : typeof n == "string" ? n : typeof t == "string" ? t . toLowerCase () : void 0 ;
2026-09-20 10:08:38 -04:00
}
constructor () {
super (), this . _$Ep = void 0 , this . isUpdatePending = ! 1 , this . hasUpdated = ! 1 , this . _$Em = null , this . _$Ev ();
}
_$Ev () {
2026-09-20 14:19:39 -04:00
this . _$ES = new Promise (( t ) => this . enableUpdating = t ), this . _$AL = /* @__PURE__ */ new Map (), this . _$E_ (), this . requestUpdate (), this . constructor . l ? . forEach (( t ) => t ( this ));
2026-09-20 10:08:38 -04:00
}
2026-09-20 14:19:39 -04:00
addController ( t ) {
( this . _$EO ??= /* @__PURE__ */ new Set ()). add ( t ), this . renderRoot !== void 0 && this . isConnected && t . hostConnected ? .();
2026-09-20 10:08:38 -04:00
}
2026-09-20 14:19:39 -04:00
removeController ( t ) {
this . _$EO ? . delete ( t );
2026-09-20 10:08:38 -04:00
}
_$E_ () {
2026-09-20 14:19:39 -04:00
const t = /* @__PURE__ */ new Map (), e = this . constructor . elementProperties ;
for ( const n of e . keys ()) this . hasOwnProperty ( n ) && ( t . set ( n , this [ n ]), delete this [ n ]);
t . size > 0 && ( this . _$Ep = t );
2026-09-20 10:08:38 -04:00
}
createRenderRoot () {
2026-09-20 14:19:39 -04:00
const t = this . shadowRoot ?? this . attachShadow ( this . constructor . shadowRootOptions );
2026-09-23 12:27:35 -04:00
return Ft ( t , this . constructor . elementStyles ), t ;
2026-09-20 10:08:38 -04:00
}
connectedCallback () {
2026-09-20 14:19:39 -04:00
this . renderRoot ??= this . createRenderRoot (), this . enableUpdating ( ! 0 ), this . _$EO ? . forEach (( t ) => t . hostConnected ? .());
2026-09-20 10:08:38 -04:00
}
2026-09-20 14:19:39 -04:00
enableUpdating ( t ) {
2026-09-20 10:08:38 -04:00
}
disconnectedCallback () {
2026-09-20 14:19:39 -04:00
this . _$EO ? . forEach (( t ) => t . hostDisconnected ? .());
2026-09-20 10:08:38 -04:00
}
2026-09-20 14:19:39 -04:00
attributeChangedCallback ( t , e , n ) {
this . _$AK ( t , n );
2026-09-20 10:08:38 -04:00
}
2026-09-20 14:19:39 -04:00
_$ET ( t , e ) {
2026-09-20 19:17:52 -04:00
const n = this . constructor . elementProperties . get ( t ), i = this . constructor . _$Eu ( t , n );
if ( i !== void 0 && n . reflect === ! 0 ) {
2026-09-20 18:39:11 -04:00
const r = ( n . converter ? . toAttribute !== void 0 ? n . converter : et ). toAttribute ( e , n . type );
2026-09-20 19:17:52 -04:00
this . _$Em = t , r == null ? this . removeAttribute ( i ) : this . setAttribute ( i , r ), this . _$Em = null ;
2026-09-20 10:08:38 -04:00
}
}
2026-09-20 14:19:39 -04:00
_$AK ( t , e ) {
2026-09-20 19:17:52 -04:00
const n = this . constructor , i = n . _$Eh . get ( t );
if ( i !== void 0 && this . _$Em !== i ) {
const r = n . getPropertyOptions ( i ), o = typeof r . converter == "function" ? { fromAttribute : r . converter } : r . converter ? . fromAttribute !== void 0 ? r . converter : et ;
this . _$Em = i ;
2026-09-20 14:19:39 -04:00
const l = o . fromAttribute ( e , r . type );
2026-09-20 19:17:52 -04:00
this [ i ] = l ?? this . _$Ej ? . get ( i ) ?? l , this . _$Em = null ;
2026-09-20 10:08:38 -04:00
}
}
2026-09-20 19:17:52 -04:00
requestUpdate ( t , e , n , i = ! 1 , r ) {
2026-09-20 14:19:39 -04:00
if ( t !== void 0 ) {
2026-09-20 13:54:14 -04:00
const o = this . constructor ;
2026-09-20 19:17:52 -04:00
if ( i === ! 1 && ( r = this [ t ]), n ??= o . getPropertyOptions ( t ), ! (( n . hasChanged ?? It )( r , e ) || n . useDefault && n . reflect && r === this . _$Ej ? . get ( t ) && ! this . hasAttribute ( o . _$Eu ( t , n )))) return ;
2026-09-20 14:19:39 -04:00
this . C ( t , e , n );
2026-09-20 10:08:38 -04:00
}
this . isUpdatePending === ! 1 && ( this . _$ES = this . _$EP ());
}
2026-09-20 19:17:52 -04:00
C ( t , e , { useDefault : n , reflect : i , wrapped : r }, o ) {
n && ! ( this . _$Ej ??= /* @__PURE__ */ new Map ()). has ( t ) && ( this . _$Ej . set ( t , o ?? e ?? this [ t ]), r !== ! 0 || o !== void 0 ) || ( this . _$AL . has ( t ) || ( this . hasUpdated || n || ( e = void 0 ), this . _$AL . set ( t , e )), i === ! 0 && this . _$Em !== t && ( this . _$Eq ??= /* @__PURE__ */ new Set ()). add ( t ));
2026-09-20 10:08:38 -04:00
}
async _$EP () {
this . isUpdatePending = ! 0 ;
try {
await this . _$ES ;
2026-09-20 14:19:39 -04:00
} catch ( e ) {
Promise . reject ( e );
2026-09-20 10:08:38 -04:00
}
2026-09-20 14:19:39 -04:00
const t = this . scheduleUpdate ();
return t != null && await t , ! this . isUpdatePending ;
2026-09-20 10:08:38 -04:00
}
scheduleUpdate () {
return this . performUpdate ();
}
performUpdate () {
if ( ! this . isUpdatePending ) return ;
if ( ! this . hasUpdated ) {
if ( this . renderRoot ??= this . createRenderRoot (), this . _$Ep ) {
2026-09-20 19:17:52 -04:00
for ( const [ i , r ] of this . _$Ep ) this [ i ] = r ;
2026-09-20 10:08:38 -04:00
this . _$Ep = void 0 ;
}
2026-09-20 12:39:47 -04:00
const n = this . constructor . elementProperties ;
2026-09-20 19:17:52 -04:00
if ( n . size > 0 ) for ( const [ i , r ] of n ) {
const { wrapped : o } = r , l = this [ i ];
o !== ! 0 || this . _$AL . has ( i ) || l === void 0 || this . C ( i , void 0 , r , l );
2026-09-20 10:08:38 -04:00
}
}
2026-09-20 14:19:39 -04:00
let t = ! 1 ;
const e = this . _$AL ;
2026-09-20 10:08:38 -04:00
try {
2026-09-20 14:19:39 -04:00
t = this . shouldUpdate ( e ), t ? ( this . willUpdate ( e ), this . _$EO ? . forEach (( n ) => n . hostUpdate ? .()), this . update ( e )) : this . _$EM ();
2026-09-20 12:39:47 -04:00
} catch ( n ) {
2026-09-20 14:19:39 -04:00
throw t = ! 1 , this . _$EM (), n ;
2026-09-20 10:08:38 -04:00
}
2026-09-20 14:19:39 -04:00
t && this . _$AE ( e );
2026-09-20 10:08:38 -04:00
}
2026-09-20 14:19:39 -04:00
willUpdate ( t ) {
2026-09-20 10:08:38 -04:00
}
2026-09-20 14:19:39 -04:00
_$AE ( t ) {
this . _$EO ? . forEach (( e ) => e . hostUpdated ? .()), this . hasUpdated || ( this . hasUpdated = ! 0 , this . firstUpdated ( t )), this . updated ( t );
2026-09-20 10:08:38 -04:00
}
_$EM () {
this . _$AL = /* @__PURE__ */ new Map (), this . isUpdatePending = ! 1 ;
}
get updateComplete () {
return this . getUpdateComplete ();
}
getUpdateComplete () {
return this . _$ES ;
}
2026-09-20 14:19:39 -04:00
shouldUpdate ( t ) {
2026-09-20 10:08:38 -04:00
return ! 0 ;
}
2026-09-20 14:19:39 -04:00
update ( t ) {
this . _$Eq &&= this . _$Eq . forEach (( e ) => this . _$ET ( e , this [ e ])), this . _$EM ();
2026-09-20 10:08:38 -04:00
}
2026-09-20 14:19:39 -04:00
updated ( t ) {
2026-09-20 10:08:38 -04:00
}
2026-09-20 14:19:39 -04:00
firstUpdated ( t ) {
2026-09-20 10:08:38 -04:00
}
};
2026-09-23 12:27:35 -04:00
E . elementStyles = [], E . shadowRootOptions = { mode : "open" }, E [ I ( "elementProperties" )] = /* @__PURE__ */ new Map (), E [ I ( "finalized" )] = /* @__PURE__ */ new Map (), Xt ? .({ ReactiveElement : E }), ( W . reactiveElementVersions ??= []). push ( "2.1.2" );
const it = globalThis , ht = ( s ) => s , F = it . trustedTypes , ut = F ? F . createPolicy ( "lit-html" , { createHTML : ( s ) => s }) : void 0 , Lt = "$lit$" , $ = `lit$ ${ Math . random (). toFixed ( 9 ). slice ( 2 ) } $` , Ut = "?" + $ , Yt = `< ${ Ut } >` , S = document , L = () => S . createComment ( "" ), U = ( s ) => s === null || typeof s != "object" && typeof s != "function" , rt = Array . isArray , te = ( s ) => rt ( s ) || typeof s ? .[ Symbol . iterator ] == "function" , V = `[
2026-09-20 19:17:52 -04:00
\f\r]` , z = /<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g , ft = /-->/g , mt = />/g , q = RegExp ( `>| ${ V } (?:([^\\s"'>=/]+)( ${ V } *= ${ V } *(?:[^
2026-09-23 12:27:35 -04:00
\f\r"'\`<>=]|("|')|))|$)` , "g" ), gt = /'/g , _t = /"/g , Rt = /^(?:script|style|textarea|title)$/i , ee = ( s ) => ( t , ... e ) => ({ _$litType$ : s , strings : t , values : e }), d = ee ( 1 ), T = /* @__PURE__ */ Symbol . for ( "lit-noChange" ), g = /* @__PURE__ */ Symbol . for ( "lit-nothing" ), yt = /* @__PURE__ */ new WeakMap (), C = S . createTreeWalker ( S , 129 );
function jt ( s , t ) {
2026-09-20 19:17:52 -04:00
if ( ! rt ( s ) || ! s . hasOwnProperty ( "raw" )) throw Error ( "invalid template strings array" );
2026-09-20 18:39:11 -04:00
return ut !== void 0 ? ut . createHTML ( t ) : t ;
2026-09-20 10:08:38 -04:00
}
2026-09-23 12:27:35 -04:00
const ne = ( s , t ) => {
2026-09-20 19:17:52 -04:00
const e = s . length - 1 , n = [];
let i , r = t === 2 ? "<svg>" : t === 3 ? "<math>" : "" , o = z ;
2026-09-20 14:19:39 -04:00
for ( let l = 0 ; l < e ; l ++ ) {
2026-09-20 19:17:52 -04:00
const a = s [ l ];
let p , u , c = - 1 , f = 0 ;
for (; f < a . length && ( o . lastIndex = f , u = o . exec ( a ), u !== null ); ) f = o . lastIndex , o === z ? u [ 1 ] === "!--" ? o = ft : u [ 1 ] !== void 0 ? o = mt : u [ 2 ] !== void 0 ? ( Rt . test ( u [ 2 ]) && ( i = RegExp ( "</" + u [ 2 ], "g" )), o = q ) : u [ 3 ] !== void 0 && ( o = q ) : o === q ? u [ 0 ] === ">" ? ( o = i ?? z , c = - 1 ) : u [ 1 ] === void 0 ? c = - 2 : ( c = o . lastIndex - u [ 2 ]. length , p = u [ 1 ], o = u [ 3 ] === void 0 ? q : u [ 3 ] === '"' ? _t : gt ) : o === _t || o === gt ? o = q : o === ft || o === mt ? o = z : ( o = q , i = void 0 );
const h = o === q && s [ l + 1 ]. startsWith ( "/>" ) ? " " : "" ;
2026-09-23 12:27:35 -04:00
r += o === z ? a + Yt : c >= 0 ? ( n . push ( p ), a . slice ( 0 , c ) + Lt + a . slice ( c ) + $ + h ) : a + $ + ( c === - 2 ? l : h );
2026-09-20 10:08:38 -04:00
}
2026-09-23 12:27:35 -04:00
return [ jt ( s , r + ( s [ e ] || "<?>" ) + ( t === 2 ? "</svg>" : t === 3 ? "</math>" : "" )), n ];
2026-09-20 10:08:38 -04:00
};
2026-09-20 19:17:52 -04:00
class R {
2026-09-20 14:19:39 -04:00
constructor ({ strings : t , _$litType$ : e }, n ) {
2026-09-20 19:17:52 -04:00
let i ;
2026-09-20 10:08:38 -04:00
this . parts = [];
2026-09-20 13:54:14 -04:00
let r = 0 , o = 0 ;
2026-09-23 12:27:35 -04:00
const l = t . length - 1 , a = this . parts , [ p , u ] = ne ( t , e );
2026-09-20 19:17:52 -04:00
if ( this . el = R . createElement ( p , n ), C . currentNode = this . el . content , e === 2 || e === 3 ) {
const c = this . el . content . firstChild ;
c . replaceWith (... c . childNodes );
2026-09-20 10:08:38 -04:00
}
2026-09-20 19:17:52 -04:00
for (; ( i = C . nextNode ()) !== null && a . length < l ; ) {
if ( i . nodeType === 1 ) {
if ( i . hasAttributes ()) for ( const c of i . getAttributeNames ()) if ( c . endsWith ( Lt )) {
const f = u [ o ++ ], h = i . getAttribute ( c ). split ( $ ), m = /([.?@])?(.*)/ . exec ( f );
2026-09-23 12:27:35 -04:00
a . push ({ type : 1 , index : r , name : m [ 2 ], strings : h , ctor : m [ 1 ] === "." ? ie : m [ 1 ] === "?" ? re : m [ 1 ] === "@" ? oe : Z }), i . removeAttribute ( c );
2026-09-20 19:17:52 -04:00
} else c . startsWith ( $ ) && ( a . push ({ type : 6 , index : r }), i . removeAttribute ( c ));
if ( Rt . test ( i . tagName )) {
const c = i . textContent . split ( $ ), f = c . length - 1 ;
2026-09-20 14:04:58 -04:00
if ( f > 0 ) {
2026-09-20 19:17:52 -04:00
i . textContent = F ? F . emptyScript : "" ;
for ( let h = 0 ; h < f ; h ++ ) i . append ( c [ h ], L ()), C . nextNode (), a . push ({ type : 2 , index : ++ r });
i . append ( c [ f ], L ());
2026-09-20 10:08:38 -04:00
}
}
2026-09-20 19:17:52 -04:00
} else if ( i . nodeType === 8 ) if ( i . data === Ut ) a . push ({ type : 2 , index : r });
2026-09-20 10:08:38 -04:00
else {
2026-09-20 19:17:52 -04:00
let c = - 1 ;
for (; ( c = i . data . indexOf ( $ , c + 1 )) !== - 1 ; ) a . push ({ type : 7 , index : r }), c += $ . length - 1 ;
2026-09-20 10:08:38 -04:00
}
2026-09-20 11:16:17 -04:00
r ++ ;
2026-09-20 10:08:38 -04:00
}
}
2026-09-20 14:19:39 -04:00
static createElement ( t , e ) {
2026-09-20 13:54:14 -04:00
const n = S . createElement ( "template" );
2026-09-20 14:19:39 -04:00
return n . innerHTML = t , n ;
2026-09-20 10:08:38 -04:00
}
}
2026-09-20 19:17:52 -04:00
function N ( s , t , e = s , n ) {
if ( t === T ) return t ;
let i = n !== void 0 ? e . _$Co ? .[ n ] : e . _$Cl ;
2026-09-20 14:19:39 -04:00
const r = U ( t ) ? void 0 : t . _$litDirective$ ;
2026-09-20 19:17:52 -04:00
return i ? . constructor !== r && ( i ? . _$AO ? .( ! 1 ), r === void 0 ? i = void 0 : ( i = new r ( s ), i . _$AT ( s , e , n )), n !== void 0 ? ( e . _$Co ??= [])[ n ] = i : e . _$Cl = i ), i !== void 0 && ( t = N ( s , i . _$AS ( s , t . values ), i , n )), t ;
2026-09-20 10:08:38 -04:00
}
2026-09-23 12:27:35 -04:00
class se {
2026-09-20 14:19:39 -04:00
constructor ( t , e ) {
this . _$AV = [], this . _$AN = void 0 , this . _$AD = t , this . _$AM = e ;
2026-09-20 10:08:38 -04:00
}
get parentNode () {
return this . _$AM . parentNode ;
}
get _$AU () {
return this . _$AM . _$AU ;
}
2026-09-20 14:19:39 -04:00
u ( t ) {
2026-09-20 19:17:52 -04:00
const { el : { content : e }, parts : n } = this . _$AD , i = ( t ? . creationScope ?? S ). importNode ( e , ! 0 );
C . currentNode = i ;
2026-09-20 18:39:11 -04:00
let r = C . nextNode (), o = 0 , l = 0 , a = n [ 0 ];
2026-09-20 13:54:14 -04:00
for (; a !== void 0 ; ) {
if ( o === a . index ) {
2026-09-20 14:19:39 -04:00
let p ;
2026-09-23 12:27:35 -04:00
a . type === 2 ? p = new O ( r , r . nextSibling , this , t ) : a . type === 1 ? p = new a . ctor ( r , a . name , a . strings , this , t ) : a . type === 6 && ( p = new ae ( r , this , t )), this . _$AV . push ( p ), a = n [ ++ l ];
2026-09-20 10:08:38 -04:00
}
2026-09-20 18:39:11 -04:00
o !== a ? . index && ( r = C . nextNode (), o ++ );
2026-09-20 10:08:38 -04:00
}
2026-09-20 19:17:52 -04:00
return C . currentNode = S , i ;
2026-09-20 10:08:38 -04:00
}
2026-09-20 14:19:39 -04:00
p ( t ) {
let e = 0 ;
for ( const n of this . _$AV ) n !== void 0 && ( n . strings !== void 0 ? ( n . _$AI ( t , n , e ), e += n . strings . length - 2 ) : n . _$AI ( t [ e ])), e ++ ;
2026-09-20 10:08:38 -04:00
}
}
2026-09-20 18:39:11 -04:00
class O {
2026-09-20 10:08:38 -04:00
get _$AU () {
return this . _$AM ? . _$AU ?? this . _$Cv ;
}
2026-09-20 19:17:52 -04:00
constructor ( t , e , n , i ) {
this . type = 2 , this . _$AH = g , this . _$AN = void 0 , this . _$AA = t , this . _$AB = e , this . _$AM = n , this . options = i , this . _$Cv = i ? . isConnected ?? ! 0 ;
2026-09-20 10:08:38 -04:00
}
get parentNode () {
2026-09-20 14:19:39 -04:00
let t = this . _$AA . parentNode ;
const e = this . _$AM ;
return e !== void 0 && t ? . nodeType === 11 && ( t = e . parentNode ), t ;
2026-09-20 10:08:38 -04:00
}
get startNode () {
return this . _$AA ;
}
get endNode () {
return this . _$AB ;
}
2026-09-20 14:19:39 -04:00
_$AI ( t , e = this ) {
2026-09-23 12:27:35 -04:00
t = N ( this , t , e ), U ( t ) ? t === g || t == null || t === "" ? ( this . _$AH !== g && this . _$AR (), this . _$AH = g ) : t !== this . _$AH && t !== T && this . _ ( t ) : t . _$litType$ !== void 0 ? this . $ ( t ) : t . nodeType !== void 0 ? this . T ( t ) : te ( t ) ? this . k ( t ) : this . _ ( t );
2026-09-20 10:08:38 -04:00
}
2026-09-20 14:19:39 -04:00
O ( t ) {
return this . _$AA . parentNode . insertBefore ( t , this . _$AB );
2026-09-20 10:08:38 -04:00
}
2026-09-20 14:19:39 -04:00
T ( t ) {
this . _$AH !== t && ( this . _$AR (), this . _$AH = this . O ( t ));
2026-09-20 10:08:38 -04:00
}
2026-09-20 14:19:39 -04:00
_ ( t ) {
this . _$AH !== g && U ( this . _$AH ) ? this . _$AA . nextSibling . data = t : this . T ( S . createTextNode ( t )), this . _$AH = t ;
2026-09-20 10:08:38 -04:00
}
2026-09-20 14:19:39 -04:00
$ ( t ) {
2026-09-23 12:27:35 -04:00
const { values : e , _$litType$ : n } = t , i = typeof n == "number" ? this . _$AC ( t ) : ( n . el === void 0 && ( n . el = R . createElement ( jt ( n . h , n . h [ 0 ]), this . options )), n );
2026-09-20 19:17:52 -04:00
if ( this . _$AH ? . _$AD === i ) this . _$AH . p ( e );
2026-09-20 10:08:38 -04:00
else {
2026-09-23 12:27:35 -04:00
const r = new se ( i , this ), o = r . u ( this . options );
2026-09-20 14:19:39 -04:00
r . p ( e ), this . T ( o ), this . _$AH = r ;
2026-09-20 10:08:38 -04:00
}
}
2026-09-20 14:19:39 -04:00
_$AC ( t ) {
2026-09-20 18:39:11 -04:00
let e = yt . get ( t . strings );
2026-09-20 19:17:52 -04:00
return e === void 0 && yt . set ( t . strings , e = new R ( t )), e ;
2026-09-20 10:08:38 -04:00
}
2026-09-20 14:19:39 -04:00
k ( t ) {
2026-09-20 18:39:11 -04:00
rt ( this . _$AH ) || ( this . _$AH = [], this . _$AR ());
2026-09-20 14:19:39 -04:00
const e = this . _$AH ;
2026-09-20 19:17:52 -04:00
let n , i = 0 ;
for ( const r of t ) i === e . length ? e . push ( n = new O ( this . O ( L ()), this . O ( L ()), this , this . options )) : n = e [ i ], n . _$AI ( r ), i ++ ;
i < e . length && ( this . _$AR ( n && n . _$AB . nextSibling , i ), e . length = i );
2026-09-20 10:08:38 -04:00
}
2026-09-20 14:19:39 -04:00
_$AR ( t = this . _$AA . nextSibling , e ) {
for ( this . _$AP ? .( ! 1 , ! 0 , e ); t !== this . _$AB ; ) {
2026-09-20 18:39:11 -04:00
const n = ht ( t ). nextSibling ;
ht ( t ). remove (), t = n ;
2026-09-20 10:08:38 -04:00
}
}
2026-09-20 14:19:39 -04:00
setConnected ( t ) {
this . _$AM === void 0 && ( this . _$Cv = t , this . _$AP ? .( t ));
2026-09-20 10:08:38 -04:00
}
}
2026-09-20 18:39:11 -04:00
class Z {
2026-09-20 10:08:38 -04:00
get tagName () {
return this . element . tagName ;
}
get _$AU () {
return this . _$AM . _$AU ;
}
2026-09-20 19:17:52 -04:00
constructor ( t , e , n , i , r ) {
this . type = 1 , this . _$AH = g , this . _$AN = void 0 , this . element = t , this . name = e , this . _$AM = i , this . options = r , n . length > 2 || n [ 0 ] !== "" || n [ 1 ] !== "" ? ( this . _$AH = Array ( n . length - 1 ). fill ( new String ()), this . strings = n ) : this . _$AH = g ;
2026-09-20 10:08:38 -04:00
}
2026-09-20 19:17:52 -04:00
_$AI ( t , e = this , n , i ) {
2026-09-20 11:16:17 -04:00
const r = this . strings ;
2026-09-20 13:54:14 -04:00
let o = ! 1 ;
2026-09-20 19:17:52 -04:00
if ( r === void 0 ) t = N ( this , t , e , 0 ), o = ! U ( t ) || t !== this . _$AH && t !== T , o && ( this . _$AH = t );
2026-09-20 10:08:38 -04:00
else {
2026-09-20 14:19:39 -04:00
const l = t ;
let a , p ;
2026-09-20 19:17:52 -04:00
for ( t = r [ 0 ], a = 0 ; a < r . length - 1 ; a ++ ) p = N ( this , l [ n + a ], e , a ), p === T && ( p = this . _$AH [ a ]), o ||= ! U ( p ) || p !== this . _$AH [ a ], p === g ? t = g : t !== g && ( t += ( p ?? "" ) + r [ a + 1 ]), this . _$AH [ a ] = p ;
2026-09-20 10:08:38 -04:00
}
2026-09-20 19:17:52 -04:00
o && ! i && this . j ( t );
2026-09-20 10:08:38 -04:00
}
2026-09-20 14:19:39 -04:00
j ( t ) {
t === g ? this . element . removeAttribute ( this . name ) : this . element . setAttribute ( this . name , t ?? "" );
2026-09-20 10:08:38 -04:00
}
}
2026-09-20 18:39:11 -04:00
class ie extends Z {
2026-09-20 10:08:38 -04:00
constructor () {
super (... arguments ), this . type = 3 ;
}
2026-09-20 14:19:39 -04:00
j ( t ) {
this . element [ this . name ] = t === g ? void 0 : t ;
2026-09-20 10:08:38 -04:00
}
}
2026-09-23 12:27:35 -04:00
class re extends Z {
2026-09-20 10:08:38 -04:00
constructor () {
super (... arguments ), this . type = 4 ;
}
2026-09-20 14:19:39 -04:00
j ( t ) {
this . element . toggleAttribute ( this . name , !! t && t !== g );
2026-09-20 10:08:38 -04:00
}
}
2026-09-23 12:27:35 -04:00
class oe extends Z {
2026-09-20 19:17:52 -04:00
constructor ( t , e , n , i , r ) {
super ( t , e , n , i , r ), this . type = 5 ;
2026-09-20 10:08:38 -04:00
}
2026-09-20 14:19:39 -04:00
_$AI ( t , e = this ) {
2026-09-20 19:17:52 -04:00
if (( t = N ( this , t , e , 0 ) ?? g ) === T ) return ;
const n = this . _$AH , i = t === g && n !== g || t . capture !== n . capture || t . once !== n . once || t . passive !== n . passive , r = t !== g && ( n === g || i );
i && this . element . removeEventListener ( this . name , this , n ), r && this . element . addEventListener ( this . name , this , t ), this . _$AH = t ;
2026-09-20 10:08:38 -04:00
}
2026-09-20 14:19:39 -04:00
handleEvent ( t ) {
typeof this . _$AH == "function" ? this . _$AH . call ( this . options ? . host ?? this . element , t ) : this . _$AH . handleEvent ( t );
2026-09-20 10:08:38 -04:00
}
}
2026-09-23 12:27:35 -04:00
class ae {
2026-09-20 14:19:39 -04:00
constructor ( t , e , n ) {
this . element = t , this . type = 6 , this . _$AN = void 0 , this . _$AM = e , this . options = n ;
2026-09-20 10:08:38 -04:00
}
get _$AU () {
return this . _$AM . _$AU ;
}
2026-09-20 14:19:39 -04:00
_$AI ( t ) {
2026-09-20 19:17:52 -04:00
N ( this , t );
2026-09-20 10:08:38 -04:00
}
}
2026-09-23 12:27:35 -04:00
const le = { I : O }, ce = it . litHtmlPolyfillSupport ;
ce ? .( R , O ), ( it . litHtmlVersions ??= []). push ( "3.3.3" );
const de = ( s , t , e ) => {
2026-09-20 14:19:39 -04:00
const n = e ? . renderBefore ?? t ;
2026-09-20 19:17:52 -04:00
let i = n . _$litPart$ ;
if ( i === void 0 ) {
2026-09-20 14:19:39 -04:00
const r = e ? . renderBefore ?? null ;
2026-09-20 19:17:52 -04:00
n . _$litPart$ = i = new O ( t . insertBefore ( L (), r ), r , void 0 , e ?? {});
2026-09-20 10:08:38 -04:00
}
2026-09-20 19:17:52 -04:00
return i . _$AI ( s ), i ;
2026-09-20 10:08:38 -04:00
};
2026-09-20 18:39:11 -04:00
const ot = globalThis ;
2026-09-20 19:17:52 -04:00
let A = class extends E {
2026-09-20 10:08:38 -04:00
constructor () {
super (... arguments ), this . renderOptions = { host : this }, this . _$Do = void 0 ;
}
createRenderRoot () {
2026-09-20 14:19:39 -04:00
const t = super . createRenderRoot ();
return this . renderOptions . renderBefore ??= t . firstChild , t ;
2026-09-20 10:08:38 -04:00
}
2026-09-20 14:19:39 -04:00
update ( t ) {
const e = this . render ();
2026-09-23 12:27:35 -04:00
this . hasUpdated || ( this . renderOptions . isConnected = this . isConnected ), super . update ( t ), this . _$Do = de ( e , this . renderRoot , this . renderOptions );
2026-09-20 10:08:38 -04:00
}
connectedCallback () {
super . connectedCallback (), this . _$Do ? . setConnected ( ! 0 );
}
disconnectedCallback () {
super . disconnectedCallback (), this . _$Do ? . setConnected ( ! 1 );
}
render () {
2026-09-20 19:17:52 -04:00
return T ;
2026-09-20 10:08:38 -04:00
}
2026-09-20 13:54:14 -04:00
};
2026-09-20 18:39:11 -04:00
A . _$litElement$ = ! 0 , A . finalized = ! 0 , ot . litElementHydrateSupport ? .({ LitElement : A });
2026-09-23 12:27:35 -04:00
const pe = ot . litElementPolyfillSupport ;
pe ? .({ LitElement : A });
2026-09-20 18:39:11 -04:00
( ot . litElementVersions ??= []). push ( "4.2.2" );
2026-09-23 12:27:35 -04:00
const Dt = ':host{--nq-p-parchment-top: #f0e4c7;--nq-p-parchment-bottom: #ddcca3;--nq-p-parchment: radial-gradient(ellipse at 25% 10%, rgba(255,255,255,.5), transparent 55%), radial-gradient(ellipse at 85% 90%, rgba(120,86,44,.28), transparent 60%), repeating-linear-gradient(93deg, rgba(150,115,70,.05) 0 2px, transparent 2px 6px), repeating-linear-gradient(2deg, rgba(150,115,70,.04) 0 3px, transparent 3px 7px), linear-gradient(var(--nq-p-parchment-top), var(--nq-p-parchment-bottom));--nq-p-vignette: inset 0 0 200px rgba(80,52,20,.35);--nq-p-card-open: linear-gradient(#fdf7e6, #f2e7c9);--nq-p-card-done: linear-gradient(#f0e8d3, #e6dcc2);--nq-p-card-panel: linear-gradient(#fcf6e6, #f1e6ca);--nq-p-card-border: rgba(120,88,48,.38);--nq-p-panel-border: rgba(92,62,26,.4);--nq-p-card-shadow: 0 3px 0 rgba(120,88,48,.2), inset 0 1px 0 rgba(255,255,255,.7);--nq-p-panel-shadow: 0 6px 0 rgba(92,62,26,.18), inset 0 2px 0 rgba(255,255,255,.7);--nq-p-frame-outer: 2px solid rgba(92,62,26,.45);--nq-p-frame-inner: 1px solid rgba(92,62,26,.28);--nq-p-rule: 2px solid rgba(92,62,26,.35);--nq-p-ink: #2b1f14;--nq-p-ink-secondary: #5c452a;--nq-p-ink-muted: #6f6455;--nq-p-ink-away: #4d4433;--nq-p-ink-late: #8f1526;--nq-brand-blue: #3B3AB8;--nq-brand-purple: #A035CC;--nq-brand-gradient: linear-gradient(135deg, var(--nq-brand-blue), var(--nq-brand-purple));--nq-p-icon-tile: var(--nq-brand-gradient);--nq-p-icon-tile-done: rgba(92,62,26,.16);--nq-p-crest: var(--nq-brand-gradient);--nq-p-crest-away: linear-gradient(135deg, #6b6b7a, #7a7286);--nq-p-seal: radial-gradient(circle at 35% 30%, #a8283a, #6d1322);--nq-p-seal-shadow: 0 4px 10px rgba(60,10,20,.4), inset 0 0 0 4px rgba(255,255,255,.14);--nq-p-seal-size: 78px;--nq-p-dock-bg: rgba(43,31,20,.9);--nq-p-dock-ink: #f7efdb;--nq-p-dock-ink-secondary: #d8c9a6;--nq-p-dock-divider: rgba(233,220,189,.3);--nq-p-dock-height: 84px;--nq-p-font-display: "Cinzel Decorative", Cinzel, serif;--nq-p-font-heading: Cinzel, serif;--nq-p-font-body: Nunito, system-ui, sans-serif;--nq-p-size-hero: 86px;--nq-p-size-wordmark: 66px;--nq-p-size-title: 56px;--nq-p-size-name: 48px;--nq-p-size-section: 32px;--nq-p-size-quest: 30px;--nq-p-size-body: 22px;--nq-p-size-label: 21px;--nq-p-track-label: .14em;--nq-p-track-kicker: .3em;--nq-p-quest-min-height: 116px;--nq-p-quest-gap: 24px;--nq-p-quest-pad: 22px;--nq-p-tile-size: 64px;--nq-p-button-height: 72px;--nq-p-button-min-width: 150px;--nq-p-confirm-button: 108px;--nq-p-radius-card: 12px;--nq-p-radius-panel: 20px;--nq-p-radius-pill: 9999px;--nq-p-page-inset: 62px;--nq-p-frame-inset: 26px;--nq-ease-out: cubic-bezier(0, 0, .2, 1);--nq-dur-micro: .12s;--nq-dur-base: .2s;--nq-dur-modal: .35s}' ;
2026-09-20 19:17:52 -04:00
function at ( s ) {
window . customCards = window . customCards ?? [], window . customCards . push ( s );
2026-09-20 10:08:38 -04:00
}
2026-09-23 12:27:35 -04:00
const he = [
2026-09-20 19:17:52 -04:00
"nestquest_quest_completed" ,
"nestquest_quest_uncompleted" ,
"nestquest_quest_missed" ,
"nestquest_child_day_complete"
], bt = /* @__PURE__ */ new Map ();
function Q ( s , t ) {
const e = ` ${ s ?? "local" } | ${ JSON . stringify ( t ) } ` , n = bt . get ( e );
2026-09-20 12:39:47 -04:00
if ( n )
return n ;
2026-09-20 19:17:52 -04:00
let i ;
2026-09-20 12:39:47 -04:00
try {
2026-09-20 19:17:52 -04:00
i = new Intl . DateTimeFormat ( "en-US" , {
2026-09-20 14:19:39 -04:00
... t ,
2026-09-20 19:17:52 -04:00
... s ? { timeZone : s } : {}
2026-09-20 12:39:47 -04:00
});
} catch {
2026-09-20 19:17:52 -04:00
i = new Intl . DateTimeFormat ( "en-US" , t );
2026-09-20 12:39:47 -04:00
}
2026-09-20 19:17:52 -04:00
return bt . set ( e , i ), i ;
2026-09-20 12:39:47 -04:00
}
2026-09-23 12:27:35 -04:00
function ue ( s ) {
2026-09-20 19:17:52 -04:00
const t = s ? . config ;
2026-09-20 14:19:39 -04:00
if ( ! t || typeof t != "object" )
2026-09-20 12:39:47 -04:00
return ;
2026-09-20 14:19:39 -04:00
const e = t . time_zone ;
return typeof e == "string" && e . trim () ? e . trim () : void 0 ;
2026-09-20 12:39:47 -04:00
}
2026-09-20 19:17:52 -04:00
function K ( s , t ) {
return ` ${ Q ( t , { weekday : "long" } ).format(s)}, ${ Q ( t , { month : "short" , day : "numeric" } ).format(s)}` ;
2026-09-20 12:39:47 -04:00
}
2026-09-23 12:27:35 -04:00
function fe ( s , t ) {
2026-09-20 18:39:11 -04:00
return Q ( t , {
2026-09-20 12:39:47 -04:00
hour : "numeric" ,
minute : "2-digit" ,
hour12 : ! 0
2026-09-20 19:17:52 -04:00
}). format ( s );
2026-09-20 12:39:47 -04:00
}
2026-09-23 12:27:35 -04:00
const me = {
2026-09-20 12:39:47 -04:00
"clear-night" : "Clear" ,
cloudy : "Cloudy" ,
exceptional : "Clear" ,
fog : "Foggy" ,
hail : "Hail" ,
lightning : "Storms" ,
"lightning-rimmed" : "Storms" ,
partlycloudy : "Partly cloudy" ,
pouring : "Heavy rain" ,
rainy : "Rain" ,
snowy : "Snow" ,
"snowy-rainy" : "Sleet" ,
sunny : "Sunny" ,
windy : "Windy" ,
"windy-variant" : "Windy"
2026-09-23 12:27:35 -04:00
}, ge = {
2026-09-20 12:39:47 -04:00
"clear-night" : "Clear night skies" ,
cloudy : "Grey skies today" ,
exceptional : "A striking day" ,
fog : "Mist on the road" ,
hail : "Ice from the sky" ,
lightning : "Storms may roll in" ,
"lightning-rimmed" : "Storms may roll in" ,
partlycloudy : "Sun between clouds" ,
pouring : "Heavy rain outside" ,
rainy : "Rain on the walls" ,
snowy : "Snow on the peaks" ,
"snowy-rainy" : "Sleet may fall" ,
sunny : "Clear skies today" ,
windy : "A blustery day" ,
"windy-variant" : "A blustery day"
};
2026-09-20 19:17:52 -04:00
function vt ( s ) {
return typeof s == "string" ? s . trim () : "" ;
2026-09-20 12:39:47 -04:00
}
2026-09-20 19:17:52 -04:00
function J ( s , t ) {
if ( s == null || s === "" )
2026-09-20 14:19:39 -04:00
return t ;
2026-09-20 19:17:52 -04:00
const e = typeof s == "number" ? s : Number ( s );
2026-09-20 14:19:39 -04:00
return Number . isFinite ( e ) ? e : t ;
2026-09-20 12:39:47 -04:00
}
2026-09-23 12:27:35 -04:00
function _e ( s ) {
if ( s === null || typeof s != "object" || Array . isArray ( s ))
return "" ;
const t = s . slug ;
return typeof t == "string" ? t . trim () : "" ;
}
2026-09-20 19:17:52 -04:00
function xt ( s ) {
return Number . isFinite ( s ) ? Math . min ( 100 , Math . max ( 0 , s )) : 0 ;
2026-09-20 12:39:47 -04:00
}
2026-09-20 19:17:52 -04:00
function wt ( s ) {
return Math . max ( 0 , Math . round ( s ));
2026-09-20 12:39:47 -04:00
}
2026-09-23 12:27:35 -04:00
function ye ( s ) {
2026-09-20 19:17:52 -04:00
return s . split ( /[-_]+/ ). filter ( Boolean ). map (( t ) => t . charAt ( 0 ). toUpperCase () + t . slice ( 1 )). join ( " " );
2026-09-20 12:39:47 -04:00
}
2026-09-23 12:27:35 -04:00
function be ( s , t ) {
2026-09-20 18:39:11 -04:00
const e = Q ( t , {
2026-09-20 12:39:47 -04:00
year : "numeric" ,
month : "2-digit" ,
day : "2-digit" ,
hour : "2-digit" ,
minute : "2-digit" ,
second : "2-digit" ,
hourCycle : "h23"
2026-09-20 19:17:52 -04:00
}). formatToParts ( new Date ( s )), n = ( r ) => {
2026-09-20 14:19:39 -04:00
const o = e . find (( l ) => l . type === r );
2026-09-20 13:54:14 -04:00
return o ? Number ( o . value ) : Number . NaN ;
2026-09-20 19:17:52 -04:00
}, i = Date . UTC (
2026-09-20 12:39:47 -04:00
n ( "year" ),
n ( "month" ) - 1 ,
n ( "day" ),
n ( "hour" ),
n ( "minute" ),
n ( "second" )
);
2026-09-20 19:17:52 -04:00
return Number . isFinite ( i ) ? i - s : 0 ;
2026-09-20 12:39:47 -04:00
}
2026-09-23 12:27:35 -04:00
function ve ( s , t ) {
2026-09-20 19:17:52 -04:00
if ( typeof s != "string" )
2026-09-20 12:39:47 -04:00
return null ;
2026-09-20 19:17:52 -04:00
const e = s . split ( "-" );
2026-09-20 14:19:39 -04:00
if ( e . length !== 3 )
2026-09-20 12:39:47 -04:00
return null ;
2026-09-20 19:17:52 -04:00
const [ n , i , r ] = e . map (( a ) => Number ( a ));
if ( ! n || ! i || ! r )
2026-09-20 12:39:47 -04:00
return null ;
2026-09-20 14:19:39 -04:00
if ( ! t ) {
2026-09-20 19:17:52 -04:00
const a = new Date ( n , i - 1 , r );
2026-09-20 13:54:14 -04:00
return Number . isNaN ( a . getTime ()) ? null : a ;
2026-09-20 12:39:47 -04:00
}
2026-09-23 12:27:35 -04:00
const o = Date . UTC ( n , i - 1 , r ), l = new Date ( o - be ( o , t ));
2026-09-20 12:39:47 -04:00
return Number . isNaN ( l . getTime ()) ? null : l ;
}
2026-09-23 12:27:35 -04:00
function xe ( s ) {
const t = me [ s ];
2026-09-20 19:17:52 -04:00
return t || s . charAt ( 0 ). toUpperCase () + s . slice ( 1 );
2026-09-20 12:39:47 -04:00
}
2026-09-23 12:27:35 -04:00
function we ( s , t ) {
return ge [ s ] ?? t ;
2026-09-20 12:39:47 -04:00
}
2026-09-23 12:27:35 -04:00
const $t = "polygon(0 0, 100% 0, 100% 62%, 50% 100%, 0 62%)" , $e = "polygon(50% 0, 93% 25%, 93% 75%, 50% 100%, 7% 75%, 7% 25%)" , qe = Pt `
2026-09-20 12:39:47 -04:00
* {
box-sizing: border-box;
}
:host {
display: block;
height: 100%;
--nq-brand-gradient-h: linear-gradient(
90deg,
var(--nq-brand-blue),
var(--nq-brand-purple)
);
}
.board {
position: relative;
display: flex;
flex-direction: column;
align-items: center;
height: 1080px;
padding: 0;
overflow: hidden;
background: var(--nq-p-parchment);
box-shadow: var(--nq-p-vignette);
font-family: var(--nq-p-font-body);
}
.frame {
position: absolute;
pointer-events: none;
}
.frame-outer {
inset: 26px;
border: var(--nq-p-frame-outer);
border-radius: 14px;
}
.frame-inner {
inset: 36px;
border: var(--nq-p-frame-inner);
border-radius: 8px;
}
.wordmark-row {
position: absolute;
top: 64px;
left: 0;
right: 0;
display: flex;
align-items: center;
justify-content: center;
gap: 26px;
width: 100%;
}
.rule {
flex: 1 1 0;
max-width: 340px;
height: 2px;
border-radius: 1px;
background: rgba(92, 62, 26, 0.35);
}
.d20 {
flex: none;
display: inline-flex;
align-items: center;
justify-content: center;
width: 34px;
height: 34px;
2026-09-23 12:27:35 -04:00
clip-path: ${ v ( $e ) } ;
2026-09-20 12:39:47 -04:00
background: var(--nq-brand-gradient);
}
.d20-numeral {
font-family: var(--nq-p-font-heading);
font-size: 15px;
font-weight: 700;
line-height: 1;
color: #ffffff;
}
.wordmark {
font-family: var(--nq-p-font-display);
font-size: var(--nq-p-size-wordmark);
font-weight: 900;
line-height: 1.15;
background: var(--nq-brand-gradient);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
-webkit-text-fill-color: transparent;
}
.kicker {
position: absolute;
top: 154px;
left: 0;
right: 0;
font-family: var(--nq-p-font-heading);
font-size: 22px;
font-weight: 600;
letter-spacing: var(--nq-p-track-kicker);
text-transform: uppercase;
line-height: 1.2;
text-align: center;
color: var(--nq-p-ink-secondary);
}
.plates {
position: absolute;
top: 262px;
left: 110px;
right: 110px;
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 56px;
}
.plate {
position: relative;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 26px;
height: 600px;
padding: 44px 28px 40px;
border: 2px solid var(--nq-p-panel-border);
border-radius: var(--nq-p-radius-panel);
background: var(--nq-p-card-panel);
box-shadow: var(--nq-p-panel-shadow);
font: inherit;
}
button.plate {
width: 100%;
color: inherit;
cursor: pointer;
-webkit-tap-highlight-color: transparent;
transition: transform var(--nq-dur-micro) var(--nq-ease-out);
}
button.plate:active {
transform: scale(0.98);
}
button.plate:focus-visible {
outline: 3px solid var(--nq-brand-purple);
outline-offset: 4px;
}
.plate.away {
border: 2px dashed var(--nq-p-panel-border);
background: linear-gradient(#f2ecdd, #e6dcc6);
box-shadow: none;
}
.crest {
position: relative;
flex: none;
width: 188px;
height: 214px;
padding: 4px;
2026-09-20 19:17:52 -04:00
clip-path: ${ v ( $t ) } ;
2026-09-20 12:39:47 -04:00
background: rgba(255, 255, 255, 0.22);
}
.crest-face {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
padding-bottom: 70px;
2026-09-20 19:17:52 -04:00
clip-path: ${ v ( $t ) } ;
2026-09-20 12:39:47 -04:00
background: var(--nq-p-crest);
}
.crest.away .crest-face {
background: var(--nq-p-crest-away);
}
.crest .initial {
font-family: var(--nq-p-font-display);
font-size: 82px;
font-weight: 700;
line-height: 1;
color: #ffffff;
}
.name {
font-family: var(--nq-p-font-heading);
font-size: var(--nq-p-size-name);
font-weight: 700;
letter-spacing: 0.02em;
line-height: 1.1;
color: var(--nq-p-ink);
}
.plate.away .name {
color: var(--nq-p-ink-away);
}
.pill {
display: inline-flex;
align-items: center;
gap: 10px;
padding: 8px 20px;
border-radius: var(--nq-p-radius-pill);
background: rgba(22, 120, 60, 0.35);
font-family: var(--nq-p-font-heading);
font-size: 22px;
font-weight: 600;
letter-spacing: 0.08em;
text-transform: uppercase;
line-height: 1;
color: #146b36;
}
.pill svg {
width: 22px;
height: 22px;
color: #157a3c;
}
.pill.away {
background: rgba(92, 62, 26, 0.16);
color: var(--nq-p-ink-away);
}
.pill.away svg {
color: var(--nq-p-ink-away);
}
.progress-line {
font-family: var(--nq-p-font-heading);
font-size: 24px;
font-weight: 700;
line-height: 1.2;
color: var(--nq-p-ink-secondary);
}
.bar {
width: 100%;
height: 16px;
border: 1px solid rgba(92, 62, 26, 0.35);
border-radius: var(--nq-p-radius-pill);
background: rgba(92, 62, 26, 0.18);
overflow: hidden;
}
.bar .fill {
display: block;
height: 100%;
border-radius: inherit;
background: var(--nq-brand-gradient-h);
}
.hint {
position: absolute;
top: 930px;
left: 0;
right: 0;
font-family: var(--nq-p-font-body);
font-size: 24px;
font-weight: 600;
line-height: 1.4;
text-align: center;
color: var(--nq-p-ink-secondary);
}
2026-09-20 14:04:58 -04:00
.plate.unknown {
border: 2px dashed var(--nq-p-panel-border);
background: linear-gradient(#f2ecdd, #e6dcc6);
box-shadow: none;
}
.notice-wrap {
position: absolute;
top: 262px;
left: 110px;
right: 110px;
bottom: 190px;
display: flex;
align-items: center;
justify-content: center;
}
.notice {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 20px;
width: 100%;
max-width: 980px;
padding: 56px 64px;
border: 2px solid var(--nq-p-panel-border);
border-radius: var(--nq-p-radius-panel);
background: var(--nq-p-card-panel);
box-shadow: var(--nq-p-panel-shadow);
text-align: center;
}
.notice svg {
width: 46px;
height: 46px;
color: var(--nq-p-ink-secondary);
}
.notice-headline {
font-family: var(--nq-p-font-heading);
font-size: 40px;
font-weight: 700;
line-height: 1.15;
color: var(--nq-p-ink);
}
.notice-body {
margin: 0;
font-family: var(--nq-p-font-body);
font-size: 24px;
font-weight: 600;
line-height: 1.4;
color: var(--nq-p-ink-secondary);
}
2026-09-20 12:39:47 -04:00
.spacer {
flex: 1 1 0;
}
.dock {
position: absolute;
left: 46px;
right: 46px;
bottom: 46px;
height: var(--nq-p-dock-height);
display: flex;
align-items: center;
justify-content: center;
gap: 24px;
padding: 0 40px;
border-radius: 14px;
background: var(--nq-p-dock-bg);
pointer-events: none;
user-select: none;
color: var(--nq-p-dock-ink);
}
.dock svg {
flex: none;
width: 40px;
height: 40px;
color: var(--nq-p-dock-ink);
}
.dock .divider {
flex: none;
width: 1px;
height: 40px;
background: var(--nq-p-dock-divider);
}
.dock .temp {
font-family: var(--nq-p-font-body);
font-size: 38px;
font-weight: 800;
line-height: 1;
}
.dock .condition {
font-family: var(--nq-p-font-body);
font-size: 26px;
font-weight: 600;
line-height: 1.2;
color: var(--nq-p-dock-ink-secondary);
}
.dock .date {
font-family: var(--nq-p-font-body);
font-size: 26px;
font-weight: 600;
line-height: 1.2;
color: var(--nq-p-dock-ink-secondary);
}
.dock .clock {
font-family: var(--nq-p-font-body);
font-size: 38px;
font-weight: 800;
line-height: 1;
}
2026-09-23 12:27:35 -04:00
` , ke = d `<svg
2026-09-20 12:39:47 -04:00
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
aria-hidden="true"
>
<circle cx="12" cy="12" r="10"></circle>
<path d="m9 12 2 2 4-4"></path>
2026-09-23 12:27:35 -04:00
</svg>` , Ce = d `<svg
2026-09-20 12:39:47 -04:00
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
aria-hidden="true"
>
<path d="M3.5 21 12 3.5 20.5 21"></path>
<path d="M9 21l3-8 3 8"></path>
2026-09-23 12:27:35 -04:00
</svg>` , Ae = d `<svg
2026-09-20 14:04:58 -04:00
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
aria-hidden="true"
>
<circle cx="12" cy="12" r="10"></circle>
<polygon points="16.24 7.76 14.12 14.12 7.76 16.24 9.88 9.88 16.24 7.76"></polygon>
2026-09-23 12:27:35 -04:00
</svg>` , Se = d `<svg
2026-09-20 14:04:58 -04:00
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
aria-hidden="true"
>
<path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3Z"></path>
<path d="M12 9v4"></path>
<path d="M12 17h.01"></path>
2026-09-23 12:27:35 -04:00
</svg>` , Te = d `<svg
2026-09-20 14:04:58 -04:00
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
aria-hidden="true"
>
<path d="M17.5 19H9a7 7 0 1 1 6.71-9h1.79a4.5 4.5 0 1 1 0 9Z"></path>
<path d="m2 2 20 20"></path>
2026-09-20 18:39:11 -04:00
</svg>` , qt = {
2026-09-23 12:27:35 -04:00
icon : Se ,
2026-09-20 14:04:58 -04:00
headline : "NestQuest is not set up yet" ,
body : "A parent needs to finish setting up NestQuest before the party can gather."
2026-09-23 12:27:35 -04:00
}, Ee = {
icon : Te ,
2026-09-20 14:04:58 -04:00
headline : "The records cannot be reached" ,
body : "The party's records are quiet right now. NestQuest will return shortly."
2026-09-23 12:27:35 -04:00
}, Ne = d `<svg
2026-09-20 12:39:47 -04:00
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
aria-hidden="true"
>
<path d="M12 2v2"></path>
<path d="m4.93 4.93 1.41 1.41"></path>
<path d="M20 12h2"></path>
<path d="m19.07 4.93-1.41 1.41"></path>
<path d="M15.947 12.65a4 4 0 0 0-5.925-4.128"></path>
<path d="M13 22H7a5 5 0 1 1 4.9-6H13a3 3 0 0 1 0 6Z"></path>
</svg>` ;
2026-09-23 12:27:35 -04:00
class Me extends A {
2026-09-20 10:08:38 -04:00
static properties = {
hass : { attribute : ! 1 },
2026-09-20 12:39:47 -04:00
_config : { state : ! 0 },
_now : { state : ! 0 }
2026-09-20 10:08:38 -04:00
};
2026-09-23 12:27:35 -04:00
static styles = [ v ( Dt ), qe ];
2026-09-20 10:08:38 -04:00
hass ;
_config ;
2026-09-20 12:39:47 -04:00
_now = /* @__PURE__ */ new Date ();
_clockTimer ;
2026-09-20 19:17:52 -04:00
_unsubs = [];
_subscribed = ! 1 ;
_subGeneration = 0 ;
_retryTimer ;
2026-09-20 14:19:39 -04:00
setConfig ( t ) {
if ( ! t || typeof t != "object" )
2026-09-20 10:08:38 -04:00
throw new Error ( "Invalid configuration" );
2026-09-20 14:19:39 -04:00
this . _config = t ;
2026-09-20 10:08:38 -04:00
}
2026-09-20 19:17:52 -04:00
_hassConnection () {
const t = this . hass ? . connection ;
return ! t || typeof t != "object" || typeof t . subscribeEvents != "function" ? null : t ;
}
_subscribeLive () {
if ( ! this . isConnected || this . _subscribed )
return ;
const t = this . _hassConnection ();
if ( ! t )
return ;
this . _subscribed = ! 0 ;
const e = ++ this . _subGeneration , n = ( i ) => {
i . then (( r ) => {
this . _subscribed && e === this . _subGeneration ? this . _unsubs . push ( r ) : r ();
}). catch (() => {
e === this . _subGeneration && ( this . _unsubscribeLive (), this . _armSubscribeRetry ());
});
};
2026-09-23 12:27:35 -04:00
for ( const i of he )
2026-09-20 19:17:52 -04:00
n (
t . subscribeEvents (() => this . requestUpdate (), i )
);
}
_armSubscribeRetry () {
this . _retryTimer === void 0 && ( this . _retryTimer = window . setTimeout (() => {
this . _retryTimer = void 0 , this . _subscribeLive ();
}, 1e3 ));
}
_clearSubscribeRetry () {
this . _retryTimer !== void 0 && ( window . clearTimeout ( this . _retryTimer ), this . _retryTimer = void 0 );
}
_unsubscribeLive () {
this . _clearSubscribeRetry (), this . _subGeneration ++ ;
for ( const t of this . _unsubs )
t ();
this . _unsubs = [], this . _subscribed = ! 1 ;
}
2026-09-20 10:08:38 -04:00
getCardSize () {
2026-09-20 12:39:47 -04:00
return 22 ;
}
connectedCallback () {
2026-09-20 19:17:52 -04:00
super . connectedCallback (), this . _subscribeLive (), this . _now = /* @__PURE__ */ new Date (), this . _clockTimer = window . setInterval (() => {
2026-09-20 12:39:47 -04:00
this . _now = /* @__PURE__ */ new Date ();
}, 1e3 );
}
2026-09-20 19:17:52 -04:00
updated () {
this . _subscribeLive ();
}
2026-09-20 12:39:47 -04:00
disconnectedCallback () {
2026-09-20 19:17:52 -04:00
this . _unsubscribeLive (), this . _clockTimer !== void 0 && ( window . clearInterval ( this . _clockTimer ), this . _clockTimer = void 0 ), super . disconnectedCallback ();
2026-09-20 10:08:38 -04:00
}
render () {
2026-09-20 14:19:39 -04:00
const t = this . _boardNotice ();
2026-09-20 19:17:52 -04:00
return d `
2026-09-20 12:39:47 -04:00
<div class="board">
<div class="frame frame-outer"></div>
<div class="frame frame-inner"></div>
<div class="wordmark-row">
<span class="rule"></span>
<span class="d20" aria-hidden="true">
<span class="d20-numeral">20</span>
</span>
<span class="wordmark">NestQuest</span>
<span class="d20" aria-hidden="true">
<span class="d20-numeral">20</span>
</span>
<span class="rule"></span>
</div>
2026-09-20 18:39:11 -04:00
<p class="kicker">The Party · ${ K ( this . _now , this . _timeZone ()) } </p>
2026-09-20 19:17:52 -04:00
${ t ? this . _renderNotice ( t ) : d `
2026-09-20 14:04:58 -04:00
<div class="plates">
2026-09-20 14:19:39 -04:00
${ this . _plates (). map (( e ) => this . _renderPlate ( e )) }
2026-09-20 14:04:58 -04:00
</div>
<p class="hint">Tap your crest to open your Quest Log</p>
` }
2026-09-20 12:39:47 -04:00
<div class="spacer"></div>
${ this . _renderDock () }
</div>
` ;
}
_timeZone () {
2026-09-23 12:27:35 -04:00
return ue ( this . hass );
2026-09-20 12:39:47 -04:00
}
2026-09-20 14:19:39 -04:00
_state ( t ) {
const n = this . hass ? . states ? .[ t ];
2026-09-20 12:39:47 -04:00
return n && typeof n == "object" ? n : null ;
}
_childSlugs () {
if ( ! this . _config )
return [];
2026-09-20 14:19:39 -04:00
const t = this . _config . child_order ;
return Array . isArray ( t ) ? t . filter (
( e ) => typeof e == "string" && e . trim (). length > 0
2026-09-23 12:27:35 -04:00
). map (( e ) => e . trim ()) : this . _discoveredChildSlugs ();
}
/** Zero-config discovery (Feature 20): the ordered child roster the
* integration publishes on the household rollup
* (custom_components/nestquest/sensor.py — ``child_roster``, the
* snapshot's sort_order, then id), each entry carrying the slug the
* per-child entity ids are built from. Consulted only when the
* config has no child_order — explicit configuration wins. */
_discoveredChildSlugs () {
const e = this . _state (
"sensor.nestquest_household_quests_due_today"
) ? . attributes ? . child_roster ;
return Array . isArray ( e ) ? e . map (( n ) => _e ( n )). filter (( n ) => n . length > 0 ) : [];
2026-09-20 12:39:47 -04:00
}
_plates () {
2026-09-20 14:19:39 -04:00
return this . _childSlugs (). map (( t ) => this . _plate ( t ));
2026-09-20 12:39:47 -04:00
}
2026-09-20 14:19:39 -04:00
_plate ( t ) {
2026-09-20 19:17:52 -04:00
const e = this . _dueSensorResolution ( t ), n = this . _state ( `sensor.nestquest_ ${ t } _quests_due_today` ), i = this . _state (
2026-09-20 14:19:39 -04:00
`sensor.nestquest_ ${ t } _quests_completed_today`
2026-09-20 12:39:47 -04:00
), r = this . _state (
2026-09-20 14:19:39 -04:00
`sensor.nestquest_ ${ t } _completion_pct_today`
2026-09-20 14:04:58 -04:00
), o = this . _state (
2026-09-20 14:19:39 -04:00
`binary_sensor.nestquest_ ${ t } _present_today`
2026-09-20 19:17:52 -04:00
), l = n ? . attributes ?? {}, a = wt ( J ( n ? . state , 0 )), p = wt ( J ( i ? . state , 0 )), u = r ? J ( r . state , Number . NaN ) : Number . NaN , c = Number . isFinite ( u ) ? xt ( u ) : a > 0 ? xt ( p / a * 100 ) : 0 ;
2026-09-20 14:04:58 -04:00
let f = ! 0 ;
const h = l . present ;
typeof h == "boolean" ? f = h : o && ( f = String ( o . state ?? "" ). trim (). toLowerCase () === "on" );
let m = "" ;
2026-09-20 14:19:39 -04:00
const _ = l . child_name ;
if ( typeof _ == "string" && _ . trim ())
m = _ . trim ();
2026-09-20 12:39:47 -04:00
else {
2026-09-20 19:17:52 -04:00
const G = o ? . attributes ? . child_name ;
typeof G == "string" && G . trim () && ( m = G . trim ());
2026-09-20 12:39:47 -04:00
}
2026-09-23 12:27:35 -04:00
m || ( m = ye ( t ));
const x = ve (
2026-09-20 14:04:58 -04:00
o ? . attributes ? . next_present ,
2026-09-20 12:39:47 -04:00
this . _timeZone ()
2026-09-23 12:27:35 -04:00
), j = x ? `Returns ${ K ( x , this . _timeZone ()) } ` : null ;
2026-09-20 12:39:47 -04:00
return {
2026-09-20 14:19:39 -04:00
slug : t ,
2026-09-20 14:04:58 -04:00
name : m ,
initial : ( m . charAt ( 0 ) || "?" ). toUpperCase (),
2026-09-20 14:19:39 -04:00
present : e === null ? f : ! 1 ,
completed : p ,
2026-09-20 14:04:58 -04:00
due : a ,
2026-09-20 19:17:52 -04:00
pct : c ,
2026-09-23 12:27:35 -04:00
returns : j ,
2026-09-20 14:19:39 -04:00
unresolved : e
2026-09-20 12:39:47 -04:00
};
}
2026-09-20 14:04:58 -04:00
/** "missing" when the due sensor does not exist (integration not
* configured), "stale" when it answers unavailable/unknown (backend
* unreachable or the child is absent from the snapshot), null when
* it resolves. */
2026-09-20 14:19:39 -04:00
_dueSensorResolution ( t ) {
const e = this . _state ( `sensor.nestquest_ ${ t } _quests_due_today` );
if ( ! e )
2026-09-20 14:04:58 -04:00
return "missing" ;
2026-09-20 14:19:39 -04:00
const n = String ( e . state ?? "" ). trim (). toLowerCase ();
2026-09-20 14:04:58 -04:00
return ! n || n === "unavailable" || n === "unknown" ? "stale" : null ;
}
_boardNotice () {
2026-09-20 14:19:39 -04:00
const t = this . _plates ();
2026-09-23 12:27:35 -04:00
return t . length === 0 ? qt : t . every (( e ) => e . unresolved !== null ) ? t . some (( e ) => e . unresolved === "stale" ) ? Ee : qt : null ;
2026-09-20 14:04:58 -04:00
}
2026-09-20 14:19:39 -04:00
_renderNotice ( t ) {
2026-09-20 19:17:52 -04:00
return d `
2026-09-20 14:04:58 -04:00
<div class="notice-wrap">
<div class="notice" role="status">
2026-09-20 14:19:39 -04:00
${ t . icon }
<span class="notice-headline"> ${ t . headline } </span>
<p class="notice-body"> ${ t . body } </p>
2026-09-20 14:04:58 -04:00
</div>
</div>
` ;
}
2026-09-20 14:19:39 -04:00
_renderPlate ( t ) {
2026-09-20 19:17:52 -04:00
return t . unresolved ? d `
2026-09-20 14:04:58 -04:00
<div class="plate unknown">
<span class="crest away">
<span class="crest-face">
2026-09-20 14:19:39 -04:00
<span class="initial"> ${ t . initial } </span>
2026-09-20 14:04:58 -04:00
</span>
</span>
2026-09-20 14:19:39 -04:00
<span class="name"> ${ t . name } </span>
2026-09-20 14:04:58 -04:00
<span class="pill away">
2026-09-23 12:27:35 -04:00
${ Ae }
2026-09-20 14:04:58 -04:00
<span>Unknown</span>
</span>
<span class="progress-line">—</span>
<span class="bar"></span>
</div>
2026-09-20 19:17:52 -04:00
` : t . present ? d `
2026-09-20 12:39:47 -04:00
<button
class="plate"
type="button"
2026-09-20 14:19:39 -04:00
aria-label="Open ${ t . name } 's Quest Log"
@click= ${ () => this . _openQuestLog ( t . slug ) }
2026-09-20 12:39:47 -04:00
>
<span class="crest">
<span class="crest-face">
2026-09-20 14:19:39 -04:00
<span class="initial"> ${ t . initial } </span>
2026-09-20 12:39:47 -04:00
</span>
</span>
2026-09-20 14:19:39 -04:00
<span class="name"> ${ t . name } </span>
2026-09-20 12:39:47 -04:00
<span class="pill">
2026-09-23 12:27:35 -04:00
${ ke }
2026-09-20 12:39:47 -04:00
<span>Home today</span>
</span>
<span class="progress-line">
2026-09-20 14:19:39 -04:00
${ t . completed } of ${ t . due } quests claimed
2026-09-20 12:39:47 -04:00
</span>
<span class="bar">
2026-09-20 14:19:39 -04:00
<span class="fill" style="width: ${ t . pct } %"></span>
2026-09-20 12:39:47 -04:00
</span>
</button>
2026-09-20 19:17:52 -04:00
` : d `
2026-09-20 12:39:47 -04:00
<div class="plate away">
<span class="crest away">
<span class="crest-face">
2026-09-20 14:19:39 -04:00
<span class="initial"> ${ t . initial } </span>
2026-09-20 12:39:47 -04:00
</span>
</span>
2026-09-20 14:19:39 -04:00
<span class="name"> ${ t . name } </span>
2026-09-20 12:39:47 -04:00
<span class="pill away">
2026-09-23 12:27:35 -04:00
${ Ce }
2026-09-20 12:39:47 -04:00
<span>On travels</span>
</span>
2026-09-20 14:19:39 -04:00
<span class="progress-line"> ${ t . returns ?? "Returns —" } </span>
2026-09-20 12:39:47 -04:00
<span class="bar"></span>
</div>
` ;
}
2026-09-20 14:19:39 -04:00
_openQuestLog ( t ) {
2026-09-20 19:17:52 -04:00
const e = vt ( this . _config ? . quest_log_path );
2026-09-20 14:19:39 -04:00
e && ( window . history . pushState ( null , "" , ` ${ e . replace ( /\/+$/ , "" ) } / ${ t } ` ), window . dispatchEvent ( new Event ( "location-changed" )));
2026-09-20 12:39:47 -04:00
}
_dockWeather () {
2026-09-20 19:17:52 -04:00
const t = vt ( this . _config ? . weather_entity );
2026-09-20 14:04:58 -04:00
if ( ! t )
return null ;
2026-09-20 14:19:39 -04:00
const e = this . _state ( t );
if ( ! e )
return null ;
const n = String ( e . state ?? "" ). trim ();
2026-09-20 12:39:47 -04:00
if ( ! n || n === "unavailable" || n === "unknown" )
return null ;
2026-09-20 19:17:52 -04:00
const i = e . attributes ?? {};
2026-09-20 13:54:14 -04:00
let r = null , o = null ;
2026-09-20 19:17:52 -04:00
const l = i . forecast ;
2026-09-20 12:39:47 -04:00
if ( Array . isArray ( l ) && l . length > 0 ) {
2026-09-20 13:54:14 -04:00
const a = l [ 0 ];
if ( a && typeof a == "object" ) {
2026-09-20 14:19:39 -04:00
const p = a ;
r = this . _optionalNumber ( p . temperature ), o = this . _optionalNumber ( p . templow );
2026-09-20 12:39:47 -04:00
}
}
return {
condition : n ,
2026-09-20 19:17:52 -04:00
temperature : this . _optionalNumber ( i . temperature ),
2026-09-20 12:39:47 -04:00
high : r ,
2026-09-20 13:54:14 -04:00
low : o
2026-09-20 12:39:47 -04:00
};
}
2026-09-20 14:19:39 -04:00
_optionalNumber ( t ) {
if ( t == null || t === "" )
2026-09-20 12:39:47 -04:00
return null ;
2026-09-20 14:19:39 -04:00
const e = typeof t == "number" ? t : Number ( t );
return Number . isFinite ( e ) ? e : null ;
2026-09-20 12:39:47 -04:00
}
_renderDock () {
2026-09-20 14:19:39 -04:00
const t = this . _dockWeather ();
if ( ! t )
2026-09-20 19:17:52 -04:00
return d `
2026-09-20 12:39:47 -04:00
<div class="dock">
2026-09-20 18:39:11 -04:00
<span class="date"> ${ K ( this . _now , this . _timeZone ()) } </span>
2026-09-20 12:39:47 -04:00
<span class="divider"></span>
2026-09-23 12:27:35 -04:00
<span class="clock"> ${ fe ( this . _now , this . _timeZone ()) } </span>
2026-09-20 12:39:47 -04:00
</div>
` ;
2026-09-23 12:27:35 -04:00
const e = xe ( t . condition ), n = we ( t . condition , e ), i = t . temperature === null ? g : d `<span class="temp"> ${ Math . round ( t . temperature ) } °</span>` , r = t . high === null || t . low === null ? null : ` ${ Math . round ( t . high ) } ° / ${ Math . round ( t . low ) } °` ;
2026-09-20 19:17:52 -04:00
return d `
2026-09-20 12:39:47 -04:00
<div class="dock">
2026-09-23 12:27:35 -04:00
${ Ne }
2026-09-20 19:17:52 -04:00
${ i }
2026-09-20 12:39:47 -04:00
<span class="divider"></span>
<span class="condition">
2026-09-20 14:19:39 -04:00
${ r === null ? e : ` ${ e } · ${ r } ` }
2026-09-20 12:39:47 -04:00
</span>
<span class="divider"></span>
<span class="condition"> ${ n } </span>
</div>
` ;
2026-09-20 10:08:38 -04:00
}
}
2026-09-23 12:27:35 -04:00
customElements . define ( "nestquest-party-board-card" , Me );
2026-09-20 18:39:11 -04:00
at ({
2026-09-20 10:08:38 -04:00
type : "nestquest-party-board-card" ,
name : "NestQuest Party Board" ,
description : "Kids' attract screen for present and away adventurers."
});
2026-09-23 12:27:35 -04:00
const Oe = { CHILD : 2 }, ze = ( s ) => (... t ) => ({ _$litDirective$ : s , values : t });
let Pe = class {
2026-09-20 14:19:39 -04:00
constructor ( t ) {
2026-09-20 13:54:14 -04:00
}
get _$AU () {
return this . _$AM . _$AU ;
}
2026-09-20 14:19:39 -04:00
_$AT ( t , e , n ) {
this . _$Ct = t , this . _$AM = e , this . _$Ci = n ;
2026-09-20 13:54:14 -04:00
}
2026-09-20 14:19:39 -04:00
_$AS ( t , e ) {
return this . update ( t , e );
2026-09-20 13:54:14 -04:00
}
2026-09-20 14:19:39 -04:00
update ( t , e ) {
return this . render (... e );
2026-09-20 13:54:14 -04:00
}
};
2026-09-23 12:27:35 -04:00
const { I : Ie } = le , kt = ( s ) => s , Ct = () => document . createComment ( "" ), P = ( s , t , e ) => {
2026-09-20 19:17:52 -04:00
const n = s . _$AA . parentNode , i = t === void 0 ? s . _$AB : t . _$AA ;
2026-09-20 14:19:39 -04:00
if ( e === void 0 ) {
2026-09-20 19:17:52 -04:00
const r = n . insertBefore ( Ct (), i ), o = n . insertBefore ( Ct (), i );
2026-09-23 12:27:35 -04:00
e = new Ie ( r , o , s , s . options );
2026-09-20 13:54:14 -04:00
} else {
2026-09-20 19:17:52 -04:00
const r = e . _$AB . nextSibling , o = e . _$AM , l = o !== s ;
2026-09-20 13:54:14 -04:00
if ( l ) {
let a ;
2026-09-20 19:17:52 -04:00
e . _$AQ ? .( s ), e . _$AM = s , e . _$AP !== void 0 && ( a = s . _$AU ) !== o . _$AU && e . _$AP ( a );
2026-09-20 13:54:14 -04:00
}
2026-09-20 19:17:52 -04:00
if ( r !== i || l ) {
2026-09-20 14:19:39 -04:00
let a = e . _$AA ;
2026-09-20 13:54:14 -04:00
for (; a !== r ; ) {
2026-09-20 18:39:11 -04:00
const p = kt ( a ). nextSibling ;
2026-09-20 19:17:52 -04:00
kt ( n ). insertBefore ( a , i ), a = p ;
2026-09-20 13:54:14 -04:00
}
}
}
2026-09-20 14:19:39 -04:00
return e ;
2026-09-23 12:27:35 -04:00
}, k = ( s , t , e = s ) => ( s . _$AI ( t , e ), s ), Le = {}, Ue = ( s , t = Le ) => s . _$AH = t , Re = ( s ) => s . _$AH , X = ( s ) => {
2026-09-20 19:17:52 -04:00
s . _$AR (), s . _$AA . remove ();
2026-09-20 13:54:14 -04:00
};
2026-09-20 19:17:52 -04:00
const At = ( s , t , e ) => {
2026-09-20 13:54:14 -04:00
const n = /* @__PURE__ */ new Map ();
2026-09-20 19:17:52 -04:00
for ( let i = t ; i <= e ; i ++ ) n . set ( s [ i ], i );
2026-09-20 13:54:14 -04:00
return n ;
2026-09-23 12:27:35 -04:00
}, St = ze ( class extends Pe {
2026-09-20 19:17:52 -04:00
constructor ( s ) {
2026-09-23 12:27:35 -04:00
if ( super ( s ), s . type !== Oe . CHILD ) throw Error ( "repeat() can only be used in text expressions" );
2026-09-20 13:54:14 -04:00
}
2026-09-20 19:17:52 -04:00
dt ( s , t , e ) {
2026-09-20 13:54:14 -04:00
let n ;
2026-09-20 14:19:39 -04:00
e === void 0 ? e = t : t !== void 0 && ( n = t );
2026-09-20 19:17:52 -04:00
const i = [], r = [];
2026-09-20 13:54:14 -04:00
let o = 0 ;
2026-09-20 19:17:52 -04:00
for ( const l of s ) i [ o ] = n ? n ( l , o ) : o , r [ o ] = e ( l , o ), o ++ ;
return { values : r , keys : i };
2026-09-20 13:54:14 -04:00
}
2026-09-20 19:17:52 -04:00
render ( s , t , e ) {
return this . dt ( s , t , e ). values ;
2026-09-20 13:54:14 -04:00
}
2026-09-20 19:17:52 -04:00
update ( s , [ t , e , n ]) {
2026-09-23 12:27:35 -04:00
const i = Re ( s ), { values : r , keys : o } = this . dt ( t , e , n );
2026-09-20 19:17:52 -04:00
if ( ! Array . isArray ( i )) return this . ut = o , r ;
2026-09-20 13:54:14 -04:00
const l = this . ut ??= [], a = [];
2026-09-20 19:17:52 -04:00
let p , u , c = 0 , f = i . length - 1 , h = 0 , m = r . length - 1 ;
for (; c <= f && h <= m ; ) if ( i [ c ] === null ) c ++ ;
else if ( i [ f ] === null ) f -- ;
else if ( l [ c ] === o [ h ]) a [ h ] = k ( i [ c ], r [ h ]), c ++ , h ++ ;
else if ( l [ f ] === o [ m ]) a [ m ] = k ( i [ f ], r [ m ]), f -- , m -- ;
else if ( l [ c ] === o [ m ]) a [ m ] = k ( i [ c ], r [ m ]), P ( s , a [ m + 1 ], i [ c ]), c ++ , m -- ;
else if ( l [ f ] === o [ h ]) a [ h ] = k ( i [ f ], r [ h ]), P ( s , i [ c ], i [ f ]), f -- , h ++ ;
else if ( p === void 0 && ( p = At ( o , h , m ), u = At ( l , c , f )), p . has ( l [ c ])) if ( p . has ( l [ f ])) {
const _ = u . get ( o [ h ]), x = _ !== void 0 ? i [ _ ] : null ;
2026-09-20 18:39:11 -04:00
if ( x === null ) {
2026-09-23 12:27:35 -04:00
const j = P ( s , i [ c ]);
k ( j , r [ h ]), a [ h ] = j ;
2026-09-20 19:17:52 -04:00
} else a [ h ] = k ( x , r [ h ]), P ( s , i [ c ], x ), i [ _ ] = null ;
2026-09-20 14:04:58 -04:00
h ++ ;
2026-09-20 19:17:52 -04:00
} else X ( i [ f ]), f -- ;
else X ( i [ c ]), c ++ ;
2026-09-20 14:04:58 -04:00
for (; h <= m ; ) {
2026-09-20 19:17:52 -04:00
const _ = P ( s , a [ m + 1 ]);
2026-09-20 18:39:11 -04:00
k ( _ , r [ h ]), a [ h ++ ] = _ ;
2026-09-20 13:54:14 -04:00
}
2026-09-20 19:17:52 -04:00
for (; c <= f ; ) {
const _ = i [ c ++ ];
2026-09-20 18:39:11 -04:00
_ !== null && X ( _ );
2026-09-20 13:54:14 -04:00
}
2026-09-23 12:27:35 -04:00
return this . ut = o , Ue ( s , a ), T ;
2026-09-20 13:54:14 -04:00
}
2026-09-23 12:27:35 -04:00
}), je = [
2026-09-20 19:17:52 -04:00
"nestquest_quest_completed" ,
"nestquest_quest_uncompleted" ,
"nestquest_quest_missed" ,
"nestquest_child_day_complete"
], Tt = /* @__PURE__ */ new Map ();
function M ( s , t ) {
const e = ` ${ s ?? "local" } | ${ JSON . stringify ( t ) } ` , n = Tt . get ( e );
2026-09-20 13:54:14 -04:00
if ( n )
return n ;
2026-09-20 19:17:52 -04:00
let i ;
2026-09-20 13:54:14 -04:00
try {
2026-09-20 19:17:52 -04:00
i = new Intl . DateTimeFormat ( "en-US" , {
2026-09-20 14:19:39 -04:00
... t ,
2026-09-20 19:17:52 -04:00
... s ? { timeZone : s } : {}
2026-09-20 13:54:14 -04:00
});
} catch {
2026-09-20 19:17:52 -04:00
i = new Intl . DateTimeFormat ( "en-US" , t );
2026-09-20 13:54:14 -04:00
}
2026-09-20 19:17:52 -04:00
return Tt . set ( e , i ), i ;
2026-09-20 13:54:14 -04:00
}
2026-09-23 12:27:35 -04:00
function De ( s ) {
2026-09-20 19:17:52 -04:00
const t = s ? . config ;
2026-09-20 14:19:39 -04:00
if ( ! t || typeof t != "object" )
2026-09-20 13:54:14 -04:00
return ;
2026-09-20 14:19:39 -04:00
const e = t . time_zone ;
return typeof e == "string" && e . trim () ? e . trim () : void 0 ;
2026-09-20 13:54:14 -04:00
}
2026-09-23 12:27:35 -04:00
function D ( s , t ) {
2026-09-20 19:17:52 -04:00
return ` ${ M ( t , { weekday : "long" } ).format(s)}, ${ M ( t , { month : "short" , day : "numeric" } ).format(s)}` ;
2026-09-20 13:54:14 -04:00
}
2026-09-23 12:27:35 -04:00
function He ( s , t ) {
2026-09-20 19:17:52 -04:00
return M ( t , { weekday : "long" }). format ( s );
2026-09-20 13:54:14 -04:00
}
2026-09-23 12:27:35 -04:00
function Be ( s , t ) {
2026-09-20 19:17:52 -04:00
const e = new Date ( s );
2026-09-20 18:39:11 -04:00
return Number . isNaN ( e . getTime ()) ? "" : M ( t , {
2026-09-20 13:54:14 -04:00
hour : "numeric" ,
minute : "2-digit" ,
hour12 : ! 0
2026-09-20 14:19:39 -04:00
}). format ( e );
2026-09-20 13:54:14 -04:00
}
2026-09-23 12:27:35 -04:00
function Fe ( s , t ) {
2026-09-20 18:39:11 -04:00
return M ( t , {
hour : "numeric" ,
minute : "2-digit" ,
hour12 : ! 0
2026-09-20 19:17:52 -04:00
}). format ( s );
2026-09-20 18:39:11 -04:00
}
2026-09-23 12:27:35 -04:00
function Qe ( s ) {
2026-09-20 19:17:52 -04:00
if ( ! s )
2026-09-20 13:54:14 -04:00
return null ;
2026-09-20 19:17:52 -04:00
const t = /^(\d{1,2}):(\d{2})$/ . exec ( s . trim ());
2026-09-20 14:19:39 -04:00
if ( ! t )
2026-09-20 13:54:14 -04:00
return null ;
2026-09-20 14:19:39 -04:00
const e = Number ( t [ 1 ]);
if ( e > 23 )
2026-09-20 13:54:14 -04:00
return null ;
2026-09-20 14:19:39 -04:00
const n = e >= 12 ? "PM" : "AM" ;
return ` ${ e % 12 === 0 ? 12 : e % 12 } : ${ t [ 2 ] } ${ n } ` ;
2026-09-20 13:54:14 -04:00
}
2026-09-20 19:17:52 -04:00
function w ( s ) {
return typeof s == "string" ? s . trim () : "" ;
2026-09-20 13:54:14 -04:00
}
2026-09-20 19:17:52 -04:00
function y ( s , t ) {
if ( s == null || s === "" )
2026-09-20 14:19:39 -04:00
return t ;
2026-09-20 19:17:52 -04:00
const e = typeof s == "number" ? s : Number ( s );
2026-09-20 14:19:39 -04:00
return Number . isFinite ( e ) ? e : t ;
2026-09-20 13:54:14 -04:00
}
2026-09-20 19:17:52 -04:00
function b ( s ) {
return Math . max ( 0 , Math . round ( s ));
2026-09-20 13:54:14 -04:00
}
2026-09-20 19:17:52 -04:00
function Y ( s ) {
return s . split ( /[-_]+/ ). filter ( Boolean ). map (( t ) => t . charAt ( 0 ). toUpperCase () + t . slice ( 1 )). join ( " " );
2026-09-20 13:54:14 -04:00
}
2026-09-23 12:27:35 -04:00
function We ( s , t ) {
2026-09-20 18:39:11 -04:00
const e = M ( t , {
2026-09-20 13:54:14 -04:00
year : "numeric" ,
month : "2-digit" ,
day : "2-digit" ,
hour : "2-digit" ,
minute : "2-digit" ,
second : "2-digit" ,
hourCycle : "h23"
2026-09-20 19:17:52 -04:00
}). formatToParts ( new Date ( s )), n = ( r ) => {
2026-09-20 14:19:39 -04:00
const o = e . find (( l ) => l . type === r );
2026-09-20 13:54:14 -04:00
return o ? Number ( o . value ) : Number . NaN ;
2026-09-20 19:17:52 -04:00
}, i = Date . UTC (
2026-09-20 13:54:14 -04:00
n ( "year" ),
n ( "month" ) - 1 ,
n ( "day" ),
n ( "hour" ),
n ( "minute" ),
n ( "second" )
);
2026-09-20 19:17:52 -04:00
return Number . isFinite ( i ) ? i - s : 0 ;
2026-09-20 13:54:14 -04:00
}
2026-09-20 19:17:52 -04:00
function Et ( s , t ) {
if ( typeof s != "string" )
2026-09-20 13:54:14 -04:00
return null ;
2026-09-20 19:17:52 -04:00
const e = s . split ( "-" );
2026-09-20 14:19:39 -04:00
if ( e . length !== 3 )
2026-09-20 13:54:14 -04:00
return null ;
2026-09-20 19:17:52 -04:00
const [ n , i , r ] = e . map (( a ) => Number ( a ));
if ( ! n || ! i || ! r )
2026-09-20 13:54:14 -04:00
return null ;
2026-09-20 14:19:39 -04:00
if ( ! t ) {
2026-09-20 19:17:52 -04:00
const a = new Date ( n , i - 1 , r );
2026-09-20 13:54:14 -04:00
return Number . isNaN ( a . getTime ()) ? null : a ;
}
2026-09-23 12:27:35 -04:00
const o = Date . UTC ( n , i - 1 , r ), l = new Date ( o - We ( o , t ));
2026-09-20 13:54:14 -04:00
return Number . isNaN ( l . getTime ()) ? null : l ;
}
2026-09-23 12:27:35 -04:00
function Ze () {
2026-09-20 19:17:52 -04:00
const s = window . location . pathname . split ( "/" ). filter ( Boolean );
return s . length > 0 ? s [ s . length - 1 ]. toLowerCase () : "" ;
2026-09-20 13:54:14 -04:00
}
2026-09-23 12:27:35 -04:00
function Ge ( s ) {
2026-09-20 19:17:52 -04:00
if ( ! s || typeof s != "object" )
2026-09-20 13:54:14 -04:00
return null ;
2026-09-20 19:17:52 -04:00
const t = s , e = w ( t . state ). toLowerCase ();
2026-09-20 14:19:39 -04:00
if ( e !== "open" && e !== "completed" )
2026-09-20 13:54:14 -04:00
return null ;
2026-09-20 14:19:39 -04:00
const n = y ( t . id , 0 );
if ( ! n )
return null ;
2026-09-20 19:17:52 -04:00
const i = y ( t . child_id , 0 );
2026-09-20 14:19:39 -04:00
return {
2026-09-20 13:54:14 -04:00
id : n ,
2026-09-20 19:17:52 -04:00
child_id : i > 0 ? i : null ,
title : w ( t . title ) || "Quest" ,
icon : w ( t . icon ) || null ,
window : w ( t . window ). toLowerCase (),
due_time : w ( t . due_time ) || null ,
2026-09-20 14:19:39 -04:00
state : e ,
overdue : t . overdue === ! 0 ,
2026-09-20 19:17:52 -04:00
completed_at : w ( t . completed_at ) || null ,
2026-09-20 18:39:11 -04:00
on_time : t . on_time === ! 0 ? ! 0 : t . on_time === ! 1 ? ! 1 : null
2026-09-20 14:19:39 -04:00
};
2026-09-20 13:54:14 -04:00
}
2026-09-23 12:27:35 -04:00
const Ve = {
2026-09-20 18:39:11 -04:00
"clear-night" : "Clear" ,
cloudy : "Cloudy" ,
exceptional : "Clear" ,
fog : "Foggy" ,
hail : "Hail" ,
lightning : "Storms" ,
"lightning-rainy" : "Storms" ,
partlycloudy : "Partly cloudy" ,
pouring : "Heavy rain" ,
rainy : "Rain" ,
snowy : "Snow" ,
"snowy-rainy" : "Sleet" ,
sunny : "Sunny" ,
windy : "Windy" ,
"windy-variant" : "Windy"
2026-09-23 12:27:35 -04:00
}, Ke = {
2026-09-20 18:39:11 -04:00
"clear-night" : "Clear night skies" ,
cloudy : "Grey skies today" ,
exceptional : "A striking day" ,
fog : "Mist on the road" ,
hail : "Ice from the sky" ,
lightning : "Storms may roll in" ,
"lightning-rainy" : "Storms may roll in" ,
partlycloudy : "Sun between clouds" ,
pouring : "Heavy rain outside" ,
rainy : "Rain on the walls" ,
snowy : "Snow on the peaks" ,
"snowy-rainy" : "Sleet may fall" ,
sunny : "Clear skies today" ,
windy : "A blustery day" ,
"windy-variant" : "A blustery day"
};
2026-09-23 12:27:35 -04:00
function Je ( s ) {
const t = Ve [ s ];
2026-09-20 19:17:52 -04:00
return t || s . charAt ( 0 ). toUpperCase () + s . slice ( 1 );
2026-09-20 18:39:11 -04:00
}
2026-09-23 12:27:35 -04:00
function Xe ( s , t ) {
return Ke [ s ] ?? t ;
2026-09-20 18:39:11 -04:00
}
2026-09-23 12:27:35 -04:00
const Nt = "polygon(0 0, 100% 0, 100% 62%, 50% 100%, 0 62%)" , Ye = "polygon(50% 0, 93% 25%, 93% 75%, 50% 100%, 7% 75%, 7% 25%)" , Mt = [ - 9 , 6 , - 4 ], tn = Pt `
2026-09-20 13:54:14 -04:00
* {
box-sizing: border-box;
}
:host {
display: block;
height: 100%;
--nq-brand-gradient-h: linear-gradient(
90deg,
var(--nq-brand-blue),
var(--nq-brand-purple)
);
}
.board {
position: relative;
display: flex;
flex-direction: column;
height: 1080px;
padding: 0;
overflow: hidden;
background: var(--nq-p-parchment);
box-shadow: var(--nq-p-vignette);
font-family: var(--nq-p-font-body);
}
.frame {
position: absolute;
pointer-events: none;
}
.frame-outer {
inset: 26px;
border: var(--nq-p-frame-outer);
border-radius: 14px;
}
.frame-inner {
inset: 36px;
border: var(--nq-p-frame-inner);
border-radius: 8px;
}
.header {
position: absolute;
top: 56px;
left: var(--nq-p-page-inset);
right: var(--nq-p-page-inset);
display: flex;
align-items: center;
gap: 28px;
}
.crest {
position: relative;
flex: none;
width: 96px;
height: 110px;
padding: 3px;
2026-09-20 19:17:52 -04:00
clip-path: ${ v ( Nt ) } ;
2026-09-20 13:54:14 -04:00
background: rgba(255, 255, 255, 0.22);
}
.crest-face {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
padding-bottom: 32px;
2026-09-20 19:17:52 -04:00
clip-path: ${ v ( Nt ) } ;
2026-09-20 13:54:14 -04:00
background: var(--nq-p-crest);
}
.crest .initial {
font-family: var(--nq-p-font-display);
font-size: 44px;
font-weight: 700;
line-height: 1;
color: #ffffff;
}
2026-09-20 14:04:58 -04:00
.crest.away .crest-face {
background: var(--nq-p-crest-away);
}
2026-09-20 13:54:14 -04:00
.titles {
display: flex;
flex-direction: column;
gap: 8px;
min-width: 0;
}
.title {
margin: 0;
font-family: var(--nq-p-font-display);
font-size: var(--nq-p-size-title);
font-weight: 700;
line-height: 1.1;
color: var(--nq-p-ink);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.sub {
margin: 0;
font-family: var(--nq-p-font-heading);
font-size: 20px;
font-weight: 600;
letter-spacing: 0.24em;
text-transform: uppercase;
line-height: 1.2;
color: var(--nq-p-ink-secondary);
}
.remaining {
margin-left: auto;
flex: none;
display: flex;
align-items: center;
gap: 20px;
padding: 18px 28px;
border: 2px solid var(--nq-p-panel-border);
border-radius: 14px;
background: var(--nq-p-card-panel);
box-shadow: var(--nq-p-panel-shadow);
}
.d20 {
flex: none;
display: inline-flex;
align-items: center;
justify-content: center;
width: 44px;
height: 44px;
2026-09-23 12:27:35 -04:00
clip-path: ${ v ( Ye ) } ;
2026-09-20 13:54:14 -04:00
background: var(--nq-brand-gradient);
}
.d20-numeral {
font-family: var(--nq-p-font-heading);
font-size: 19px;
font-weight: 700;
line-height: 1;
color: #ffffff;
}
.remaining-text {
display: flex;
flex-direction: column;
gap: 4px;
}
.remaining-count {
font-family: var(--nq-p-font-heading);
font-size: 28px;
font-weight: 700;
line-height: 1.1;
color: var(--nq-p-ink);
}
.party-line {
font-family: var(--nq-p-font-body);
font-size: var(--nq-p-size-body);
font-weight: 600;
line-height: 1.2;
color: var(--nq-p-ink-secondary);
}
.columns {
position: absolute;
top: 236px;
left: var(--nq-p-page-inset);
right: var(--nq-p-page-inset);
bottom: 130px;
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 34px;
}
.column {
display: flex;
flex-direction: column;
min-height: 0;
}
.column-head {
flex: none;
display: flex;
align-items: center;
gap: 14px;
padding-bottom: 14px;
border-bottom: var(--nq-p-rule);
}
.column-head svg {
flex: none;
width: 34px;
height: 34px;
color: var(--nq-p-ink-secondary);
}
.column-names {
display: flex;
flex-direction: column;
gap: 2px;
min-width: 0;
}
.column-name {
font-family: var(--nq-p-font-heading);
font-size: var(--nq-p-size-section);
font-weight: 700;
line-height: 1.1;
color: var(--nq-p-ink);
}
.column-range {
font-family: var(--nq-p-font-heading);
font-size: var(--nq-p-size-label);
font-weight: 600;
letter-spacing: var(--nq-p-track-label);
text-transform: uppercase;
line-height: 1.2;
color: var(--nq-p-ink-secondary);
}
.column-count {
margin-left: auto;
flex: none;
font-family: var(--nq-p-font-heading);
font-size: 26px;
font-weight: 700;
line-height: 1.1;
color: var(--nq-p-ink-secondary);
}
.stack {
display: flex;
flex-direction: column;
flex: 1;
min-height: 0;
overflow: visible;
gap: var(--nq-p-quest-gap);
margin-top: 22px;
}
.quest {
position: relative;
display: flex;
align-items: center;
gap: 22px;
min-height: var(--nq-p-quest-min-height);
padding: var(--nq-p-quest-pad);
border: 1px solid var(--nq-p-card-border);
border-radius: var(--nq-p-radius-card);
background: var(--nq-p-card-open);
box-shadow: var(--nq-p-card-shadow);
-webkit-tap-highlight-color: transparent;
transition: transform var(--nq-dur-micro) var(--nq-ease-out);
}
.quest.tappable {
cursor: pointer;
}
.quest.tappable:active {
transform: scale(0.98);
}
.quest.sealed {
background: var(--nq-p-card-done);
opacity: 0.82;
box-shadow: none;
}
.tile {
flex: none;
display: inline-flex;
align-items: center;
justify-content: center;
width: var(--nq-p-tile-size);
height: var(--nq-p-tile-size);
border-radius: 10px;
background: var(--nq-p-icon-tile);
color: #ffffff;
}
.tile svg {
width: 34px;
height: 34px;
}
.sealed .tile {
background: var(--nq-p-icon-tile-done);
color: var(--nq-p-ink-secondary);
}
.quest .body {
flex: 1 1 0;
min-width: 0;
display: flex;
flex-direction: column;
gap: 6px;
}
.quest .quest-title {
font-family: var(--nq-p-font-heading);
font-size: var(--nq-p-size-quest);
font-weight: 700;
line-height: 1.15;
color: var(--nq-p-ink);
overflow-wrap: anywhere;
}
.sealed .quest-title {
color: var(--nq-p-ink-muted);
text-decoration: line-through;
}
.quest .meta {
font-family: var(--nq-p-font-body);
font-size: var(--nq-p-size-body);
font-weight: 600;
line-height: 1.2;
color: var(--nq-p-ink-secondary);
}
.quest .meta.late {
font-family: var(--nq-p-font-heading);
font-weight: 700;
letter-spacing: 0.1em;
text-transform: uppercase;
color: var(--nq-p-ink-late);
}
button.complete {
flex: none;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 10px;
height: var(--nq-p-button-height);
min-width: var(--nq-p-button-min-width);
border: none;
border-radius: 10px;
background: var(--nq-brand-gradient);
color: #ffffff;
font-family: var(--nq-p-font-heading);
font-size: 24px;
font-weight: 700;
line-height: 1;
box-shadow: 0 3px 0 rgba(40, 20, 60, 0.35);
cursor: pointer;
-webkit-tap-highlight-color: transparent;
transition: transform var(--nq-dur-micro) var(--nq-ease-out);
}
button.complete:active {
transform: scale(0.98);
}
button.complete svg {
width: 30px;
height: 30px;
}
button:focus-visible {
outline: 3px solid var(--nq-brand-purple);
outline-offset: 4px;
}
.seal {
position: absolute;
right: 16px;
top: -12px;
display: inline-flex;
align-items: center;
justify-content: center;
width: var(--nq-p-seal-size);
height: var(--nq-p-seal-size);
border-radius: var(--nq-p-radius-pill);
background: var(--nq-p-seal);
box-shadow: var(--nq-p-seal-shadow);
color: rgba(255, 235, 235, 0.95);
transform: rotate(var(--seal-rot, 0deg));
animation: seal-in var(--nq-dur-base) var(--nq-ease-out);
pointer-events: none;
}
.seal svg {
width: 38px;
height: 38px;
}
@keyframes seal-in {
from {
opacity: 0;
transform: scale(1.15) rotate(var(--seal-rot, 0deg));
}
to {
opacity: 1;
transform: scale(1) rotate(var(--seal-rot, 0deg));
}
}
.rollup {
border: 2px dashed var(--nq-p-panel-border);
border-radius: 14px;
padding: 16px 22px;
}
.rollup-label {
display: block;
font-family: var(--nq-p-font-heading);
font-size: 18px;
font-weight: 600;
letter-spacing: var(--nq-p-track-label);
text-transform: uppercase;
line-height: 1.2;
color: var(--nq-p-ink-secondary);
}
.rollup-body {
margin: 6px 0 0;
font-family: var(--nq-p-font-body);
font-size: 23px;
font-weight: 600;
line-height: 1.35;
color: var(--nq-p-ink-secondary);
}
2026-09-20 14:04:58 -04:00
.notice-wrap {
position: absolute;
top: 236px;
left: var(--nq-p-page-inset);
right: var(--nq-p-page-inset);
bottom: 130px;
display: flex;
align-items: center;
justify-content: center;
}
.notice {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 20px;
width: 100%;
max-width: 980px;
padding: 56px 64px;
border: 2px solid var(--nq-p-panel-border);
border-radius: 20px;
background: var(--nq-p-card-panel);
box-shadow: var(--nq-p-panel-shadow);
text-align: center;
}
.notice svg {
width: 46px;
height: 46px;
color: var(--nq-p-ink-secondary);
}
.notice.away {
background: linear-gradient(#f2ecdd, #e6dcc6);
border-style: dashed;
box-shadow: none;
}
.notice-headline {
font-family: var(--nq-p-font-heading);
font-size: 40px;
font-weight: 700;
line-height: 1.15;
color: var(--nq-p-ink);
}
.notice-body {
margin: 0;
font-family: var(--nq-p-font-body);
font-size: 24px;
font-weight: 600;
line-height: 1.4;
color: var(--nq-p-ink-secondary);
}
.notice-seal {
display: inline-flex;
align-items: center;
justify-content: center;
width: 78px;
height: 78px;
border-radius: var(--nq-p-radius-pill);
background: var(--nq-p-seal);
box-shadow: var(--nq-p-seal-shadow);
color: rgba(255, 235, 235, 0.95);
transform: rotate(-6deg);
}
.notice-seal svg {
width: 38px;
height: 38px;
color: rgba(255, 235, 235, 0.95);
}
2026-09-20 13:54:14 -04:00
.scrim {
position: absolute;
inset: 0;
z-index: 10;
background: rgba(30, 20, 10, 0.62);
}
.dialog {
position: absolute;
top: 196px;
left: 460px;
width: 1000px;
border: 3px solid rgba(92, 62, 26, 0.5);
border-radius: 20px;
background: var(--nq-p-card-panel);
box-shadow: 0 26px 60px rgba(20, 10, 0, 0.5);
padding: 64px 68px 56px;
animation: dialog-in var(--nq-dur-modal) var(--nq-ease-out);
}
@keyframes dialog-in {
from {
opacity: 0;
transform: scale(0.96);
}
to {
opacity: 1;
transform: scale(1);
}
}
.dialog-header {
display: flex;
align-items: center;
gap: 24px;
}
.dialog-tile {
flex: none;
display: inline-flex;
align-items: center;
justify-content: center;
width: 104px;
height: 104px;
border-radius: 12px;
background: var(--nq-p-icon-tile);
color: #ffffff;
}
.dialog-tile svg {
width: 56px;
height: 56px;
}
.dialog-titles {
display: flex;
flex-direction: column;
gap: 8px;
min-width: 0;
}
.dialog-kicker {
font-family: var(--nq-p-font-heading);
font-size: var(--nq-p-size-label);
font-weight: 600;
letter-spacing: 0.24em;
text-transform: uppercase;
line-height: 1.2;
color: var(--nq-p-ink-secondary);
}
.dialog-quest-title {
font-family: var(--nq-p-font-display);
font-size: 58px;
font-weight: 700;
line-height: 1.1;
color: var(--nq-p-ink);
overflow-wrap: anywhere;
}
.dialog-body {
margin: 28px 0 0;
font-family: var(--nq-p-font-body);
font-size: 32px;
font-weight: 600;
line-height: 1.35;
color: #3f2f1c;
}
.dialog-buttons {
display: flex;
gap: 24px;
margin-top: 40px;
}
button.confirm-button {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 12px;
height: var(--nq-p-confirm-button);
border-radius: 10px;
font-family: var(--nq-p-font-heading);
font-weight: 700;
line-height: 1;
cursor: pointer;
-webkit-tap-highlight-color: transparent;
transition: transform var(--nq-dur-micro) var(--nq-ease-out);
}
button.confirm-button:active {
transform: scale(0.98);
}
button.not-yet {
flex: 1;
border: 2px solid rgba(92, 62, 26, 0.5);
background: rgba(92, 62, 26, 0.1);
color: var(--nq-p-ink);
font-size: 30px;
}
button.not-yet svg {
width: 34px;
height: 34px;
}
button.do-complete {
flex: 2;
border: none;
background: var(--nq-brand-gradient);
color: #ffffff;
font-size: 32px;
}
button.do-complete svg {
width: 38px;
height: 38px;
}
2026-09-20 14:19:39 -04:00
.toast {
position: absolute;
left: 50%;
bottom: 158px;
z-index: 20;
transform: translateX(-50%);
max-width: calc(100% - 124px);
padding: 20px 32px;
border: 2px solid var(--nq-p-panel-border);
border-radius: 14px;
background: var(--nq-p-card-panel);
box-shadow: var(--nq-p-panel-shadow);
font-family: var(--nq-p-font-body);
font-size: 23px;
font-weight: 600;
line-height: 1.2;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
color: var(--nq-p-ink-secondary);
animation: toast-in var(--nq-dur-base) var(--nq-ease-out);
pointer-events: none;
}
@keyframes toast-in {
from {
opacity: 0;
transform: translate(-50%, 12px);
}
to {
opacity: 1;
transform: translate(-50%, 0);
}
}
2026-09-20 18:39:11 -04:00
.complete-screen {
position: absolute;
inset: 0;
display: flex;
flex-direction: column;
align-items: center;
padding: 96px 62px 130px;
text-align: center;
}
.complete-seal {
display: inline-flex;
align-items: center;
justify-content: center;
width: 168px;
height: 168px;
border-radius: var(--nq-p-radius-pill);
background: var(--nq-p-seal);
box-shadow: 0 10px 24px rgba(60, 10, 20, 0.42);
color: rgba(255, 235, 235, 0.95);
transform: rotate(-6deg);
}
.complete-seal svg {
width: 86px;
height: 86px;
}
.complete-title {
margin: 28px 0 0;
font-family: var(--nq-p-font-display);
font-size: 86px;
font-weight: 900;
line-height: 1.1;
background: var(--nq-brand-gradient-h);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
-webkit-text-fill-color: transparent;
}
.complete-sub {
margin: 16px 0 0;
max-width: 1000px;
font-family: var(--nq-p-font-body);
font-size: 34px;
font-weight: 600;
line-height: 1.35;
color: var(--nq-p-ink-secondary);
text-wrap: pretty;
}
.complete-countdown {
margin: 12px 0 0;
font-family: var(--nq-p-font-body);
font-size: 25px;
font-weight: 600;
line-height: 1.2;
color: var(--nq-p-ink-secondary);
}
.complete-stats {
position: absolute;
top: 540px;
left: 200px;
right: 200px;
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 26px;
}
.complete-stat {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 8px;
padding: 28px 16px;
border: 2px solid var(--nq-p-panel-border);
border-radius: 16px;
background: var(--nq-p-card-panel);
box-shadow: var(--nq-p-panel-shadow);
}
.complete-stat .numeral {
font-family: var(--nq-p-font-heading);
font-size: 58px;
font-weight: 900;
line-height: 1;
color: var(--nq-p-ink);
}
.complete-stat .label {
font-family: var(--nq-p-font-heading);
font-size: 17px;
font-weight: 600;
letter-spacing: 0.14em;
text-transform: uppercase;
line-height: 1.2;
color: var(--nq-p-ink-secondary);
}
.dock {
position: absolute;
left: 46px;
right: 46px;
bottom: 46px;
height: var(--nq-p-dock-height);
display: flex;
align-items: center;
justify-content: center;
gap: 24px;
padding: 0 40px;
border-radius: 14px;
background: var(--nq-p-dock-bg);
pointer-events: none;
user-select: none;
color: var(--nq-p-dock-ink);
}
.dock svg {
flex: none;
width: 40px;
height: 40px;
color: var(--nq-p-dock-ink);
}
.dock .divider {
flex: none;
width: 1px;
height: 40px;
background: var(--nq-p-dock-divider);
}
.dock .temp {
font-family: var(--nq-p-font-body);
font-size: 38px;
font-weight: 800;
line-height: 1;
}
.dock .condition {
font-family: var(--nq-p-font-body);
font-size: 26px;
font-weight: 600;
line-height: 1.2;
color: var(--nq-p-dock-ink-secondary);
}
.dock .date {
font-family: var(--nq-p-font-body);
font-size: 26px;
font-weight: 600;
line-height: 1.2;
color: var(--nq-p-dock-ink-secondary);
}
.dock .clock {
font-family: var(--nq-p-font-body);
font-size: 38px;
font-weight: 800;
line-height: 1;
}
2026-09-20 19:17:52 -04:00
` , H = d `<svg
2026-09-20 13:54:14 -04:00
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
aria-hidden="true"
>
<path d="M20 6 9 17l-5-5"></path>
2026-09-23 12:27:35 -04:00
</svg>` , en = d `<svg
2026-09-20 13:54:14 -04:00
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
aria-hidden="true"
>
<path d="M18 6 6 18"></path>
<path d="m6 6 12 12"></path>
2026-09-20 19:17:52 -04:00
</svg>` , tt = d `<svg
2026-09-20 13:54:14 -04:00
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
aria-hidden="true"
>
<polygon
points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26"
></polygon>
2026-09-23 12:27:35 -04:00
</svg>` , nn = d `<svg
2026-09-20 13:54:14 -04:00
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
aria-hidden="true"
>
<path d="M12 2v8"></path>
<path d="m4.93 10.93 1.41 1.41"></path>
<path d="M2 18h2"></path>
<path d="M20 18h2"></path>
<path d="m19.07 10.93-1.41 1.41"></path>
<path d="M22 22H2"></path>
<path d="m8 6 4-4 4 4"></path>
<path d="M16 18a4 4 0 0 0-8 0"></path>
2026-09-20 19:17:52 -04:00
</svg>` , Ht = d `<svg
2026-09-20 13:54:14 -04:00
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
aria-hidden="true"
>
<circle cx="12" cy="12" r="4"></circle>
<path d="M12 2v2"></path>
<path d="M12 20v2"></path>
<path d="m4.93 4.93 1.41 1.41"></path>
<path d="m17.66 17.66 1.41 1.41"></path>
<path d="M2 12h2"></path>
<path d="M20 12h2"></path>
<path d="m6.34 17.66-1.41 1.41"></path>
<path d="m19.07 4.93-1.41 1.41"></path>
2026-09-23 12:27:35 -04:00
</svg>` , sn = d `<svg
2026-09-20 13:54:14 -04:00
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
aria-hidden="true"
>
<path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z"></path>
2026-09-23 12:27:35 -04:00
</svg>` , rn = d `<svg
2026-09-20 14:04:58 -04:00
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
aria-hidden="true"
>
<path d="M3.5 21 12 3.5 20.5 21"></path>
<path d="M9 21l3-8 3 8"></path>
2026-09-23 12:27:35 -04:00
</svg>` , on = d `<svg
2026-09-20 14:04:58 -04:00
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
aria-hidden="true"
>
<circle cx="12" cy="12" r="10"></circle>
<polygon points="16.24 7.76 14.12 14.12 7.76 16.24 9.88 9.88 16.24 7.76"></polygon>
2026-09-23 12:27:35 -04:00
</svg>` , an = d `<svg
2026-09-20 14:04:58 -04:00
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
aria-hidden="true"
>
<path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3Z"></path>
<path d="M12 9v4"></path>
<path d="M12 17h.01"></path>
2026-09-23 12:27:35 -04:00
</svg>` , ln = d `<svg
2026-09-20 14:04:58 -04:00
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
aria-hidden="true"
>
<path d="M17.5 19H9a7 7 0 1 1 6.71-9h1.79a4.5 4.5 0 1 1 0 9Z"></path>
<path d="m2 2 20 20"></path>
2026-09-23 12:27:35 -04:00
</svg>` , cn = d `<svg
2026-09-20 18:39:11 -04:00
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
aria-hidden="true"
>
<path d="M13 16a3 3 0 1 1 0 6H7a5 5 0 1 1 4.9-6Z"></path>
<path d="M10.1 9A6 6 0 0 1 16 4a4.5 4.5 0 0 0 8.9 4.2v.1a6 6 0 0 1-5.2 5.7"></path>
2026-09-23 12:27:35 -04:00
</svg>` , dn = {
icon : on ,
2026-09-20 14:04:58 -04:00
headline : "No adventurer chosen" ,
body : "Open The Party and tap your crest to open your quest log."
2026-09-23 12:27:35 -04:00
}, pn = {
icon : an ,
2026-09-20 14:04:58 -04:00
headline : "NestQuest is not set up yet" ,
body : "A parent needs to finish setting up NestQuest."
2026-09-23 12:27:35 -04:00
}, hn = {
icon : ln ,
2026-09-20 14:04:58 -04:00
headline : "The records cannot be reached" ,
body : "The party's records are quiet right now. NestQuest will return shortly."
2026-09-20 14:19:39 -04:00
}, Ot = [
2026-09-23 12:27:35 -04:00
{ key : "morning" , name : "Morning" , range : "Until 11:59 AM" , icon : nn },
2026-09-20 19:17:52 -04:00
{ key : "afternoon" , name : "Afternoon" , range : "12:00– 5:00 PM" , icon : Ht },
2026-09-23 12:27:35 -04:00
{ key : "evening" , name : "Evening" , range : "5:00– 9:00 PM" , icon : sn }
2026-09-20 13:54:14 -04:00
];
2026-09-23 12:27:35 -04:00
class un extends A {
2026-09-20 10:08:38 -04:00
static properties = {
hass : { attribute : ! 1 },
2026-09-20 13:54:14 -04:00
_config : { state : ! 0 },
_now : { state : ! 0 },
2026-09-20 14:19:39 -04:00
_confirm : { state : ! 0 },
_optimistic : { state : ! 0 },
2026-09-20 18:39:11 -04:00
_toast : { state : ! 0 },
_countdown : { state : ! 0 }
2026-09-20 10:08:38 -04:00
};
2026-09-23 12:27:35 -04:00
static styles = [ v ( Dt ), tn ];
2026-09-20 10:08:38 -04:00
hass ;
_config ;
2026-09-20 13:54:14 -04:00
_now = /* @__PURE__ */ new Date ();
_confirm = null ;
2026-09-20 14:19:39 -04:00
/** instanceId → the completion instant stamped before the service has
* answered; the seal shows immediately and reverts on failure. */
_optimistic = /* @__PURE__ */ new Map ();
_toast = null ;
2026-09-20 18:39:11 -04:00
_countdown = null ;
2026-09-20 13:54:14 -04:00
_clockTimer ;
_idleTimer ;
_confirmTimer ;
2026-09-20 14:19:39 -04:00
_toastTimer ;
2026-09-20 18:39:11 -04:00
_completeTimer ;
2026-09-20 19:17:52 -04:00
_unsubs = [];
_subscribed = ! 1 ;
_subGeneration = 0 ;
_retryTimer ;
2026-09-20 14:19:39 -04:00
setConfig ( t ) {
if ( ! t || typeof t != "object" )
2026-09-20 10:08:38 -04:00
throw new Error ( "Invalid configuration" );
2026-09-20 14:19:39 -04:00
this . _config = t ;
2026-09-20 10:08:38 -04:00
}
2026-09-20 19:17:52 -04:00
_hassConnection () {
const t = this . hass ? . connection ;
return ! t || typeof t != "object" || typeof t . subscribeEvents != "function" ? null : t ;
}
_subscribeLive () {
if ( ! this . isConnected || this . _subscribed )
return ;
const t = this . _hassConnection ();
if ( ! t )
return ;
this . _subscribed = ! 0 ;
const e = ++ this . _subGeneration , n = ( i ) => {
i . then (( r ) => {
this . _subscribed && e === this . _subGeneration ? this . _unsubs . push ( r ) : r ();
}). catch (() => {
e === this . _subGeneration && ( this . _unsubscribeLive (), this . _armSubscribeRetry ());
});
};
2026-09-23 12:27:35 -04:00
for ( const i of je )
2026-09-20 19:17:52 -04:00
n (
t . subscribeEvents (() => this . requestUpdate (), i )
);
}
_armSubscribeRetry () {
this . _retryTimer === void 0 && ( this . _retryTimer = window . setTimeout (() => {
this . _retryTimer = void 0 , this . _subscribeLive ();
}, 1e3 ));
}
_clearSubscribeRetry () {
this . _retryTimer !== void 0 && ( window . clearTimeout ( this . _retryTimer ), this . _retryTimer = void 0 );
}
_unsubscribeLive () {
this . _clearSubscribeRetry (), this . _subGeneration ++ ;
for ( const t of this . _unsubs )
t ();
this . _unsubs = [], this . _subscribed = ! 1 ;
}
2026-09-20 10:08:38 -04:00
getCardSize () {
2026-09-20 13:54:14 -04:00
return 22 ;
}
connectedCallback () {
2026-09-20 19:17:52 -04:00
super . connectedCallback (), this . _subscribeLive (), this . _now = /* @__PURE__ */ new Date (), this . _clockTimer = window . setInterval (() => {
2026-09-20 13:54:14 -04:00
this . _now = /* @__PURE__ */ new Date ();
2026-09-20 18:39:11 -04:00
}, 6e4 ), window . addEventListener ( "pointerdown" , this . _onActivity , ! 0 ), window . addEventListener ( "touchstart" , this . _onActivity , ! 0 ), window . addEventListener ( "keydown" , this . _onActivity , ! 0 ), this . _armIdle (), this . _logView (). kind === "complete-day" && this . _armCompleteTimer ();
}
updated () {
2026-09-20 19:17:52 -04:00
this . _subscribeLive (), this . _logView (). kind === "complete-day" ? ( this . _clearIdle (), this . _armCompleteTimer ()) : ( this . _clearCompleteTimer (), this . _countdown = null , this . _idleTimer === void 0 && this . _armIdle ());
2026-09-20 13:54:14 -04:00
}
disconnectedCallback () {
2026-09-20 19:17:52 -04:00
this . _unsubscribeLive (), this . _stopClock (), this . _clearIdle (), this . _clearConfirmTimer (), this . _clearToastTimer (), this . _clearCompleteTimer (), window . removeEventListener ( "pointerdown" , this . _onActivity , ! 0 ), window . removeEventListener ( "touchstart" , this . _onActivity , ! 0 ), window . removeEventListener ( "keydown" , this . _onActivity , ! 0 ), super . disconnectedCallback ();
2026-09-20 10:08:38 -04:00
}
render () {
2026-09-20 14:19:39 -04:00
const t = this . _logView ();
2026-09-20 19:17:52 -04:00
return d `
2026-09-20 13:54:14 -04:00
<div class="board">
<div class="frame frame-outer"></div>
<div class="frame frame-inner"></div>
2026-09-20 14:19:39 -04:00
${ this . _renderMain ( t ) }
2026-09-20 13:54:14 -04:00
${ this . _renderConfirm () }
2026-09-20 14:19:39 -04:00
${ this . _renderToast () }
2026-09-20 13:54:14 -04:00
</div>
` ;
2026-09-20 10:08:38 -04:00
}
2026-09-20 14:19:39 -04:00
_renderToast () {
2026-09-20 19:17:52 -04:00
return this . _toast === null ? g : d `
2026-09-20 14:19:39 -04:00
<div class="toast" role="status"> ${ this . _toast } </div>
` ;
}
_renderMain ( t ) {
switch ( t . kind ) {
2026-09-20 14:04:58 -04:00
case "no-adventurer" :
2026-09-20 19:17:52 -04:00
return this . _renderNotice ( dn );
2026-09-23 12:27:35 -04:00
case "not-set-up" :
return this . _renderNotice ( pn );
case "unreachable" :
return this . _renderNotice ( hn );
2026-09-20 14:04:58 -04:00
case "away" : {
2026-09-20 14:19:39 -04:00
const e = [ "The quest log unlocks when they return." ];
2026-09-20 19:17:52 -04:00
return t . returns && e . push ( `Returns ${ t . returns } ` ), d `
2026-09-20 14:19:39 -04:00
${ this . _renderHeader ( t ) }
2026-09-20 14:04:58 -04:00
<div class="notice-wrap">
<div class="notice away" role="status">
2026-09-23 12:27:35 -04:00
${ rn }
2026-09-20 14:19:39 -04:00
<span class="notice-headline"> ${ t . name } is on travels</span>
2026-09-20 19:17:52 -04:00
${ e . map (( n ) => d `<p class="notice-body"> ${ n } </p>` ) }
2026-09-20 14:04:58 -04:00
</div>
</div>
` ;
}
case "empty-day" :
2026-09-20 19:17:52 -04:00
return d `
2026-09-20 14:19:39 -04:00
${ this . _renderHeader ( t ) }
2026-09-20 14:04:58 -04:00
<div class="notice-wrap">
<div class="notice" role="status">
2026-09-20 19:17:52 -04:00
${ Ht }
2026-09-20 14:04:58 -04:00
<span class="notice-headline">No quests today</span>
<p class="notice-body">
2026-09-20 14:19:39 -04:00
${ `Nothing was posted for today, ${ t . name } . Enjoy the day's rest!` }
2026-09-20 14:04:58 -04:00
</p>
</div>
</div>
` ;
2026-09-20 18:39:11 -04:00
case "complete-day" : {
const e = this . _completeStats (), n = this . _countdown ?? this . _completeSeconds ();
2026-09-20 19:17:52 -04:00
return d `
2026-09-20 18:39:11 -04:00
<div class="complete-screen" role="status">
2026-09-20 19:17:52 -04:00
<span class="complete-seal" aria-hidden="true"> ${ H } </span>
2026-09-20 18:39:11 -04:00
<h1 class="complete-title">Quest complete</h1>
<p class="complete-sub"> ${ this . _completeSub ( t . name ) } </p>
<p class="complete-countdown">
Returning to The Party in ${ n } seconds
</p>
<div class="complete-stats">
<div class="complete-stat">
<span class="numeral"> ${ e . claimed } </span>
<span class="label">Quests claimed</span>
</div>
<div class="complete-stat">
<span class="numeral"> ${ e . onTime } </span>
<span class="label">On time</span>
</div>
<div class="complete-stat">
<span class="numeral"> ${ e . late } </span>
<span class="label">Late</span>
</div>
<div class="complete-stat">
<span class="numeral"> ${ e . party } </span>
<span class="label">The Party</span>
</div>
2026-09-20 14:04:58 -04:00
</div>
</div>
2026-09-20 18:39:11 -04:00
${ this . _renderDock () }
2026-09-20 14:04:58 -04:00
` ;
2026-09-20 18:39:11 -04:00
}
2026-09-20 14:04:58 -04:00
default :
2026-09-20 19:17:52 -04:00
return d `
2026-09-20 14:19:39 -04:00
${ this . _renderHeader ( t ) }
2026-09-20 14:04:58 -04:00
<div class="columns">
2026-09-20 14:19:39 -04:00
${ Ot . map (( e ) => this . _renderColumn ( e )) }
2026-09-20 14:04:58 -04:00
</div>
` ;
}
2026-09-20 13:54:14 -04:00
}
2026-09-20 14:04:58 -04:00
/** Resolve the log's single render state; the priority order is
* design/PANEL-EMPTY-STATES.md §2. */
_logView () {
2026-09-20 14:19:39 -04:00
const t = this . _childSlug ();
if ( ! t )
2026-09-20 14:04:58 -04:00
return { kind : "no-adventurer" };
2026-09-20 14:19:39 -04:00
const e = this . _dueSensorResolution ( t );
if ( e === "missing" )
2026-09-20 14:04:58 -04:00
return { kind : "not-set-up" };
2026-09-20 14:19:39 -04:00
if ( e === "stale" )
2026-09-20 14:04:58 -04:00
return { kind : "unreachable" };
2026-09-20 18:39:11 -04:00
const n = this . _childName ( t ) ?? Y ( t );
2026-09-20 14:19:39 -04:00
if ( ! this . _childPresent ( t ))
return { kind : "away" , name : n , returns : this . _awayReturns ( t ) };
2026-09-20 19:17:52 -04:00
const i = this . _state ( `binary_sensor.nestquest_ ${ t } _all_done` );
if ( i && String ( i . state ?? "" ). trim (). toLowerCase () === "on" )
2026-09-20 18:39:11 -04:00
return { kind : "complete-day" , name : n };
const r = this . _state ( `sensor.nestquest_ ${ t } _quests_due_today` );
2026-09-20 19:17:52 -04:00
return b ( y ( r ? . state , 0 )) === 0 ? { kind : "empty-day" , name : n } : this . _remaining () === 0 ? { kind : "complete-day" , name : n } : { kind : "normal" };
2026-09-20 14:04:58 -04:00
}
/** "missing" when the due sensor does not exist (integration not
* configured), "stale" when it answers unavailable/unknown (backend
* unreachable or the child is absent from the snapshot), null when
* it resolves. */
2026-09-20 14:19:39 -04:00
_dueSensorResolution ( t ) {
const e = this . _state ( `sensor.nestquest_ ${ t } _quests_due_today` );
if ( ! e )
2026-09-20 14:04:58 -04:00
return "missing" ;
2026-09-20 14:19:39 -04:00
const n = String ( e . state ?? "" ). trim (). toLowerCase ();
2026-09-20 14:04:58 -04:00
return ! n || n === "unavailable" || n === "unknown" ? "stale" : null ;
}
2026-09-20 14:19:39 -04:00
_childPresent ( t ) {
const n = this . _state ( `sensor.nestquest_ ${ t } _quests_due_today` ) ? . attributes ? . present ;
2026-09-20 14:04:58 -04:00
if ( typeof n == "boolean" )
return n ;
2026-09-20 19:17:52 -04:00
const i = this . _state (
2026-09-20 14:19:39 -04:00
`binary_sensor.nestquest_ ${ t } _present_today`
2026-09-20 14:04:58 -04:00
);
2026-09-20 19:17:52 -04:00
return i ? String ( i . state ?? "" ). trim (). toLowerCase () === "on" : ! 0 ;
2026-09-20 14:04:58 -04:00
}
2026-09-20 14:19:39 -04:00
_awayReturns ( t ) {
const e = this . _timeZone (), n = this . _state (
`binary_sensor.nestquest_ ${ t } _present_today`
2026-09-20 19:17:52 -04:00
), i = Et (
2026-09-20 14:04:58 -04:00
n ? . attributes ? . next_present ,
2026-09-20 14:19:39 -04:00
e
2026-09-20 14:04:58 -04:00
);
2026-09-23 12:27:35 -04:00
return i ? D ( i , e ) : null ;
2026-09-20 14:04:58 -04:00
}
2026-09-20 14:19:39 -04:00
_renderNotice ( t ) {
2026-09-20 19:17:52 -04:00
return d `
2026-09-20 14:04:58 -04:00
<div class="notice-wrap">
<div class="notice" role="status">
2026-09-20 14:19:39 -04:00
${ t . icon }
<span class="notice-headline"> ${ t . headline } </span>
<p class="notice-body"> ${ t . body } </p>
2026-09-20 14:04:58 -04:00
</div>
</div>
` ;
}
_timeZone () {
2026-09-23 12:27:35 -04:00
return De ( this . hass );
2026-09-20 14:04:58 -04:00
}
2026-09-20 14:19:39 -04:00
_state ( t ) {
const n = this . hass ? . states ? .[ t ];
2026-09-20 13:54:14 -04:00
return n && typeof n == "object" ? n : null ;
}
_childSlug () {
2026-09-23 12:27:35 -04:00
return Ze ();
2026-09-20 13:54:14 -04:00
}
_boardPath () {
2026-09-20 19:17:52 -04:00
return w ( this . _config ? . board_path ). replace ( /\/+$/ , "" );
2026-09-20 13:54:14 -04:00
}
_idleSeconds () {
2026-09-20 14:19:39 -04:00
const t = y ( this . _config ? . idle_return_seconds , 40 );
return t > 0 ? t : 40 ;
2026-09-20 13:54:14 -04:00
}
_confirmSeconds () {
2026-09-20 14:19:39 -04:00
const t = y ( this . _config ? . confirm_timeout_seconds , 15 );
return t > 0 ? t : 15 ;
2026-09-20 13:54:14 -04:00
}
2026-09-20 18:39:11 -04:00
_completeSeconds () {
const t = y ( this . _config ? . complete_screen_seconds , 12 );
return t > 0 ? t : 12 ;
}
2026-09-20 14:19:39 -04:00
_childName ( t ) {
if ( ! t )
2026-09-20 13:54:14 -04:00
return null ;
2026-09-20 14:19:39 -04:00
const e = this . _state ( `sensor.nestquest_ ${ t } _quests_due_today` ) ? . attributes ? . child_name ;
return typeof e == "string" && e . trim () ? e . trim () : null ;
2026-09-20 13:54:14 -04:00
}
2026-09-20 14:19:39 -04:00
_childCounts ( t ) {
const e = this . _state ( `sensor.nestquest_ ${ t } _quests_due_today` ), n = this . _state (
`sensor.nestquest_ ${ t } _quests_completed_today`
2026-09-20 19:17:52 -04:00
), i = b ( y ( e ? . state , 0 )), r = b ( y ( n ? . state , 0 ));
return { due : i , completed : r };
2026-09-20 13:54:14 -04:00
}
_instances () {
2026-09-20 14:19:39 -04:00
const t = this . _childSlug ();
if ( ! t )
2026-09-20 13:54:14 -04:00
return [];
2026-09-20 14:19:39 -04:00
const e = this . _state ( `sensor.nestquest_ ${ t } _quests_due_today` ) ? . attributes ? . instances ;
if ( ! Array . isArray ( e ))
return [];
2026-09-23 12:27:35 -04:00
const n = e . map ( Ge ). filter (( r ) => r !== null );
2026-09-20 14:19:39 -04:00
if ( this . _optimistic . size === 0 )
return n ;
2026-09-20 19:17:52 -04:00
let i = ! 1 ;
2026-09-20 14:19:39 -04:00
for ( const r of n ) {
const o = this . _optimistic . get ( r . id );
if ( o !== void 0 ) {
if ( r . state === "completed" ) {
2026-09-20 19:17:52 -04:00
this . _optimistic . delete ( r . id ), i = ! 0 ;
2026-09-20 14:19:39 -04:00
continue ;
}
r . state = "completed" , r . overdue = ! 1 , r . completed_at = o ;
}
}
2026-09-20 19:17:52 -04:00
return i && ( this . _optimistic = new Map ( this . _optimistic )), n ;
2026-09-20 13:54:14 -04:00
}
_remaining () {
2026-09-20 14:19:39 -04:00
const t = this . _childSlug ();
if ( ! t )
2026-09-20 13:54:14 -04:00
return 0 ;
2026-09-20 14:19:39 -04:00
const e = this . _state (
`sensor.nestquest_ ${ t } _quests_remaining_today`
2026-09-20 13:54:14 -04:00
);
2026-09-20 14:19:39 -04:00
if ( e )
2026-09-20 19:17:52 -04:00
return b ( y ( e . state , 0 ));
const { due : n , completed : i } = this . _childCounts ( t );
return b ( n - i );
2026-09-20 13:54:14 -04:00
}
_partyCounts () {
2026-09-20 14:19:39 -04:00
const t = this . _state (
2026-09-20 13:54:14 -04:00
"sensor.nestquest_household_quests_due_today"
2026-09-20 14:19:39 -04:00
), e = this . _state (
2026-09-20 13:54:14 -04:00
"sensor.nestquest_household_quests_completed_today"
);
2026-09-20 14:19:39 -04:00
if ( t || e )
2026-09-20 13:54:14 -04:00
return {
2026-09-20 19:17:52 -04:00
completed : b ( y ( e ? . state , 0 )),
due : b ( y ( t ? . state , 0 ))
2026-09-20 13:54:14 -04:00
};
2026-09-20 19:17:52 -04:00
const n = this . _childSlug (), { due : i , completed : r } = this . _childCounts ( n );
return { completed : r , due : i };
2026-09-20 18:39:11 -04:00
}
_completeStats () {
const t = this . _childCounts ( this . _childSlug ()). completed , e = this . _instances (). filter (
( r ) => r . on_time === ! 0
2026-09-20 19:17:52 -04:00
). length , n = b ( t - e ), i = this . _partyCounts ();
2026-09-20 18:39:11 -04:00
return {
claimed : t ,
onTime : e ,
late : n ,
2026-09-20 19:17:52 -04:00
party : ` ${ i . completed } / ${ i . due } `
2026-09-20 18:39:11 -04:00
};
}
_completeSub ( t ) {
2026-09-23 12:27:35 -04:00
const e = D ( this . _now , this . _timeZone ()), { claimed : n , onTime : i , late : r } = this . _completeStats ();
2026-09-20 19:17:52 -04:00
return n === 0 ? ` ${ t } sealed the day on ${ e } .` : r === 0 ? ` ${ t } claimed every quest on ${ e } — all on time.` : i === 0 ? ` ${ t } claimed every quest on ${ e } — all late.` : ` ${ t } claimed every quest on ${ e } — ${ i } on time, ${ r } late.` ;
2026-09-20 13:54:14 -04:00
}
_otherChildren () {
2026-09-20 14:19:39 -04:00
const t = this . hass ? . states ;
if ( ! t )
2026-09-20 13:54:14 -04:00
return [];
2026-09-20 19:17:52 -04:00
const e = this . _childSlug (), n = this . _timeZone (), i = [];
2026-09-20 14:19:39 -04:00
for ( const r of Object . keys ( t )) {
2026-09-20 13:54:14 -04:00
const o = /^sensor\.nestquest_(.+)_quests_due_today$/ . exec ( r );
2026-09-20 14:19:39 -04:00
if ( ! o || o [ 1 ] === "household" || o [ 1 ] === e )
2026-09-20 13:54:14 -04:00
continue ;
2026-09-20 14:19:39 -04:00
const l = o [ 1 ], a = t [ r ] ? . attributes ?? {};
let p = "" ;
2026-09-20 18:39:11 -04:00
typeof a . child_name == "string" && a . child_name . trim () ? p = a . child_name . trim () : p = Y ( l );
2026-09-20 13:54:14 -04:00
let u = ! 0 ;
if ( typeof a . present == "boolean" )
u = a . present ;
else {
2026-09-20 14:19:39 -04:00
const _ = this . _state (
2026-09-20 13:54:14 -04:00
`binary_sensor.nestquest_ ${ l } _present_today`
);
2026-09-20 14:19:39 -04:00
u = _ === null || String ( _ . state ?? "" ). trim (). toLowerCase () !== "off" ;
2026-09-20 13:54:14 -04:00
}
2026-09-20 19:17:52 -04:00
const c = this . _state (
2026-09-20 13:54:14 -04:00
`sensor.nestquest_ ${ l } _quests_completed_today`
2026-09-20 19:17:52 -04:00
), f = b ( y ( t [ r ] ? . state , 0 )), h = b ( y ( c ? . state , 0 ));
2026-09-20 14:04:58 -04:00
let m = null ;
2026-09-20 13:54:14 -04:00
if ( ! u ) {
2026-09-20 14:19:39 -04:00
const _ = this . _state (
2026-09-20 13:54:14 -04:00
`binary_sensor.nestquest_ ${ l } _present_today`
2026-09-20 19:17:52 -04:00
), x = Et (
2026-09-20 14:19:39 -04:00
_ ? . attributes ? . next_present ,
2026-09-20 13:54:14 -04:00
n
);
2026-09-23 12:27:35 -04:00
m = x ? He ( x , n ) : null ;
2026-09-20 13:54:14 -04:00
}
2026-09-20 19:17:52 -04:00
i . push ({
2026-09-20 13:54:14 -04:00
slug : l ,
2026-09-20 14:19:39 -04:00
name : p ,
2026-09-20 13:54:14 -04:00
present : u ,
2026-09-20 14:04:58 -04:00
due : f ,
completed : h ,
returnsWeekday : m
2026-09-20 13:54:14 -04:00
});
}
2026-09-20 19:17:52 -04:00
return i . sort (( r , o ) => r . name . localeCompare ( o . name ));
2026-09-20 13:54:14 -04:00
}
2026-09-20 14:19:39 -04:00
_renderHeader ( t ) {
2026-09-20 19:17:52 -04:00
const e = this . _childSlug (), n = t . kind === "away" , i = n ? t . name : this . _childName ( e ) ?? ( e ? Y ( e ) : null ), { due : r , completed : o } = this . _childCounts ( e ), l = this . _remaining (), a = this . _partyCounts (), p = i ? ` ${ i } 's Quest Log` : "Quest Log" , u = ( i ? . charAt ( 0 ) || "?" ). toUpperCase ();
return d `
2026-09-20 13:54:14 -04:00
<header class="header">
2026-09-20 14:04:58 -04:00
<span class="crest ${ n ? " away" : g } " aria-hidden="true">
2026-09-20 13:54:14 -04:00
<span class="crest-face">
2026-09-20 14:04:58 -04:00
<span class="initial"> ${ u } </span>
2026-09-20 13:54:14 -04:00
</span>
</span>
<div class="titles">
2026-09-20 14:19:39 -04:00
<h1 class="title"> ${ p } </h1>
2026-09-20 13:54:14 -04:00
<p class="sub">
2026-09-23 12:27:35 -04:00
${ D ( this . _now , this . _timeZone ()) } ·
2026-09-20 14:04:58 -04:00
${ n ? "On travels" : ` ${ o } of ${ r } claimed` }
2026-09-20 13:54:14 -04:00
</p>
</div>
2026-09-20 19:17:52 -04:00
${ n ? g : d `
2026-09-20 14:04:58 -04:00
<div class="remaining">
<span class="d20" aria-hidden="true">
<span class="d20-numeral"> ${ l } </span>
</span>
<div class="remaining-text">
<span class="remaining-count">
${ l } quest ${ l === 1 ? "" : "s" } left
</span>
<span class="party-line">
Party progress · ${ a . completed } of ${ a . due } today
</span>
</div>
</div>
` }
2026-09-20 13:54:14 -04:00
</header>
` ;
}
2026-09-20 14:19:39 -04:00
_renderColumn ( t ) {
const e = this . _instances (). filter (
( l ) => l . window === t . key
), n = e . filter (( l ) => l . state === "open" ). sort (
2026-09-20 13:54:14 -04:00
( l , a ) => ( l . due_time ?? "99:99" ). localeCompare ( a . due_time ?? "99:99" )
2026-09-20 19:17:52 -04:00
), i = e . filter (
2026-09-20 13:54:14 -04:00
( l ) => l . state === "completed"
2026-09-20 14:19:39 -04:00
), r = e . length ;
2026-09-20 14:04:58 -04:00
let o = g ;
2026-09-20 13:54:14 -04:00
if ( r > 0 ) {
2026-09-20 14:19:39 -04:00
const a = 644 - ( t . key === "afternoon" && this . _otherChildren (). length > 0 ? 160 : 0 ), p = Math . min (
2026-09-20 13:54:14 -04:00
24 ,
Math . max ( 8 , Math . floor (( a - r * 74 ) / Math . max ( r - 1 , 1 )))
), u = Math . min (
116 ,
2026-09-20 14:19:39 -04:00
Math . max ( 58 , Math . floor (( a - ( r - 1 ) * p ) / r ))
2026-09-20 19:17:52 -04:00
), c = Math . max ( 56 , Math . min ( 72 , u - 2 ));
let f = `--nq-p-quest-gap: ${ p } px; --nq-p-quest-min-height: ${ u } px; --nq-p-button-height: ${ c } px` ;
2026-09-20 13:54:14 -04:00
if ( r >= 5 ) {
2026-09-20 19:17:52 -04:00
const h = Math . max ( 0 , Math . min ( 22 , Math . floor (( u - c - 2 ) / 2 ))), m = Math . max ( 44 , Math . min ( 64 , u - 2 * h - 2 ));
2026-09-20 14:04:58 -04:00
f += `; --nq-p-quest-pad: ${ h } px; --nq-p-tile-size: ${ m } px` ;
2026-09-20 13:54:14 -04:00
}
2026-09-20 14:04:58 -04:00
o = f ;
2026-09-20 13:54:14 -04:00
}
2026-09-20 19:17:52 -04:00
return d `
2026-09-20 13:54:14 -04:00
<section
class="column"
2026-09-20 14:19:39 -04:00
aria-label=" ${ t . name } quests"
2026-09-20 13:54:14 -04:00
style= ${ o }
>
<div class="column-head">
2026-09-20 14:19:39 -04:00
${ t . icon }
2026-09-20 13:54:14 -04:00
<div class="column-names">
2026-09-20 14:19:39 -04:00
<span class="column-name"> ${ t . name } </span>
<span class="column-range"> ${ t . range } </span>
2026-09-20 13:54:14 -04:00
</div>
2026-09-20 19:17:52 -04:00
<span class="column-count"> ${ i . length } / ${ e . length } </span>
2026-09-20 13:54:14 -04:00
</div>
<div class="stack">
2026-09-20 18:39:11 -04:00
${ St (
2026-09-20 13:54:14 -04:00
n ,
( l ) => l . id ,
( l ) => this . _renderQuest ( l , ! 1 , 0 )
) }
2026-09-20 18:39:11 -04:00
${ St (
2026-09-20 19:17:52 -04:00
i ,
2026-09-20 13:54:14 -04:00
( l ) => l . id ,
( l , a ) => this . _renderQuest ( l , ! 0 , a )
) }
2026-09-20 14:19:39 -04:00
${ t . key === "afternoon" ? this . _renderRollup () : g }
2026-09-20 13:54:14 -04:00
</div>
</section>
` ;
}
2026-09-20 14:19:39 -04:00
_renderQuest ( t , e , n ) {
if ( e ) {
2026-09-23 12:27:35 -04:00
const o = Mt [ n % Mt . length ], l = t . completed_at ? Be ( t . completed_at , this . _timeZone ()) : "" ;
2026-09-20 19:17:52 -04:00
return d `
2026-09-20 14:19:39 -04:00
<div class="quest sealed" data-instance-id= ${ t . id } >
2026-09-20 18:39:11 -04:00
<span class="tile" aria-hidden="true"> ${ tt } </span>
2026-09-20 13:54:14 -04:00
<div class="body">
2026-09-20 14:19:39 -04:00
<span class="quest-title"> ${ t . title } </span>
2026-09-20 13:54:14 -04:00
<span class="meta">
${ l ? `Claimed ${ l } ` : "Claimed" }
</span>
</div>
<span
class="seal"
aria-hidden="true"
style="--seal-rot: ${ o } deg"
>
2026-09-20 19:17:52 -04:00
${ H }
2026-09-20 13:54:14 -04:00
</span>
</div>
` ;
}
2026-09-23 12:27:35 -04:00
const i = Qe ( t . due_time ), r = t . overdue ? {
2026-09-20 19:17:52 -04:00
text : i ? `Overdue · due ${ i } ` : "Overdue" ,
2026-09-20 13:54:14 -04:00
late : ! 0
} : {
2026-09-20 19:17:52 -04:00
text : i ? `Due by ${ i } ` : "Due today" ,
2026-09-20 13:54:14 -04:00
late : ! 1
};
2026-09-20 19:17:52 -04:00
return d `
2026-09-20 13:54:14 -04:00
<div
class="quest tappable"
role="button"
tabindex="0"
2026-09-20 14:19:39 -04:00
data-instance-id= ${ t . id }
aria-label="Complete ${ t . title } "
@click= ${ () => this . _openConfirm ( t . id ) }
2026-09-20 13:54:14 -04:00
@keydown= ${ ( o ) => {
2026-09-20 14:19:39 -04:00
( o . key === "Enter" || o . key === " " ) && ( o . preventDefault (), this . _openConfirm ( t . id ));
2026-09-20 13:54:14 -04:00
} }
>
2026-09-20 18:39:11 -04:00
<span class="tile" aria-hidden="true"> ${ tt } </span>
2026-09-20 13:54:14 -04:00
<div class="body">
2026-09-20 14:19:39 -04:00
<span class="quest-title"> ${ t . title } </span>
2026-09-20 14:04:58 -04:00
<span class="meta ${ r . late ? "late" : g } "> ${ r . text } </span>
2026-09-20 13:54:14 -04:00
</div>
<button
class="complete"
type="button"
2026-09-20 14:19:39 -04:00
@click= ${ () => this . _openConfirm ( t . id ) }
2026-09-20 13:54:14 -04:00
>
2026-09-20 19:17:52 -04:00
${ H }
2026-09-20 13:54:14 -04:00
<span>Complete</span>
</button>
</div>
` ;
}
_renderRollup () {
2026-09-20 14:19:39 -04:00
const t = this . _otherChildren ();
if ( t . length === 0 )
2026-09-20 14:04:58 -04:00
return g ;
2026-09-20 14:19:39 -04:00
const e = t . slice ( 0 , 2 ). map (( n ) => n . present ? n . due > 0 && n . completed >= n . due ? ` ${ n . name } has finished their log.` : n . due > n . completed ? ` ${ n . name } has ${ n . due - n . completed } quests left.` : ` ${ n . name } has no quests today.` : n . returnsWeekday ? ` ${ n . name } is on travels until ${ n . returnsWeekday } .` : ` ${ n . name } is on travels.` );
2026-09-20 19:17:52 -04:00
return d `
2026-09-20 13:54:14 -04:00
<div class="rollup">
<span class="rollup-label">Party roll-up</span>
2026-09-20 14:19:39 -04:00
<p class="rollup-body"> ${ e . join ( " " ) } </p>
2026-09-20 13:54:14 -04:00
</div>
` ;
}
_renderConfirm () {
if ( this . _confirm === null )
2026-09-20 14:04:58 -04:00
return g ;
2026-09-20 14:19:39 -04:00
const t = this . _instances (). find (
2026-09-20 13:54:14 -04:00
( n ) => n . id === this . _confirm
);
2026-09-20 14:19:39 -04:00
if ( ! t )
2026-09-20 14:04:58 -04:00
return g ;
2026-09-20 14:19:39 -04:00
const e = Ot . find (( n ) => n . key === t . window );
2026-09-20 19:17:52 -04:00
return d `
2026-09-20 13:54:14 -04:00
<div class="scrim" @click= ${ () => this . _closeConfirm () } >
<div
class="dialog"
role="dialog"
aria-modal="true"
@click= ${ ( n ) => n . stopPropagation () }
>
<div class="dialog-header">
2026-09-20 18:39:11 -04:00
<span class="dialog-tile" aria-hidden="true"> ${ tt } </span>
2026-09-20 13:54:14 -04:00
<div class="dialog-titles">
<span class="dialog-kicker">
2026-09-20 14:19:39 -04:00
${ e ? . name ?? "Quest" }
2026-09-20 13:54:14 -04:00
</span>
2026-09-20 14:19:39 -04:00
<span class="dialog-quest-title"> ${ t . title } </span>
2026-09-20 13:54:14 -04:00
</div>
</div>
<p class="dialog-body">
Mark this quest complete? Once the seal is set, only a parent can
undo it.
</p>
<div class="dialog-buttons">
<button
class="confirm-button not-yet"
type="button"
@click= ${ () => this . _closeConfirm () }
>
2026-09-23 12:27:35 -04:00
${ en }
2026-09-20 13:54:14 -04:00
<span>Not yet</span>
</button>
<button
class="confirm-button do-complete"
type="button"
@click= ${ () => this . _confirmComplete () }
>
2026-09-20 19:17:52 -04:00
${ H }
2026-09-20 13:54:14 -04:00
<span>Complete</span>
</button>
</div>
</div>
</div>
` ;
}
2026-09-20 14:19:39 -04:00
_openConfirm ( t ) {
this . _confirm = t , this . _armConfirmTimer ();
2026-09-20 13:54:14 -04:00
}
_closeConfirm () {
this . _clearConfirmTimer (), this . _confirm = null ;
}
_confirmComplete () {
2026-09-20 14:19:39 -04:00
const t = this . _confirm === null ? void 0 : this . _instances (). find (
( e ) => e . id === this . _confirm
);
this . _closeConfirm (), ! ( ! t || t . state !== "open" ) && this . _completeQuest ( t );
}
/** Seal first, ask the service second: the seal is stamped and the column
* re-sorted immediately (PANEL-SPEC §4); a service failure reverts the
* card and raises the parchment toast. */
async _completeQuest ( t ) {
if ( this . _optimistic . has ( t . id ))
return ;
const e = ( /* @__PURE__ */ new Date ()). toISOString ();
this . _optimistic = new Map ( this . _optimistic ). set ( t . id , e );
try {
await this . _callCompleteQuest ( t );
} catch {
const n = new Map ( this . _optimistic );
n . delete ( t . id ), this . _optimistic = n , this . _showToast (
"NestQuest could not set the seal just now. Please try again."
);
}
}
async _callCompleteQuest ( t ) {
const e = this . hass ;
if ( typeof e ? . callService != "function" )
throw new Error ( "Home Assistant is not connected" );
const n = this . _actorChildId ( t );
if ( n === null )
throw new Error ( "The tapped adventurer is unknown" );
await e . callService . call ( e , "nestquest" , "complete_quest" , {
instance_id : t . id ,
actor : "panel" ,
actor_child_id : n
});
}
/** The tapped profile (decision 9): the instance's own child_id, falling
* back to the due sensor's child-level attribute. */
_actorChildId ( t ) {
if ( t . child_id !== null )
return t . child_id ;
const e = this . _childSlug (), n = y (
this . _state ( `sensor.nestquest_ ${ e } _quests_due_today` ) ? . attributes ? . child_id ,
0
);
return n > 0 ? n : null ;
}
_showToast ( t ) {
this . _toast = t , this . _clearToastTimer (), this . _toastTimer = window . setTimeout (() => {
this . _toastTimer = void 0 , this . _toast = null ;
}, 6e3 );
}
_clearToastTimer () {
this . _toastTimer !== void 0 && ( window . clearTimeout ( this . _toastTimer ), this . _toastTimer = void 0 );
2026-09-20 13:54:14 -04:00
}
_armConfirmTimer () {
this . _clearConfirmTimer (), this . _confirmTimer = window . setTimeout (() => {
this . _confirmTimer = void 0 , this . _closeConfirm ();
}, this . _confirmSeconds () * 1e3 );
}
_clearConfirmTimer () {
this . _confirmTimer !== void 0 && ( window . clearTimeout ( this . _confirmTimer ), this . _confirmTimer = void 0 );
}
_armIdle () {
this . _clearIdle (), this . _idleTimer = window . setTimeout (() => {
this . _idleTimer = void 0 , this . _returnToBoard ();
}, this . _idleSeconds () * 1e3 );
}
_clearIdle () {
this . _idleTimer !== void 0 && ( window . clearTimeout ( this . _idleTimer ), this . _idleTimer = void 0 );
}
2026-09-20 18:39:11 -04:00
_armCompleteTimer () {
if ( this . _completeTimer === void 0 ) {
if ( this . _countdown === null && ( this . _countdown = this . _completeSeconds ()), this . _countdown <= 0 ) {
this . _returnToBoard ();
return ;
}
this . _completeTimer = window . setInterval (() => {
const t = ( this . _countdown ?? 1 ) - 1 ;
if ( t <= 0 ) {
this . _countdown = 0 , this . _clearCompleteTimer (), this . _returnToBoard ();
return ;
}
this . _countdown = t ;
}, 1e3 );
}
}
_clearCompleteTimer () {
this . _completeTimer !== void 0 && ( window . clearInterval ( this . _completeTimer ), this . _completeTimer = void 0 );
}
_optionalNumber ( t ) {
if ( t == null || t === "" )
return null ;
const e = typeof t == "number" ? t : Number ( t );
return Number . isFinite ( e ) ? e : null ;
}
_dockWeather () {
2026-09-20 19:17:52 -04:00
const t = w ( this . _config ? . weather_entity );
2026-09-20 18:39:11 -04:00
if ( ! t )
return null ;
const e = this . _state ( t );
if ( ! e )
return null ;
const n = String ( e . state ?? "" ). trim ();
if ( ! n || n === "unavailable" || n === "unknown" )
return null ;
2026-09-20 19:17:52 -04:00
const i = e . attributes ?? {};
2026-09-20 18:39:11 -04:00
let r = null , o = null ;
2026-09-20 19:17:52 -04:00
const l = i . forecast ;
2026-09-20 18:39:11 -04:00
if ( Array . isArray ( l ) && l . length > 0 ) {
const a = l [ 0 ];
if ( a && typeof a == "object" ) {
const p = a ;
r = this . _optionalNumber ( p . temperature ), o = this . _optionalNumber ( p . templow );
}
}
return {
condition : n ,
2026-09-20 19:17:52 -04:00
temperature : this . _optionalNumber ( i . temperature ),
2026-09-20 18:39:11 -04:00
high : r ,
low : o
};
}
_renderDock () {
const t = this . _dockWeather ();
if ( ! t )
2026-09-20 19:17:52 -04:00
return d `
2026-09-20 18:39:11 -04:00
<div class="dock">
2026-09-23 12:27:35 -04:00
<span class="date"> ${ D ( this . _now , this . _timeZone ()) } </span>
2026-09-20 18:39:11 -04:00
<span class="divider"></span>
2026-09-23 12:27:35 -04:00
<span class="clock"> ${ Fe ( this . _now , this . _timeZone ()) } </span>
2026-09-20 18:39:11 -04:00
</div>
` ;
2026-09-23 12:27:35 -04:00
const e = Je ( t . condition ), n = Xe ( t . condition , e ), i = t . temperature === null ? g : d `<span class="temp"> ${ Math . round ( t . temperature ) } °</span>` , r = t . high === null || t . low === null ? null : ` ${ Math . round ( t . high ) } ° / ${ Math . round ( t . low ) } °` ;
2026-09-20 19:17:52 -04:00
return d `
2026-09-20 18:39:11 -04:00
<div class="dock">
2026-09-23 12:27:35 -04:00
${ cn }
2026-09-20 19:17:52 -04:00
${ i }
2026-09-20 18:39:11 -04:00
<span class="divider"></span>
<span class="condition">
${ r === null ? e : ` ${ e } · ${ r } ` }
</span>
<span class="divider"></span>
<span class="condition"> ${ n } </span>
</div>
` ;
}
2026-09-20 13:54:14 -04:00
_returnToBoard () {
2026-09-20 14:19:39 -04:00
const t = this . _boardPath ();
t && ( window . history . pushState ( null , "" , t ), window . dispatchEvent ( new Event ( "location-changed" )));
2026-09-20 13:54:14 -04:00
}
_stopClock () {
this . _clockTimer !== void 0 && ( window . clearInterval ( this . _clockTimer ), this . _clockTimer = void 0 );
}
_onActivity = () => {
2026-09-20 18:39:11 -04:00
this . _logView (). kind !== "complete-day" && this . _armIdle (), this . _confirm !== null && this . _armConfirmTimer ();
2026-09-20 13:54:14 -04:00
};
2026-09-20 10:08:38 -04:00
}
2026-09-23 12:27:35 -04:00
customElements . define ( "nestquest-quest-log-card" , un );
2026-09-20 18:39:11 -04:00
at ({
2026-09-20 10:08:38 -04:00
type : "nestquest-quest-log-card" ,
name : "NestQuest Quest Log" ,
description : "One child's daily quests, grouped by window."
});
2026-09-23 12:27:35 -04:00
const fn = ":host{--nq-brand-blue: #3B3AB8;--nq-brand-purple: #A035CC;--nq-brand-gradient: linear-gradient(135deg, var(--nq-brand-blue), var(--nq-brand-purple));--nq-brand-gradient-h: linear-gradient(90deg, var(--nq-brand-blue), var(--nq-brand-purple));--nq-a-page: #F4F4F6;--nq-a-surface: #FFFFFF;--nq-a-surface-subtle: #FAFAFA;--nq-a-selected: #EBEBF8;--nq-a-border: #E4E4EA;--nq-a-divider: #EDEDF1;--nq-a-ink: #18181D;--nq-a-ink-secondary: #52525E;--nq-a-ink-tertiary: #70707E;--nq-a-success: #15803D;--nq-a-danger: #DC2626;--nq-a-danger-strong: #B91C1C;--nq-a-danger-bg: #FEE2E2;--nq-a-warning-ink: #92400E;--nq-a-warning-ink-2: #78350F;--nq-a-warning-bg: #FEF3C7;--nq-a-warning-border: rgba(217,119,6,.35);--nq-a-info-bg: #DBEAFE;--nq-a-info-ink: #1E3A8A;--nq-a-info-icon: #1D4ED8;--nq-a-reversal: #7D28A0;--nq-a-font: Nunito, system-ui, sans-serif;--nq-a-size-screen: 24px;--nq-a-size-hero: 32px;--nq-a-size-card-title: 19px;--nq-a-size-stat: 22px;--nq-a-size-row: 13.5px;--nq-a-size-meta: 11px;--nq-a-size-label: 10px;--nq-a-track-label: .1em;--nq-a-density-page-pad: 14px 16px 92px;--nq-a-density-gap: 10px;--nq-a-density-card-pad: 13px;--nq-a-density-row-pad: 11px 13px;--nq-a-density-radius: 8px;--nq-a-density-shadow: none;--nq-a-tabbar-height: 70px;--nq-a-tap-min: 44px;--nq-a-radius-pill: 9999px;--nq-a-radius-sheet: 20px 20px 0 0;--nq-a-sheet-shadow: 0 -8px 28px rgba(9,9,11,.18);--nq-a-progress-height: 6px;--nq-ease-out: cubic-bezier(0, 0, .2, 1);--nq-dur-micro: .12s;--nq-dur-base: .2s;--nq-dur-modal: .35s}" ;
class mn extends A {
2026-09-20 10:08:38 -04:00
static properties = {
hass : { attribute : ! 1 },
_config : { state : ! 0 }
};
2026-09-23 12:27:35 -04:00
static styles = [ v ( fn )];
2026-09-20 10:08:38 -04:00
hass ;
_config ;
2026-09-20 14:19:39 -04:00
setConfig ( t ) {
if ( ! t || typeof t != "object" )
2026-09-20 10:08:38 -04:00
throw new Error ( "Invalid configuration" );
2026-09-20 14:19:39 -04:00
this . _config = t ;
2026-09-20 10:08:38 -04:00
}
getCardSize () {
return 8 ;
}
render () {
2026-09-20 19:17:52 -04:00
return d `<div>NestQuest Admin</div>` ;
2026-09-20 10:08:38 -04:00
}
}
2026-09-23 12:27:35 -04:00
customElements . define ( "nestquest-admin-card" , mn );
2026-09-20 18:39:11 -04:00
at ({
2026-09-20 10:08:38 -04:00
type : "nestquest-admin-card" ,
name : "NestQuest Admin" ,
description : "Parent phone view for today, tasks, schedule, and history."
});
2026-09-23 12:27:35 -04:00
function Bt ( s ) {
return typeof s == "string" ? s . trim () : "" ;
}
function gn ( s ) {
if ( s === null || typeof s != "object" || Array . isArray ( s ))
return "" ;
const t = s . slug ;
return typeof t == "string" ? t . trim () : "" ;
}
function _n ( s ) {
const t = Bt ( s . url_path ). replace ( /^\/+|\/+$/g , "" );
return t || ( window . location . pathname . split ( "/" ). filter ( Boolean )[ 0 ] ?? "" );
}
function yn ( s ) {
if ( s === null || typeof s != "object" || Array . isArray ( s ))
return "" ;
const t = s . name ;
return typeof t == "string" ? t . trim () : "" ;
}
function bn ( s ) {
const n = s ? . states ? .[ "sensor.nestquest_household_quests_due_today" ] ? . attributes ? . child_roster ;
return Array . isArray ( n ) ? n . map (( i ) => ({ slug : gn ( i ), name : yn ( i ) })). filter (( i ) => i . slug . length > 0 ) : [];
}
class vn {
static async generate ( t , e ) {
const n = `/ ${ _n ( t ) } ` , i = Bt ( t . weather_entity ), r = {
type : "custom:nestquest-party-board-card" ,
quest_log_path : n
};
i && ( r . weather_entity = i );
const o = {
type : "custom:nestquest-quest-log-card" ,
board_path : n
};
return i && ( o . weather_entity = i ), {
views : [
{
path : "party" ,
title : "The Party" ,
type : "panel" ,
cards : [ r ]
},
... bn ( e ). map (( l ) => ({
path : l . slug ,
title : l . name ? ` ${ l . name } 's Quest Log` : ` ${ l . slug } 's Quest Log` ,
type : "panel" ,
cards : [{ ... o }]
}))
]
};
}
}
window . customStrategies = window . customStrategies ?? {};
window . customStrategies [ "nestquest-party" ] = vn ;
const xn = "/nestquest-static/nestquest-fonts.css" ;
2026-09-20 11:16:17 -04:00
if ( ! document . querySelector ( 'link[data-nq-fonts=""]' )) {
2026-09-20 19:17:52 -04:00
const s = document . createElement ( "link" );
2026-09-23 12:27:35 -04:00
s . rel = "stylesheet" , s . href = xn , s . dataset . nqFonts = "" , document . head . appendChild ( s );
2026-09-20 11:16:17 -04:00
}