Kids' panel: definition icon on the open quest card only

The sealed card's tile goes back to the static star (the wax seal is
unchanged); only the open card resolves the definition's namespaced icon
(lucide/fa/emoji, legacy bare name as Lucide, star fallback). The
quest-log jsdom harness now reports each card's tile, and new panel
tests cover every icon kind, the fallback, and the sealed star. Bundle
rebuilt from this branch.

Task: 5e3f3a5a-f963-4519-87af-95046d40a4e3

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-09-26 08:18:32 -04:00
co-authored by Claude Opus 5.5
parent a93f91d4af
commit a5f5086617
4 changed files with 255 additions and 127 deletions
+122 -122
View File
@@ -1,5 +1,5 @@
const F = globalThis, se = F.ShadowRoot && (F.ShadyCSS === void 0 || F.ShadyCSS.nativeShadow) && "adoptedStyleSheets" in Document.prototype && "replace" in CSSStyleSheet.prototype, ie = /* @__PURE__ */ Symbol(), ce = /* @__PURE__ */ new WeakMap(); const F = globalThis, se = F.ShadowRoot && (F.ShadyCSS === void 0 || F.ShadyCSS.nativeShadow) && "adoptedStyleSheets" in Document.prototype && "replace" in CSSStyleSheet.prototype, ie = /* @__PURE__ */ Symbol(), ce = /* @__PURE__ */ new WeakMap();
let Ie = class { let Pe = class {
constructor(e, t, n) { constructor(e, t, n) {
if (this._$cssResult$ = !0, n !== ie) throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead."); if (this._$cssResult$ = !0, n !== ie) throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");
this.cssText = e, this.t = t; this.cssText = e, this.t = t;
@@ -17,14 +17,14 @@ let Ie = class {
return this.cssText; return this.cssText;
} }
}; };
const v = (s) => new Ie(typeof s == "string" ? s : s + "", void 0, ie), He = (s, ...e) => { const v = (s) => new Pe(typeof s == "string" ? s : s + "", void 0, ie), Ie = (s, ...e) => {
const t = s.length === 1 ? s[0] : e.reduce((n, i, a) => n + ((r) => { const t = s.length === 1 ? s[0] : e.reduce((n, i, a) => n + ((r) => {
if (r._$cssResult$ === !0) return r.cssText; if (r._$cssResult$ === !0) return r.cssText;
if (typeof r == "number") return r; if (typeof r == "number") return r;
throw Error("Value passed to 'css' function must be a 'css' function result: " + r + ". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security."); throw Error("Value passed to 'css' function must be a 'css' function result: " + r + ". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.");
})(i) + s[a + 1], s[0]); })(i) + s[a + 1], s[0]);
return new Ie(t, s, ie); return new Pe(t, s, ie);
}, Ge = (s, e) => { }, We = (s, e) => {
if (se) s.adoptedStyleSheets = e.map((t) => t instanceof CSSStyleSheet ? t : t.styleSheet); if (se) s.adoptedStyleSheets = e.map((t) => t instanceof CSSStyleSheet ? t : t.styleSheet);
else for (const t of e) { else for (const t of e) {
const n = document.createElement("style"), i = F.litNonce; const n = document.createElement("style"), i = F.litNonce;
@@ -35,10 +35,10 @@ const v = (s) => new Ie(typeof s == "string" ? s : s + "", void 0, ie), He = (s,
for (const n of e.cssRules) t += n.cssText; for (const n of e.cssRules) t += n.cssText;
return v(t); return v(t);
})(s) : s; })(s) : s;
const { is: Ke, defineProperty: Je, getOwnPropertyDescriptor: Xe, getOwnPropertyNames: Ye, getOwnPropertySymbols: et, getPrototypeOf: tt } = Object, Z = globalThis, pe = Z.trustedTypes, nt = pe ? pe.emptyScript : "", st = Z.reactiveElementPolyfillSupport, P = (s, e) => s, ne = { toAttribute(s, e) { const { is: Ge, defineProperty: Ke, getOwnPropertyDescriptor: Je, getOwnPropertyNames: Xe, getOwnPropertySymbols: Ye, getPrototypeOf: et } = Object, Z = globalThis, pe = Z.trustedTypes, tt = pe ? pe.emptyScript : "", nt = Z.reactiveElementPolyfillSupport, P = (s, e) => s, ne = { toAttribute(s, e) {
switch (e) { switch (e) {
case Boolean: case Boolean:
s = s ? nt : null; s = s ? tt : null;
break; break;
case Object: case Object:
case Array: case Array:
@@ -63,7 +63,7 @@ const { is: Ke, defineProperty: Je, getOwnPropertyDescriptor: Xe, getOwnProperty
} }
} }
return t; return t;
} }, je = (s, e) => !Ke(s, e), he = { attribute: !0, type: String, converter: ne, reflect: !1, useDefault: !1, hasChanged: je }; } }, He = (s, e) => !Ge(s, e), he = { attribute: !0, type: String, converter: ne, reflect: !1, useDefault: !1, hasChanged: He };
Symbol.metadata ??= /* @__PURE__ */ Symbol("metadata"), Z.litPropertyMetadata ??= /* @__PURE__ */ new WeakMap(); Symbol.metadata ??= /* @__PURE__ */ Symbol("metadata"), Z.litPropertyMetadata ??= /* @__PURE__ */ new WeakMap();
let T = class extends HTMLElement { let T = class extends HTMLElement {
static addInitializer(e) { static addInitializer(e) {
@@ -75,11 +75,11 @@ let T = class extends HTMLElement {
static createProperty(e, t = he) { static createProperty(e, t = he) {
if (t.state && (t.attribute = !1), this._$Ei(), this.prototype.hasOwnProperty(e) && ((t = Object.create(t)).wrapped = !0), this.elementProperties.set(e, t), !t.noAccessor) { if (t.state && (t.attribute = !1), this._$Ei(), this.prototype.hasOwnProperty(e) && ((t = Object.create(t)).wrapped = !0), this.elementProperties.set(e, t), !t.noAccessor) {
const n = /* @__PURE__ */ Symbol(), i = this.getPropertyDescriptor(e, n, t); const n = /* @__PURE__ */ Symbol(), i = this.getPropertyDescriptor(e, n, t);
i !== void 0 && Je(this.prototype, e, i); i !== void 0 && Ke(this.prototype, e, i);
} }
} }
static getPropertyDescriptor(e, t, n) { static getPropertyDescriptor(e, t, n) {
const { get: i, set: a } = Xe(this.prototype, e) ?? { get() { const { get: i, set: a } = Je(this.prototype, e) ?? { get() {
return this[t]; return this[t];
}, set(r) { }, set(r) {
this[t] = r; this[t] = r;
@@ -94,13 +94,13 @@ let T = class extends HTMLElement {
} }
static _$Ei() { static _$Ei() {
if (this.hasOwnProperty(P("elementProperties"))) return; if (this.hasOwnProperty(P("elementProperties"))) return;
const e = tt(this); const e = et(this);
e.finalize(), e.l !== void 0 && (this.l = [...e.l]), this.elementProperties = new Map(e.elementProperties); e.finalize(), e.l !== void 0 && (this.l = [...e.l]), this.elementProperties = new Map(e.elementProperties);
} }
static finalize() { static finalize() {
if (this.hasOwnProperty(P("finalized"))) return; if (this.hasOwnProperty(P("finalized"))) return;
if (this.finalized = !0, this._$Ei(), this.hasOwnProperty(P("properties"))) { if (this.finalized = !0, this._$Ei(), this.hasOwnProperty(P("properties"))) {
const t = this.properties, n = [...Ye(t), ...et(t)]; const t = this.properties, n = [...Xe(t), ...Ye(t)];
for (const i of n) this.createProperty(i, t[i]); for (const i of n) this.createProperty(i, t[i]);
} }
const e = this[Symbol.metadata]; const e = this[Symbol.metadata];
@@ -146,7 +146,7 @@ let T = class extends HTMLElement {
} }
createRenderRoot() { createRenderRoot() {
const e = this.shadowRoot ?? this.attachShadow(this.constructor.shadowRootOptions); const e = this.shadowRoot ?? this.attachShadow(this.constructor.shadowRootOptions);
return Ge(e, this.constructor.elementStyles), e; return We(e, this.constructor.elementStyles), e;
} }
connectedCallback() { connectedCallback() {
this.renderRoot ??= this.createRenderRoot(), this.enableUpdating(!0), this._$EO?.forEach((e) => e.hostConnected?.()); this.renderRoot ??= this.createRenderRoot(), this.enableUpdating(!0), this._$EO?.forEach((e) => e.hostConnected?.());
@@ -178,7 +178,7 @@ let T = class extends HTMLElement {
requestUpdate(e, t, n, i = !1, a) { requestUpdate(e, t, n, i = !1, a) {
if (e !== void 0) { if (e !== void 0) {
const r = this.constructor; const r = this.constructor;
if (i === !1 && (a = this[e]), n ??= r.getPropertyOptions(e), !((n.hasChanged ?? je)(a, t) || n.useDefault && n.reflect && a === this._$Ej?.get(e) && !this.hasAttribute(r._$Eu(e, n)))) return; if (i === !1 && (a = this[e]), n ??= r.getPropertyOptions(e), !((n.hasChanged ?? He)(a, t) || n.useDefault && n.reflect && a === this._$Ej?.get(e) && !this.hasAttribute(r._$Eu(e, n)))) return;
this.C(e, t, n); this.C(e, t, n);
} }
this.isUpdatePending === !1 && (this._$ES = this._$EP()); this.isUpdatePending === !1 && (this._$ES = this._$EP());
@@ -246,43 +246,43 @@ let T = class extends HTMLElement {
firstUpdated(e) { firstUpdated(e) {
} }
}; };
T.elementStyles = [], T.shadowRootOptions = { mode: "open" }, T[P("elementProperties")] = /* @__PURE__ */ new Map(), T[P("finalized")] = /* @__PURE__ */ new Map(), st?.({ ReactiveElement: T }), (Z.reactiveElementVersions ??= []).push("2.1.2"); T.elementStyles = [], T.shadowRootOptions = { mode: "open" }, T[P("elementProperties")] = /* @__PURE__ */ new Map(), T[P("finalized")] = /* @__PURE__ */ new Map(), nt?.({ ReactiveElement: T }), (Z.reactiveElementVersions ??= []).push("2.1.2");
const ae = globalThis, ue = (s) => s, Q = ae.trustedTypes, fe = Q ? Q.createPolicy("lit-html", { createHTML: (s) => s }) : void 0, Re = "$lit$", k = `lit$${Math.random().toFixed(9).slice(2)}$`, Ue = "?" + k, it = `<${Ue}>`, A = document, I = () => A.createComment(""), H = (s) => s === null || typeof s != "object" && typeof s != "function", re = Array.isArray, at = (s) => re(s) || typeof s?.[Symbol.iterator] == "function", K = `[ const ae = globalThis, ue = (s) => s, Q = ae.trustedTypes, fe = Q ? Q.createPolicy("lit-html", { createHTML: (s) => s }) : void 0, je = "$lit$", k = `lit$${Math.random().toFixed(9).slice(2)}$`, Re = "?" + k, st = `<${Re}>`, A = document, I = () => A.createComment(""), H = (s) => s === null || typeof s != "object" && typeof s != "function", re = Array.isArray, it = (s) => re(s) || typeof s?.[Symbol.iterator] == "function", K = `[
\f\r]`, L = /<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g, me = /-->/g, ge = />/g, $ = RegExp(`>|${K}(?:([^\\s"'>=/]+)(${K}*=${K}*(?:[^ \f\r]`, L = /<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g, me = /-->/g, ge = />/g, $ = RegExp(`>|${K}(?:([^\\s"'>=/]+)(${K}*=${K}*(?:[^
\f\r"'\`<>=]|("|')|))|$)`, "g"), _e = /'/g, ye = /"/g, De = /^(?:script|style|textarea|title)$/i, Fe = (s) => (e, ...t) => ({ _$litType$: s, strings: e, values: t }), d = Fe(1), be = Fe(2), S = /* @__PURE__ */ Symbol.for("lit-noChange"), g = /* @__PURE__ */ Symbol.for("lit-nothing"), ve = /* @__PURE__ */ new WeakMap(), C = A.createTreeWalker(A, 129); \f\r"'\`<>=]|("|')|))|$)`, "g"), _e = /'/g, ye = /"/g, Ue = /^(?:script|style|textarea|title)$/i, De = (s) => (e, ...t) => ({ _$litType$: s, strings: e, values: t }), d = De(1), be = De(2), S = /* @__PURE__ */ Symbol.for("lit-noChange"), g = /* @__PURE__ */ Symbol.for("lit-nothing"), ve = /* @__PURE__ */ new WeakMap(), C = A.createTreeWalker(A, 129);
function Qe(s, e) { function Fe(s, e) {
if (!re(s) || !s.hasOwnProperty("raw")) throw Error("invalid template strings array"); if (!re(s) || !s.hasOwnProperty("raw")) throw Error("invalid template strings array");
return fe !== void 0 ? fe.createHTML(e) : e; return fe !== void 0 ? fe.createHTML(e) : e;
} }
const rt = (s, e) => { const at = (s, e) => {
const t = s.length - 1, n = []; const t = s.length - 1, n = [];
let i, a = e === 2 ? "<svg>" : e === 3 ? "<math>" : "", r = L; let i, a = e === 2 ? "<svg>" : e === 3 ? "<math>" : "", r = L;
for (let l = 0; l < t; l++) { for (let l = 0; l < t; l++) {
const o = s[l]; const o = s[l];
let p, u, c = -1, f = 0; let p, u, c = -1, f = 0;
for (; f < o.length && (r.lastIndex = f, u = r.exec(o), u !== null); ) f = r.lastIndex, r === L ? u[1] === "!--" ? r = me : u[1] !== void 0 ? r = ge : u[2] !== void 0 ? (De.test(u[2]) && (i = RegExp("</" + u[2], "g")), r = $) : u[3] !== void 0 && (r = $) : r === $ ? u[0] === ">" ? (r = i ?? L, c = -1) : u[1] === void 0 ? c = -2 : (c = r.lastIndex - u[2].length, p = u[1], r = u[3] === void 0 ? $ : u[3] === '"' ? ye : _e) : r === ye || r === _e ? r = $ : r === me || r === ge ? r = L : (r = $, i = void 0); for (; f < o.length && (r.lastIndex = f, u = r.exec(o), u !== null); ) f = r.lastIndex, r === L ? u[1] === "!--" ? r = me : u[1] !== void 0 ? r = ge : u[2] !== void 0 ? (Ue.test(u[2]) && (i = RegExp("</" + u[2], "g")), r = $) : u[3] !== void 0 && (r = $) : r === $ ? u[0] === ">" ? (r = i ?? L, c = -1) : u[1] === void 0 ? c = -2 : (c = r.lastIndex - u[2].length, p = u[1], r = u[3] === void 0 ? $ : u[3] === '"' ? ye : _e) : r === ye || r === _e ? r = $ : r === me || r === ge ? r = L : (r = $, i = void 0);
const h = r === $ && s[l + 1].startsWith("/>") ? " " : ""; const h = r === $ && s[l + 1].startsWith("/>") ? " " : "";
a += r === L ? o + it : c >= 0 ? (n.push(p), o.slice(0, c) + Re + o.slice(c) + k + h) : o + k + (c === -2 ? l : h); a += r === L ? o + st : c >= 0 ? (n.push(p), o.slice(0, c) + je + o.slice(c) + k + h) : o + k + (c === -2 ? l : h);
} }
return [Qe(s, a + (s[t] || "<?>") + (e === 2 ? "</svg>" : e === 3 ? "</math>" : "")), n]; return [Fe(s, a + (s[t] || "<?>") + (e === 2 ? "</svg>" : e === 3 ? "</math>" : "")), n];
}; };
class j { class j {
constructor({ strings: e, _$litType$: t }, n) { constructor({ strings: e, _$litType$: t }, n) {
let i; let i;
this.parts = []; this.parts = [];
let a = 0, r = 0; let a = 0, r = 0;
const l = e.length - 1, o = this.parts, [p, u] = rt(e, t); const l = e.length - 1, o = this.parts, [p, u] = at(e, t);
if (this.el = j.createElement(p, n), C.currentNode = this.el.content, t === 2 || t === 3) { if (this.el = j.createElement(p, n), C.currentNode = this.el.content, t === 2 || t === 3) {
const c = this.el.content.firstChild; const c = this.el.content.firstChild;
c.replaceWith(...c.childNodes); c.replaceWith(...c.childNodes);
} }
for (; (i = C.nextNode()) !== null && o.length < l; ) { for (; (i = C.nextNode()) !== null && o.length < l; ) {
if (i.nodeType === 1) { if (i.nodeType === 1) {
if (i.hasAttributes()) for (const c of i.getAttributeNames()) if (c.endsWith(Re)) { if (i.hasAttributes()) for (const c of i.getAttributeNames()) if (c.endsWith(je)) {
const f = u[r++], h = i.getAttribute(c).split(k), m = /([.?@])?(.*)/.exec(f); const f = u[r++], h = i.getAttribute(c).split(k), m = /([.?@])?(.*)/.exec(f);
o.push({ type: 1, index: a, name: m[2], strings: h, ctor: m[1] === "." ? lt : m[1] === "?" ? ct : m[1] === "@" ? dt : W }), i.removeAttribute(c); o.push({ type: 1, index: a, name: m[2], strings: h, ctor: m[1] === "." ? ot : m[1] === "?" ? lt : m[1] === "@" ? ct : W }), i.removeAttribute(c);
} else c.startsWith(k) && (o.push({ type: 6, index: a }), i.removeAttribute(c)); } else c.startsWith(k) && (o.push({ type: 6, index: a }), i.removeAttribute(c));
if (De.test(i.tagName)) { if (Ue.test(i.tagName)) {
const c = i.textContent.split(k), f = c.length - 1; const c = i.textContent.split(k), f = c.length - 1;
if (f > 0) { if (f > 0) {
i.textContent = Q ? Q.emptyScript : ""; i.textContent = Q ? Q.emptyScript : "";
@@ -290,7 +290,7 @@ class j {
i.append(c[f], I()); i.append(c[f], I());
} }
} }
} else if (i.nodeType === 8) if (i.data === Ue) o.push({ type: 2, index: a }); } else if (i.nodeType === 8) if (i.data === Re) o.push({ type: 2, index: a });
else { else {
let c = -1; let c = -1;
for (; (c = i.data.indexOf(k, c + 1)) !== -1; ) o.push({ type: 7, index: a }), c += k.length - 1; for (; (c = i.data.indexOf(k, c + 1)) !== -1; ) o.push({ type: 7, index: a }), c += k.length - 1;
@@ -309,7 +309,7 @@ function z(s, e, t = s, n) {
const a = H(e) ? void 0 : e._$litDirective$; const a = H(e) ? void 0 : e._$litDirective$;
return i?.constructor !== a && (i?._$AO?.(!1), a === void 0 ? i = void 0 : (i = new a(s), i._$AT(s, t, n)), n !== void 0 ? (t._$Co ??= [])[n] = i : t._$Cl = i), i !== void 0 && (e = z(s, i._$AS(s, e.values), i, n)), e; return i?.constructor !== a && (i?._$AO?.(!1), a === void 0 ? i = void 0 : (i = new a(s), i._$AT(s, t, n)), n !== void 0 ? (t._$Co ??= [])[n] = i : t._$Cl = i), i !== void 0 && (e = z(s, i._$AS(s, e.values), i, n)), e;
} }
class ot { class rt {
constructor(e, t) { constructor(e, t) {
this._$AV = [], this._$AN = void 0, this._$AD = e, this._$AM = t; this._$AV = [], this._$AN = void 0, this._$AD = e, this._$AM = t;
} }
@@ -326,7 +326,7 @@ class ot {
for (; o !== void 0; ) { for (; o !== void 0; ) {
if (r === o.index) { if (r === o.index) {
let p; let p;
o.type === 2 ? p = new N(a, a.nextSibling, this, e) : o.type === 1 ? p = new o.ctor(a, o.name, o.strings, this, e) : o.type === 6 && (p = new pt(a, this, e)), this._$AV.push(p), o = n[++l]; o.type === 2 ? p = new N(a, a.nextSibling, this, e) : o.type === 1 ? p = new o.ctor(a, o.name, o.strings, this, e) : o.type === 6 && (p = new dt(a, this, e)), this._$AV.push(p), o = n[++l];
} }
r !== o?.index && (a = C.nextNode(), r++); r !== o?.index && (a = C.nextNode(), r++);
} }
@@ -356,7 +356,7 @@ class N {
return this._$AB; return this._$AB;
} }
_$AI(e, t = this) { _$AI(e, t = this) {
e = z(this, e, t), H(e) ? e === g || e == null || e === "" ? (this._$AH !== g && this._$AR(), this._$AH = g) : e !== this._$AH && e !== S && this._(e) : e._$litType$ !== void 0 ? this.$(e) : e.nodeType !== void 0 ? this.T(e) : at(e) ? this.k(e) : this._(e); e = z(this, e, t), H(e) ? e === g || e == null || e === "" ? (this._$AH !== g && this._$AR(), this._$AH = g) : e !== this._$AH && e !== S && this._(e) : e._$litType$ !== void 0 ? this.$(e) : e.nodeType !== void 0 ? this.T(e) : it(e) ? this.k(e) : this._(e);
} }
O(e) { O(e) {
return this._$AA.parentNode.insertBefore(e, this._$AB); return this._$AA.parentNode.insertBefore(e, this._$AB);
@@ -368,10 +368,10 @@ class N {
this._$AH !== g && H(this._$AH) ? this._$AA.nextSibling.data = e : this.T(A.createTextNode(e)), this._$AH = e; this._$AH !== g && H(this._$AH) ? this._$AA.nextSibling.data = e : this.T(A.createTextNode(e)), this._$AH = e;
} }
$(e) { $(e) {
const { values: t, _$litType$: n } = e, i = typeof n == "number" ? this._$AC(e) : (n.el === void 0 && (n.el = j.createElement(Qe(n.h, n.h[0]), this.options)), n); const { values: t, _$litType$: n } = e, i = typeof n == "number" ? this._$AC(e) : (n.el === void 0 && (n.el = j.createElement(Fe(n.h, n.h[0]), this.options)), n);
if (this._$AH?._$AD === i) this._$AH.p(t); if (this._$AH?._$AD === i) this._$AH.p(t);
else { else {
const a = new ot(i, this), r = a.u(this.options); const a = new rt(i, this), r = a.u(this.options);
a.p(t), this.T(r), this._$AH = a; a.p(t), this.T(r), this._$AH = a;
} }
} }
@@ -421,7 +421,7 @@ class W {
e === g ? this.element.removeAttribute(this.name) : this.element.setAttribute(this.name, e ?? ""); e === g ? this.element.removeAttribute(this.name) : this.element.setAttribute(this.name, e ?? "");
} }
} }
class lt extends W { class ot extends W {
constructor() { constructor() {
super(...arguments), this.type = 3; super(...arguments), this.type = 3;
} }
@@ -429,7 +429,7 @@ class lt extends W {
this.element[this.name] = e === g ? void 0 : e; this.element[this.name] = e === g ? void 0 : e;
} }
} }
class ct extends W { class lt extends W {
constructor() { constructor() {
super(...arguments), this.type = 4; super(...arguments), this.type = 4;
} }
@@ -437,7 +437,7 @@ class ct extends W {
this.element.toggleAttribute(this.name, !!e && e !== g); this.element.toggleAttribute(this.name, !!e && e !== g);
} }
} }
class dt extends W { class ct extends W {
constructor(e, t, n, i, a) { constructor(e, t, n, i, a) {
super(e, t, n, i, a), this.type = 5; super(e, t, n, i, a), this.type = 5;
} }
@@ -450,7 +450,7 @@ class dt extends W {
typeof this._$AH == "function" ? this._$AH.call(this.options?.host ?? this.element, e) : this._$AH.handleEvent(e); typeof this._$AH == "function" ? this._$AH.call(this.options?.host ?? this.element, e) : this._$AH.handleEvent(e);
} }
} }
class pt { class dt {
constructor(e, t, n) { constructor(e, t, n) {
this.element = e, this.type = 6, this._$AN = void 0, this._$AM = t, this.options = n; this.element = e, this.type = 6, this._$AN = void 0, this._$AM = t, this.options = n;
} }
@@ -461,9 +461,9 @@ class pt {
z(this, e); z(this, e);
} }
} }
const ht = { I: N }, ut = ae.litHtmlPolyfillSupport; const pt = { I: N }, ht = ae.litHtmlPolyfillSupport;
ut?.(j, N), (ae.litHtmlVersions ??= []).push("3.3.3"); ht?.(j, N), (ae.litHtmlVersions ??= []).push("3.3.3");
const ft = (s, e, t) => { const ut = (s, e, t) => {
const n = t?.renderBefore ?? e; const n = t?.renderBefore ?? e;
let i = n._$litPart$; let i = n._$litPart$;
if (i === void 0) { if (i === void 0) {
@@ -483,7 +483,7 @@ let M = class extends T {
} }
update(e) { update(e) {
const t = this.render(); const t = this.render();
this.hasUpdated || (this.renderOptions.isConnected = this.isConnected), super.update(e), this._$Do = ft(t, this.renderRoot, this.renderOptions); this.hasUpdated || (this.renderOptions.isConnected = this.isConnected), super.update(e), this._$Do = ut(t, this.renderRoot, this.renderOptions);
} }
connectedCallback() { connectedCallback() {
super.connectedCallback(), this._$Do?.setConnected(!0); super.connectedCallback(), this._$Do?.setConnected(!0);
@@ -496,14 +496,14 @@ let M = class extends T {
} }
}; };
M._$litElement$ = !0, M.finalized = !0, oe.litElementHydrateSupport?.({ LitElement: M }); M._$litElement$ = !0, M.finalized = !0, oe.litElementHydrateSupport?.({ LitElement: M });
const mt = oe.litElementPolyfillSupport; const ft = oe.litElementPolyfillSupport;
mt?.({ LitElement: M }); ft?.({ LitElement: M });
(oe.litElementVersions ??= []).push("4.2.2"); (oe.litElementVersions ??= []).push("4.2.2");
const Ve = ':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}'; const Qe = ':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}';
function le(s) { function le(s) {
window.customCards = window.customCards ?? [], window.customCards.push(s); window.customCards = window.customCards ?? [], window.customCards.push(s);
} }
const gt = [ const mt = [
"nestquest_quest_completed", "nestquest_quest_completed",
"nestquest_quest_uncompleted", "nestquest_quest_uncompleted",
"nestquest_quest_missed", "nestquest_quest_missed",
@@ -524,7 +524,7 @@ function V(s, e) {
} }
return xe.set(t, i), i; return xe.set(t, i), i;
} }
function _t(s) { function gt(s) {
const e = s?.config; const e = s?.config;
if (!e || typeof e != "object") if (!e || typeof e != "object")
return; return;
@@ -534,14 +534,14 @@ function _t(s) {
function J(s, e) { function J(s, e) {
return `${V(e, { weekday: "long" }).format(s)}, ${V(e, { month: "short", day: "numeric" }).format(s)}`; return `${V(e, { weekday: "long" }).format(s)}, ${V(e, { month: "short", day: "numeric" }).format(s)}`;
} }
function yt(s, e) { function _t(s, e) {
return V(e, { return V(e, {
hour: "numeric", hour: "numeric",
minute: "2-digit", minute: "2-digit",
hour12: !0 hour12: !0
}).format(s); }).format(s);
} }
const bt = { const yt = {
"clear-night": "Clear", "clear-night": "Clear",
cloudy: "Cloudy", cloudy: "Cloudy",
exceptional: "Clear", exceptional: "Clear",
@@ -557,7 +557,7 @@ const bt = {
sunny: "Sunny", sunny: "Sunny",
windy: "Windy", windy: "Windy",
"windy-variant": "Windy" "windy-variant": "Windy"
}, vt = { }, bt = {
"clear-night": "Clear night skies", "clear-night": "Clear night skies",
cloudy: "Grey skies today", cloudy: "Grey skies today",
exceptional: "A striking day", exceptional: "A striking day",
@@ -583,7 +583,7 @@ function X(s, e) {
const t = typeof s == "number" ? s : Number(s); const t = typeof s == "number" ? s : Number(s);
return Number.isFinite(t) ? t : e; return Number.isFinite(t) ? t : e;
} }
function xt(s) { function vt(s) {
if (s === null || typeof s != "object" || Array.isArray(s)) if (s === null || typeof s != "object" || Array.isArray(s))
return ""; return "";
const e = s.slug; const e = s.slug;
@@ -595,10 +595,10 @@ function ke(s) {
function $e(s) { function $e(s) {
return Math.max(0, Math.round(s)); return Math.max(0, Math.round(s));
} }
function wt(s) { function xt(s) {
return s.split(/[-_]+/).filter(Boolean).map((e) => e.charAt(0).toUpperCase() + e.slice(1)).join(" "); return s.split(/[-_]+/).filter(Boolean).map((e) => e.charAt(0).toUpperCase() + e.slice(1)).join(" ");
} }
function kt(s, e) { function wt(s, e) {
const t = V(e, { const t = V(e, {
year: "numeric", year: "numeric",
month: "2-digit", month: "2-digit",
@@ -620,7 +620,7 @@ function kt(s, e) {
); );
return Number.isFinite(i) ? i - s : 0; return Number.isFinite(i) ? i - s : 0;
} }
function $t(s, e) { function kt(s, e) {
if (typeof s != "string") if (typeof s != "string")
return null; return null;
const t = s.split("-"); const t = s.split("-");
@@ -633,17 +633,17 @@ function $t(s, e) {
const o = new Date(n, i - 1, a); const o = new Date(n, i - 1, a);
return Number.isNaN(o.getTime()) ? null : o; return Number.isNaN(o.getTime()) ? null : o;
} }
const r = Date.UTC(n, i - 1, a), l = new Date(r - kt(r, e)); const r = Date.UTC(n, i - 1, a), l = new Date(r - wt(r, e));
return Number.isNaN(l.getTime()) ? null : l; return Number.isNaN(l.getTime()) ? null : l;
} }
function qt(s) { function $t(s) {
const e = bt[s]; const e = yt[s];
return e || s.charAt(0).toUpperCase() + s.slice(1); return e || s.charAt(0).toUpperCase() + s.slice(1);
} }
function Ct(s, e) { function qt(s, e) {
return vt[s] ?? e; return bt[s] ?? e;
} }
const qe = "polygon(0 0, 100% 0, 100% 62%, 50% 100%, 0 62%)", Mt = "polygon(50% 0, 93% 25%, 93% 75%, 50% 100%, 7% 75%, 7% 25%)", At = He` const qe = "polygon(0 0, 100% 0, 100% 62%, 50% 100%, 0 62%)", Ct = "polygon(50% 0, 93% 25%, 93% 75%, 50% 100%, 7% 75%, 7% 25%)", Mt = Ie`
* { * {
box-sizing: border-box; box-sizing: border-box;
} }
@@ -715,7 +715,7 @@ const qe = "polygon(0 0, 100% 0, 100% 62%, 50% 100%, 0 62%)", Mt = "polygon(50%
justify-content: center; justify-content: center;
width: 34px; width: 34px;
height: 34px; height: 34px;
clip-path: ${v(Mt)}; clip-path: ${v(Ct)};
background: var(--nq-brand-gradient); background: var(--nq-brand-gradient);
} }
@@ -1038,7 +1038,7 @@ const qe = "polygon(0 0, 100% 0, 100% 62%, 50% 100%, 0 62%)", Mt = "polygon(50%
font-weight: 800; font-weight: 800;
line-height: 1; line-height: 1;
} }
`, St = d`<svg `, At = d`<svg
viewBox="0 0 24 24" viewBox="0 0 24 24"
fill="none" fill="none"
stroke="currentColor" stroke="currentColor"
@@ -1049,7 +1049,7 @@ const qe = "polygon(0 0, 100% 0, 100% 62%, 50% 100%, 0 62%)", Mt = "polygon(50%
> >
<circle cx="12" cy="12" r="10"></circle> <circle cx="12" cy="12" r="10"></circle>
<path d="m9 12 2 2 4-4"></path> <path d="m9 12 2 2 4-4"></path>
</svg>`, Tt = d`<svg </svg>`, St = d`<svg
viewBox="0 0 24 24" viewBox="0 0 24 24"
fill="none" fill="none"
stroke="currentColor" stroke="currentColor"
@@ -1060,7 +1060,7 @@ const qe = "polygon(0 0, 100% 0, 100% 62%, 50% 100%, 0 62%)", Mt = "polygon(50%
> >
<path d="M3.5 21 12 3.5 20.5 21"></path> <path d="M3.5 21 12 3.5 20.5 21"></path>
<path d="M9 21l3-8 3 8"></path> <path d="M9 21l3-8 3 8"></path>
</svg>`, zt = d`<svg </svg>`, Tt = d`<svg
viewBox="0 0 24 24" viewBox="0 0 24 24"
fill="none" fill="none"
stroke="currentColor" stroke="currentColor"
@@ -1071,7 +1071,7 @@ const qe = "polygon(0 0, 100% 0, 100% 62%, 50% 100%, 0 62%)", Mt = "polygon(50%
> >
<circle cx="12" cy="12" r="10"></circle> <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> <polygon points="16.24 7.76 14.12 14.12 7.76 16.24 9.88 9.88 16.24 7.76"></polygon>
</svg>`, Et = d`<svg </svg>`, zt = d`<svg
viewBox="0 0 24 24" viewBox="0 0 24 24"
fill="none" fill="none"
stroke="currentColor" stroke="currentColor"
@@ -1083,7 +1083,7 @@ const qe = "polygon(0 0, 100% 0, 100% 62%, 50% 100%, 0 62%)", Mt = "polygon(50%
<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="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 9v4"></path>
<path d="M12 17h.01"></path> <path d="M12 17h.01"></path>
</svg>`, Nt = d`<svg </svg>`, Et = d`<svg
viewBox="0 0 24 24" viewBox="0 0 24 24"
fill="none" fill="none"
stroke="currentColor" stroke="currentColor"
@@ -1095,14 +1095,14 @@ const qe = "polygon(0 0, 100% 0, 100% 62%, 50% 100%, 0 62%)", Mt = "polygon(50%
<path d="M17.5 19H9a7 7 0 1 1 6.71-9h1.79a4.5 4.5 0 1 1 0 9Z"></path> <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> <path d="m2 2 20 20"></path>
</svg>`, Ce = { </svg>`, Ce = {
icon: Et, icon: zt,
headline: "NestQuest is not set up yet", headline: "NestQuest is not set up yet",
body: "A parent needs to finish setting up NestQuest before the party can gather." body: "A parent needs to finish setting up NestQuest before the party can gather."
}, Lt = { }, Nt = {
icon: Nt, icon: Et,
headline: "The records cannot be reached", headline: "The records cannot be reached",
body: "The party's records are quiet right now. NestQuest will return shortly." body: "The party's records are quiet right now. NestQuest will return shortly."
}, Bt = d`<svg }, Lt = d`<svg
viewBox="0 0 24 24" viewBox="0 0 24 24"
fill="none" fill="none"
stroke="currentColor" stroke="currentColor"
@@ -1118,13 +1118,13 @@ const qe = "polygon(0 0, 100% 0, 100% 62%, 50% 100%, 0 62%)", Mt = "polygon(50%
<path d="M15.947 12.65a4 4 0 0 0-5.925-4.128"></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> <path d="M13 22H7a5 5 0 1 1 4.9-6H13a3 3 0 0 1 0 6Z"></path>
</svg>`; </svg>`;
class Ot extends M { class Bt extends M {
static properties = { static properties = {
hass: { attribute: !1 }, hass: { attribute: !1 },
_config: { state: !0 }, _config: { state: !0 },
_now: { state: !0 } _now: { state: !0 }
}; };
static styles = [v(Ve), At]; static styles = [v(Qe), Mt];
hass; hass;
_config; _config;
_now = /* @__PURE__ */ new Date(); _now = /* @__PURE__ */ new Date();
@@ -1156,7 +1156,7 @@ class Ot extends M {
t === this._subGeneration && (this._unsubscribeLive(), this._armSubscribeRetry()); t === this._subGeneration && (this._unsubscribeLive(), this._armSubscribeRetry());
}); });
}; };
for (const i of gt) for (const i of mt)
n( n(
e.subscribeEvents(() => this.requestUpdate(), i) e.subscribeEvents(() => this.requestUpdate(), i)
); );
@@ -1219,7 +1219,7 @@ class Ot extends M {
`; `;
} }
_timeZone() { _timeZone() {
return _t(this.hass); return gt(this.hass);
} }
_state(e) { _state(e) {
const n = this.hass?.states?.[e]; const n = this.hass?.states?.[e];
@@ -1243,7 +1243,7 @@ class Ot extends M {
const t = this._state( const t = this._state(
"sensor.nestquest_household_quests_due_today" "sensor.nestquest_household_quests_due_today"
)?.attributes?.child_roster; )?.attributes?.child_roster;
return Array.isArray(t) ? t.map((n) => xt(n)).filter((n) => n.length > 0) : []; return Array.isArray(t) ? t.map((n) => vt(n)).filter((n) => n.length > 0) : [];
} }
_plates() { _plates() {
return this._childSlugs().map((e) => this._plate(e)); return this._childSlugs().map((e) => this._plate(e));
@@ -1267,8 +1267,8 @@ class Ot extends M {
const G = r?.attributes?.child_name; const G = r?.attributes?.child_name;
typeof G == "string" && G.trim() && (m = G.trim()); typeof G == "string" && G.trim() && (m = G.trim());
} }
m || (m = wt(e)); m || (m = xt(e));
const x = $t( const x = kt(
r?.attributes?.next_present, r?.attributes?.next_present,
this._timeZone() this._timeZone()
), R = x ? `Returns ${J(x, this._timeZone())}` : null; ), R = x ? `Returns ${J(x, this._timeZone())}` : null;
@@ -1297,7 +1297,7 @@ class Ot extends M {
} }
_boardNotice() { _boardNotice() {
const e = this._plates(); const e = this._plates();
return e.length === 0 ? Ce : e.every((t) => t.unresolved !== null) ? e.some((t) => t.unresolved === "stale") ? Lt : Ce : null; return e.length === 0 ? Ce : e.every((t) => t.unresolved !== null) ? e.some((t) => t.unresolved === "stale") ? Nt : Ce : null;
} }
_renderNotice(e) { _renderNotice(e) {
return d` return d`
@@ -1320,7 +1320,7 @@ class Ot extends M {
</span> </span>
<span class="name">${e.name}</span> <span class="name">${e.name}</span>
<span class="pill away"> <span class="pill away">
${zt} ${Tt}
<span>Unknown</span> <span>Unknown</span>
</span> </span>
<span class="progress-line">&mdash;</span> <span class="progress-line">&mdash;</span>
@@ -1340,7 +1340,7 @@ class Ot extends M {
</span> </span>
<span class="name">${e.name}</span> <span class="name">${e.name}</span>
<span class="pill"> <span class="pill">
${St} ${At}
<span>Home today</span> <span>Home today</span>
</span> </span>
<span class="progress-line"> <span class="progress-line">
@@ -1359,7 +1359,7 @@ class Ot extends M {
</span> </span>
<span class="name">${e.name}</span> <span class="name">${e.name}</span>
<span class="pill away"> <span class="pill away">
${Tt} ${St}
<span>On travels</span> <span>On travels</span>
</span> </span>
<span class="progress-line">${e.returns ?? "Returns —"}</span> <span class="progress-line">${e.returns ?? "Returns —"}</span>
@@ -1411,13 +1411,13 @@ class Ot extends M {
<div class="dock"> <div class="dock">
<span class="date">${J(this._now, this._timeZone())}</span> <span class="date">${J(this._now, this._timeZone())}</span>
<span class="divider"></span> <span class="divider"></span>
<span class="clock">${yt(this._now, this._timeZone())}</span> <span class="clock">${_t(this._now, this._timeZone())}</span>
</div> </div>
`; `;
const t = qt(e.condition), n = Ct(e.condition, t), i = e.temperature === null ? g : d`<span class="temp">${Math.round(e.temperature)}°</span>`, a = e.high === null || e.low === null ? null : `${Math.round(e.high)}° / ${Math.round(e.low)}°`; const t = $t(e.condition), n = qt(e.condition, t), i = e.temperature === null ? g : d`<span class="temp">${Math.round(e.temperature)}°</span>`, a = e.high === null || e.low === null ? null : `${Math.round(e.high)}° / ${Math.round(e.low)}°`;
return d` return d`
<div class="dock"> <div class="dock">
${Bt} ${Lt}
${i} ${i}
<span class="divider"></span> <span class="divider"></span>
<span class="condition"> <span class="condition">
@@ -1429,14 +1429,14 @@ class Ot extends M {
`; `;
} }
} }
customElements.define("nestquest-party-board-card", Ot); customElements.define("nestquest-party-board-card", Bt);
le({ le({
type: "nestquest-party-board-card", type: "nestquest-party-board-card",
name: "NestQuest Party Board", name: "NestQuest Party Board",
description: "Kids' attract screen for present and away adventurers." description: "Kids' attract screen for present and away adventurers."
}); });
const Pt = { CHILD: 2 }, It = (s) => (...e) => ({ _$litDirective$: s, values: e }); const Ot = { CHILD: 2 }, Pt = (s) => (...e) => ({ _$litDirective$: s, values: e });
let Ht = class { let It = class {
constructor(e) { constructor(e) {
} }
get _$AU() { get _$AU() {
@@ -1452,11 +1452,11 @@ let Ht = class {
return this.render(...t); return this.render(...t);
} }
}; };
const { I: jt } = ht, Me = (s) => s, Ae = () => document.createComment(""), B = (s, e, t) => { const { I: Ht } = pt, Me = (s) => s, Ae = () => document.createComment(""), B = (s, e, t) => {
const n = s._$AA.parentNode, i = e === void 0 ? s._$AB : e._$AA; const n = s._$AA.parentNode, i = e === void 0 ? s._$AB : e._$AA;
if (t === void 0) { if (t === void 0) {
const a = n.insertBefore(Ae(), i), r = n.insertBefore(Ae(), i); const a = n.insertBefore(Ae(), i), r = n.insertBefore(Ae(), i);
t = new jt(a, r, s, s.options); t = new Ht(a, r, s, s.options);
} else { } else {
const a = t._$AB.nextSibling, r = t._$AM, l = r !== s; const a = t._$AB.nextSibling, r = t._$AM, l = r !== s;
if (l) { if (l) {
@@ -1472,16 +1472,16 @@ const { I: jt } = ht, Me = (s) => s, Ae = () => document.createComment(""), B =
} }
} }
return t; return t;
}, q = (s, e, t = s) => (s._$AI(e, t), s), Rt = {}, Ut = (s, e = Rt) => s._$AH = e, Dt = (s) => s._$AH, Y = (s) => { }, q = (s, e, t = s) => (s._$AI(e, t), s), jt = {}, Rt = (s, e = jt) => s._$AH = e, Ut = (s) => s._$AH, Y = (s) => {
s._$AR(), s._$AA.remove(); s._$AR(), s._$AA.remove();
}; };
const Se = (s, e, t) => { const Se = (s, e, t) => {
const n = /* @__PURE__ */ new Map(); const n = /* @__PURE__ */ new Map();
for (let i = e; i <= t; i++) n.set(s[i], i); for (let i = e; i <= t; i++) n.set(s[i], i);
return n; return n;
}, Te = It(class extends Ht { }, Te = Pt(class extends It {
constructor(s) { constructor(s) {
if (super(s), s.type !== Pt.CHILD) throw Error("repeat() can only be used in text expressions"); if (super(s), s.type !== Ot.CHILD) throw Error("repeat() can only be used in text expressions");
} }
dt(s, e, t) { dt(s, e, t) {
let n; let n;
@@ -1495,7 +1495,7 @@ const Se = (s, e, t) => {
return this.dt(s, e, t).values; return this.dt(s, e, t).values;
} }
update(s, [e, t, n]) { update(s, [e, t, n]) {
const i = Dt(s), { values: a, keys: r } = this.dt(e, t, n); const i = Ut(s), { values: a, keys: r } = this.dt(e, t, n);
if (!Array.isArray(i)) return this.ut = r, a; if (!Array.isArray(i)) return this.ut = r, a;
const l = this.ut ??= [], o = []; const l = this.ut ??= [], o = [];
let p, u, c = 0, f = i.length - 1, h = 0, m = a.length - 1; let p, u, c = 0, f = i.length - 1, h = 0, m = a.length - 1;
@@ -1522,9 +1522,9 @@ const Se = (s, e, t) => {
const _ = i[c++]; const _ = i[c++];
_ !== null && Y(_); _ !== null && Y(_);
} }
return this.ut = r, Ut(s, o), S; return this.ut = r, Rt(s, o), S;
} }
}), Ft = [ }), Dt = [
{ {
kind: "lucide", kind: "lucide",
key: "lucide:bed", key: "lucide:bed",
@@ -1994,7 +1994,7 @@ const Se = (s, e, t) => {
"m3 7 2 2 4-4" "m3 7 2 2 4-4"
] ]
} }
], Qt = [ ], Ft = [
{ {
kind: "fa", kind: "fa",
key: "fa:broom", key: "fa:broom",
@@ -2215,20 +2215,20 @@ const Se = (s, e, t) => {
"M384 512L96 512c-53 0-96-43-96-96L0 96C0 43 43 0 96 0L400 0c26.5 0 48 21.5 48 48l0 288c0 20.9-13.4 38.7-32 45.3l0 66.7c17.7 0 32 14.3 32 32s-14.3 32-32 32l-32 0zM96 384c-17.7 0-32 14.3-32 32s14.3 32 32 32l256 0 0-64-256 0zm32-232c0 13.3 10.7 24 24 24l176 0c13.3 0 24-10.7 24-24s-10.7-24-24-24l-176 0c-13.3 0-24 10.7-24 24zm24 72c-13.3 0-24 10.7-24 24s10.7 24 24 24l176 0c13.3 0 24-10.7 24-24s-10.7-24-24-24l-176 0z" "M384 512L96 512c-53 0-96-43-96-96L0 96C0 43 43 0 96 0L400 0c26.5 0 48 21.5 48 48l0 288c0 20.9-13.4 38.7-32 45.3l0 66.7c17.7 0 32 14.3 32 32s-14.3 32-32 32l-32 0zM96 384c-17.7 0-32 14.3-32 32s14.3 32 32 32l256 0 0-64-256 0zm32-232c0 13.3 10.7 24 24 24l176 0c13.3 0 24-10.7 24-24s-10.7-24-24-24l-176 0c-13.3 0-24 10.7-24 24zm24 72c-13.3 0-24 10.7-24 24s10.7 24 24 24l176 0c13.3 0 24-10.7 24-24s-10.7-24-24-24l-176 0z"
] ]
} }
], O = { kind: "fallback", key: null }, Vt = 8, ze = new Map(Ft.map((s) => [s.name, s])), Zt = new Map(Qt.map((s) => [s.name, s])); ], O = { kind: "fallback", key: null }, Qt = 8, ze = new Map(Dt.map((s) => [s.name, s])), Vt = new Map(Ft.map((s) => [s.name, s]));
function Wt(s) { function Zt(s) {
const e = [...s]; const e = [...s];
return e.length === 0 || e.length > Vt ? !1 : !e.some((t) => new RegExp("[\\s<>&]|\\p{Cc}", "u").test(t)); return e.length === 0 || e.length > Qt ? !1 : !e.some((t) => new RegExp("[\\s<>&]|\\p{Cc}", "u").test(t));
} }
function Gt(s) { function Wt(s) {
if (!s || !s.trim()) return O; if (!s || !s.trim()) return O;
const e = s.indexOf(":"); const e = s.indexOf(":");
if (e === -1) return ze.get(s) ?? O; if (e === -1) return ze.get(s) ?? O;
const t = s.slice(0, e), n = s.slice(e + 1); const t = s.slice(0, e), n = s.slice(e + 1);
return t === "lucide" ? ze.get(n) ?? O : t === "fa" ? Zt.get(n) ?? O : t === "emoji" && Wt(n) ? { kind: "emoji", key: s, text: n } : O; return t === "lucide" ? ze.get(n) ?? O : t === "fa" ? Vt.get(n) ?? O : t === "emoji" && Zt(n) ? { kind: "emoji", key: s, text: n } : O;
} }
function Ee(s, e) { function Gt(s, e) {
const t = Gt(s); const t = Wt(s);
switch (t.kind) { switch (t.kind) {
case "lucide": case "lucide":
return d`<svg return d`<svg
@@ -2263,9 +2263,9 @@ const Kt = [
"nestquest_quest_uncompleted", "nestquest_quest_uncompleted",
"nestquest_quest_missed", "nestquest_quest_missed",
"nestquest_child_day_complete" "nestquest_child_day_complete"
], Ne = /* @__PURE__ */ new Map(); ], Ee = /* @__PURE__ */ new Map();
function E(s, e) { function E(s, e) {
const t = `${s ?? "local"}|${JSON.stringify(e)}`, n = Ne.get(t); const t = `${s ?? "local"}|${JSON.stringify(e)}`, n = Ee.get(t);
if (n) if (n)
return n; return n;
let i; let i;
@@ -2277,7 +2277,7 @@ function E(s, e) {
} catch { } catch {
i = new Intl.DateTimeFormat("en-US", e); i = new Intl.DateTimeFormat("en-US", e);
} }
return Ne.set(t, i), i; return Ee.set(t, i), i;
} }
function Jt(s) { function Jt(s) {
const e = s?.config; const e = s?.config;
@@ -2356,7 +2356,7 @@ function nn(s, e) {
); );
return Number.isFinite(i) ? i - s : 0; return Number.isFinite(i) ? i - s : 0;
} }
function Le(s, e) { function Ne(s, e) {
if (typeof s != "string") if (typeof s != "string")
return null; return null;
const t = s.split("-"); const t = s.split("-");
@@ -2439,7 +2439,7 @@ function ln(s) {
function cn(s, e) { function cn(s, e) {
return on[s] ?? e; return on[s] ?? e;
} }
const Be = "polygon(0 0, 100% 0, 100% 62%, 50% 100%, 0 62%)", dn = "polygon(50% 0, 93% 25%, 93% 75%, 50% 100%, 7% 75%, 7% 25%)", Oe = [-9, 6, -4], pn = He` const Le = "polygon(0 0, 100% 0, 100% 62%, 50% 100%, 0 62%)", dn = "polygon(50% 0, 93% 25%, 93% 75%, 50% 100%, 7% 75%, 7% 25%)", Be = [-9, 6, -4], pn = Ie`
* { * {
box-sizing: border-box; box-sizing: border-box;
} }
@@ -2499,7 +2499,7 @@ const Be = "polygon(0 0, 100% 0, 100% 62%, 50% 100%, 0 62%)", dn = "polygon(50%
width: 96px; width: 96px;
height: 110px; height: 110px;
padding: 3px; padding: 3px;
clip-path: ${v(Be)}; clip-path: ${v(Le)};
background: rgba(255, 255, 255, 0.22); background: rgba(255, 255, 255, 0.22);
} }
@@ -2510,7 +2510,7 @@ const Be = "polygon(0 0, 100% 0, 100% 62%, 50% 100%, 0 62%)", dn = "polygon(50%
align-items: center; align-items: center;
justify-content: center; justify-content: center;
padding-bottom: 32px; padding-bottom: 32px;
clip-path: ${v(Be)}; clip-path: ${v(Le)};
background: var(--nq-p-crest); background: var(--nq-p-crest);
} }
@@ -3341,7 +3341,7 @@ const Be = "polygon(0 0, 100% 0, 100% 62%, 50% 100%, 0 62%)", dn = "polygon(50%
<path d="M22 22H2"></path> <path d="M22 22H2"></path>
<path d="m8 6 4-4 4 4"></path> <path d="m8 6 4-4 4 4"></path>
<path d="M16 18a4 4 0 0 0-8 0"></path> <path d="M16 18a4 4 0 0 0-8 0"></path>
</svg>`, Ze = d`<svg </svg>`, Ve = d`<svg
viewBox="0 0 24 24" viewBox="0 0 24 24"
fill="none" fill="none"
stroke="currentColor" stroke="currentColor"
@@ -3437,9 +3437,9 @@ const Be = "polygon(0 0, 100% 0, 100% 62%, 50% 100%, 0 62%)", dn = "polygon(50%
icon: yn, icon: yn,
headline: "The records cannot be reached", headline: "The records cannot be reached",
body: "The party's records are quiet right now. NestQuest will return shortly." body: "The party's records are quiet right now. NestQuest will return shortly."
}, Pe = [ }, Oe = [
{ key: "morning", name: "Morning", range: "Until 11:59 AM", icon: un }, { key: "morning", name: "Morning", range: "Until 11:59 AM", icon: un },
{ key: "afternoon", name: "Afternoon", range: "12:00–5:00 PM", icon: Ze }, { key: "afternoon", name: "Afternoon", range: "12:00–5:00 PM", icon: Ve },
{ key: "evening", name: "Evening", range: "5:00–9:00 PM", icon: fn } { key: "evening", name: "Evening", range: "5:00–9:00 PM", icon: fn }
]; ];
class kn extends M { class kn extends M {
@@ -3452,7 +3452,7 @@ class kn extends M {
_toast: { state: !0 }, _toast: { state: !0 },
_countdown: { state: !0 } _countdown: { state: !0 }
}; };
static styles = [v(Ve), pn]; static styles = [v(Qe), pn];
hass; hass;
_config; _config;
_now = /* @__PURE__ */ new Date(); _now = /* @__PURE__ */ new Date();
@@ -3570,7 +3570,7 @@ class kn extends M {
${this._renderHeader(e)} ${this._renderHeader(e)}
<div class="notice-wrap"> <div class="notice-wrap">
<div class="notice" role="status"> <div class="notice" role="status">
${Ze} ${Ve}
<span class="notice-headline">No quests today</span> <span class="notice-headline">No quests today</span>
<p class="notice-body"> <p class="notice-body">
${`Nothing was posted for today, ${e.name}. Enjoy the day's rest!`} ${`Nothing was posted for today, ${e.name}. Enjoy the day's rest!`}
@@ -3614,7 +3614,7 @@ class kn extends M {
return d` return d`
${this._renderHeader(e)} ${this._renderHeader(e)}
<div class="columns"> <div class="columns">
${Pe.map((t) => this._renderColumn(t))} ${Oe.map((t) => this._renderColumn(t))}
</div> </div>
`; `;
} }
@@ -3662,7 +3662,7 @@ class kn extends M {
_awayReturns(e) { _awayReturns(e) {
const t = this._timeZone(), n = this._state( const t = this._timeZone(), n = this._state(
`binary_sensor.nestquest_${e}_present_today` `binary_sensor.nestquest_${e}_present_today`
), i = Le( ), i = Ne(
n?.attributes?.next_present, n?.attributes?.next_present,
t t
); );
@@ -3808,7 +3808,7 @@ class kn extends M {
if (!u) { if (!u) {
const _ = this._state( const _ = this._state(
`binary_sensor.nestquest_${l}_present_today` `binary_sensor.nestquest_${l}_present_today`
), x = Le( ), x = Ne(
_?.attributes?.next_present, _?.attributes?.next_present,
n n
); );
@@ -3915,10 +3915,10 @@ class kn extends M {
} }
_renderQuest(e, t, n) { _renderQuest(e, t, n) {
if (t) { if (t) {
const r = Oe[n % Oe.length], l = e.completed_at ? Yt(e.completed_at, this._timeZone()) : ""; const r = Be[n % Be.length], l = e.completed_at ? Yt(e.completed_at, this._timeZone()) : "";
return d` return d`
<div class="quest sealed" data-instance-id=${e.id}> <div class="quest sealed" data-instance-id=${e.id}>
<span class="tile" aria-hidden="true">${Ee(e.icon, te)}</span> <span class="tile" aria-hidden="true">${te}</span>
<div class="body"> <div class="body">
<span class="quest-title">${e.title}</span> <span class="quest-title">${e.title}</span>
<span class="meta"> <span class="meta">
@@ -3954,7 +3954,7 @@ class kn extends M {
(r.key === "Enter" || r.key === " ") && (r.preventDefault(), this._openConfirm(e.id)); (r.key === "Enter" || r.key === " ") && (r.preventDefault(), this._openConfirm(e.id));
}} }}
> >
<span class="tile" aria-hidden="true">${Ee(e.icon, te)}</span> <span class="tile" aria-hidden="true">${Gt(e.icon, te)}</span>
<div class="body"> <div class="body">
<span class="quest-title">${e.title}</span> <span class="quest-title">${e.title}</span>
<span class="meta ${a.late ? "late" : g}">${a.text}</span> <span class="meta ${a.late ? "late" : g}">${a.text}</span>
@@ -3990,7 +3990,7 @@ class kn extends M {
); );
if (!e) if (!e)
return g; return g;
const t = Pe.find((n) => n.key === e.window); const t = Oe.find((n) => n.key === e.window);
return d` return d`
<div class="scrim" @click=${() => this._closeConfirm()}> <div class="scrim" @click=${() => this._closeConfirm()}>
<div <div
@@ -4231,7 +4231,7 @@ le({
name: "NestQuest Admin", name: "NestQuest Admin",
description: "Parent phone view for today, tasks, schedule, and history." description: "Parent phone view for today, tasks, schedule, and history."
}); });
function We(s) { function Ze(s) {
return typeof s == "string" ? s.trim() : ""; return typeof s == "string" ? s.trim() : "";
} }
function Cn(s) { function Cn(s) {
@@ -4241,7 +4241,7 @@ function Cn(s) {
return typeof e == "string" ? e.trim() : ""; return typeof e == "string" ? e.trim() : "";
} }
function Mn(s) { function Mn(s) {
const e = We(s.url_path).replace(/^\/+|\/+$/g, ""); const e = Ze(s.url_path).replace(/^\/+|\/+$/g, "");
return e || (window.location.pathname.split("/").filter(Boolean)[0] ?? ""); return e || (window.location.pathname.split("/").filter(Boolean)[0] ?? "");
} }
function An(s) { function An(s) {
@@ -4256,7 +4256,7 @@ function Sn(s) {
} }
class Tn { class Tn {
static async generate(e, t) { static async generate(e, t) {
const n = `/${Mn(e)}`, i = We(e.weather_entity), a = { const n = `/${Mn(e)}`, i = Ze(e.weather_entity), a = {
type: "custom:nestquest-party-board-card", type: "custom:nestquest-party-board-card",
quest_log_path: n quest_log_path: n
}; };
+1 -1
View File
@@ -2057,7 +2057,7 @@ export class NestQuestQuestLogCard extends LitElement {
: ""; : "";
return html` return html`
<div class="quest sealed" data-instance-id=${instance.id}> <div class="quest sealed" data-instance-id=${instance.id}>
<span class="tile" aria-hidden="true">${renderQuestIcon(instance.icon, ICON_STAR)}</span> <span class="tile" aria-hidden="true">${ICON_STAR}</span>
<div class="body"> <div class="body">
<span class="quest-title">${instance.title}</span> <span class="quest-title">${instance.title}</span>
<span class="meta"> <span class="meta">
+20 -4
View File
@@ -7,10 +7,10 @@
* the card is mounted at the given URL (it resolves its child from the * the card is mounted at the given URL (it resolves its child from the
* pathname's last segment), after the optional probe wait one snapshot of * pathname's last segment), after the optional probe wait one snapshot of
* the render is taken mid-wait, then after the optional idle wait stdout * the render is taken mid-wait, then after the optional idle wait stdout
* receives one JSON object {location, headline, countdown, html, probe} — * receives one JSON object {location, headline, countdown, html, tiles,
* the final window pathname, the rendered title, the complete-screen * probe} — the final window pathname, the rendered title, the
* countdown text, the rendered shadow DOM, and the probe snapshot when * complete-screen countdown text, the rendered shadow DOM, each quest
* probe_ms was given. The Python panel tests drive this harness so the * card's icon tile, and the probe snapshot when probe_ms was given. The Python panel tests drive this harness so the
* assertions run against the exact bundle HACS ships. * assertions run against the exact bundle HACS ships.
*/ */
import { readFileSync } from "node:fs"; import { readFileSync } from "node:fs";
@@ -56,6 +56,22 @@ const snapshot = () => ({
element.shadowRoot.querySelector(".complete-countdown")?.textContent?.trim() ?? element.shadowRoot.querySelector(".complete-countdown")?.textContent?.trim() ??
"", "",
html: element.shadowRoot.innerHTML, html: element.shadowRoot.innerHTML,
// Each quest card's icon tile: the registry glyph it rendered (its
// data-icon key and svg fill), its text (an emoji), and whether it shows
// the static star (the star's polygon).
tiles: [...element.shadowRoot.querySelectorAll(".quest")].map((quest) => {
const tile = quest.querySelector(".tile");
const glyph = tile?.querySelector("[data-icon]");
return {
id: Number(quest.dataset.instanceId),
sealed: quest.classList.contains("sealed"),
icon: glyph?.getAttribute("data-icon") ?? null,
fill: glyph?.getAttribute("fill") ?? null,
paths: tile?.querySelectorAll("path").length ?? 0,
text: tile?.textContent?.trim() ?? "",
star: Boolean(tile?.querySelector("polygon")),
};
}),
}); });
let probe = null; let probe = null;
+112
View File
@@ -886,3 +886,115 @@ def test_quest_complete_screen_returns_to_the_board_after_the_countdown() -> Non
assert result["probe"]["countdown"] == "Returning to The Party in 1 seconds" assert result["probe"]["countdown"] == "Returning to The Party in 1 seconds"
# …and at zero the card has returned to the party board. # …and at zero the card has returned to the party board.
assert result["location"] == "/nestquest" assert result["location"] == "/nestquest"
# --- Quest card icons (definition icon on the open tile) ---------------------
def _quest_row(instance_id: int, icon: str | None, state: str = "open") -> dict:
"""One ``instances`` attribute row for Ada's quests-due sensor."""
row = {
"id": instance_id,
"child_id": 1,
"title": f"Quest {instance_id}",
"icon": icon,
"window": "morning",
"due_time": "08:00",
"state": state,
"overdue": False,
"completed_at": None,
"on_time": None,
}
if state == "completed":
row["completed_at"] = "2026-09-26T07:30:00+00:00"
row["on_time"] = True
return row
def _quest_log_tiles(rows: list[dict]) -> dict[int, dict]:
"""Render Ada's quest log with ``rows`` and key its tiles by instance id."""
states = _three_child_states()
states["sensor.nestquest_ada_quests_due_today"] = _state(
str(len(rows)), child_name="Ada", present=True, instances=rows
)
result = _render_quest_log(
{"type": "custom:nestquest-quest-log-card"},
states,
url="http://homeassistant.local/nestquest/ada",
)
return {tile["id"]: tile for tile in result["tiles"]}
def test_open_quest_tile_renders_the_definition_icon() -> None:
"""The open card's tile shows the definition's namespaced icon, drawn
from the bundled registry: Lucide as a stroked svg, Font Awesome as a
filled svg, an emoji as its text, and a legacy bare name as Lucide."""
tiles = _quest_log_tiles(
[
_quest_row(1, "lucide:bed"),
_quest_row(2, "fa:broom"),
_quest_row(3, "emoji:🦊"),
_quest_row(4, "bath"),
]
)
assert tiles[1]["icon"] == "lucide:bed"
assert tiles[1]["fill"] == "none"
assert tiles[1]["paths"] > 0
assert tiles[2]["icon"] == "fa:broom"
assert tiles[2]["fill"] == "currentColor"
assert tiles[2]["paths"] > 0
assert tiles[3]["icon"] == "emoji:🦊"
assert tiles[3]["text"] == "🦊"
assert tiles[4]["icon"] == "lucide:bath"
assert tiles[4]["fill"] == "none"
for tile in tiles.values():
assert not tile["sealed"]
assert not tile["star"]
def test_open_quest_tile_falls_back_to_the_star() -> None:
"""An unknown name, an unknown namespace, or no icon at all keeps the
open card's current star glyph."""
tiles = _quest_log_tiles(
[
_quest_row(1, "lucide:not-a-real-icon"),
_quest_row(2, "fa:not-a-real-icon"),
_quest_row(3, "mdi:bed"),
_quest_row(4, ""),
_quest_row(5, None),
]
)
assert set(tiles) == {1, 2, 3, 4, 5}
for tile in tiles.values():
assert tile["star"]
assert tile["icon"] is None
def test_sealed_quest_tile_keeps_the_star() -> None:
"""A sealed card keeps its star tile (and its wax seal) whatever the
definition's icon; only the open card shows the quest's icon."""
tiles = _quest_log_tiles(
[
_quest_row(1, "lucide:bed", state="completed"),
_quest_row(2, "fa:broom", state="completed"),
_quest_row(3, "emoji:🦊", state="completed"),
]
)
for tile in tiles.values():
assert tile["sealed"]
assert tile["star"]
assert tile["icon"] is None
assert tile["text"] == ""
def test_only_the_open_tile_calls_the_icon_resolver() -> None:
source = _read(QUEST_LOG)
sealed_start = source.index('<div class="quest sealed"')
sealed_block = source[sealed_start : source.index("</div>", sealed_start)]
assert '<span class="tile" aria-hidden="true">${ICON_STAR}</span>' in sealed_block
assert "renderQuestIcon" not in sealed_block
assert (
source.count("renderQuestIcon(instance.icon, ICON_STAR)") == 1
), "only the open card's tile resolves the definition icon"
open_start = source.index('class="quest tappable"')
assert "renderQuestIcon(instance.icon, ICON_STAR)" in source[open_start:]