@wral/hsot-data 0.1.5 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,50 +1,50 @@
1
- import { LitElement as ae, html as l, css as y, nothing as p, svg as Y } from "lit";
2
- const re = 50;
3
- function oe(a = {}) {
1
+ import { LitElement as te, html as i, css as b, nothing as p, svg as X } from "lit";
2
+ const ie = 50;
3
+ function ne(a = {}) {
4
4
  const e = Object.entries(a).filter(([, s]) => s != null && s !== "");
5
5
  if (!e.length) return "";
6
6
  const t = new URLSearchParams();
7
7
  return e.forEach(([s, r]) => t.set(s, String(r))), `?${t.toString()}`;
8
8
  }
9
- function ne({ baseUrl: a, token: e = "", fetchFn: t } = {}) {
9
+ function le({ baseUrl: a, token: e = "", fetchFn: t } = {}) {
10
10
  if (!a) throw new Error("createClient requires a baseUrl");
11
- const s = a.replace(/\/+$/, ""), r = t || ((...i) => fetch(...i));
12
- async function o(i) {
13
- const d = { Accept: "application/json" };
14
- e && (d.Authorization = `Bearer ${e}`);
15
- const h = await r(`${s}${i}`, { headers: d });
16
- if (!h.ok) {
17
- const c = new Error(`api-hsot ${h.status} on ${i}`);
18
- throw c.status = h.status, c;
11
+ const s = a.replace(/\/+$/, ""), r = t || ((...n) => fetch(...n));
12
+ async function o(n) {
13
+ const h = { Accept: "application/json" };
14
+ e && (h.Authorization = `Bearer ${e}`);
15
+ const l = await r(`${s}${n}`, { headers: h });
16
+ if (!l.ok) {
17
+ const d = new Error(`api-hsot ${l.status} on ${n}`);
18
+ throw d.status = l.status, d;
19
19
  }
20
- return h.json();
21
- }
22
- async function n(i, d = {}) {
23
- const h = [];
24
- let c = null;
25
- for (let m = 0; m < re; m += 1) {
26
- const f = oe(c ? { ...d, cursor: c } : d), g = await o(`${i}${f}`);
27
- if (h.push(...g.items || []), c = g.nextCursor || null, !c) break;
20
+ return l.json();
21
+ }
22
+ async function c(n, h = {}) {
23
+ const l = [];
24
+ let d = null;
25
+ for (let m = 0; m < ie; m += 1) {
26
+ const f = ne(d ? { ...h, cursor: d } : h), g = await o(`${n}${f}`);
27
+ if (l.push(...g.items || []), d = g.nextCursor || null, !d) break;
28
28
  }
29
- return { items: h, total: h.length, nextCursor: null };
29
+ return { items: l, total: l.length, nextCursor: null };
30
30
  }
31
31
  return {
32
- listSchools: (i) => n("/schools", i),
33
- getSchool: (i) => o(`/schools/${i}`),
34
- listTeams: (i) => n("/teams", i),
35
- getTeam: (i) => o(`/teams/${i}`),
36
- listConferences: (i) => n("/conferences", i),
37
- listPlayers: (i) => n("/players", i),
38
- listRosters: (i) => n("/rosters", i),
39
- listGames: (i) => n("/games", i),
40
- getGame: (i) => o(`/games/${i}`),
41
- listTournaments: (i) => n("/tournaments", i),
42
- listSeedings: (i, d) => n(`/tournaments/${i}/seedings`, d),
43
- listRankings: (i) => n("/rankings", i),
32
+ listSchools: (n) => c("/schools", n),
33
+ getSchool: (n) => o(`/schools/${n}`),
34
+ listTeams: (n) => c("/teams", n),
35
+ getTeam: (n) => o(`/teams/${n}`),
36
+ listConferences: (n) => c("/conferences", n),
37
+ listPlayers: (n) => c("/players", n),
38
+ listRosters: (n) => c("/rosters", n),
39
+ listGames: (n) => c("/games", n),
40
+ getGame: (n) => o(`/games/${n}`),
41
+ listTournaments: (n) => c("/tournaments", n),
42
+ listSeedings: (n, h) => c(`/tournaments/${n}/seedings`, h),
43
+ listRankings: (n) => c("/rankings", n),
44
44
  listSports: () => o("/sports")
45
45
  };
46
46
  }
47
- const O = {
47
+ const U = {
48
48
  game: "/{sport}/game/{id}/",
49
49
  school: "/school/{id}/",
50
50
  section: "/{sport}/{view}/"
@@ -54,56 +54,62 @@ function u(a, e) {
54
54
  }
55
55
  function D(a) {
56
56
  return {
57
- game: a.getAttribute("game-href") || O.game,
58
- school: a.getAttribute("school-href") || O.school,
59
- section: a.getAttribute("section-href") || O.section
57
+ game: a.getAttribute("game-href") || U.game,
58
+ school: a.getAttribute("school-href") || U.school,
59
+ section: a.getAttribute("section-href") || U.section
60
60
  };
61
61
  }
62
62
  const T = (a) => a ? a.charAt(0).toUpperCase() + a.slice(1) : "";
63
- function b(a, e) {
63
+ function $(a, e) {
64
64
  if (!a) return "TBD";
65
65
  const [t, s, r] = String(a).split("-").map(Number);
66
66
  return !t || !s || !r ? "TBD" : new Date(t, s - 1, r).toLocaleDateString("en-US", e || { weekday: "short", month: "short", day: "numeric" });
67
67
  }
68
- function A(a) {
68
+ function L(a) {
69
69
  if (!a) return "";
70
70
  const [e, t] = String(a).split(":").map(Number);
71
71
  if (Number.isNaN(e)) return "";
72
72
  const s = e >= 12 ? "PM" : "AM";
73
73
  return `${(e + 11) % 12 + 1}:${String(t || 0).padStart(2, "0")} ${s}`;
74
74
  }
75
- function ie(a) {
75
+ function ce(a) {
76
76
  return a ? `${Math.floor(a / 12)}-${a % 12}` : "·";
77
77
  }
78
- function E(a = /* @__PURE__ */ new Date()) {
78
+ function N(a = /* @__PURE__ */ new Date()) {
79
79
  const e = a.getFullYear();
80
80
  return a.getMonth() >= 6 ? `${e}-${e + 1}` : `${e - 1}-${e}`;
81
81
  }
82
- function U(a = /* @__PURE__ */ new Date()) {
82
+ function j(a = /* @__PURE__ */ new Date()) {
83
83
  const e = (t) => String(t).padStart(2, "0");
84
84
  return `${a.getFullYear()}-${e(a.getMonth() + 1)}-${e(a.getDate())}`;
85
85
  }
86
- function M(a) {
86
+ function de(a, e = j()) {
87
+ const t = [...new Set((a || []).filter(Boolean))].sort();
88
+ if (!t.length || t.includes(e)) return e;
89
+ const s = t.filter((r) => r < e);
90
+ return s.length ? s[s.length - 1] : t[0];
91
+ }
92
+ function G(a) {
87
93
  return a ? (a.abbr || a.name || "?").slice(0, 4).toUpperCase() : "?";
88
94
  }
89
- function B(a) {
95
+ function E(a) {
90
96
  if (!a || !/^#[0-9a-fA-F]{6}$/.test(a)) return "#FFFFFF";
91
97
  const e = parseInt(a.slice(1), 16), t = e >> 16 & 255, s = e >> 8 & 255, r = e & 255;
92
98
  return 0.299 * t + 0.587 * s + 0.114 * r > 150 ? "#0F1B33" : "#FFFFFF";
93
99
  }
94
- const le = (a) => {
100
+ const he = (a) => {
95
101
  const e = ["th", "st", "nd", "rd"], t = a % 100;
96
102
  return a + (e[(t - 20) % 10] || e[t] || e[0]);
97
103
  };
98
- function ce(a) {
104
+ function me(a) {
99
105
  if (a.state === "live") return { kind: "live", label: `Live · ${a.period || ""}`.replace(/ · $/, "") };
100
106
  if (a.state === "final") {
101
107
  const e = [];
102
108
  return a.finish === "overtime" && e.push("OT"), a.finish === "shootout" && e.push("PK-SO"), a.forfeit && a.forfeit !== "none" && e.push("Forfeit"), { kind: "final", label: `Final${e.length ? ` · ${e.join(" · ")}` : ""}` };
103
109
  }
104
- return a.state === "postponed" ? { kind: "warn", label: "Postponed" } : a.state === "canceled" ? { kind: "warn", label: "Canceled" } : { kind: "sched", label: `${b(a.date, { month: "short", day: "numeric" })} · ${A(a.time)}`.replace(/ · $/, "") };
110
+ return a.state === "postponed" ? { kind: "warn", label: "Postponed" } : a.state === "canceled" ? { kind: "warn", label: "Canceled" } : { kind: "sched", label: `${$(a.date, { month: "short", day: "numeric" })} · ${L(a.time)}`.replace(/ · $/, "") };
105
111
  }
106
- const de = /* @__PURE__ */ new Set(["game", "story", "page", "forum", "video", "gallery"]);
112
+ const pe = /* @__PURE__ */ new Set(["game", "story", "page", "forum", "video", "gallery"]);
107
113
  function x(a) {
108
114
  let e = String(a || "").replace(/^[a-z][a-z0-9+.-]*:\/\/[^/#?]*/i, "");
109
115
  const t = e.indexOf("#");
@@ -112,26 +118,26 @@ function x(a) {
112
118
  let r = e.split("?")[0] + s;
113
119
  return r = r.replace(/([^:])\/{2,}/g, "$1/").replace(/^\/{2,}/, "/"), r = r.replace(/^\/(?=#)/, ""), r.length > 1 && (r = r.replace(/\/+$/, "")), r.toLowerCase();
114
120
  }
115
- function Z() {
121
+ function se() {
116
122
  const a = globalThis.location;
117
123
  if (!a) return "";
118
124
  const e = (a.hash || "").startsWith("#/") ? a.hash : "";
119
125
  return x((a.pathname || "") + e);
120
126
  }
121
- function he(a, e, t) {
127
+ function fe(a, e, t) {
122
128
  if (!t) return null;
123
129
  const s = x(a);
124
130
  if (!s) return null;
125
131
  const r = x(u(e.game, { sport: t, id: "" })), o = x(u(e.school, { id: "" }));
126
132
  if (s === r || s.startsWith(`${r}/`) || s === o || s.startsWith(`${o}/`)) return null;
127
- const n = x(u(e.section, { sport: t, view: "" }));
128
- if (s === n) return "";
129
- if (!s.startsWith(`${n}/`)) return null;
130
- const i = s.slice(n.length + 1), d = i.split("/");
131
- return d.length > 2 || d.some((h) => !/^[a-z][a-z-]*$/.test(h)) || de.has(d[0]) ? null : i;
133
+ const c = x(u(e.section, { sport: t, view: "" }));
134
+ if (s === c) return "";
135
+ if (!s.startsWith(`${c}/`)) return null;
136
+ const n = s.slice(c.length + 1), h = n.split("/");
137
+ return h.length > 2 || h.some((l) => !/^[a-z][a-z-]*$/.test(l)) || pe.has(h[0]) ? null : n;
132
138
  }
133
- function me(a, e, t) {
134
- const s = (n) => u(t.section, { sport: a, view: n }).replace(/([^:])\/{2,}/g, "$1/"), o = new Set((e || []).map((n) => n && n.gender).filter((n) => n === "boys" || n === "girls")).size === 2 ? [
139
+ function ue(a, e, t) {
140
+ const s = (c) => u(t.section, { sport: a, view: c }).replace(/([^:])\/{2,}/g, "$1/"), o = new Set((e || []).map((c) => c && c.gender).filter((c) => c === "boys" || c === "girls")).size === 2 ? [
135
141
  { label: "Boys Standings", href: s("boys/standings") },
136
142
  { label: "Girls Standings", href: s("girls/standings") }
137
143
  ] : [{ label: "Standings", href: s("standings") }];
@@ -143,28 +149,31 @@ function me(a, e, t) {
143
149
  { label: "Polls & Rankings", href: s("rankings") }
144
150
  ];
145
151
  }
146
- function pe(a, e = Z()) {
152
+ function ge(a, e = se()) {
147
153
  const t = x(e);
148
154
  for (const s of a.querySelectorAll(':scope > a[slot="nav"]'))
149
155
  t && x(s.getAttribute("href")) === t ? s.setAttribute("aria-current", "page") : s.removeAttribute("aria-current");
150
156
  }
151
- class $ extends ae {
157
+ class y extends te {
152
158
  static properties = {
153
159
  api: { type: String },
154
160
  refreshInterval: { type: Number, attribute: "refresh-interval" },
161
+ promoHref: { type: String, attribute: "promo-href" },
162
+ promoImage: { type: String, attribute: "promo-image" },
163
+ promoAlt: { type: String, attribute: "promo-alt" },
155
164
  data: { state: !0 },
156
165
  loading: { state: !0 },
157
166
  error: { state: !0 }
158
167
  };
159
168
  constructor() {
160
- super(), this.api = "", this.refreshInterval = 0, this.data = null, this.loading = !1, this.error = "", this._client = null, this._refreshId = null;
169
+ super(), this.api = "", this.refreshInterval = 0, this.promoHref = "", this.promoImage = "", this.promoAlt = "", this.data = null, this.loading = !1, this.error = "", this._client = null, this._refreshId = null;
161
170
  }
162
171
  /** Injected client wins; otherwise build a fetch client from the api attribute. */
163
172
  set client(e) {
164
173
  this._client = e, this.isConnected && this.load();
165
174
  }
166
175
  get client() {
167
- return this._client ? this._client : this.api ? ne({ baseUrl: this.api }) : null;
176
+ return this._client ? this._client : this.api ? le({ baseUrl: this.api }) : null;
168
177
  }
169
178
  connectedCallback() {
170
179
  super.connectedCallback(), this._setupInterval();
@@ -176,7 +185,7 @@ class $ extends ae {
176
185
  this.load();
177
186
  }
178
187
  updated(e) {
179
- e.has("api") && e.get("api") !== void 0 && e.get("api") !== this.api && this.load(), e.has("refreshInterval") && this._setupInterval(), pe(this);
188
+ e.has("api") && e.get("api") !== void 0 && e.get("api") !== this.api && this.load(), e.has("refreshInterval") && this._setupInterval(), ge(this);
180
189
  }
181
190
  async load() {
182
191
  const e = this.client;
@@ -205,13 +214,13 @@ class $ extends ae {
205
214
  this._refreshId && (clearInterval(this._refreshId), this._refreshId = null);
206
215
  }
207
216
  render() {
208
- return this.error === "not-configured" ? l`<div class="error">This component needs an <code>api</code> attribute (the api-hsot public read-surface base URL) or an injected client.</div>` : this.error ? l`<div class="error">Unable to load right now. <button class="chip" @click=${() => this.load()}>Retry</button></div>` : this.data ? this.renderView() : l`<div class="loading" role="status">Loading…</div>`;
217
+ return this.error === "not-configured" ? i`<div class="error">This component needs an <code>api</code> attribute (the api-hsot public read-surface base URL) or an injected client.</div>` : this.error ? i`<div class="error">Unable to load right now. <button class="chip" @click=${() => this.load()}>Retry</button></div>` : this.data ? this.renderView() : i`<div class="loading" role="status">Loading…</div>`;
209
218
  }
210
219
  renderView() {
211
- return l``;
220
+ return i``;
212
221
  }
213
222
  }
214
- const v = (a) => Object.fromEntries((a || []).map((e) => [e.id, e])), fe = y`
223
+ const v = (a) => Object.fromEntries((a || []).map((e) => [e.id, e])), ve = b`
215
224
  :host {
216
225
  --hsot-red: var(--color-red, #D1232A);
217
226
  --hsot-red-deep: var(--color-red-dark, #951C21);
@@ -249,7 +258,7 @@ const v = (a) => Object.fromEntries((a || []).map((e) => [e.id, e])), fe = y`
249
258
  outline-offset: 1px;
250
259
  }
251
260
  .mut { color: var(--hsot-gray-5); }
252
- `, ue = y`
261
+ `, be = b`
253
262
  .band { background: var(--hsot-white); color: var(--hsot-black); }
254
263
  .band .inner { max-width: 1366px; margin: 0 auto; padding: 1.1rem 1.25rem 0; }
255
264
  .band h1, .band h2.bandtitle {
@@ -298,8 +307,29 @@ const v = (a) => Object.fromEntries((a || []).map((e) => [e.id, e])), fe = y`
298
307
  @media (max-width: 720px) {
299
308
  .band h1, .band h2.bandtitle, .band.section h1, .band.section h2.bandtitle { font-size: 1.8rem; }
300
309
  }
301
- `, ge = y`
310
+ `, $e = b`
302
311
  .view { max-width: 1366px; margin: 0 auto; padding: 1.25rem; box-sizing: border-box; }
312
+ /* Optional right rail (slot="rail" light-DOM children): a divided 300px
313
+ column on desktop, stacked under the view content on smaller screens. */
314
+ .viewmain, .viewrail { min-width: 0; }
315
+ .view.withrail .viewrail {
316
+ margin-top: 2rem; padding-top: 2rem;
317
+ border-top: 1px solid var(--hsot-gray-2, #E5E3E1);
318
+ }
319
+ @media (min-width: 1200px) {
320
+ .view.withrail {
321
+ /* 332px = 300px rail content + the 2rem divider padding. */
322
+ display: grid; grid-template-columns: minmax(0, 1fr) 332px;
323
+ gap: 2rem; align-items: stretch;
324
+ }
325
+ .view.withrail .viewrail {
326
+ margin-top: 0; padding-top: 0; border-top: none;
327
+ padding-left: 2rem;
328
+ border-left: 1px solid var(--hsot-gray-2, #E5E3E1);
329
+ }
330
+ }
331
+ .promo { text-align: center; margin: 0 0 1.1rem; }
332
+ .promo img { max-width: 100%; height: auto; display: inline-block; }
303
333
  .toolbar { display: flex; flex-wrap: wrap; gap: 0.6rem; align-items: center; margin: 0 0 1.1rem; }
304
334
  .toolbar .spacer { flex: 1; }
305
335
  .asof { font-size: 0.8125rem; color: var(--hsot-gray-5); }
@@ -341,7 +371,7 @@ const v = (a) => Object.fromEntries((a || []).map((e) => [e.id, e])), fe = y`
341
371
  .error { padding: 1.2rem 1rem; color: var(--hsot-red-deep); font-size: 0.9rem; }
342
372
  .note { font-size: 0.8125rem; color: var(--hsot-gray-5); margin: 0.6rem 0 0; }
343
373
  .loading { padding: 1.2rem; color: var(--hsot-gray-5); font-family: var(--hsot-heading-font); }
344
- `, ve = y`
374
+ `, ye = b`
345
375
  .pill {
346
376
  display: inline-block; font-family: var(--hsot-heading-font); font-weight: 700;
347
377
  font-size: 0.6875rem; text-transform: uppercase; letter-spacing: 0.04em;
@@ -356,7 +386,7 @@ const v = (a) => Object.fromEntries((a || []).map((e) => [e.id, e])), fe = y`
356
386
  .pill.champ { background: var(--hsot-straw); color: #6b5900; }
357
387
  @keyframes hsot-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.55; } }
358
388
  @media (prefers-reduced-motion: reduce) { .pill.live { animation: none; } }
359
- `, be = y`
389
+ `, we = b`
360
390
  .tablewrap { overflow-x: auto; }
361
391
  table.data { font-family: var(--hsot-heading-font); font-size: 14px; border-collapse: collapse; width: 100%; }
362
392
  table.data th {
@@ -374,7 +404,7 @@ const v = (a) => Object.fromEntries((a || []).map((e) => [e.id, e])), fe = y`
374
404
  table.data tbody tr.rowlink:hover { background: var(--hsot-gray-1); }
375
405
  table.data td.teamcell a { color: inherit; text-decoration: none; font-weight: 500; }
376
406
  table.data td.teamcell a:hover { text-decoration: underline; }
377
- `, $e = y`
407
+ `, xe = b`
378
408
  .swatch {
379
409
  display: inline-flex; align-items: center; justify-content: center;
380
410
  width: 26px; height: 26px; border-radius: 50%;
@@ -398,7 +428,7 @@ const v = (a) => Object.fromEntries((a || []).map((e) => [e.id, e])), fe = y`
398
428
  .dot.W { background: var(--hsot-win); }
399
429
  .dot.L { background: var(--hsot-loss); }
400
430
  .dot.T { background: var(--hsot-tie); }
401
- `, ye = y`
431
+ `, ke = b`
402
432
  ul.gamelist { list-style: none; margin: 0; padding: 0; }
403
433
  .gamelist li {
404
434
  display: flex; align-items: center; gap: 0.7rem; padding: 0.55rem 1rem;
@@ -415,77 +445,77 @@ const v = (a) => Object.fromEntries((a || []).map((e) => [e.id, e])), fe = y`
415
445
  .gamelist .opp a:hover { text-decoration: underline; }
416
446
  .gamelist .where { color: var(--hsot-gray-5); font-size: 0.78rem; }
417
447
  .gamelist a.box { font-size: 0.78rem; }
418
- `, F = [fe, ue, ge, ve, be, $e, ye];
419
- function j(a) {
448
+ `, F = [ve, be, $e, ye, we, xe, ke];
449
+ function q(a) {
420
450
  return a.state !== "final" ? null : a.forfeit && a.forfeit !== "none" ? a.forfeit : a.homeScore > a.awayScore ? "home" : a.awayScore > a.homeScore ? "away" : a.tiebreakWinner && a.tiebreakWinner !== "none" ? a.tiebreakWinner : "tie";
421
451
  }
422
452
  function z(a, e) {
423
- const t = {}, s = (o) => (t[o] = t[o] || { w: 0, l: 0, t: 0, cw: 0, cl: 0, ct: 0, pf: 0, pa: 0, results: [] }, t[o]), r = a.filter((o) => o.state === "final" && o.gameType !== "scrimmage" && (!e || o.date <= e)).sort((o, n) => String(o.date).localeCompare(String(n.date)));
453
+ const t = {}, s = (o) => (t[o] = t[o] || { w: 0, l: 0, t: 0, cw: 0, cl: 0, ct: 0, pf: 0, pa: 0, results: [] }, t[o]), r = a.filter((o) => o.state === "final" && o.gameType !== "scrimmage" && (!e || o.date <= e)).sort((o, c) => String(o.date).localeCompare(String(c.date)));
424
454
  for (const o of r) {
425
- const n = j(o), i = o.gameType === "conference";
426
- for (const d of ["home", "away"]) {
427
- const h = d === "home" ? o.homeTeamId : o.awayTeamId;
428
- if (!h) continue;
429
- const c = s(h), m = d === "home" ? o.homeScore : o.awayScore, f = d === "home" ? o.awayScore : o.homeScore;
430
- c.pf += m, c.pa += f;
455
+ const c = q(o), n = o.gameType === "conference";
456
+ for (const h of ["home", "away"]) {
457
+ const l = h === "home" ? o.homeTeamId : o.awayTeamId;
458
+ if (!l) continue;
459
+ const d = s(l), m = h === "home" ? o.homeScore : o.awayScore, f = h === "home" ? o.awayScore : o.homeScore;
460
+ d.pf += m, d.pa += f;
431
461
  let g = "T";
432
- n === "tie" ? (c.t += 1, i && (c.ct += 1)) : n === d ? (c.w += 1, i && (c.cw += 1), g = "W") : (c.l += 1, i && (c.cl += 1), g = "L"), c.results.push({ gameId: o.id, date: o.date, mark: g, my: m, their: f, opp: d === "home" ? o.awayTeamId : o.homeTeamId, conf: i });
462
+ c === "tie" ? (d.t += 1, n && (d.ct += 1)) : c === h ? (d.w += 1, n && (d.cw += 1), g = "W") : (d.l += 1, n && (d.cl += 1), g = "L"), d.results.push({ gameId: o.id, date: o.date, mark: g, my: m, their: f, opp: h === "home" ? o.awayTeamId : o.homeTeamId, conf: n });
433
463
  }
434
464
  }
435
465
  return t;
436
466
  }
437
- function L(a) {
467
+ function O(a) {
438
468
  if (!a || !a.length) return "";
439
469
  const e = a[a.length - 1].mark;
440
470
  let t = 0;
441
471
  for (let s = a.length - 1; s >= 0 && a[s].mark === e; s -= 1) t += 1;
442
472
  return e + t;
443
473
  }
444
- const Q = (a, e, t) => {
474
+ const Z = (a, e, t) => {
445
475
  const s = a + e + t;
446
476
  return s ? (a + t / 2) / s : 0;
447
- }, K = (a) => a.toFixed(3).replace("0.", ".");
477
+ }, J = (a) => a.toFixed(3).replace("0.", ".");
448
478
  function w(a, e = !1) {
449
479
  if (!a) return "0-0";
450
480
  const t = e ? a.cw : a.w, s = e ? a.cl : a.l, r = e ? a.ct : a.t;
451
481
  return `${t}-${s}${r ? `-${r}` : ""}`;
452
482
  }
453
- function J(a, e) {
483
+ function ae(a, e) {
454
484
  return a.map((t) => {
455
485
  const s = e[t.id] || { w: 0, l: 0, t: 0, cw: 0, cl: 0, ct: 0, pf: 0, pa: 0, results: [] };
456
- return { team: t, rec: s, confPct: Q(s.cw, s.cl, s.ct), overallPct: Q(s.w, s.l, s.t) };
486
+ return { team: t, rec: s, confPct: Z(s.cw, s.cl, s.ct), overallPct: Z(s.w, s.l, s.t) };
457
487
  }).sort((t, s) => s.confPct - t.confPct || s.overallPct - t.overallPct || s.rec.pf - s.rec.pa - (t.rec.pf - t.rec.pa));
458
488
  }
459
- function G(a, e) {
489
+ function W(a, e) {
460
490
  return a.filter((t) => (t.homeTeamId === e || t.awayTeamId === e) && (t.state === "scheduled" || t.state === "live") && t.gameType !== "scrimmage").sort((t, s) => String(t.date).localeCompare(String(s.date)))[0] || null;
461
491
  }
462
- function X(a, e) {
492
+ function ee(a, e) {
463
493
  const t = a[e];
464
494
  return t && t.results.length ? t.results[t.results.length - 1] : null;
465
495
  }
466
- function Ee(a, e, t, s = "") {
496
+ function Me(a, e, t, s = "") {
467
497
  let r = null;
468
498
  for (const o of a || [])
469
499
  o.sport === e && (t && o.effectiveDate > t || s && o.gender && o.gender !== s || (!r || o.effectiveDate > r.effectiveDate) && (r = o));
470
500
  return r;
471
501
  }
472
- function ee(a, e, t, s, r) {
502
+ function V(a, e, t, s, r) {
473
503
  const o = e[t];
474
504
  if (!o) return null;
475
- const n = /* @__PURE__ */ new Map();
476
- for (const d of a || []) {
477
- if (d.sport !== s || r && d.effectiveDate > r || d.gender && o.gender !== d.gender && o.gender !== "coed") continue;
478
- const h = d.gender || "", c = n.get(h);
479
- (!c || d.effectiveDate > c.effectiveDate) && n.set(h, d);
480
- }
481
- let i = null;
482
- for (const d of n.values()) {
483
- const h = (d.teamIds || []).indexOf(t);
484
- h !== -1 && (!i || d.effectiveDate > i.effectiveDate) && (i = { poll: d, rank: h + 1 });
485
- }
486
- return i ? i.rank : null;
505
+ const c = /* @__PURE__ */ new Map();
506
+ for (const h of a || []) {
507
+ if (h.sport !== s || r && h.effectiveDate > r || h.gender && o.gender !== h.gender && o.gender !== "coed") continue;
508
+ const l = h.gender || "", d = c.get(l);
509
+ (!d || h.effectiveDate > d.effectiveDate) && c.set(l, h);
510
+ }
511
+ let n = null;
512
+ for (const h of c.values()) {
513
+ const l = (h.teamIds || []).indexOf(t);
514
+ l !== -1 && (!n || h.effectiveDate > n.effectiveDate) && (n = { poll: h, rank: l + 1 });
515
+ }
516
+ return n ? n.rank : null;
487
517
  }
488
- function we(a, e, t) {
518
+ function Te(a, e, t) {
489
519
  if (!a) return { kind: "none", delta: 0 };
490
520
  const s = (a.teamIds || []).indexOf(t) + 1;
491
521
  if (!s) return { kind: "none", delta: 0 };
@@ -495,109 +525,121 @@ function we(a, e, t) {
495
525
  const o = r - s;
496
526
  return o > 0 ? { kind: "up", delta: o } : o < 0 ? { kind: "down", delta: -o } : { kind: "same", delta: 0 };
497
527
  }
498
- function xe(a) {
528
+ function Ie(a) {
499
529
  return /^https?:\/\//i.test(String(a || ""));
500
530
  }
501
- function P(a, e) {
531
+ function _(a, e) {
502
532
  const t = a?.logoAssetId;
503
- if (!xe(t)) return "";
533
+ if (!Ie(t)) return "";
504
534
  const s = Math.max(1, Math.round(e * 2)), r = t.includes("?") ? "&" : "?";
505
535
  return `${t}${r}w=${s}&h=${s}&f=webp`;
506
536
  }
507
- function W(a, e, { title: t, sub: s, teams: r }) {
508
- const o = Z(), i = !!a.querySelector(':scope > a[slot="nav"]') || he(o, e.hrefs, e.sport) !== null;
509
- return l`
537
+ function Y(a, e, { title: t, sub: s, teams: r }) {
538
+ const o = se(), n = !!a.querySelector(':scope > a[slot="nav"]') || fe(o, e.hrefs, e.sport) !== null;
539
+ return i`
510
540
  <div class="band section">
511
541
  <div class="inner">
512
542
  <h1>${t}</h1>
513
- ${s ? l`<p class="sub">${s}</p>` : p}
543
+ ${s ? i`<p class="sub">${s}</p>` : p}
514
544
  </div>
515
- ${i ? l`
545
+ ${n ? i`
516
546
  <nav class="sectionnav" aria-label="${T(e.sport)} section">
517
547
  <div class="navrow">
518
548
  <slot name="nav">
519
- ${me(e.sport, r, e.hrefs).map((d) => l`<a href=${d.href}
520
- aria-current=${o && x(d.href) === o ? "page" : p}>${d.label}</a>`)}
549
+ ${ue(e.sport, r, e.hrefs).map((h) => i`<a href=${h.href}
550
+ aria-current=${o && x(h.href) === o ? "page" : p}>${h.label}</a>`)}
521
551
  </slot>
522
552
  </div>
523
553
  </nav>` : p}
524
554
  </div>
525
555
  `;
526
556
  }
527
- const I = (a, e) => {
557
+ const S = (a, e) => {
528
558
  const t = a.teamsById[e];
529
559
  return t ? a.schoolsById[t.schoolId] : null;
530
- }, S = (a, e) => I(a, e)?.name || "TBD", _ = (a, e) => I(a, e)?.abbr || "TBD";
560
+ }, I = (a, e) => S(a, e)?.name || "TBD", A = (a, e) => S(a, e)?.abbr || "TBD";
531
561
  function C(a, e = 26) {
532
562
  if (!a) return p;
533
- const t = P(a, e);
563
+ const t = _(a, e);
534
564
  if (t)
535
- return l`<img class="swatch logo" aria-hidden="true" alt="" loading="lazy"
565
+ return i`<img class="swatch logo" aria-hidden="true" alt="" loading="lazy"
536
566
  src=${t} style="width:${e}px;height:${e}px" />`;
537
- const s = a.colorPrimary || "#030711", r = B(s);
538
- return l`<span class="swatch" aria-hidden="true"
567
+ const s = a.colorPrimary || "#030711", r = E(s);
568
+ return i`<span class="swatch" aria-hidden="true"
539
569
  style="width:${e}px;height:${e}px;background:${s};color:${r};font-size:${Math.max(8, e * 0.28)}px"
540
- >${M(a)}</span>`;
570
+ >${G(a)}</span>`;
541
571
  }
542
- function q(a, e, t) {
543
- const s = ee(a.rankings, a.teamsById, e, a.sport, t);
544
- return s ? l`<span class="rankbadge">#${s}</span>` : p;
572
+ function K(a, e, t) {
573
+ const s = V(a.rankings, a.teamsById, e, a.sport, t);
574
+ return s ? i`<span class="rankbadge">#${s}</span>` : p;
545
575
  }
546
- function H(a, e, t) {
547
- const s = I(a, e);
548
- return s ? l`${q(a, e, t)}<a href=${u(a.hrefs.school, { id: s.id })}>${s.name}</a>` : l`<span class="mut">TBD</span>`;
576
+ function M(a, e, t) {
577
+ const s = S(a, e);
578
+ return s ? i`${K(a, e, t)}<a href=${u(a.hrefs.school, { id: s.id })}>${s.name}</a>` : i`<span class="mut">TBD</span>`;
549
579
  }
550
- function V(a, e, t = 5) {
580
+ function Q(a, e, t = 5) {
551
581
  const s = a.records[e];
552
- if (!s || !s.results.length) return l`<span class="mut">·</span>`;
582
+ if (!s || !s.results.length) return i`<span class="mut">·</span>`;
553
583
  const r = s.results.slice(-1 * t);
554
- return l`<span class="dots" role="img" aria-label="last ${r.length} results">
555
- ${r.map((o) => l`<a class="dot ${o.mark}"
556
- title="${o.mark} ${o.my}-${o.their} vs ${S(a, o.opp)}"
584
+ return i`<span class="dots" role="img" aria-label="last ${r.length} results">
585
+ ${r.map((o) => i`<a class="dot ${o.mark}"
586
+ title="${o.mark} ${o.my}-${o.their} vs ${I(a, o.opp)}"
557
587
  href=${u(a.hrefs.game, { sport: a.sport, id: o.gameId })}>${o.mark}</a>`)}
558
588
  </span>`;
559
589
  }
590
+ function B(a, e) {
591
+ return a.querySelector(':scope > [slot="rail"]') ? i`<div class="view withrail">
592
+ <div class="viewmain">${e}</div>
593
+ <aside class="viewrail"><slot name="rail"></slot></aside>
594
+ </div>` : i`<div class="view">${e}</div>`;
595
+ }
596
+ function P(a) {
597
+ if (!a.promoImage) return p;
598
+ const e = i`<img src=${a.promoImage} alt=${a.promoAlt || "Sponsor"}>`;
599
+ return i`<div class="promo">${a.promoHref ? i`<a href=${a.promoHref} target="_blank" rel="sponsored noopener">${e}</a>` : e}</div>`;
600
+ }
560
601
  function R(a) {
561
- const e = ce(a);
562
- return l`<span class="pill ${e.kind}">${e.label}</span>`;
602
+ const e = me(a);
603
+ return i`<span class="pill ${e.kind}">${e.label}</span>`;
563
604
  }
564
- function te(a, e, t) {
565
- if (!e) return l`<span class="mut">·</span>`;
605
+ function re(a, e, t) {
606
+ if (!e) return i`<span class="mut">·</span>`;
566
607
  const s = e.homeTeamId === t ? e.awayTeamId : e.homeTeamId, r = e.homeTeamId === t ? "vs" : "at";
567
- return l`${e.state === "live" ? l`<span class="pill live">Live</span> ` : l`${b(e.date, { month: "numeric", day: "numeric" })} `}${r} ${_(a, s)}`;
608
+ return i`${e.state === "live" ? i`<span class="pill live">Live</span> ` : i`${$(e.date, { month: "numeric", day: "numeric" })} `}${r} ${A(a, s)}`;
568
609
  }
569
- class ke extends $ {
610
+ class Se extends y {
570
611
  static styles = F;
571
612
  static properties = {
572
- ...$.properties,
613
+ ...y.properties,
573
614
  sport: { type: String },
574
615
  season: { type: String },
575
616
  date: { type: String }
576
617
  };
577
618
  constructor() {
578
- super(), this.sport = "football", this.season = "", this.date = "";
619
+ super(), this.sport = "football", this.season = "", this.date = "", this._datePinned = !1;
579
620
  }
580
621
  connectedCallback() {
581
622
  if (super.connectedCallback(), !this.date) {
582
623
  const e = new URLSearchParams(globalThis.location?.search || "").get("date");
583
- this.date = e || U();
624
+ e && (this.date = e);
584
625
  }
626
+ this._datePinned = !!this.date;
585
627
  }
586
628
  async fetchData(e) {
587
- const t = this.season || E(), [s, r, o, n, i] = await Promise.all([
629
+ const t = this.season || N(), [s, r, o, c, n] = await Promise.all([
588
630
  e.listSchools(),
589
631
  e.listTeams({ sport: this.sport }),
590
632
  e.listConferences(),
591
633
  e.listGames({ sport: this.sport, season: t }),
592
634
  e.listRankings({ sport: this.sport })
593
635
  ]);
594
- return {
636
+ return this._datePinned || (this.date = de(c.items.map((h) => h.date)), this._datePinned = !0), {
595
637
  season: t,
596
638
  schools: s.items,
597
639
  teams: r.items,
598
640
  conferences: o.items,
599
- games: n.items,
600
- rankings: i.items
641
+ games: c.items,
642
+ rankings: n.items
601
643
  };
602
644
  }
603
645
  get ctx() {
@@ -611,24 +653,30 @@ class ke extends $ {
611
653
  }, this._ctxData = this.data), this._ctx;
612
654
  }
613
655
  renderView() {
614
- const e = this.ctx, t = v(this.data.conferences), s = [...new Set(this.data.games.map((n) => n.date).filter(Boolean))].sort(), r = this.data.games.filter((n) => n.date === this.date).sort((n, i) => (n.state === "live" ? -1 : 1) - (i.state === "live" ? -1 : 1)), o = /* @__PURE__ */ new Map();
615
- return r.forEach((n) => {
616
- const i = n.gameType === "conference" && n.conferenceId ? t[n.conferenceId]?.name || "Conference" : n.gameType === "playoff" ? "Playoffs" : n.gameType === "scrimmage" ? "Scrimmages" : "Nonconference";
617
- o.has(i) || o.set(i, []), o.get(i).push(n);
618
- }), l`
619
- ${W(this, e, {
620
- title: l`${T(this.sport)} scores &amp; schedules`,
621
- sub: l`${b(this.date, { weekday: "long", month: "long", day: "numeric", year: "numeric" })} · ${r.length} games`,
656
+ const e = this.ctx, t = v(this.data.conferences), s = [...new Set(this.data.games.map((l) => l.date).filter(Boolean))].sort(), r = Number.MAX_SAFE_INTEGER, o = (l) => {
657
+ const d = [l.awayTeamId, l.homeTeamId].map((m) => V(e.rankings, e.teamsById, m, this.sport, l.date)).filter(Boolean);
658
+ return d.length ? Math.min(...d) : r;
659
+ }, c = this.data.games.filter((l) => l.date === this.date), n = new Map(c.map((l) => [l, o(l)]));
660
+ c.sort((l, d) => (l.state === "live" ? 0 : 1) - (d.state === "live" ? 0 : 1) || n.get(l) - n.get(d));
661
+ const h = /* @__PURE__ */ new Map();
662
+ return c.forEach((l) => {
663
+ const d = l.gameType === "conference" && l.conferenceId ? t[l.conferenceId]?.name || "Conference" : l.gameType === "playoff" ? "Playoffs" : l.gameType === "scrimmage" ? "Scrimmages" : "Nonconference";
664
+ h.has(d) || h.set(d, []), h.get(d).push(l);
665
+ }), i`
666
+ ${Y(this, e, {
667
+ title: i`${T(this.sport)} scores &amp; schedules`,
668
+ sub: i`${$(this.date, { weekday: "long", month: "long", day: "numeric", year: "numeric" })} · ${c.length} games`,
622
669
  teams: this.data.teams
623
670
  })}
624
- <div class="view">
671
+ ${B(this, i`
672
+ ${P(this)}
625
673
  <div class="toolbar">
626
674
  <label class="asof" for="datesel">Date</label>
627
- <select id="datesel" @change=${(n) => {
628
- this.date = n.target.value;
675
+ <select id="datesel" @change=${(l) => {
676
+ this.date = l.target.value;
629
677
  }}>
630
- ${s.map((n) => l`<option value=${n} ?selected=${n === this.date}>
631
- ${b(n, { weekday: "short", month: "short", day: "numeric" })}${n === U() ? " · today" : ""}
678
+ ${(s.includes(this.date) ? s : [...s, this.date].sort()).map((l) => i`<option value=${l} ?selected=${l === this.date}>
679
+ ${$(l, { weekday: "short", month: "short", day: "numeric" })}${l === j() ? " · today" : ""}
632
680
  </option>`)}
633
681
  </select>
634
682
  <button class="chip" ?disabled=${s.indexOf(this.date) <= 0}
@@ -642,35 +690,35 @@ class ke extends $ {
642
690
  <span class="spacer"></span>
643
691
  <span class="asof">Live games first · report a score to see it update here</span>
644
692
  </div>
645
- ${r.length ? p : l`<p class="empty">No ${this.sport} games on this date.</p>`}
646
- ${[...o.entries()].map(([n, i]) => l`
647
- <div class="section-title">${n}</div>
693
+ ${c.length ? p : i`<p class="empty">No ${this.sport} games on this date.</p>`}
694
+ ${[...h.entries()].map(([l, d]) => i`
695
+ <div class="section-title">${l}</div>
648
696
  <div class="card"><ul class="gamelist">
649
- ${i.map((d) => this.renderGame(e, d))}
697
+ ${d.map((m) => this.renderGame(e, m))}
650
698
  </ul></div>
651
699
  `)}
652
- </div>
700
+ `)}
653
701
  `;
654
702
  }
655
703
  renderGame(e, t) {
656
- const s = t.state === "final" || t.state === "live" ? `${t.awayScore}-${t.homeScore}` : A(t.time);
657
- return l`
704
+ const s = t.state === "final" || t.state === "live" ? `${t.awayScore}-${t.homeScore}` : L(t.time);
705
+ return i`
658
706
  <li>
659
707
  ${R(t)}
660
- <span class="opp">${H(e, t.awayTeamId, t.date)} at ${H(e, t.homeTeamId, t.date)}</span>
708
+ <span class="opp">${M(e, t.awayTeamId, t.date)} at ${M(e, t.homeTeamId, t.date)}</span>
661
709
  <span class="res" style="width:auto">${s}</span>
662
710
  <span class="where">${t.venue || ""}</span>
663
- ${t.broadcast ? l`<span class="pill class">${t.broadcast}</span>` : p}
711
+ ${t.broadcast ? i`<span class="pill class">${t.broadcast}</span>` : p}
664
712
  <a class="box" href=${u(e.hrefs.game, { sport: this.sport, id: t.id })}>Box score →</a>
665
713
  </li>
666
714
  `;
667
715
  }
668
716
  }
669
- globalThis?.customElements && !globalThis.customElements.get("hsot-scores") && globalThis.customElements.define("hsot-scores", ke);
670
- class Te extends $ {
717
+ globalThis?.customElements && !globalThis.customElements.get("hsot-scores") && globalThis.customElements.define("hsot-scores", Se);
718
+ class Ce extends y {
671
719
  static styles = F;
672
720
  static properties = {
673
- ...$.properties,
721
+ ...y.properties,
674
722
  sport: { type: String },
675
723
  season: { type: String },
676
724
  classFilter: { state: !0 },
@@ -680,7 +728,7 @@ class Te extends $ {
680
728
  super(), this.sport = "football", this.season = "", this.classFilter = "All", this.query = "";
681
729
  }
682
730
  async fetchData(e) {
683
- const t = this.season || E(), [s, r, o, n, i] = await Promise.all([
731
+ const t = this.season || N(), [s, r, o, c, n] = await Promise.all([
684
732
  e.listConferences({ active: !0 }),
685
733
  e.listSchools(),
686
734
  e.listTeams({ sport: this.sport }),
@@ -692,8 +740,8 @@ class Te extends $ {
692
740
  conferences: s.items,
693
741
  schools: r.items,
694
742
  teams: o.items,
695
- games: n.items,
696
- rankings: i.items
743
+ games: c.items,
744
+ rankings: n.items
697
745
  };
698
746
  }
699
747
  get ctx() {
@@ -708,16 +756,17 @@ class Te extends $ {
708
756
  }
709
757
  renderView() {
710
758
  const e = this.ctx, t = ["All", ...new Set(this.data.conferences.flatMap((r) => r.classifications || []))].slice(0, 9), s = this.data.conferences.filter((r) => r.active !== !1).filter((r) => this.classFilter === "All" || (r.classifications || []).includes(this.classFilter));
711
- return l`
712
- ${W(this, e, {
713
- title: l`${T(this.sport)} standings`,
714
- sub: l`${this.data.season} season · every conference, computed live from reported results`,
759
+ return i`
760
+ ${Y(this, e, {
761
+ title: i`${T(this.sport)} standings`,
762
+ sub: i`${this.data.season} season · every conference, computed live from reported results`,
715
763
  teams: this.data.teams
716
764
  })}
717
- <div class="view">
765
+ ${B(this, i`
766
+ ${P(this)}
718
767
  <div class="toolbar">
719
768
  <div role="group" aria-label="Classification filter">
720
- ${t.map((r) => l`<button class="chip ${this.classFilter === r ? "on" : ""}"
769
+ ${t.map((r) => i`<button class="chip ${this.classFilter === r ? "on" : ""}"
721
770
  @click=${() => {
722
771
  this.classFilter = r;
723
772
  }}>${r}</button>`)}
@@ -727,21 +776,21 @@ class Te extends $ {
727
776
  this.query = r.target.value;
728
777
  }}>
729
778
  <span class="spacer"></span>
730
- <span class="asof">Records through ${b(U(), { month: "long", day: "numeric" })} · conference games count toward both records · scrimmages toward neither</span>
779
+ <span class="asof">Records through ${$(j(), { month: "long", day: "numeric" })} · conference games count toward both records · scrimmages toward neither</span>
731
780
  </div>
732
781
  ${s.map((r) => this.renderConference(e, r))}
733
- </div>
782
+ `)}
734
783
  `;
735
784
  }
736
785
  renderConference(e, t) {
737
- const s = this.data.teams.filter((n) => n.conferenceId === t.id);
786
+ const s = this.data.teams.filter((c) => c.conferenceId === t.id);
738
787
  if (!s.length) return p;
739
- const r = this.query.trim().toLowerCase(), o = J(s, e.records);
740
- return l`
788
+ const r = this.query.trim().toLowerCase(), o = ae(s, e.records);
789
+ return i`
741
790
  <div class="card">
742
791
  <div class="card-head">
743
792
  <h2>${t.name}</h2>
744
- ${(t.classifications || []).map((n) => l`<span class="pill class">${n}</span>`)}
793
+ ${(t.classifications || []).map((c) => i`<span class="pill class">${c}</span>`)}
745
794
  <span class="meta">${o.length} teams · membership derives from teams</span>
746
795
  </div>
747
796
  <div class="tablewrap"><table class="data">
@@ -751,44 +800,44 @@ class Te extends $ {
751
800
  <th>Streak</th><th>Last 5</th><th>Next</th>
752
801
  </tr></thead>
753
802
  <tbody>
754
- ${o.map((n, i) => this.renderRow(e, n, i, r))}
803
+ ${o.map((c, n) => this.renderRow(e, c, n, r))}
755
804
  </tbody>
756
805
  </table></div>
757
806
  </div>
758
807
  `;
759
808
  }
760
809
  renderRow(e, t, s, r) {
761
- const o = e.schoolsById[t.team.schoolId], n = o?.name || t.team.name || "TBD";
762
- if (r && !n.toLowerCase().includes(r)) return p;
763
- const i = t.rec.pf - t.rec.pa, d = G(this.data.games, t.team.id), h = (t.team.championships || []).map((m) => l`
764
- <span class="pill champ" title="${m.season} ${m.title} champion">★ ${m.season} ${m.title}</span>`), c = () => {
810
+ const o = e.schoolsById[t.team.schoolId], c = o?.name || t.team.name || "TBD";
811
+ if (r && !c.toLowerCase().includes(r)) return p;
812
+ const n = t.rec.pf - t.rec.pa, h = W(this.data.games, t.team.id), l = (t.team.championships || []).map((m) => i`
813
+ <span class="pill champ" title="${m.season} ${m.title} champion">★ ${m.season} ${m.title}</span>`), d = () => {
765
814
  location.href = u(e.hrefs.school, { id: t.team.schoolId });
766
815
  };
767
- return l`
816
+ return i`
768
817
  <tr class="rowlink" @click=${(m) => {
769
- m.target.closest("a") || c();
818
+ m.target.closest("a") || d();
770
819
  }}>
771
820
  <td class="mut">${s + 1}</td>
772
821
  <td class="teamcell">
773
- ${C(o)}${q(e, t.team.id, null)}
774
- <a href=${u(e.hrefs.school, { id: t.team.schoolId })}>${n}</a> ${h}
822
+ ${C(o)}${K(e, t.team.id, null)}
823
+ <a href=${u(e.hrefs.school, { id: t.team.schoolId })}>${c}</a> ${l}
775
824
  </td>
776
825
  <td class="num">${w(t.rec, !0)}</td>
777
- <td class="num">${K(t.confPct)}</td>
826
+ <td class="num">${J(t.confPct)}</td>
778
827
  <td class="num">${w(t.rec)}</td>
779
- <td class="num">${K(t.overallPct)}</td>
828
+ <td class="num">${J(t.overallPct)}</td>
780
829
  <td class="num">${t.rec.pf}</td>
781
830
  <td class="num">${t.rec.pa}</td>
782
- <td class="num" style="color:${i >= 0 ? "var(--hsot-win)" : "var(--hsot-loss)"}">${i > 0 ? "+" : ""}${i}</td>
783
- <td>${L(t.rec.results) || "·"}</td>
784
- <td>${V(e, t.team.id)}</td>
785
- <td>${te(e, d, t.team.id)}</td>
831
+ <td class="num" style="color:${n >= 0 ? "var(--hsot-win)" : "var(--hsot-loss)"}">${n > 0 ? "+" : ""}${n}</td>
832
+ <td>${O(t.rec.results) || "·"}</td>
833
+ <td>${Q(e, t.team.id)}</td>
834
+ <td>${re(e, h, t.team.id)}</td>
786
835
  </tr>
787
836
  `;
788
837
  }
789
838
  }
790
- globalThis?.customElements && !globalThis.customElements.get("hsot-standings") && globalThis.customElements.define("hsot-standings", Te);
791
- const Se = y`
839
+ globalThis?.customElements && !globalThis.customElements.get("hsot-standings") && globalThis.customElements.define("hsot-standings", Ce);
840
+ const De = b`
792
841
  .hero1 {
793
842
  border-radius: var(--hsot-radius-md); color: var(--hsot-white);
794
843
  padding: 1.3rem 1.4rem; display: flex; align-items: center; gap: 1.2rem;
@@ -805,10 +854,10 @@ const Se = y`
805
854
  .delta.new { background: var(--hsot-straw); color: #6b5900; border-radius: var(--hsot-radius-xs); padding: 0.1rem 0.3rem; font-size: 0.7rem; }
806
855
  .sparkline { vertical-align: middle; }
807
856
  `;
808
- class Ie extends $ {
809
- static styles = [...F, Se];
857
+ class Fe extends y {
858
+ static styles = [...F, De];
810
859
  static properties = {
811
- ...$.properties,
860
+ ...y.properties,
812
861
  sport: { type: String },
813
862
  gender: { type: String },
814
863
  season: { type: String },
@@ -823,20 +872,20 @@ class Ie extends $ {
823
872
  e && (this.pollDate = e);
824
873
  }
825
874
  async fetchData(e) {
826
- const t = this.season || E(), [s, r, o, n, i] = await Promise.all([
875
+ const t = this.season || N(), [s, r, o, c, n] = await Promise.all([
827
876
  e.listRankings({ sport: this.sport, ...this.gender ? { gender: this.gender } : {} }),
828
877
  e.listSchools(),
829
878
  e.listTeams({ sport: this.sport }),
830
879
  e.listConferences(),
831
880
  e.listGames({ sport: this.sport, season: t })
832
- ]), d = s.items.filter((h) => !this.gender || !h.gender || h.gender === this.gender).sort((h, c) => c.effectiveDate.localeCompare(h.effectiveDate));
881
+ ]), h = s.items.filter((l) => !this.gender || !l.gender || l.gender === this.gender).sort((l, d) => d.effectiveDate.localeCompare(l.effectiveDate));
833
882
  return {
834
883
  season: t,
835
- polls: d,
884
+ polls: h,
836
885
  schools: r.items,
837
886
  teams: o.items,
838
- conferences: n.items,
839
- games: i.items
887
+ conferences: c.items,
888
+ games: n.items
840
889
  };
841
890
  }
842
891
  get ctx() {
@@ -850,45 +899,46 @@ class Ie extends $ {
850
899
  }, this._ctxData = this.data), this._ctx;
851
900
  }
852
901
  sparkline(e, t, s) {
853
- const i = t.map((m, f) => {
902
+ const n = t.map((m, f) => {
854
903
  const g = (m.teamIds || []).indexOf(e);
855
904
  if (g === -1) return null;
856
- const k = t.length === 1 ? 96 / 2 : f / (t.length - 1) * 90 + 3, N = 3 + g / 24 * 20;
857
- return { x: k, y: N };
858
- }), d = [];
859
- let h = [];
860
- if (i.forEach((m) => {
861
- m ? h.push(m) : h.length && (d.push(h), h = []);
862
- }), h.length && d.push(h), !d.length) return p;
863
- const c = i[s];
864
- return l`<svg class="sparkline" width=${96} height=${26} viewBox="0 0 ${96} ${26}" role="img" aria-label="rank history">
865
- ${d.map((m) => Y`<polyline fill="none" stroke="var(--hsot-red)" stroke-width="2"
905
+ const k = t.length === 1 ? 96 / 2 : f / (t.length - 1) * 90 + 3, H = 3 + g / 24 * 20;
906
+ return { x: k, y: H };
907
+ }), h = [];
908
+ let l = [];
909
+ if (n.forEach((m) => {
910
+ m ? l.push(m) : l.length && (h.push(l), l = []);
911
+ }), l.length && h.push(l), !h.length) return p;
912
+ const d = n[s];
913
+ return i`<svg class="sparkline" width=${96} height=${26} viewBox="0 0 ${96} ${26}" role="img" aria-label="rank history">
914
+ ${h.map((m) => X`<polyline fill="none" stroke="var(--hsot-red)" stroke-width="2"
866
915
  points=${m.map((f) => `${f.x.toFixed(1)},${f.y.toFixed(1)}`).join(" ")}></polyline>`)}
867
- ${c ? Y`<circle cx=${c.x.toFixed(1)} cy=${c.y.toFixed(1)} r="3" fill="var(--hsot-black)"></circle>` : p}
916
+ ${d ? X`<circle cx=${d.x.toFixed(1)} cy=${d.y.toFixed(1)} r="3" fill="var(--hsot-black)"></circle>` : p}
868
917
  </svg>`;
869
918
  }
870
919
  movement(e, t, s) {
871
- const r = we(e, t, s);
872
- return r.kind === "up" ? l`<span class="delta up">▲ ${r.delta}</span>` : r.kind === "down" ? l`<span class="delta down">▼ ${r.delta}</span>` : r.kind === "new" ? l`<span class="delta new">NEW</span>` : r.kind === "same" ? l`<span class="delta same">—</span>` : l`<span class="delta same">·</span>`;
920
+ const r = Te(e, t, s);
921
+ return r.kind === "up" ? i`<span class="delta up">▲ ${r.delta}</span>` : r.kind === "down" ? i`<span class="delta down">▼ ${r.delta}</span>` : r.kind === "new" ? i`<span class="delta new">NEW</span>` : r.kind === "same" ? i`<span class="delta same">—</span>` : i`<span class="delta same">·</span>`;
873
922
  }
874
923
  renderView() {
875
924
  const e = this.ctx, t = this.data.polls;
876
- if (!t.length) return l`<div class="view"><p class="empty">No ${this.sport} polls published yet this season.</p></div>`;
877
- const s = Math.max(0, t.findIndex((m) => m.effectiveDate === this.pollDate)), r = t[s] || t[0], o = t[s + 1] || null, n = t.slice().reverse(), i = n.indexOf(r), d = v(this.data.conferences), h = (r.teamIds || [])[0], c = h ? I(e, h) : null;
878
- return l`
879
- ${W(this, e, {
880
- title: l`${T(this.sport)} Top 25`,
881
- sub: l`The HighSchoolOT poll · updated weekly · ${t.length} polls this season`,
925
+ if (!t.length) return i`<div class="view"><p class="empty">No ${this.sport} polls published yet this season.</p></div>`;
926
+ const s = Math.max(0, t.findIndex((m) => m.effectiveDate === this.pollDate)), r = t[s] || t[0], o = t[s + 1] || null, c = t.slice().reverse(), n = c.indexOf(r), h = v(this.data.conferences), l = (r.teamIds || [])[0], d = l ? S(e, l) : null;
927
+ return i`
928
+ ${Y(this, e, {
929
+ title: i`${T(this.sport)} Top 25`,
930
+ sub: i`The HighSchoolOT poll · updated weekly · ${t.length} polls this season`,
882
931
  teams: this.data.teams
883
932
  })}
884
- <div class="view">
933
+ ${B(this, i`
934
+ ${P(this)}
885
935
  <div class="toolbar">
886
936
  <label class="asof" for="pollsel">Poll of</label>
887
937
  <select id="pollsel" @change=${(m) => {
888
938
  this.pollDate = m.target.value;
889
939
  }}>
890
- ${t.map((m, f) => l`<option value=${m.effectiveDate} ?selected=${m === r}>
891
- ${b(m.effectiveDate, { month: "long", day: "numeric", year: "numeric" })}${f === 0 ? " · current" : ""}
940
+ ${t.map((m, f) => i`<option value=${m.effectiveDate} ?selected=${m === r}>
941
+ ${$(m.effectiveDate, { month: "long", day: "numeric", year: "numeric" })}${f === 0 ? " · current" : ""}
892
942
  </option>`)}
893
943
  </select>
894
944
  <button class="chip" ?disabled=${s >= t.length - 1}
@@ -902,65 +952,65 @@ class Ie extends $ {
902
952
  <span class="spacer"></span>
903
953
  <span class="asof">Movement vs. the previous poll · sparkline = season rank history</span>
904
954
  </div>
905
- ${c ? this.renderHero(e, r, o, h, c, d) : p}
955
+ ${d ? this.renderHero(e, r, o, l, d, h) : p}
906
956
  <div class="card"><div class="tablewrap"><table class="data">
907
957
  <thead><tr>
908
958
  <th class="num">Rk</th><th>Mvmt</th><th>Team</th><th class="num">Record</th>
909
959
  <th>Conference</th><th>Last result</th><th>Next</th><th>Season</th>
910
960
  </tr></thead>
911
961
  <tbody>
912
- ${(r.teamIds || []).map((m, f) => f === 0 || !m ? p : this.renderRow(e, r, o, n, i, d, m, f + 1))}
962
+ ${(r.teamIds || []).map((m, f) => f === 0 || !m ? p : this.renderRow(e, r, o, c, n, h, m, f + 1))}
913
963
  </tbody>
914
964
  </table></div></div>
915
965
  <p class="note">Ranks elsewhere on the site resolve the poll in effect on the game date, so past box scores keep the ranks they were played under.</p>
916
- </div>
966
+ `)}
917
967
  `;
918
968
  }
919
- renderHero(e, t, s, r, o, n) {
920
- const i = e.records[r], d = X(e.records, r), h = n[e.teamsById[r]?.conferenceId], c = `linear-gradient(120deg, ${o.colorPrimary || "#030711"} 0%, var(--hsot-black) 85%)`;
921
- return l`
922
- <div class="hero1" style="background:${c}">
969
+ renderHero(e, t, s, r, o, c) {
970
+ const n = e.records[r], h = ee(e.records, r), l = c[e.teamsById[r]?.conferenceId], d = `linear-gradient(120deg, ${o.colorPrimary || "#030711"} 0%, var(--hsot-black) 85%)`;
971
+ return i`
972
+ <div class="hero1" style="background:${d}">
923
973
  <div class="bigrank">#1</div>
924
974
  ${C(o, 64)}
925
975
  <div>
926
976
  <h2><a href=${u(e.hrefs.school, { id: o.id })}>${o.name} ${o.mascot || ""}</a></h2>
927
977
  <div class="facts">
928
- ${w(i)} overall${h ? l` · ${w(i, !0)} ${h.name}` : p}
929
- · streak ${L(i?.results) || "·"}
930
- ${d ? l` · last: ${d.mark} ${d.my}-${d.their} vs ${_(e, d.opp)}` : p}
978
+ ${w(n)} overall${l ? i` · ${w(n, !0)} ${l.name}` : p}
979
+ · streak ${O(n?.results) || "·"}
980
+ ${h ? i` · last: ${h.mark} ${h.my}-${h.their} vs ${A(e, h.opp)}` : p}
931
981
  &nbsp;${this.movement(t, s, r)}
932
982
  </div>
933
983
  </div>
934
984
  </div>
935
985
  `;
936
986
  }
937
- renderRow(e, t, s, r, o, n, i, d) {
938
- const h = I(e, i);
939
- if (!h) return p;
940
- const c = e.records[i], m = X(e.records, i), f = G(this.data.games, i), g = n[e.teamsById[i]?.conferenceId], k = () => {
941
- location.href = u(e.hrefs.school, { id: h.id });
987
+ renderRow(e, t, s, r, o, c, n, h) {
988
+ const l = S(e, n);
989
+ if (!l) return p;
990
+ const d = e.records[n], m = ee(e.records, n), f = W(this.data.games, n), g = c[e.teamsById[n]?.conferenceId], k = () => {
991
+ location.href = u(e.hrefs.school, { id: l.id });
942
992
  };
943
- return l`
944
- <tr class="rowlink" @click=${(N) => {
945
- N.target.closest("a") || k();
993
+ return i`
994
+ <tr class="rowlink" @click=${(H) => {
995
+ H.target.closest("a") || k();
946
996
  }}>
947
- <td class="num" style="font-weight:700">${d}</td>
948
- <td>${this.movement(t, s, i)}</td>
949
- <td class="teamcell">${C(h)}<a href=${u(e.hrefs.school, { id: h.id })}>${h.name}</a>
950
- <span class="mut" style="font-size:0.78rem">${h.mascot || ""}</span></td>
951
- <td class="num">${w(c)}</td>
997
+ <td class="num" style="font-weight:700">${h}</td>
998
+ <td>${this.movement(t, s, n)}</td>
999
+ <td class="teamcell">${C(l)}<a href=${u(e.hrefs.school, { id: l.id })}>${l.name}</a>
1000
+ <span class="mut" style="font-size:0.78rem">${l.mascot || ""}</span></td>
1001
+ <td class="num">${w(d)}</td>
952
1002
  <td class="mut">${g?.name || "Independent"}</td>
953
- <td>${m ? l`<a class="box" style="text-decoration:none" href=${u(e.hrefs.game, { sport: this.sport, id: m.gameId })}>
1003
+ <td>${m ? i`<a class="box" style="text-decoration:none" href=${u(e.hrefs.game, { sport: this.sport, id: m.gameId })}>
954
1004
  <b style="color:${m.mark === "W" ? "var(--hsot-win)" : m.mark === "L" ? "var(--hsot-loss)" : "var(--hsot-tie)"}">${m.mark}</b>
955
- ${m.my}-${m.their} vs ${_(e, m.opp)}</a>` : l`<span class="mut">·</span>`}</td>
956
- <td>${te(e, f, i)}</td>
957
- <td>${this.sparkline(i, r, o)}</td>
1005
+ ${m.my}-${m.their} vs ${A(e, m.opp)}</a>` : i`<span class="mut">·</span>`}</td>
1006
+ <td>${re(e, f, n)}</td>
1007
+ <td>${this.sparkline(n, r, o)}</td>
958
1008
  </tr>
959
1009
  `;
960
1010
  }
961
1011
  }
962
- globalThis?.customElements && !globalThis.customElements.get("hsot-rankings") && globalThis.customElements.define("hsot-rankings", Ie);
963
- const Ce = y`
1012
+ globalThis?.customElements && !globalThis.customElements.get("hsot-rankings") && globalThis.customElements.define("hsot-rankings", Fe);
1013
+ const ze = b`
964
1014
  .schoolhero { color: var(--hsot-white); padding: 1.6rem 1.25rem 1.3rem; }
965
1015
  .schoolhero .inner { max-width: 1366px; margin: 0 auto; display: flex; gap: 1.2rem; align-items: center; flex-wrap: wrap; }
966
1016
  .schoolhero .crest {
@@ -985,10 +1035,10 @@ const Ce = y`
985
1035
  .cols { display: grid; grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); gap: 1.25rem; }
986
1036
  @media (max-width: 900px) { .cols { grid-template-columns: 1fr; } .schoolhero h1 { font-size: 1.9rem; } }
987
1037
  `;
988
- class De extends $ {
989
- static styles = [...F, Ce];
1038
+ class Be extends y {
1039
+ static styles = [...F, ze];
990
1040
  static properties = {
991
- ...$.properties,
1041
+ ...y.properties,
992
1042
  schoolId: { type: String, attribute: "school-id" },
993
1043
  sport: { type: String },
994
1044
  season: { type: String },
@@ -1003,26 +1053,26 @@ class De extends $ {
1003
1053
  e && !this.sport && (this.sport = e);
1004
1054
  }
1005
1055
  async fetchData(e) {
1006
- const t = this.season || E(), s = await e.getSchool(this.schoolId), o = (await e.listTeams({ schoolId: this.schoolId })).items, n = o.find((k) => k.sport === (this.sport || "football")) || o[0] || null, [i, d, h, c, m, f, g] = await Promise.all([
1007
- n ? e.listGames({ sport: n.sport, season: t }) : Promise.resolve({ items: [] }),
1008
- n ? e.listTeams({ sport: n.sport }) : Promise.resolve({ items: [] }),
1056
+ const t = this.season || N(), s = await e.getSchool(this.schoolId), o = (await e.listTeams({ schoolId: this.schoolId })).items, c = o.find((k) => k.sport === (this.sport || "football")) || o[0] || null, [n, h, l, d, m, f, g] = await Promise.all([
1057
+ c ? e.listGames({ sport: c.sport, season: t }) : Promise.resolve({ items: [] }),
1058
+ c ? e.listTeams({ sport: c.sport }) : Promise.resolve({ items: [] }),
1009
1059
  e.listSchools(),
1010
1060
  e.listConferences(),
1011
- n ? e.listRankings({ sport: n.sport }) : Promise.resolve({ items: [] }),
1012
- n ? e.listRosters({ teamId: n.id }) : Promise.resolve({ items: [] }),
1061
+ c ? e.listRankings({ sport: c.sport }) : Promise.resolve({ items: [] }),
1062
+ c ? e.listRosters({ teamId: c.id }) : Promise.resolve({ items: [] }),
1013
1063
  // teamId is the public surface's one players filter (roster
1014
1064
  // membership) — never fetch the whole collection.
1015
- n ? e.listPlayers({ teamId: n.id }) : Promise.resolve({ items: [] })
1065
+ c ? e.listPlayers({ teamId: c.id }) : Promise.resolve({ items: [] })
1016
1066
  ]);
1017
1067
  return {
1018
1068
  season: t,
1019
1069
  school: s,
1020
1070
  teams: o,
1021
- active: n,
1022
- games: i.items,
1023
- allTeams: d.items,
1024
- schools: h.items,
1025
- conferences: c.items,
1071
+ active: c,
1072
+ games: n.items,
1073
+ allTeams: h.items,
1074
+ schools: l.items,
1075
+ conferences: d.items,
1026
1076
  rankings: m.items,
1027
1077
  roster: f.items.find((k) => k.season === t) || null,
1028
1078
  players: g.items
@@ -1043,61 +1093,62 @@ class De extends $ {
1043
1093
  }
1044
1094
  renderView() {
1045
1095
  const { school: e, teams: t, active: s, season: r } = this.data;
1046
- if (!e) return l`<div class="view"><p class="empty">School not found.</p></div>`;
1047
- const o = this.ctx, n = B(e.colorPrimary || "#030711"), i = (e.adm || [])[0], d = v(this.data.conferences), h = s ? d[s.conferenceId] : null;
1048
- return l`
1049
- <div class="schoolhero" style="background:linear-gradient(115deg, ${e.colorPrimary || "#030711"} 0%, ${e.colorPrimary || "#030711"} 55%, var(--hsot-black) 100%);color:${n}">
1096
+ if (!e) return i`<div class="view"><p class="empty">School not found.</p></div>`;
1097
+ const o = this.ctx, c = E(e.colorPrimary || "#030711"), n = (e.adm || [])[0], h = v(this.data.conferences), l = s ? h[s.conferenceId] : null;
1098
+ return i`
1099
+ <div class="schoolhero" style="background:linear-gradient(115deg, ${e.colorPrimary || "#030711"} 0%, ${e.colorPrimary || "#030711"} 55%, var(--hsot-black) 100%);color:${c}">
1050
1100
  <div class="inner">
1051
- ${P(e, 84) ? l`<img class="crest logo" alt="" loading="lazy" src=${P(e, 84)} />` : l`<div class="crest" style="background:${e.colorSecondary || "#7C7C7C"};color:${B(e.colorSecondary || "#7C7C7C")}">${M(e)}</div>`}
1101
+ ${_(e, 84) ? i`<img class="crest logo" alt="" loading="lazy" src=${_(e, 84)} />` : i`<div class="crest" style="background:${e.colorSecondary || "#7C7C7C"};color:${E(e.colorSecondary || "#7C7C7C")}">${G(e)}</div>`}
1052
1102
  <div style="min-width:260px">
1053
1103
  <h1>${e.name} <span class="mascot">${e.mascot || ""}</span></h1>
1054
1104
  <div class="facts">
1055
- ${e.location ? l`<span><b>Location</b>${e.location}${e.county ? l` · ${e.county} County` : p}</span>` : p}
1056
- ${e.association ? l`<span><b>League</b>${e.association}${e.classification ? l` · ${e.classification}` : p}</span>` : p}
1057
- ${h ? l`<span><b>Conference</b>${h.name}</span>` : p}
1058
- ${i ? l`<span><b>Enrollment</b>${i.value.toLocaleString()} (${i.season} ADM)</span>` : p}
1059
- ${e.openingYear ? l`<span><b>Opened</b>${e.openingYear}</span>` : p}
1060
- ${e.areaCode ? l`<span><b>Area</b>${e.areaCode}</span>` : p}
1061
- ${e.tagSlug ? l`<span><b>Tag</b>#${e.tagSlug}</span>` : p}
1105
+ ${e.location ? i`<span><b>Location</b>${e.location}${e.county ? i` · ${e.county} County` : p}</span>` : p}
1106
+ ${e.association ? i`<span><b>League</b>${e.association}${e.classification ? i` · ${e.classification}` : p}</span>` : p}
1107
+ ${l ? i`<span><b>Conference</b>${l.name}</span>` : p}
1108
+ ${n ? i`<span><b>Enrollment</b>${n.value.toLocaleString()} (${n.season} ADM)</span>` : p}
1109
+ ${e.openingYear ? i`<span><b>Opened</b>${e.openingYear}</span>` : p}
1110
+ ${e.areaCode ? i`<span><b>Area</b>${e.areaCode}</span>` : p}
1111
+ ${e.tagSlug ? i`<span><b>Tag</b>#${e.tagSlug}</span>` : p}
1062
1112
  </div>
1063
1113
  </div>
1064
1114
  </div>
1065
1115
  </div>
1066
1116
  <div class="band">
1067
1117
  <nav class="tabs" aria-label="Teams">
1068
- ${t.map((c) => c.id === s?.id ? l`<a class="on" href="#" @click=${(m) => m.preventDefault()}>${c.name}</a>` : l`<a href="#" @click=${(m) => {
1069
- m.preventDefault(), this.switchSport(c.sport);
1070
- }}>${c.name}</a>`)}
1118
+ ${t.map((d) => d.id === s?.id ? i`<a class="on" href="#" @click=${(m) => m.preventDefault()}>${d.name}</a>` : i`<a href="#" @click=${(m) => {
1119
+ m.preventDefault(), this.switchSport(d.sport);
1120
+ }}>${d.name}</a>`)}
1071
1121
  </nav>
1072
1122
  </div>
1073
- <div class="view">
1074
- ${s ? this.renderTeam(o, s, h, r) : l`<p class="empty">No teams recorded for this school yet.</p>`}
1075
- </div>
1123
+ ${B(this, i`
1124
+ ${P(this)}
1125
+ ${s ? this.renderTeam(o, s, l, r) : i`<p class="empty">No teams recorded for this school yet.</p>`}
1126
+ `)}
1076
1127
  `;
1077
1128
  }
1078
1129
  renderTeam(e, t, s, r) {
1079
- const o = e.records[t.id] || { w: 0, l: 0, t: 0, cw: 0, cl: 0, ct: 0, pf: 0, pa: 0, results: [] }, n = o.w + o.l + o.t, i = s ? this.data.allTeams.filter((m) => m.conferenceId === s.id) : [], d = s ? J(i, e.records).findIndex((m) => m.team.id === t.id) + 1 : 0, h = ee(e.rankings, e.teamsById, t.id, t.sport, null), c = this.data.games.filter((m) => m.homeTeamId === t.id || m.awayTeamId === t.id).sort((m, f) => String(m.date).localeCompare(String(f.date)));
1080
- return l`
1130
+ const o = e.records[t.id] || { w: 0, l: 0, t: 0, cw: 0, cl: 0, ct: 0, pf: 0, pa: 0, results: [] }, c = o.w + o.l + o.t, n = s ? this.data.allTeams.filter((m) => m.conferenceId === s.id) : [], h = s ? ae(n, e.records).findIndex((m) => m.team.id === t.id) + 1 : 0, l = V(e.rankings, e.teamsById, t.id, t.sport, null), d = this.data.games.filter((m) => m.homeTeamId === t.id || m.awayTeamId === t.id).sort((m, f) => String(m.date).localeCompare(String(f.date)));
1131
+ return i`
1081
1132
  <div class="tiles">
1082
- <div class="tile"><div class="k">Overall</div><div class="v">${w(o)}</div><div class="s">${n} games played</div></div>
1133
+ <div class="tile"><div class="k">Overall</div><div class="v">${w(o)}</div><div class="s">${c} games played</div></div>
1083
1134
  <div class="tile"><div class="k">${s?.name || "Conference"}</div><div class="v">${w(o, !0)}</div>
1084
- <div class="s">${d ? `${le(d)} of ${i.length}` : "·"}</div></div>
1085
- <div class="tile"><div class="k">Points</div><div class="v">${n ? (o.pf / n).toFixed(1) : "0.0"}</div>
1086
- <div class="s">scored per game · ${n ? (o.pa / n).toFixed(1) : "0.0"} allowed</div></div>
1087
- <div class="tile"><div class="k">Streak</div><div class="v">${L(o.results) || "·"}</div>
1088
- <div class="s">last 5: ${V(e, t.id)}</div></div>
1089
- <div class="tile"><div class="k">HSOT Top 25</div><div class="v">${h ? `#${h}` : "NR"}</div>
1135
+ <div class="s">${h ? `${he(h)} of ${n.length}` : "·"}</div></div>
1136
+ <div class="tile"><div class="k">Points</div><div class="v">${c ? (o.pf / c).toFixed(1) : "0.0"}</div>
1137
+ <div class="s">scored per game · ${c ? (o.pa / c).toFixed(1) : "0.0"} allowed</div></div>
1138
+ <div class="tile"><div class="k">Streak</div><div class="v">${O(o.results) || "·"}</div>
1139
+ <div class="s">last 5: ${Q(e, t.id)}</div></div>
1140
+ <div class="tile"><div class="k">HSOT Top 25</div><div class="v">${l ? `#${l}` : "NR"}</div>
1090
1141
  <div class="s"><a href=${u(e.hrefs.section, { sport: t.sport, view: "rankings" })}>full poll</a></div></div>
1091
1142
  </div>
1092
- ${(t.championships || []).length ? l`
1143
+ ${(t.championships || []).length ? i`
1093
1144
  <div style="margin:-0.2rem 0 1rem;display:flex;gap:0.4rem;flex-wrap:wrap">
1094
- ${t.championships.map((m) => l`<span class="pill champ">★ ${m.season} ${m.title} champion${m.classification ? ` · ${m.classification}` : ""}${m.region ? ` · ${m.region}` : ""}</span>`)}
1145
+ ${t.championships.map((m) => i`<span class="pill champ">★ ${m.season} ${m.title} champion${m.classification ? ` · ${m.classification}` : ""}${m.region ? ` · ${m.region}` : ""}</span>`)}
1095
1146
  </div>` : p}
1096
1147
  <div class="cols">
1097
1148
  <div>
1098
1149
  <div class="section-title">Schedule &amp; results</div>
1099
1150
  <div class="card">
1100
- ${c.length ? l`<ul class="gamelist">${c.map((m) => this.renderGameRow(e, t, m))}</ul>` : l`<p class="empty">No ${t.sport} games recorded for ${r}.</p>`}
1151
+ ${d.length ? i`<ul class="gamelist">${d.map((m) => this.renderGameRow(e, t, m))}</ul>` : i`<p class="empty">No ${t.sport} games recorded for ${r}.</p>`}
1101
1152
  </div>
1102
1153
  </div>
1103
1154
  <div>
@@ -1108,21 +1159,21 @@ class De extends $ {
1108
1159
  `;
1109
1160
  }
1110
1161
  renderGameRow(e, t, s) {
1111
- const r = s.homeTeamId === t.id, o = r ? s.awayTeamId : s.homeTeamId, n = r ? s.homeScore : s.awayScore, i = r ? s.awayScore : s.homeScore;
1112
- let d = l`<span class="mut">${A(s.time)}</span>`;
1162
+ const r = s.homeTeamId === t.id, o = r ? s.awayTeamId : s.homeTeamId, c = r ? s.homeScore : s.awayScore, n = r ? s.awayScore : s.homeScore;
1163
+ let h = i`<span class="mut">${L(s.time)}</span>`;
1113
1164
  if (s.state === "final") {
1114
- const c = j(s), m = c === "tie" ? "T" : c === (r ? "home" : "away") ? "W" : "L";
1115
- d = l`<span class=${m}>${m}</span> ${n}-${i}${s.finish === "overtime" ? l` <span class="mut">OT</span>` : p}${s.forfeit && s.forfeit !== "none" ? l` <span class="mut">FF</span>` : p}`;
1116
- } else s.state === "live" && (d = l`<span style="color:var(--hsot-red)">${n}-${i}</span>`);
1117
- const h = s.gameType === "conference" ? "Conf" : s.gameType === "nonconference" ? "Non-conf" : s.gameType === "playoff" ? `Playoff${s.label ? ` · ${s.label}` : ""}` : "Scrimmage";
1118
- return l`
1165
+ const d = q(s), m = d === "tie" ? "T" : d === (r ? "home" : "away") ? "W" : "L";
1166
+ h = i`<span class=${m}>${m}</span> ${c}-${n}${s.finish === "overtime" ? i` <span class="mut">OT</span>` : p}${s.forfeit && s.forfeit !== "none" ? i` <span class="mut">FF</span>` : p}`;
1167
+ } else s.state === "live" && (h = i`<span style="color:var(--hsot-red)">${c}-${n}</span>`);
1168
+ const l = s.gameType === "conference" ? "Conf" : s.gameType === "nonconference" ? "Non-conf" : s.gameType === "playoff" ? `Playoff${s.label ? ` · ${s.label}` : ""}` : "Scrimmage";
1169
+ return i`
1119
1170
  <li>
1120
- <span class="d">${b(s.date)}</span>
1171
+ <span class="d">${$(s.date)}</span>
1121
1172
  ${R(s)}
1122
- <span class="res">${d}</span>
1123
- <span class="opp">${r ? "vs" : "at"} ${H(e, o, s.date)}
1124
- <span class="pill type">${h}</span>
1125
- ${s.broadcast ? l`<span class="pill class">${s.broadcast}</span>` : p}
1173
+ <span class="res">${h}</span>
1174
+ <span class="opp">${r ? "vs" : "at"} ${M(e, o, s.date)}
1175
+ <span class="pill type">${l}</span>
1176
+ ${s.broadcast ? i`<span class="pill class">${s.broadcast}</span>` : p}
1126
1177
  </span>
1127
1178
  <span class="where">${s.venue || ""}</span>
1128
1179
  <a class="box" href=${u(e.hrefs.game, { sport: t.sport, id: s.id })}>Box score →</a>
@@ -1132,21 +1183,21 @@ class De extends $ {
1132
1183
  renderRoster(e) {
1133
1184
  const t = this.data.roster;
1134
1185
  if (!t)
1135
- return l`<p class="empty">Roster not published for ${e}.</p>`;
1136
- const s = v(this.data.players), r = t.entries.slice().sort((o, n) => (o.number || 0) - (n.number || 0));
1137
- return l`
1186
+ return i`<p class="empty">Roster not published for ${e}.</p>`;
1187
+ const s = v(this.data.players), r = t.entries.slice().sort((o, c) => (o.number || 0) - (c.number || 0));
1188
+ return i`
1138
1189
  <div class="tablewrap"><table class="data">
1139
1190
  <thead><tr><th class="num">No.</th><th>Player</th><th>Pos</th><th>Class</th><th class="num">Ht</th><th class="num">Wt</th></tr></thead>
1140
1191
  <tbody>
1141
1192
  ${r.map((o) => {
1142
- const n = s[o.playerId];
1143
- return n ? l`<tr>
1193
+ const c = s[o.playerId];
1194
+ return c ? i`<tr>
1144
1195
  <td class="num mut">${o.number ?? "·"}</td>
1145
- <td style="font-weight:500">${n.firstName} ${n.lastName}</td>
1196
+ <td style="font-weight:500">${c.firstName} ${c.lastName}</td>
1146
1197
  <td>${o.position || "·"}</td>
1147
- <td class="mut">${n.classOf || "·"}</td>
1148
- <td class="num">${ie(n.heightIn)}</td>
1149
- <td class="num">${n.weightLb || "·"}</td>
1198
+ <td class="mut">${c.classOf || "·"}</td>
1199
+ <td class="num">${ce(c.heightIn)}</td>
1200
+ <td class="num">${c.weightLb || "·"}</td>
1150
1201
  </tr>` : p;
1151
1202
  })}
1152
1203
  </tbody>
@@ -1154,16 +1205,16 @@ class De extends $ {
1154
1205
  `;
1155
1206
  }
1156
1207
  }
1157
- globalThis?.customElements && !globalThis.customElements.get("hsot-school") && globalThis.customElements.define("hsot-school", De);
1158
- const Fe = "https://api.wral.com/search";
1159
- function ze(a) {
1208
+ globalThis?.customElements && !globalThis.customElements.get("hsot-school") && globalThis.customElements.define("hsot-school", Be);
1209
+ const Pe = "https://api.wral.com/search";
1210
+ function Ee(a) {
1160
1211
  return a.map((e) => `uri:"${e}"`).join(" OR ");
1161
1212
  }
1162
- function Be(a, e) {
1163
- const t = String(a || Fe).replace(/\/+$/, ""), s = new URLSearchParams({ query: ze(e), sort: "score", lang: "en" });
1213
+ function _e(a, e) {
1214
+ const t = String(a || Pe).replace(/\/+$/, ""), s = new URLSearchParams({ query: Ee(e), sort: "score", lang: "en" });
1164
1215
  return `${t}/v1/query?${s}`;
1165
1216
  }
1166
- function se(a) {
1217
+ function oe(a) {
1167
1218
  try {
1168
1219
  const e = new URL(a);
1169
1220
  if (/(^|\.)smugmug\.com$/i.test(e.hostname)) {
@@ -1178,13 +1229,13 @@ function se(a) {
1178
1229
  }
1179
1230
  return { uri: a, title: a };
1180
1231
  }
1181
- async function Pe(a, e, t) {
1182
- const r = await ((...i) => fetch(...i))(Be(a, e));
1232
+ async function Ae(a, e, t) {
1233
+ const r = await ((...n) => fetch(...n))(_e(a, e));
1183
1234
  if (!r.ok) throw new Error(`search answered ${r.status}`);
1184
- const o = await r.json(), n = new Map((o.items || []).map((i) => [i.uri, i]));
1185
- return e.map((i) => n.get(i) || se(i));
1235
+ const o = await r.json(), c = new Map((o.items || []).map((n) => [n.uri, n]));
1236
+ return e.map((n) => c.get(n) || oe(n));
1186
1237
  }
1187
- const _e = y`
1238
+ const Re = b`
1188
1239
  .breadcrumbs { font-size: 0.8125rem; margin: 0.9rem 0 0; color: var(--hsot-gray-5); }
1189
1240
  .breadcrumbs a { text-decoration: none; }
1190
1241
  .scorehead { display: grid; grid-template-columns: 1fr auto 1fr; gap: 1rem; align-items: center; padding: 1.4rem 1rem; }
@@ -1223,10 +1274,10 @@ const _e = y`
1223
1274
  .cols { grid-template-columns: 1fr; }
1224
1275
  }
1225
1276
  `;
1226
- class Re extends $ {
1227
- static styles = [...F, _e];
1277
+ class Le extends y {
1278
+ static styles = [...F, Re];
1228
1279
  static properties = {
1229
- ...$.properties,
1280
+ ...y.properties,
1230
1281
  gameId: { type: String, attribute: "game-id" },
1231
1282
  // The public site search that resolves Game.coverageUrls into cards
1232
1283
  // (DEV-1236). Shared cross-stage by design — see the studio host's
@@ -1238,7 +1289,7 @@ class Re extends $ {
1238
1289
  super(), this.gameId = "", this.searchApi = "";
1239
1290
  }
1240
1291
  async fetchData(e) {
1241
- const t = await e.getGame(this.gameId), s = Array.isArray(t.coverageUrls) ? t.coverageUrls : [], [r, o, n, i, d, h] = await Promise.all([
1292
+ const t = await e.getGame(this.gameId), s = Array.isArray(t.coverageUrls) ? t.coverageUrls : [], [r, o, c, n, h, l] = await Promise.all([
1242
1293
  e.listSchools(),
1243
1294
  e.listTeams({ sport: t.sport }),
1244
1295
  e.listConferences(),
@@ -1246,16 +1297,16 @@ class Re extends $ {
1246
1297
  e.listGames({ sport: t.sport, season: t.season }),
1247
1298
  // A search outage must not blank the box score — degrade to bare
1248
1299
  // links (fetchCoverage already degrades per-URL index misses).
1249
- s.length ? Pe(this.searchApi, s).catch(() => s.map(se)) : Promise.resolve([])
1300
+ s.length ? Ae(this.searchApi, s).catch(() => s.map(oe)) : Promise.resolve([])
1250
1301
  ]);
1251
1302
  return {
1252
1303
  game: t,
1253
1304
  schools: r.items,
1254
1305
  teams: o.items,
1255
- conferences: n.items,
1256
- rankings: i.items,
1257
- games: d.items,
1258
- coverage: h
1306
+ conferences: c.items,
1307
+ rankings: n.items,
1308
+ games: h.items,
1309
+ coverage: l
1259
1310
  };
1260
1311
  }
1261
1312
  get ctx() {
@@ -1270,49 +1321,50 @@ class Re extends $ {
1270
1321
  }
1271
1322
  renderView() {
1272
1323
  const e = this.data.game;
1273
- if (!e) return l`<div class="view"><p class="empty">Game not found.</p></div>`;
1274
- const t = this.ctx, s = v(this.data.conferences), r = t.teamsById[e.awayTeamId] ? t.schoolsById[t.teamsById[e.awayTeamId].schoolId] : null, o = t.teamsById[e.homeTeamId] ? t.schoolsById[t.teamsById[e.homeTeamId].schoolId] : null, n = j(e), i = (c) => e.state === "final" && n !== c && n !== "tie" ? "opacity:0.45" : "", d = e.conferenceId ? s[e.conferenceId] : null, h = this.data.games.filter((c) => c.id !== e.id && c.state === "final" && c.gameType !== "scrimmage" && (c.homeTeamId === e.homeTeamId && c.awayTeamId === e.awayTeamId || c.homeTeamId === e.awayTeamId && c.awayTeamId === e.homeTeamId));
1275
- return l`
1276
- <div class="view">
1324
+ if (!e) return i`<div class="view"><p class="empty">Game not found.</p></div>`;
1325
+ const t = this.ctx, s = v(this.data.conferences), r = t.teamsById[e.awayTeamId] ? t.schoolsById[t.teamsById[e.awayTeamId].schoolId] : null, o = t.teamsById[e.homeTeamId] ? t.schoolsById[t.teamsById[e.homeTeamId].schoolId] : null, c = q(e), n = (d) => e.state === "final" && c !== d && c !== "tie" ? "opacity:0.45" : "", h = e.conferenceId ? s[e.conferenceId] : null, l = this.data.games.filter((d) => d.id !== e.id && d.state === "final" && d.gameType !== "scrimmage" && (d.homeTeamId === e.homeTeamId && d.awayTeamId === e.awayTeamId || d.homeTeamId === e.awayTeamId && d.awayTeamId === e.homeTeamId));
1326
+ return i`
1327
+ ${B(this, i`
1328
+ ${P(this)}
1277
1329
  <p class="breadcrumbs">
1278
1330
  <a href=${u(t.hrefs.section, { sport: e.sport, view: "scores" })}>${T(e.sport)}</a> /
1279
1331
  <a href=${u(t.hrefs.section, { sport: e.sport, view: "scores" })}>Scores/Schedules</a> /
1280
- ${S(t, e.awayTeamId)} at ${S(t, e.homeTeamId)}
1332
+ ${I(t, e.awayTeamId)} at ${I(t, e.homeTeamId)}
1281
1333
  </p>
1282
1334
  <div class="card">
1283
1335
  <div class="scorehead">
1284
1336
  ${this.teamBlock(t, e, e.awayTeamId, r, !1)}
1285
1337
  <div class="mid">
1286
1338
  <div class="bigscore">
1287
- <span style=${i("away")}>${e.awayScore}</span>
1339
+ <span style=${n("away")}>${e.awayScore}</span>
1288
1340
  <span class="mut" style="font-size:1.6rem">–</span>
1289
- <span style=${i("home")}>${e.homeScore}</span>
1341
+ <span style=${n("home")}>${e.homeScore}</span>
1290
1342
  </div>
1291
1343
  <div class="status">${R(e)}</div>
1292
- <div class="status">${b(e.date, { weekday: "short", month: "short", day: "numeric", year: "numeric" })}${e.state === "scheduled" && e.time ? l` · ${A(e.time)}` : p} · ${e.venue || "Venue TBD"}
1293
- ${e.broadcast ? l` · <span class="pill class">${e.broadcast}</span>` : p}</div>
1344
+ <div class="status">${$(e.date, { weekday: "short", month: "short", day: "numeric", year: "numeric" })}${e.state === "scheduled" && e.time ? i` · ${L(e.time)}` : p} · ${e.venue || "Venue TBD"}
1345
+ ${e.broadcast ? i` · <span class="pill class">${e.broadcast}</span>` : p}</div>
1294
1346
  <div class="status">
1295
- <span class="pill type">${e.gameType === "conference" ? `${d?.name || "Conference"} game` : e.gameType}</span>
1296
- ${e.label ? l`<span class="pill type">Bracket ${e.label}</span>` : p}
1297
- ${(e.tags || []).map((c) => l`<span class="pill type">${c}</span>`)}
1347
+ <span class="pill type">${e.gameType === "conference" ? `${h?.name || "Conference"} game` : e.gameType}</span>
1348
+ ${e.label ? i`<span class="pill type">Bracket ${e.label}</span>` : p}
1349
+ ${(e.tags || []).map((d) => i`<span class="pill type">${d}</span>`)}
1298
1350
  </div>
1299
1351
  </div>
1300
1352
  ${this.teamBlock(t, e, e.homeTeamId, o, !0)}
1301
1353
  </div>
1302
1354
  ${this.renderLineScore(e, r, o)}
1303
- ${e.notes ? l`<p class="note" style="padding:0 1rem 0.9rem;text-align:center">${e.notes}</p>` : p}
1355
+ ${e.notes ? i`<p class="note" style="padding:0 1rem 0.9rem;text-align:center">${e.notes}</p>` : p}
1304
1356
  </div>
1305
- ${(this.data.coverage || []).length ? l`
1357
+ ${(this.data.coverage || []).length ? i`
1306
1358
  <div class="section-title">Coverage</div>
1307
1359
  <div class="covgrid">
1308
- ${this.data.coverage.map((c) => l`
1309
- <a class="card covcard" href=${c.uri}>
1310
- ${c.image ? l`<img class="covimg" src=${c.image} alt="" loading="lazy" />` : p}
1360
+ ${this.data.coverage.map((d) => i`
1361
+ <a class="card covcard" href=${d.uri}>
1362
+ ${d.image ? i`<img class="covimg" src=${d.image} alt="" loading="lazy" />` : p}
1311
1363
  <div class="covbody">
1312
- <div class="covtitle">${c.videoDuration ? l`<span class="pill live" style="animation:none">Video</span> ` : p}${c.photos ? l`<span class="pill live" style="animation:none">Photos</span> ` : p}${c.title || c.uri}</div>
1313
- ${c.description ? l`<p class="covdesc">${c.description}</p>` : p}
1314
- ${c.author || c.publishedTime ? l`
1315
- <div class="covmeta">${[c.author, c.publishedTime ? new Date(c.publishedTime).toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" }) : ""].filter(Boolean).join(" · ")}</div>
1364
+ <div class="covtitle">${d.videoDuration ? i`<span class="pill live" style="animation:none">Video</span> ` : p}${d.photos ? i`<span class="pill live" style="animation:none">Photos</span> ` : p}${d.title || d.uri}</div>
1365
+ ${d.description ? i`<p class="covdesc">${d.description}</p>` : p}
1366
+ ${d.author || d.publishedTime ? i`
1367
+ <div class="covmeta">${[d.author, d.publishedTime ? new Date(d.publishedTime).toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" }) : ""].filter(Boolean).join(" · ")}</div>
1316
1368
  ` : p}
1317
1369
  </div>
1318
1370
  </a>
@@ -1320,29 +1372,29 @@ class Re extends $ {
1320
1372
  </div>` : p}
1321
1373
  <div class="section-title">Season context</div>
1322
1374
  <div class="cols">
1323
- ${[[e.awayTeamId, r], [e.homeTeamId, o]].map(([c, m]) => this.renderContext(t, c, m))}
1375
+ ${[[e.awayTeamId, r], [e.homeTeamId, o]].map(([d, m]) => this.renderContext(t, d, m))}
1324
1376
  </div>
1325
- ${h.length ? l`
1377
+ ${l.length ? i`
1326
1378
  <div class="section-title">Head to head this season</div>
1327
1379
  <div class="card"><ul class="gamelist">
1328
- ${h.map((c) => l`<li>
1329
- <span class="d">${b(c.date)}</span>${R(c)}
1330
- <span class="opp">${S(t, c.awayTeamId)} ${c.awayScore}, ${S(t, c.homeTeamId)} ${c.homeScore}</span>
1331
- <a class="box" href=${u(t.hrefs.game, { sport: e.sport, id: c.id })}>Box score →</a>
1380
+ ${l.map((d) => i`<li>
1381
+ <span class="d">${$(d.date)}</span>${R(d)}
1382
+ <span class="opp">${I(t, d.awayTeamId)} ${d.awayScore}, ${I(t, d.homeTeamId)} ${d.homeScore}</span>
1383
+ <a class="box" href=${u(t.hrefs.game, { sport: e.sport, id: d.id })}>Box score →</a>
1332
1384
  </li>`)}
1333
1385
  </ul></div>` : p}
1334
- </div>
1386
+ `)}
1335
1387
  `;
1336
1388
  }
1337
1389
  teamBlock(e, t, s, r, o) {
1338
- if (!r) return l`<div class="teamblock ${o ? "right" : ""}"><div class="tname">TBD</div></div>`;
1339
- const n = e.teamsById[s], i = e.records[s], d = P(r, 58);
1340
- return l`
1390
+ if (!r) return i`<div class="teamblock ${o ? "right" : ""}"><div class="tname">TBD</div></div>`;
1391
+ const c = e.teamsById[s], n = e.records[s], h = _(r, 58);
1392
+ return i`
1341
1393
  <div class="teamblock ${o ? "right" : ""}">
1342
- ${d ? l`<img class="crest logo" alt="" loading="lazy" src=${d} />` : l`<span class="crest" style="background:${r.colorPrimary || "#030711"};color:${B(r.colorPrimary || "#030711")}">${M(r)}</span>`}
1394
+ ${h ? i`<img class="crest logo" alt="" loading="lazy" src=${h} />` : i`<span class="crest" style="background:${r.colorPrimary || "#030711"};color:${E(r.colorPrimary || "#030711")}">${G(r)}</span>`}
1343
1395
  <div>
1344
- <div class="tname">${q(e, s, t.date)}<a href=${u(e.hrefs.school, { id: r.id })}>${r.name}</a></div>
1345
- <div class="trec">${r.mascot || ""} · ${w(i)}${n?.conferenceId ? l` · ${w(i, !0)} conf` : p}</div>
1396
+ <div class="tname">${K(e, s, t.date)}<a href=${u(e.hrefs.school, { id: r.id })}>${r.name}</a></div>
1397
+ <div class="trec">${r.mascot || ""} · ${w(n)}${c?.conferenceId ? i` · ${w(n, !0)} conf` : p}</div>
1346
1398
  </div>
1347
1399
  </div>
1348
1400
  `;
@@ -1350,23 +1402,23 @@ class Re extends $ {
1350
1402
  renderLineScore(e, t, s) {
1351
1403
  const r = e.periodScores || [];
1352
1404
  if (!r.length)
1353
- return l`<p class="empty" style="text-align:center">Period scoring will appear once the game starts.</p>`;
1354
- const o = Math.max(4, ...r.map((h) => h.period)), n = (h) => h <= 4 ? String(h) : `OT${h > 5 ? h - 4 : ""}`, i = (h, c) => {
1355
- const m = r.find((f) => f.period === c);
1356
- return m ? m[h] : e.state === "final" ? 0 : "·";
1357
- }, d = (h, c, m) => l`
1405
+ return i`<p class="empty" style="text-align:center">Period scoring will appear once the game starts.</p>`;
1406
+ const o = Math.max(4, ...r.map((l) => l.period)), c = (l) => l <= 4 ? String(l) : `OT${l > 5 ? l - 4 : ""}`, n = (l, d) => {
1407
+ const m = r.find((f) => f.period === d);
1408
+ return m ? m[l] : e.state === "final" ? 0 : "·";
1409
+ }, h = (l, d, m) => i`
1358
1410
  <tr>
1359
- <td class="teamcell">${C(h, 20)}${h?.abbr || "TBD"}</td>
1360
- ${Array.from({ length: o }, (f, g) => l`<td class="num">${i(c, g + 1)}</td>`)}
1411
+ <td class="teamcell">${C(l, 20)}${l?.abbr || "TBD"}</td>
1412
+ ${Array.from({ length: o }, (f, g) => i`<td class="num">${n(d, g + 1)}</td>`)}
1361
1413
  <td class="num" style="font-weight:700">${m}</td>
1362
1414
  </tr>`;
1363
- return l`
1415
+ return i`
1364
1416
  <div class="tablewrap" style="border-top:1px solid var(--hsot-gray-2)">
1365
1417
  <table class="data" style="max-width:560px;margin:0.6rem auto 0.9rem">
1366
- <thead><tr><th>Team</th>${Array.from({ length: o }, (h, c) => l`<th class="num">${n(c + 1)}</th>`)}<th class="num">T</th></tr></thead>
1418
+ <thead><tr><th>Team</th>${Array.from({ length: o }, (l, d) => i`<th class="num">${c(d + 1)}</th>`)}<th class="num">T</th></tr></thead>
1367
1419
  <tbody>
1368
- ${d(t, "away", e.awayScore)}
1369
- ${d(s, "home", e.homeScore)}
1420
+ ${h(t, "away", e.awayScore)}
1421
+ ${h(s, "home", e.homeScore)}
1370
1422
  </tbody>
1371
1423
  </table>
1372
1424
  </div>
@@ -1374,37 +1426,217 @@ class Re extends $ {
1374
1426
  }
1375
1427
  renderContext(e, t, s) {
1376
1428
  if (!s) return p;
1377
- const r = e.records[t], o = G(this.data.games, t);
1378
- return l`
1429
+ const r = e.records[t], o = W(this.data.games, t);
1430
+ return i`
1379
1431
  <div class="card ctxcard">
1380
1432
  <div class="who">${C(s)}${s.name}</div>
1381
1433
  <div class="row">
1382
- <span>Last 5: ${V(e, t)}</span>
1383
- <span>Streak: <b>${r ? L(r.results) : "·"}</b></span>
1434
+ <span>Last 5: ${Q(e, t)}</span>
1435
+ <span>Streak: <b>${r ? O(r.results) : "·"}</b></span>
1384
1436
  <span>PF/PA: <b>${r ? `${r.pf} / ${r.pa}` : "·"}</b></span>
1385
- <span>Next: ${o ? l`${b(o.date, { month: "numeric", day: "numeric" })}
1386
- ${o.homeTeamId === t ? "vs" : "at"} ${_(e, o.homeTeamId === t ? o.awayTeamId : o.homeTeamId)}` : "·"}</span>
1437
+ <span>Next: ${o ? i`${$(o.date, { month: "numeric", day: "numeric" })}
1438
+ ${o.homeTeamId === t ? "vs" : "at"} ${A(e, o.homeTeamId === t ? o.awayTeamId : o.homeTeamId)}` : "·"}</span>
1387
1439
  </div>
1388
1440
  </div>
1389
1441
  `;
1390
1442
  }
1391
1443
  }
1392
- globalThis?.customElements && !globalThis.customElements.get("hsot-boxscore") && globalThis.customElements.define("hsot-boxscore", Re);
1444
+ globalThis?.customElements && !globalThis.customElements.get("hsot-boxscore") && globalThis.customElements.define("hsot-boxscore", Le);
1445
+ const Ne = 250, Oe = 2;
1446
+ class He extends te {
1447
+ static properties = {
1448
+ api: { type: String },
1449
+ schoolHref: { type: String, attribute: "school-href" },
1450
+ limit: { type: Number },
1451
+ placeholder: { type: String },
1452
+ results: { state: !0 },
1453
+ open: { state: !0 },
1454
+ activeIndex: { state: !0 },
1455
+ searched: { state: !0 }
1456
+ };
1457
+ static styles = b`
1458
+ :host {
1459
+ display: block;
1460
+ position: relative;
1461
+ font-family: var(--font-family, sans-serif);
1462
+ }
1463
+ input {
1464
+ width: 100%;
1465
+ box-sizing: border-box;
1466
+ padding: 0.625rem 0.75rem;
1467
+ font-size: 1rem;
1468
+ font-family: inherit;
1469
+ color: var(--color-black, #000);
1470
+ background: var(--color-white, #fff);
1471
+ border: 1px solid var(--color-gray-4, #ccc);
1472
+ border-bottom: 3px solid var(--color-red, #b90100);
1473
+ border-radius: 2px;
1474
+ }
1475
+ input:focus {
1476
+ outline: 2px solid var(--color-red, #b90100);
1477
+ outline-offset: -1px;
1478
+ }
1479
+ ul {
1480
+ position: absolute;
1481
+ z-index: 10;
1482
+ left: 0;
1483
+ right: 0;
1484
+ margin: 0;
1485
+ padding: 0;
1486
+ list-style: none;
1487
+ max-height: 20rem;
1488
+ overflow-y: auto;
1489
+ background: var(--color-white, #fff);
1490
+ border: 1px solid var(--color-gray-4, #ccc);
1491
+ border-top: none;
1492
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
1493
+ }
1494
+ li {
1495
+ padding: 0.5rem 0.75rem;
1496
+ cursor: pointer;
1497
+ }
1498
+ li[aria-selected="true"], li:hover {
1499
+ background: var(--color-gray-1, #f9f9f9);
1500
+ }
1501
+ li .name {
1502
+ font-weight: 700;
1503
+ color: var(--color-black, #000);
1504
+ }
1505
+ li .where {
1506
+ display: block;
1507
+ font-size: 0.8rem;
1508
+ color: var(--color-gray-5, #666);
1509
+ }
1510
+ li.empty {
1511
+ cursor: default;
1512
+ color: var(--color-gray-5, #666);
1513
+ }
1514
+ li.empty:hover {
1515
+ background: none;
1516
+ }
1517
+ `;
1518
+ constructor() {
1519
+ super(), this.api = "https://api.highschoolot.com/hsot/v1/public", this.schoolHref = "/school/{id}/", this.limit = 10, this.placeholder = "Find Your School", this.results = [], this.open = !1, this.activeIndex = -1, this.searched = !1;
1520
+ }
1521
+ disconnectedCallback() {
1522
+ super.disconnectedCallback(), clearTimeout(this.debounceTimer), this.abortController?.abort();
1523
+ }
1524
+ onInput(e) {
1525
+ const t = e.target.value.trim();
1526
+ if (clearTimeout(this.debounceTimer), t.length < Oe) {
1527
+ this.abortController?.abort(), this.results = [], this.open = !1, this.searched = !1;
1528
+ return;
1529
+ }
1530
+ this.debounceTimer = setTimeout(() => this.search(t), Ne);
1531
+ }
1532
+ async search(e) {
1533
+ this.abortController?.abort(), this.abortController = new AbortController();
1534
+ try {
1535
+ const t = `${this.api}/schools?q=${encodeURIComponent(e)}&limit=${this.limit}`, s = await fetch(t, {
1536
+ signal: this.abortController.signal
1537
+ });
1538
+ if (!s.ok)
1539
+ return;
1540
+ const r = await s.json();
1541
+ this.results = r.items || [], this.activeIndex = -1, this.searched = !0, this.open = !0;
1542
+ } catch (t) {
1543
+ t.name !== "AbortError" && console.warn("school search failed", t);
1544
+ }
1545
+ }
1546
+ onKeyDown(e) {
1547
+ if (e.key === "Escape") {
1548
+ this.open = !1;
1549
+ return;
1550
+ }
1551
+ if (!(!this.open || !this.results.length))
1552
+ if (e.key === "ArrowDown")
1553
+ e.preventDefault(), this.activeIndex = (this.activeIndex + 1) % this.results.length;
1554
+ else if (e.key === "ArrowUp") {
1555
+ e.preventDefault();
1556
+ const t = this.results.length;
1557
+ this.activeIndex = (this.activeIndex - 1 + t) % t;
1558
+ } else e.key === "Enter" && (e.preventDefault(), this.go(this.results[this.activeIndex] || this.results[0]));
1559
+ }
1560
+ onBlur() {
1561
+ setTimeout(() => {
1562
+ this.open = !1;
1563
+ }, 150);
1564
+ }
1565
+ onFocus() {
1566
+ this.results.length && (this.open = !0);
1567
+ }
1568
+ go(e) {
1569
+ e && (globalThis.location.href = this.schoolHref.replace("{id}", e.id));
1570
+ }
1571
+ where(e) {
1572
+ return [e.location, e.county && `${e.county} County`].filter(Boolean).join(" — ");
1573
+ }
1574
+ renderOption(e, t) {
1575
+ const s = this.where(e), r = (o) => {
1576
+ o.preventDefault(), this.go(e);
1577
+ };
1578
+ return i`
1579
+ <li
1580
+ id="school-option-${t}"
1581
+ role="option"
1582
+ aria-selected="${t === this.activeIndex ? "true" : "false"}"
1583
+ @pointerdown="${r}"
1584
+ @mousemove="${() => {
1585
+ this.activeIndex = t;
1586
+ }}"
1587
+ >
1588
+ <span class="name">${e.name}</span>
1589
+ ${s ? i`<span class="where">${s}</span>` : p}
1590
+ </li>
1591
+ `;
1592
+ }
1593
+ renderListbox() {
1594
+ const e = this.searched && !this.results.length, t = i`<li class="empty">No schools found</li>`;
1595
+ return i`
1596
+ <ul id="school-search-listbox" role="listbox" aria-label="Schools">
1597
+ ${this.results.map((s, r) => this.renderOption(s, r))}
1598
+ ${e ? t : p}
1599
+ </ul>
1600
+ `;
1601
+ }
1602
+ render() {
1603
+ const e = this.activeIndex >= 0 ? `school-option-${this.activeIndex}` : "";
1604
+ return i`
1605
+ <input
1606
+ type="text"
1607
+ role="combobox"
1608
+ aria-label="Find your school"
1609
+ aria-expanded="${this.open ? "true" : "false"}"
1610
+ aria-controls="school-search-listbox"
1611
+ aria-activedescendant="${e}"
1612
+ autocomplete="off"
1613
+ placeholder="${this.placeholder}"
1614
+ @input="${this.onInput}"
1615
+ @keydown="${this.onKeyDown}"
1616
+ @blur="${this.onBlur}"
1617
+ @focus="${this.onFocus}"
1618
+ >
1619
+ ${this.open ? this.renderListbox() : p}
1620
+ `;
1621
+ }
1622
+ }
1623
+ globalThis?.customElements && !globalThis.customElements.get("hsot-school-search") && globalThis.customElements.define("hsot-school-search", He);
1393
1624
  export {
1394
- O as D,
1395
- Re as H,
1396
- Ie as a,
1397
- De as b,
1398
- ke as c,
1399
- Te as d,
1400
- z as e,
1401
- ne as f,
1402
- u as g,
1403
- j as h,
1404
- Ee as i,
1405
- L as j,
1406
- we as p,
1625
+ U as D,
1626
+ Le as H,
1627
+ Fe as a,
1628
+ Be as b,
1629
+ He as c,
1630
+ Se as d,
1631
+ Ce as e,
1632
+ z as f,
1633
+ le as g,
1634
+ u as h,
1635
+ q as i,
1636
+ Me as j,
1637
+ O as k,
1638
+ Te as p,
1407
1639
  w as r,
1408
- J as s,
1409
- ee as t
1640
+ ae as s,
1641
+ V as t
1410
1642
  };