@wral/hsot-data 0.1.5 → 0.1.7

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 ne = 50;
3
+ function le(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 ce({ 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 < ne; m += 1) {
26
+ const f = le(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 H = {
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") || H.game,
58
+ school: a.getAttribute("school-href") || H.school,
59
+ section: a.getAttribute("section-href") || H.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 M(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 de(a) {
76
76
  return a ? `${Math.floor(a / 12)}-${a % 12}` : "·";
77
77
  }
78
- function E(a = /* @__PURE__ */ new Date()) {
78
+ function L(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 he(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 me = (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 se(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" })} · ${M(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 ae() {
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 = ae()) {
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 ? ce({ 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;
@@ -407,6 +437,14 @@ const v = (a) => Object.fromEntries((a || []).map((e) => [e.id, e])), fe = y`
407
437
  .gamelist li:last-child { border-bottom: none; }
408
438
  .gamelist .d { width: 84px; flex: none; color: var(--hsot-gray-5); font-size: 0.8rem; }
409
439
  .gamelist .res { width: 86px; flex: none; font-family: var(--hsot-heading-font); font-weight: 700; }
440
+ /* Per-team score block on the scoreboard, in the status pills' bubble shape. */
441
+ .gamelist .score {
442
+ display: inline-block; min-width: 1.15em; text-align: center;
443
+ background: var(--hsot-red); color: var(--hsot-white);
444
+ font-family: var(--hsot-heading-font); font-weight: 700; font-size: 0.8125rem;
445
+ line-height: 1.2; border-radius: var(--hsot-radius-md); padding: 0.14rem 0.4rem;
446
+ margin-left: 0.45rem; vertical-align: middle; font-variant-numeric: tabular-nums;
447
+ }
410
448
  .gamelist .res .W { color: var(--hsot-win); }
411
449
  .gamelist .res .L { color: var(--hsot-loss); }
412
450
  .gamelist .res .T { color: var(--hsot-tie); }
@@ -415,77 +453,77 @@ const v = (a) => Object.fromEntries((a || []).map((e) => [e.id, e])), fe = y`
415
453
  .gamelist .opp a:hover { text-decoration: underline; }
416
454
  .gamelist .where { color: var(--hsot-gray-5); font-size: 0.78rem; }
417
455
  .gamelist a.box { font-size: 0.78rem; }
418
- `, F = [fe, ue, ge, ve, be, $e, ye];
419
- function j(a) {
456
+ `, F = [ve, be, $e, ye, we, xe, ke];
457
+ function q(a) {
420
458
  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
459
  }
422
460
  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)));
461
+ 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
462
  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;
463
+ const c = q(o), n = o.gameType === "conference";
464
+ for (const h of ["home", "away"]) {
465
+ const l = h === "home" ? o.homeTeamId : o.awayTeamId;
466
+ if (!l) continue;
467
+ const d = s(l), m = h === "home" ? o.homeScore : o.awayScore, f = h === "home" ? o.awayScore : o.homeScore;
468
+ d.pf += m, d.pa += f;
431
469
  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 });
470
+ 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
471
  }
434
472
  }
435
473
  return t;
436
474
  }
437
- function L(a) {
475
+ function N(a) {
438
476
  if (!a || !a.length) return "";
439
477
  const e = a[a.length - 1].mark;
440
478
  let t = 0;
441
479
  for (let s = a.length - 1; s >= 0 && a[s].mark === e; s -= 1) t += 1;
442
480
  return e + t;
443
481
  }
444
- const Q = (a, e, t) => {
482
+ const Z = (a, e, t) => {
445
483
  const s = a + e + t;
446
484
  return s ? (a + t / 2) / s : 0;
447
- }, K = (a) => a.toFixed(3).replace("0.", ".");
485
+ }, J = (a) => a.toFixed(3).replace("0.", ".");
448
486
  function w(a, e = !1) {
449
487
  if (!a) return "0-0";
450
488
  const t = e ? a.cw : a.w, s = e ? a.cl : a.l, r = e ? a.ct : a.t;
451
489
  return `${t}-${s}${r ? `-${r}` : ""}`;
452
490
  }
453
- function J(a, e) {
491
+ function re(a, e) {
454
492
  return a.map((t) => {
455
493
  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) };
494
+ return { team: t, rec: s, confPct: Z(s.cw, s.cl, s.ct), overallPct: Z(s.w, s.l, s.t) };
457
495
  }).sort((t, s) => s.confPct - t.confPct || s.overallPct - t.overallPct || s.rec.pf - s.rec.pa - (t.rec.pf - t.rec.pa));
458
496
  }
459
- function G(a, e) {
497
+ function W(a, e) {
460
498
  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
499
  }
462
- function X(a, e) {
500
+ function ee(a, e) {
463
501
  const t = a[e];
464
502
  return t && t.results.length ? t.results[t.results.length - 1] : null;
465
503
  }
466
- function Ee(a, e, t, s = "") {
504
+ function Me(a, e, t, s = "") {
467
505
  let r = null;
468
506
  for (const o of a || [])
469
507
  o.sport === e && (t && o.effectiveDate > t || s && o.gender && o.gender !== s || (!r || o.effectiveDate > r.effectiveDate) && (r = o));
470
508
  return r;
471
509
  }
472
- function ee(a, e, t, s, r) {
510
+ function V(a, e, t, s, r) {
473
511
  const o = e[t];
474
512
  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;
513
+ const c = /* @__PURE__ */ new Map();
514
+ for (const h of a || []) {
515
+ if (h.sport !== s || r && h.effectiveDate > r || h.gender && o.gender !== h.gender && o.gender !== "coed") continue;
516
+ const l = h.gender || "", d = c.get(l);
517
+ (!d || h.effectiveDate > d.effectiveDate) && c.set(l, h);
518
+ }
519
+ let n = null;
520
+ for (const h of c.values()) {
521
+ const l = (h.teamIds || []).indexOf(t);
522
+ l !== -1 && (!n || h.effectiveDate > n.effectiveDate) && (n = { poll: h, rank: l + 1 });
523
+ }
524
+ return n ? n.rank : null;
487
525
  }
488
- function we(a, e, t) {
526
+ function Te(a, e, t) {
489
527
  if (!a) return { kind: "none", delta: 0 };
490
528
  const s = (a.teamIds || []).indexOf(t) + 1;
491
529
  if (!s) return { kind: "none", delta: 0 };
@@ -495,109 +533,121 @@ function we(a, e, t) {
495
533
  const o = r - s;
496
534
  return o > 0 ? { kind: "up", delta: o } : o < 0 ? { kind: "down", delta: -o } : { kind: "same", delta: 0 };
497
535
  }
498
- function xe(a) {
536
+ function Ie(a) {
499
537
  return /^https?:\/\//i.test(String(a || ""));
500
538
  }
501
- function P(a, e) {
539
+ function _(a, e) {
502
540
  const t = a?.logoAssetId;
503
- if (!xe(t)) return "";
541
+ if (!Ie(t)) return "";
504
542
  const s = Math.max(1, Math.round(e * 2)), r = t.includes("?") ? "&" : "?";
505
543
  return `${t}${r}w=${s}&h=${s}&f=webp`;
506
544
  }
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`
545
+ function Y(a, e, { title: t, sub: s, teams: r }) {
546
+ const o = ae(), n = !!a.querySelector(':scope > a[slot="nav"]') || fe(o, e.hrefs, e.sport) !== null;
547
+ return i`
510
548
  <div class="band section">
511
549
  <div class="inner">
512
550
  <h1>${t}</h1>
513
- ${s ? l`<p class="sub">${s}</p>` : p}
551
+ ${s ? i`<p class="sub">${s}</p>` : p}
514
552
  </div>
515
- ${i ? l`
553
+ ${n ? i`
516
554
  <nav class="sectionnav" aria-label="${T(e.sport)} section">
517
555
  <div class="navrow">
518
556
  <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>`)}
557
+ ${ue(e.sport, r, e.hrefs).map((h) => i`<a href=${h.href}
558
+ aria-current=${o && x(h.href) === o ? "page" : p}>${h.label}</a>`)}
521
559
  </slot>
522
560
  </div>
523
561
  </nav>` : p}
524
562
  </div>
525
563
  `;
526
564
  }
527
- const I = (a, e) => {
565
+ const S = (a, e) => {
528
566
  const t = a.teamsById[e];
529
567
  return t ? a.schoolsById[t.schoolId] : null;
530
- }, S = (a, e) => I(a, e)?.name || "TBD", _ = (a, e) => I(a, e)?.abbr || "TBD";
568
+ }, I = (a, e) => S(a, e)?.name || "TBD", A = (a, e) => S(a, e)?.abbr || "TBD";
531
569
  function C(a, e = 26) {
532
570
  if (!a) return p;
533
- const t = P(a, e);
571
+ const t = _(a, e);
534
572
  if (t)
535
- return l`<img class="swatch logo" aria-hidden="true" alt="" loading="lazy"
573
+ return i`<img class="swatch logo" aria-hidden="true" alt="" loading="lazy"
536
574
  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"
575
+ const s = a.colorPrimary || "#030711", r = E(s);
576
+ return i`<span class="swatch" aria-hidden="true"
539
577
  style="width:${e}px;height:${e}px;background:${s};color:${r};font-size:${Math.max(8, e * 0.28)}px"
540
- >${M(a)}</span>`;
578
+ >${G(a)}</span>`;
541
579
  }
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;
580
+ function K(a, e, t) {
581
+ const s = V(a.rankings, a.teamsById, e, a.sport, t);
582
+ return s ? i`<span class="rankbadge">#${s}</span>` : p;
545
583
  }
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>`;
584
+ function U(a, e, t) {
585
+ const s = S(a, e);
586
+ 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
587
  }
550
- function V(a, e, t = 5) {
588
+ function Q(a, e, t = 5) {
551
589
  const s = a.records[e];
552
- if (!s || !s.results.length) return l`<span class="mut">·</span>`;
590
+ if (!s || !s.results.length) return i`<span class="mut">·</span>`;
553
591
  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)}"
592
+ return i`<span class="dots" role="img" aria-label="last ${r.length} results">
593
+ ${r.map((o) => i`<a class="dot ${o.mark}"
594
+ title="${o.mark} ${o.my}-${o.their} vs ${I(a, o.opp)}"
557
595
  href=${u(a.hrefs.game, { sport: a.sport, id: o.gameId })}>${o.mark}</a>`)}
558
596
  </span>`;
559
597
  }
598
+ function B(a, e) {
599
+ return a.querySelector(':scope > [slot="rail"]') ? i`<div class="view withrail">
600
+ <div class="viewmain">${e}</div>
601
+ <aside class="viewrail"><slot name="rail"></slot></aside>
602
+ </div>` : i`<div class="view">${e}</div>`;
603
+ }
604
+ function P(a) {
605
+ if (!a.promoImage) return p;
606
+ const e = i`<img src=${a.promoImage} alt=${a.promoAlt || "Sponsor"}>`;
607
+ return i`<div class="promo">${a.promoHref ? i`<a href=${a.promoHref} target="_blank" rel="sponsored noopener">${e}</a>` : e}</div>`;
608
+ }
560
609
  function R(a) {
561
- const e = ce(a);
562
- return l`<span class="pill ${e.kind}">${e.label}</span>`;
610
+ const e = se(a);
611
+ return i`<span class="pill ${e.kind}">${e.label}</span>`;
563
612
  }
564
- function te(a, e, t) {
565
- if (!e) return l`<span class="mut">·</span>`;
613
+ function oe(a, e, t) {
614
+ if (!e) return i`<span class="mut">·</span>`;
566
615
  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)}`;
616
+ return i`${e.state === "live" ? i`<span class="pill live">Live</span> ` : i`${$(e.date, { month: "numeric", day: "numeric" })} `}${r} ${A(a, s)}`;
568
617
  }
569
- class ke extends $ {
618
+ class Se extends y {
570
619
  static styles = F;
571
620
  static properties = {
572
- ...$.properties,
621
+ ...y.properties,
573
622
  sport: { type: String },
574
623
  season: { type: String },
575
624
  date: { type: String }
576
625
  };
577
626
  constructor() {
578
- super(), this.sport = "football", this.season = "", this.date = "";
627
+ super(), this.sport = "football", this.season = "", this.date = "", this._datePinned = !1;
579
628
  }
580
629
  connectedCallback() {
581
630
  if (super.connectedCallback(), !this.date) {
582
631
  const e = new URLSearchParams(globalThis.location?.search || "").get("date");
583
- this.date = e || U();
632
+ e && (this.date = e);
584
633
  }
634
+ this._datePinned = !!this.date;
585
635
  }
586
636
  async fetchData(e) {
587
- const t = this.season || E(), [s, r, o, n, i] = await Promise.all([
637
+ const t = this.season || L(), [s, r, o, c, n] = await Promise.all([
588
638
  e.listSchools(),
589
639
  e.listTeams({ sport: this.sport }),
590
640
  e.listConferences(),
591
641
  e.listGames({ sport: this.sport, season: t }),
592
642
  e.listRankings({ sport: this.sport })
593
643
  ]);
594
- return {
644
+ return this._datePinned || (this.date = he(c.items.map((h) => h.date)), this._datePinned = !0), {
595
645
  season: t,
596
646
  schools: s.items,
597
647
  teams: r.items,
598
648
  conferences: o.items,
599
- games: n.items,
600
- rankings: i.items
649
+ games: c.items,
650
+ rankings: n.items
601
651
  };
602
652
  }
603
653
  get ctx() {
@@ -611,24 +661,30 @@ class ke extends $ {
611
661
  }, this._ctxData = this.data), this._ctx;
612
662
  }
613
663
  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`,
664
+ 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) => {
665
+ const d = [l.awayTeamId, l.homeTeamId].map((m) => V(e.rankings, e.teamsById, m, this.sport, l.date)).filter(Boolean);
666
+ return d.length ? Math.min(...d) : r;
667
+ }, c = this.data.games.filter((l) => l.date === this.date), n = new Map(c.map((l) => [l, o(l)]));
668
+ c.sort((l, d) => (l.state === "live" ? 0 : 1) - (d.state === "live" ? 0 : 1) || n.get(l) - n.get(d));
669
+ const h = /* @__PURE__ */ new Map();
670
+ return c.forEach((l) => {
671
+ const d = l.gameType === "conference" && l.conferenceId ? t[l.conferenceId]?.name || "Conference" : l.gameType === "playoff" ? "Playoffs" : l.gameType === "scrimmage" ? "Scrimmages" : "Nonconference";
672
+ h.has(d) || h.set(d, []), h.get(d).push(l);
673
+ }), i`
674
+ ${Y(this, e, {
675
+ title: i`${T(this.sport)} scores &amp; schedules`,
676
+ sub: i`${$(this.date, { weekday: "long", month: "long", day: "numeric", year: "numeric" })} · ${c.length} games`,
622
677
  teams: this.data.teams
623
678
  })}
624
- <div class="view">
679
+ ${B(this, i`
680
+ ${P(this)}
625
681
  <div class="toolbar">
626
682
  <label class="asof" for="datesel">Date</label>
627
- <select id="datesel" @change=${(n) => {
628
- this.date = n.target.value;
683
+ <select id="datesel" @change=${(l) => {
684
+ this.date = l.target.value;
629
685
  }}>
630
- ${s.map((n) => l`<option value=${n} ?selected=${n === this.date}>
631
- ${b(n, { weekday: "short", month: "short", day: "numeric" })}${n === U() ? " · today" : ""}
686
+ ${(s.includes(this.date) ? s : [...s, this.date].sort()).map((l) => i`<option value=${l} ?selected=${l === this.date}>
687
+ ${$(l, { weekday: "short", month: "short", day: "numeric" })}${l === j() ? " · today" : ""}
632
688
  </option>`)}
633
689
  </select>
634
690
  <button class="chip" ?disabled=${s.indexOf(this.date) <= 0}
@@ -642,35 +698,38 @@ class ke extends $ {
642
698
  <span class="spacer"></span>
643
699
  <span class="asof">Live games first · report a score to see it update here</span>
644
700
  </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>
701
+ ${c.length ? p : i`<p class="empty">No ${this.sport} games on this date.</p>`}
702
+ ${[...h.entries()].map(([l, d]) => i`
703
+ <div class="section-title">${l}</div>
648
704
  <div class="card"><ul class="gamelist">
649
- ${i.map((d) => this.renderGame(e, d))}
705
+ ${d.map((m) => this.renderGame(e, m))}
650
706
  </ul></div>
651
707
  `)}
652
- </div>
708
+ `)}
653
709
  `;
654
710
  }
711
+ // Each team's score rides in a block beside its name (reader feedback:
712
+ // a lone score column on the far right read as detached from the teams).
713
+ // Scheduled games carry their start time on the status pill alone.
655
714
  renderGame(e, t) {
656
- const s = t.state === "final" || t.state === "live" ? `${t.awayScore}-${t.homeScore}` : A(t.time);
657
- return l`
715
+ const s = t.state === "final" || t.state === "live";
716
+ return i`
658
717
  <li>
659
718
  ${R(t)}
660
- <span class="opp">${H(e, t.awayTeamId, t.date)} at ${H(e, t.homeTeamId, t.date)}</span>
661
- <span class="res" style="width:auto">${s}</span>
719
+ <span class="opp">${U(e, t.awayTeamId, t.date)}${s ? i`<span class="score">${t.awayScore}</span>` : p}
720
+ at ${U(e, t.homeTeamId, t.date)}${s ? i`<span class="score">${t.homeScore}</span>` : p}</span>
662
721
  <span class="where">${t.venue || ""}</span>
663
- ${t.broadcast ? l`<span class="pill class">${t.broadcast}</span>` : p}
722
+ ${t.broadcast ? i`<span class="pill class">${t.broadcast}</span>` : p}
664
723
  <a class="box" href=${u(e.hrefs.game, { sport: this.sport, id: t.id })}>Box score →</a>
665
724
  </li>
666
725
  `;
667
726
  }
668
727
  }
669
- globalThis?.customElements && !globalThis.customElements.get("hsot-scores") && globalThis.customElements.define("hsot-scores", ke);
670
- class Te extends $ {
728
+ globalThis?.customElements && !globalThis.customElements.get("hsot-scores") && globalThis.customElements.define("hsot-scores", Se);
729
+ class Ce extends y {
671
730
  static styles = F;
672
731
  static properties = {
673
- ...$.properties,
732
+ ...y.properties,
674
733
  sport: { type: String },
675
734
  season: { type: String },
676
735
  classFilter: { state: !0 },
@@ -680,7 +739,7 @@ class Te extends $ {
680
739
  super(), this.sport = "football", this.season = "", this.classFilter = "All", this.query = "";
681
740
  }
682
741
  async fetchData(e) {
683
- const t = this.season || E(), [s, r, o, n, i] = await Promise.all([
742
+ const t = this.season || L(), [s, r, o, c, n] = await Promise.all([
684
743
  e.listConferences({ active: !0 }),
685
744
  e.listSchools(),
686
745
  e.listTeams({ sport: this.sport }),
@@ -692,8 +751,8 @@ class Te extends $ {
692
751
  conferences: s.items,
693
752
  schools: r.items,
694
753
  teams: o.items,
695
- games: n.items,
696
- rankings: i.items
754
+ games: c.items,
755
+ rankings: n.items
697
756
  };
698
757
  }
699
758
  get ctx() {
@@ -708,16 +767,17 @@ class Te extends $ {
708
767
  }
709
768
  renderView() {
710
769
  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`,
770
+ return i`
771
+ ${Y(this, e, {
772
+ title: i`${T(this.sport)} standings`,
773
+ sub: i`${this.data.season} season · every conference, computed live from reported results`,
715
774
  teams: this.data.teams
716
775
  })}
717
- <div class="view">
776
+ ${B(this, i`
777
+ ${P(this)}
718
778
  <div class="toolbar">
719
779
  <div role="group" aria-label="Classification filter">
720
- ${t.map((r) => l`<button class="chip ${this.classFilter === r ? "on" : ""}"
780
+ ${t.map((r) => i`<button class="chip ${this.classFilter === r ? "on" : ""}"
721
781
  @click=${() => {
722
782
  this.classFilter = r;
723
783
  }}>${r}</button>`)}
@@ -727,21 +787,21 @@ class Te extends $ {
727
787
  this.query = r.target.value;
728
788
  }}>
729
789
  <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>
790
+ <span class="asof">Records through ${$(j(), { month: "long", day: "numeric" })} · conference games count toward both records · scrimmages toward neither</span>
731
791
  </div>
732
792
  ${s.map((r) => this.renderConference(e, r))}
733
- </div>
793
+ `)}
734
794
  `;
735
795
  }
736
796
  renderConference(e, t) {
737
- const s = this.data.teams.filter((n) => n.conferenceId === t.id);
797
+ const s = this.data.teams.filter((c) => c.conferenceId === t.id);
738
798
  if (!s.length) return p;
739
- const r = this.query.trim().toLowerCase(), o = J(s, e.records);
740
- return l`
799
+ const r = this.query.trim().toLowerCase(), o = re(s, e.records);
800
+ return i`
741
801
  <div class="card">
742
802
  <div class="card-head">
743
803
  <h2>${t.name}</h2>
744
- ${(t.classifications || []).map((n) => l`<span class="pill class">${n}</span>`)}
804
+ ${(t.classifications || []).map((c) => i`<span class="pill class">${c}</span>`)}
745
805
  <span class="meta">${o.length} teams · membership derives from teams</span>
746
806
  </div>
747
807
  <div class="tablewrap"><table class="data">
@@ -751,44 +811,44 @@ class Te extends $ {
751
811
  <th>Streak</th><th>Last 5</th><th>Next</th>
752
812
  </tr></thead>
753
813
  <tbody>
754
- ${o.map((n, i) => this.renderRow(e, n, i, r))}
814
+ ${o.map((c, n) => this.renderRow(e, c, n, r))}
755
815
  </tbody>
756
816
  </table></div>
757
817
  </div>
758
818
  `;
759
819
  }
760
820
  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 = () => {
821
+ const o = e.schoolsById[t.team.schoolId], c = o?.name || t.team.name || "TBD";
822
+ if (r && !c.toLowerCase().includes(r)) return p;
823
+ const n = t.rec.pf - t.rec.pa, h = W(this.data.games, t.team.id), l = (t.team.championships || []).map((m) => i`
824
+ <span class="pill champ" title="${m.season} ${m.title} champion">★ ${m.season} ${m.title}</span>`), d = () => {
765
825
  location.href = u(e.hrefs.school, { id: t.team.schoolId });
766
826
  };
767
- return l`
827
+ return i`
768
828
  <tr class="rowlink" @click=${(m) => {
769
- m.target.closest("a") || c();
829
+ m.target.closest("a") || d();
770
830
  }}>
771
831
  <td class="mut">${s + 1}</td>
772
832
  <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}
833
+ ${C(o)}${K(e, t.team.id, null)}
834
+ <a href=${u(e.hrefs.school, { id: t.team.schoolId })}>${c}</a> ${l}
775
835
  </td>
776
836
  <td class="num">${w(t.rec, !0)}</td>
777
- <td class="num">${K(t.confPct)}</td>
837
+ <td class="num">${J(t.confPct)}</td>
778
838
  <td class="num">${w(t.rec)}</td>
779
- <td class="num">${K(t.overallPct)}</td>
839
+ <td class="num">${J(t.overallPct)}</td>
780
840
  <td class="num">${t.rec.pf}</td>
781
841
  <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>
842
+ <td class="num" style="color:${n >= 0 ? "var(--hsot-win)" : "var(--hsot-loss)"}">${n > 0 ? "+" : ""}${n}</td>
843
+ <td>${N(t.rec.results) || "·"}</td>
844
+ <td>${Q(e, t.team.id)}</td>
845
+ <td>${oe(e, h, t.team.id)}</td>
786
846
  </tr>
787
847
  `;
788
848
  }
789
849
  }
790
- globalThis?.customElements && !globalThis.customElements.get("hsot-standings") && globalThis.customElements.define("hsot-standings", Te);
791
- const Se = y`
850
+ globalThis?.customElements && !globalThis.customElements.get("hsot-standings") && globalThis.customElements.define("hsot-standings", Ce);
851
+ const De = b`
792
852
  .hero1 {
793
853
  border-radius: var(--hsot-radius-md); color: var(--hsot-white);
794
854
  padding: 1.3rem 1.4rem; display: flex; align-items: center; gap: 1.2rem;
@@ -805,10 +865,10 @@ const Se = y`
805
865
  .delta.new { background: var(--hsot-straw); color: #6b5900; border-radius: var(--hsot-radius-xs); padding: 0.1rem 0.3rem; font-size: 0.7rem; }
806
866
  .sparkline { vertical-align: middle; }
807
867
  `;
808
- class Ie extends $ {
809
- static styles = [...F, Se];
868
+ class Fe extends y {
869
+ static styles = [...F, De];
810
870
  static properties = {
811
- ...$.properties,
871
+ ...y.properties,
812
872
  sport: { type: String },
813
873
  gender: { type: String },
814
874
  season: { type: String },
@@ -823,20 +883,20 @@ class Ie extends $ {
823
883
  e && (this.pollDate = e);
824
884
  }
825
885
  async fetchData(e) {
826
- const t = this.season || E(), [s, r, o, n, i] = await Promise.all([
886
+ const t = this.season || L(), [s, r, o, c, n] = await Promise.all([
827
887
  e.listRankings({ sport: this.sport, ...this.gender ? { gender: this.gender } : {} }),
828
888
  e.listSchools(),
829
889
  e.listTeams({ sport: this.sport }),
830
890
  e.listConferences(),
831
891
  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));
892
+ ]), h = s.items.filter((l) => !this.gender || !l.gender || l.gender === this.gender).sort((l, d) => d.effectiveDate.localeCompare(l.effectiveDate));
833
893
  return {
834
894
  season: t,
835
- polls: d,
895
+ polls: h,
836
896
  schools: r.items,
837
897
  teams: o.items,
838
- conferences: n.items,
839
- games: i.items
898
+ conferences: c.items,
899
+ games: n.items
840
900
  };
841
901
  }
842
902
  get ctx() {
@@ -850,45 +910,46 @@ class Ie extends $ {
850
910
  }, this._ctxData = this.data), this._ctx;
851
911
  }
852
912
  sparkline(e, t, s) {
853
- const i = t.map((m, f) => {
913
+ const n = t.map((m, f) => {
854
914
  const g = (m.teamIds || []).indexOf(e);
855
915
  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"
916
+ const k = t.length === 1 ? 96 / 2 : f / (t.length - 1) * 90 + 3, O = 3 + g / 24 * 20;
917
+ return { x: k, y: O };
918
+ }), h = [];
919
+ let l = [];
920
+ if (n.forEach((m) => {
921
+ m ? l.push(m) : l.length && (h.push(l), l = []);
922
+ }), l.length && h.push(l), !h.length) return p;
923
+ const d = n[s];
924
+ return i`<svg class="sparkline" width=${96} height=${26} viewBox="0 0 ${96} ${26}" role="img" aria-label="rank history">
925
+ ${h.map((m) => X`<polyline fill="none" stroke="var(--hsot-red)" stroke-width="2"
866
926
  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}
927
+ ${d ? X`<circle cx=${d.x.toFixed(1)} cy=${d.y.toFixed(1)} r="3" fill="var(--hsot-black)"></circle>` : p}
868
928
  </svg>`;
869
929
  }
870
930
  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>`;
931
+ const r = Te(e, t, s);
932
+ 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
933
  }
874
934
  renderView() {
875
935
  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`,
936
+ if (!t.length) return i`<div class="view"><p class="empty">No ${this.sport} polls published yet this season.</p></div>`;
937
+ 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;
938
+ return i`
939
+ ${Y(this, e, {
940
+ title: i`${T(this.sport)} Top 25`,
941
+ sub: i`The HighSchoolOT poll · updated weekly · ${t.length} polls this season`,
882
942
  teams: this.data.teams
883
943
  })}
884
- <div class="view">
944
+ ${B(this, i`
945
+ ${P(this)}
885
946
  <div class="toolbar">
886
947
  <label class="asof" for="pollsel">Poll of</label>
887
948
  <select id="pollsel" @change=${(m) => {
888
949
  this.pollDate = m.target.value;
889
950
  }}>
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" : ""}
951
+ ${t.map((m, f) => i`<option value=${m.effectiveDate} ?selected=${m === r}>
952
+ ${$(m.effectiveDate, { month: "long", day: "numeric", year: "numeric" })}${f === 0 ? " · current" : ""}
892
953
  </option>`)}
893
954
  </select>
894
955
  <button class="chip" ?disabled=${s >= t.length - 1}
@@ -902,65 +963,65 @@ class Ie extends $ {
902
963
  <span class="spacer"></span>
903
964
  <span class="asof">Movement vs. the previous poll · sparkline = season rank history</span>
904
965
  </div>
905
- ${c ? this.renderHero(e, r, o, h, c, d) : p}
966
+ ${d ? this.renderHero(e, r, o, l, d, h) : p}
906
967
  <div class="card"><div class="tablewrap"><table class="data">
907
968
  <thead><tr>
908
969
  <th class="num">Rk</th><th>Mvmt</th><th>Team</th><th class="num">Record</th>
909
970
  <th>Conference</th><th>Last result</th><th>Next</th><th>Season</th>
910
971
  </tr></thead>
911
972
  <tbody>
912
- ${(r.teamIds || []).map((m, f) => f === 0 || !m ? p : this.renderRow(e, r, o, n, i, d, m, f + 1))}
973
+ ${(r.teamIds || []).map((m, f) => f === 0 || !m ? p : this.renderRow(e, r, o, c, n, h, m, f + 1))}
913
974
  </tbody>
914
975
  </table></div></div>
915
976
  <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>
977
+ `)}
917
978
  `;
918
979
  }
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}">
980
+ renderHero(e, t, s, r, o, c) {
981
+ 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%)`;
982
+ return i`
983
+ <div class="hero1" style="background:${d}">
923
984
  <div class="bigrank">#1</div>
924
985
  ${C(o, 64)}
925
986
  <div>
926
987
  <h2><a href=${u(e.hrefs.school, { id: o.id })}>${o.name} ${o.mascot || ""}</a></h2>
927
988
  <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}
989
+ ${w(n)} overall${l ? i` · ${w(n, !0)} ${l.name}` : p}
990
+ · streak ${N(n?.results) || "·"}
991
+ ${h ? i` · last: ${h.mark} ${h.my}-${h.their} vs ${A(e, h.opp)}` : p}
931
992
  &nbsp;${this.movement(t, s, r)}
932
993
  </div>
933
994
  </div>
934
995
  </div>
935
996
  `;
936
997
  }
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 });
998
+ renderRow(e, t, s, r, o, c, n, h) {
999
+ const l = S(e, n);
1000
+ if (!l) return p;
1001
+ const d = e.records[n], m = ee(e.records, n), f = W(this.data.games, n), g = c[e.teamsById[n]?.conferenceId], k = () => {
1002
+ location.href = u(e.hrefs.school, { id: l.id });
942
1003
  };
943
- return l`
944
- <tr class="rowlink" @click=${(N) => {
945
- N.target.closest("a") || k();
1004
+ return i`
1005
+ <tr class="rowlink" @click=${(O) => {
1006
+ O.target.closest("a") || k();
946
1007
  }}>
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>
1008
+ <td class="num" style="font-weight:700">${h}</td>
1009
+ <td>${this.movement(t, s, n)}</td>
1010
+ <td class="teamcell">${C(l)}<a href=${u(e.hrefs.school, { id: l.id })}>${l.name}</a>
1011
+ <span class="mut" style="font-size:0.78rem">${l.mascot || ""}</span></td>
1012
+ <td class="num">${w(d)}</td>
952
1013
  <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 })}>
1014
+ <td>${m ? i`<a class="box" style="text-decoration:none" href=${u(e.hrefs.game, { sport: this.sport, id: m.gameId })}>
954
1015
  <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>
1016
+ ${m.my}-${m.their} vs ${A(e, m.opp)}</a>` : i`<span class="mut">·</span>`}</td>
1017
+ <td>${oe(e, f, n)}</td>
1018
+ <td>${this.sparkline(n, r, o)}</td>
958
1019
  </tr>
959
1020
  `;
960
1021
  }
961
1022
  }
962
- globalThis?.customElements && !globalThis.customElements.get("hsot-rankings") && globalThis.customElements.define("hsot-rankings", Ie);
963
- const Ce = y`
1023
+ globalThis?.customElements && !globalThis.customElements.get("hsot-rankings") && globalThis.customElements.define("hsot-rankings", Fe);
1024
+ const ze = b`
964
1025
  .schoolhero { color: var(--hsot-white); padding: 1.6rem 1.25rem 1.3rem; }
965
1026
  .schoolhero .inner { max-width: 1366px; margin: 0 auto; display: flex; gap: 1.2rem; align-items: center; flex-wrap: wrap; }
966
1027
  .schoolhero .crest {
@@ -985,10 +1046,10 @@ const Ce = y`
985
1046
  .cols { display: grid; grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); gap: 1.25rem; }
986
1047
  @media (max-width: 900px) { .cols { grid-template-columns: 1fr; } .schoolhero h1 { font-size: 1.9rem; } }
987
1048
  `;
988
- class De extends $ {
989
- static styles = [...F, Ce];
1049
+ class Be extends y {
1050
+ static styles = [...F, ze];
990
1051
  static properties = {
991
- ...$.properties,
1052
+ ...y.properties,
992
1053
  schoolId: { type: String, attribute: "school-id" },
993
1054
  sport: { type: String },
994
1055
  season: { type: String },
@@ -1003,26 +1064,26 @@ class De extends $ {
1003
1064
  e && !this.sport && (this.sport = e);
1004
1065
  }
1005
1066
  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: [] }),
1067
+ const t = this.season || L(), 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([
1068
+ c ? e.listGames({ sport: c.sport, season: t }) : Promise.resolve({ items: [] }),
1069
+ c ? e.listTeams({ sport: c.sport }) : Promise.resolve({ items: [] }),
1009
1070
  e.listSchools(),
1010
1071
  e.listConferences(),
1011
- n ? e.listRankings({ sport: n.sport }) : Promise.resolve({ items: [] }),
1012
- n ? e.listRosters({ teamId: n.id }) : Promise.resolve({ items: [] }),
1072
+ c ? e.listRankings({ sport: c.sport }) : Promise.resolve({ items: [] }),
1073
+ c ? e.listRosters({ teamId: c.id }) : Promise.resolve({ items: [] }),
1013
1074
  // teamId is the public surface's one players filter (roster
1014
1075
  // membership) — never fetch the whole collection.
1015
- n ? e.listPlayers({ teamId: n.id }) : Promise.resolve({ items: [] })
1076
+ c ? e.listPlayers({ teamId: c.id }) : Promise.resolve({ items: [] })
1016
1077
  ]);
1017
1078
  return {
1018
1079
  season: t,
1019
1080
  school: s,
1020
1081
  teams: o,
1021
- active: n,
1022
- games: i.items,
1023
- allTeams: d.items,
1024
- schools: h.items,
1025
- conferences: c.items,
1082
+ active: c,
1083
+ games: n.items,
1084
+ allTeams: h.items,
1085
+ schools: l.items,
1086
+ conferences: d.items,
1026
1087
  rankings: m.items,
1027
1088
  roster: f.items.find((k) => k.season === t) || null,
1028
1089
  players: g.items
@@ -1043,61 +1104,61 @@ class De extends $ {
1043
1104
  }
1044
1105
  renderView() {
1045
1106
  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}">
1107
+ if (!e) return i`<div class="view"><p class="empty">School not found.</p></div>`;
1108
+ const o = this.ctx, c = E(e.colorPrimary || "#030711"), n = (e.adm || [])[0], h = v(this.data.conferences), l = s ? h[s.conferenceId] : null;
1109
+ return i`
1110
+ <div class="schoolhero" style="background:linear-gradient(115deg, ${e.colorPrimary || "#030711"} 0%, ${e.colorPrimary || "#030711"} 55%, var(--hsot-black) 100%);color:${c}">
1050
1111
  <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>`}
1112
+ ${_(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
1113
  <div style="min-width:260px">
1053
1114
  <h1>${e.name} <span class="mascot">${e.mascot || ""}</span></h1>
1054
1115
  <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}
1116
+ ${e.location ? i`<span><b>Location</b>${e.location}${e.county ? i` · ${e.county} County` : p}</span>` : p}
1117
+ ${e.association ? i`<span><b>League</b>${e.association}${e.classification ? i` · ${e.classification}` : p}</span>` : p}
1118
+ ${l ? i`<span><b>Conference</b>${l.name}</span>` : p}
1119
+ ${n ? i`<span><b>Enrollment</b>${n.value.toLocaleString()} (${n.season} ADM)</span>` : p}
1120
+ ${e.openingYear ? i`<span><b>Opened</b>${e.openingYear}</span>` : p}
1121
+ ${e.areaCode ? i`<span><b>Area</b>${e.areaCode}</span>` : p}
1062
1122
  </div>
1063
1123
  </div>
1064
1124
  </div>
1065
1125
  </div>
1066
1126
  <div class="band">
1067
1127
  <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>`)}
1128
+ ${t.map((d) => d.id === s?.id ? i`<a class="on" href="#" @click=${(m) => m.preventDefault()}>${d.name}</a>` : i`<a href="#" @click=${(m) => {
1129
+ m.preventDefault(), this.switchSport(d.sport);
1130
+ }}>${d.name}</a>`)}
1071
1131
  </nav>
1072
1132
  </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>
1133
+ ${B(this, i`
1134
+ ${P(this)}
1135
+ ${s ? this.renderTeam(o, s, l, r) : i`<p class="empty">No teams recorded for this school yet.</p>`}
1136
+ `)}
1076
1137
  `;
1077
1138
  }
1078
1139
  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`
1140
+ 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 ? re(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)));
1141
+ return i`
1081
1142
  <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>
1143
+ <div class="tile"><div class="k">Overall</div><div class="v">${w(o)}</div><div class="s">${c} games played</div></div>
1083
1144
  <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>
1145
+ <div class="s">${h ? `${me(h)} of ${n.length}` : "·"}</div></div>
1146
+ <div class="tile"><div class="k">Points</div><div class="v">${c ? (o.pf / c).toFixed(1) : "0.0"}</div>
1147
+ <div class="s">scored per game · ${c ? (o.pa / c).toFixed(1) : "0.0"} allowed</div></div>
1148
+ <div class="tile"><div class="k">Streak</div><div class="v">${N(o.results) || "·"}</div>
1149
+ <div class="s">last 5: ${Q(e, t.id)}</div></div>
1150
+ <div class="tile"><div class="k">HSOT Top 25</div><div class="v">${l ? `#${l}` : "NR"}</div>
1090
1151
  <div class="s"><a href=${u(e.hrefs.section, { sport: t.sport, view: "rankings" })}>full poll</a></div></div>
1091
1152
  </div>
1092
- ${(t.championships || []).length ? l`
1153
+ ${(t.championships || []).length ? i`
1093
1154
  <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>`)}
1155
+ ${t.championships.map((m) => i`<span class="pill champ">★ ${m.season} ${m.title} champion${m.classification ? ` · ${m.classification}` : ""}${m.region ? ` · ${m.region}` : ""}</span>`)}
1095
1156
  </div>` : p}
1096
1157
  <div class="cols">
1097
1158
  <div>
1098
1159
  <div class="section-title">Schedule &amp; results</div>
1099
1160
  <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>`}
1161
+ ${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
1162
  </div>
1102
1163
  </div>
1103
1164
  <div>
@@ -1108,21 +1169,21 @@ class De extends $ {
1108
1169
  `;
1109
1170
  }
1110
1171
  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>`;
1172
+ const r = s.homeTeamId === t.id, o = r ? s.awayTeamId : s.homeTeamId, c = r ? s.homeScore : s.awayScore, n = r ? s.awayScore : s.homeScore;
1173
+ let h = i`<span class="mut">${M(s.time)}</span>`;
1113
1174
  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`
1175
+ const d = q(s), m = d === "tie" ? "T" : d === (r ? "home" : "away") ? "W" : "L";
1176
+ 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}`;
1177
+ } else s.state === "live" && (h = i`<span style="color:var(--hsot-red)">${c}-${n}</span>`);
1178
+ const l = s.gameType === "conference" ? "Conf" : s.gameType === "nonconference" ? "Non-conf" : s.gameType === "playoff" ? `Playoff${s.label ? ` · ${s.label}` : ""}` : "Scrimmage";
1179
+ return i`
1119
1180
  <li>
1120
- <span class="d">${b(s.date)}</span>
1121
- ${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}
1181
+ <span class="d">${$(s.date)}</span>
1182
+ ${se(s).kind === "sched" ? p : R(s)}
1183
+ <span class="res">${h}</span>
1184
+ <span class="opp">${r ? "vs" : "at"} ${U(e, o, s.date)}
1185
+ <span class="pill type">${l}</span>
1186
+ ${s.broadcast ? i`<span class="pill class">${s.broadcast}</span>` : p}
1126
1187
  </span>
1127
1188
  <span class="where">${s.venue || ""}</span>
1128
1189
  <a class="box" href=${u(e.hrefs.game, { sport: t.sport, id: s.id })}>Box score →</a>
@@ -1132,21 +1193,21 @@ class De extends $ {
1132
1193
  renderRoster(e) {
1133
1194
  const t = this.data.roster;
1134
1195
  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`
1196
+ return i`<p class="empty">Roster not published for ${e}.</p>`;
1197
+ const s = v(this.data.players), r = t.entries.slice().sort((o, c) => (o.number || 0) - (c.number || 0));
1198
+ return i`
1138
1199
  <div class="tablewrap"><table class="data">
1139
1200
  <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
1201
  <tbody>
1141
1202
  ${r.map((o) => {
1142
- const n = s[o.playerId];
1143
- return n ? l`<tr>
1203
+ const c = s[o.playerId];
1204
+ return c ? i`<tr>
1144
1205
  <td class="num mut">${o.number ?? "·"}</td>
1145
- <td style="font-weight:500">${n.firstName} ${n.lastName}</td>
1206
+ <td style="font-weight:500">${c.firstName} ${c.lastName}</td>
1146
1207
  <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>
1208
+ <td class="mut">${c.classOf || "·"}</td>
1209
+ <td class="num">${de(c.heightIn)}</td>
1210
+ <td class="num">${c.weightLb || "·"}</td>
1150
1211
  </tr>` : p;
1151
1212
  })}
1152
1213
  </tbody>
@@ -1154,16 +1215,16 @@ class De extends $ {
1154
1215
  `;
1155
1216
  }
1156
1217
  }
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) {
1218
+ globalThis?.customElements && !globalThis.customElements.get("hsot-school") && globalThis.customElements.define("hsot-school", Be);
1219
+ const Pe = "https://api.wral.com/search";
1220
+ function Ee(a) {
1160
1221
  return a.map((e) => `uri:"${e}"`).join(" OR ");
1161
1222
  }
1162
- function Be(a, e) {
1163
- const t = String(a || Fe).replace(/\/+$/, ""), s = new URLSearchParams({ query: ze(e), sort: "score", lang: "en" });
1223
+ function _e(a, e) {
1224
+ const t = String(a || Pe).replace(/\/+$/, ""), s = new URLSearchParams({ query: Ee(e), sort: "score", lang: "en" });
1164
1225
  return `${t}/v1/query?${s}`;
1165
1226
  }
1166
- function se(a) {
1227
+ function ie(a) {
1167
1228
  try {
1168
1229
  const e = new URL(a);
1169
1230
  if (/(^|\.)smugmug\.com$/i.test(e.hostname)) {
@@ -1178,13 +1239,13 @@ function se(a) {
1178
1239
  }
1179
1240
  return { uri: a, title: a };
1180
1241
  }
1181
- async function Pe(a, e, t) {
1182
- const r = await ((...i) => fetch(...i))(Be(a, e));
1242
+ async function Ae(a, e, t) {
1243
+ const r = await ((...n) => fetch(...n))(_e(a, e));
1183
1244
  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));
1245
+ const o = await r.json(), c = new Map((o.items || []).map((n) => [n.uri, n]));
1246
+ return e.map((n) => c.get(n) || ie(n));
1186
1247
  }
1187
- const _e = y`
1248
+ const Re = b`
1188
1249
  .breadcrumbs { font-size: 0.8125rem; margin: 0.9rem 0 0; color: var(--hsot-gray-5); }
1189
1250
  .breadcrumbs a { text-decoration: none; }
1190
1251
  .scorehead { display: grid; grid-template-columns: 1fr auto 1fr; gap: 1rem; align-items: center; padding: 1.4rem 1rem; }
@@ -1223,10 +1284,10 @@ const _e = y`
1223
1284
  .cols { grid-template-columns: 1fr; }
1224
1285
  }
1225
1286
  `;
1226
- class Re extends $ {
1227
- static styles = [...F, _e];
1287
+ class Le extends y {
1288
+ static styles = [...F, Re];
1228
1289
  static properties = {
1229
- ...$.properties,
1290
+ ...y.properties,
1230
1291
  gameId: { type: String, attribute: "game-id" },
1231
1292
  // The public site search that resolves Game.coverageUrls into cards
1232
1293
  // (DEV-1236). Shared cross-stage by design — see the studio host's
@@ -1238,7 +1299,7 @@ class Re extends $ {
1238
1299
  super(), this.gameId = "", this.searchApi = "";
1239
1300
  }
1240
1301
  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([
1302
+ const t = await e.getGame(this.gameId), s = Array.isArray(t.coverageUrls) ? t.coverageUrls : [], [r, o, c, n, h, l] = await Promise.all([
1242
1303
  e.listSchools(),
1243
1304
  e.listTeams({ sport: t.sport }),
1244
1305
  e.listConferences(),
@@ -1246,16 +1307,16 @@ class Re extends $ {
1246
1307
  e.listGames({ sport: t.sport, season: t.season }),
1247
1308
  // A search outage must not blank the box score — degrade to bare
1248
1309
  // links (fetchCoverage already degrades per-URL index misses).
1249
- s.length ? Pe(this.searchApi, s).catch(() => s.map(se)) : Promise.resolve([])
1310
+ s.length ? Ae(this.searchApi, s).catch(() => s.map(ie)) : Promise.resolve([])
1250
1311
  ]);
1251
1312
  return {
1252
1313
  game: t,
1253
1314
  schools: r.items,
1254
1315
  teams: o.items,
1255
- conferences: n.items,
1256
- rankings: i.items,
1257
- games: d.items,
1258
- coverage: h
1316
+ conferences: c.items,
1317
+ rankings: n.items,
1318
+ games: h.items,
1319
+ coverage: l
1259
1320
  };
1260
1321
  }
1261
1322
  get ctx() {
@@ -1270,49 +1331,50 @@ class Re extends $ {
1270
1331
  }
1271
1332
  renderView() {
1272
1333
  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">
1334
+ if (!e) return i`<div class="view"><p class="empty">Game not found.</p></div>`;
1335
+ 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));
1336
+ return i`
1337
+ ${B(this, i`
1338
+ ${P(this)}
1277
1339
  <p class="breadcrumbs">
1278
1340
  <a href=${u(t.hrefs.section, { sport: e.sport, view: "scores" })}>${T(e.sport)}</a> /
1279
1341
  <a href=${u(t.hrefs.section, { sport: e.sport, view: "scores" })}>Scores/Schedules</a> /
1280
- ${S(t, e.awayTeamId)} at ${S(t, e.homeTeamId)}
1342
+ ${I(t, e.awayTeamId)} at ${I(t, e.homeTeamId)}
1281
1343
  </p>
1282
1344
  <div class="card">
1283
1345
  <div class="scorehead">
1284
1346
  ${this.teamBlock(t, e, e.awayTeamId, r, !1)}
1285
1347
  <div class="mid">
1286
1348
  <div class="bigscore">
1287
- <span style=${i("away")}>${e.awayScore}</span>
1349
+ <span style=${n("away")}>${e.awayScore}</span>
1288
1350
  <span class="mut" style="font-size:1.6rem">–</span>
1289
- <span style=${i("home")}>${e.homeScore}</span>
1351
+ <span style=${n("home")}>${e.homeScore}</span>
1290
1352
  </div>
1291
1353
  <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>
1354
+ <div class="status">${$(e.date, { weekday: "short", month: "short", day: "numeric", year: "numeric" })}${e.state === "scheduled" && e.time ? i` · ${M(e.time)}` : p} · ${e.venue || "Venue TBD"}
1355
+ ${e.broadcast ? i` · <span class="pill class">${e.broadcast}</span>` : p}</div>
1294
1356
  <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>`)}
1357
+ <span class="pill type">${e.gameType === "conference" ? `${h?.name || "Conference"} game` : e.gameType}</span>
1358
+ ${e.label ? i`<span class="pill type">Bracket ${e.label}</span>` : p}
1359
+ ${(e.tags || []).map((d) => i`<span class="pill type">${d}</span>`)}
1298
1360
  </div>
1299
1361
  </div>
1300
1362
  ${this.teamBlock(t, e, e.homeTeamId, o, !0)}
1301
1363
  </div>
1302
1364
  ${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}
1365
+ ${e.notes ? i`<p class="note" style="padding:0 1rem 0.9rem;text-align:center">${e.notes}</p>` : p}
1304
1366
  </div>
1305
- ${(this.data.coverage || []).length ? l`
1367
+ ${(this.data.coverage || []).length ? i`
1306
1368
  <div class="section-title">Coverage</div>
1307
1369
  <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}
1370
+ ${this.data.coverage.map((d) => i`
1371
+ <a class="card covcard" href=${d.uri}>
1372
+ ${d.image ? i`<img class="covimg" src=${d.image} alt="" loading="lazy" />` : p}
1311
1373
  <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>
1374
+ <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>
1375
+ ${d.description ? i`<p class="covdesc">${d.description}</p>` : p}
1376
+ ${d.author || d.publishedTime ? i`
1377
+ <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
1378
  ` : p}
1317
1379
  </div>
1318
1380
  </a>
@@ -1320,29 +1382,29 @@ class Re extends $ {
1320
1382
  </div>` : p}
1321
1383
  <div class="section-title">Season context</div>
1322
1384
  <div class="cols">
1323
- ${[[e.awayTeamId, r], [e.homeTeamId, o]].map(([c, m]) => this.renderContext(t, c, m))}
1385
+ ${[[e.awayTeamId, r], [e.homeTeamId, o]].map(([d, m]) => this.renderContext(t, d, m))}
1324
1386
  </div>
1325
- ${h.length ? l`
1387
+ ${l.length ? i`
1326
1388
  <div class="section-title">Head to head this season</div>
1327
1389
  <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>
1390
+ ${l.map((d) => i`<li>
1391
+ <span class="d">${$(d.date)}</span>${R(d)}
1392
+ <span class="opp">${I(t, d.awayTeamId)} ${d.awayScore}, ${I(t, d.homeTeamId)} ${d.homeScore}</span>
1393
+ <a class="box" href=${u(t.hrefs.game, { sport: e.sport, id: d.id })}>Box score →</a>
1332
1394
  </li>`)}
1333
1395
  </ul></div>` : p}
1334
- </div>
1396
+ `)}
1335
1397
  `;
1336
1398
  }
1337
1399
  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`
1400
+ if (!r) return i`<div class="teamblock ${o ? "right" : ""}"><div class="tname">TBD</div></div>`;
1401
+ const c = e.teamsById[s], n = e.records[s], h = _(r, 58);
1402
+ return i`
1341
1403
  <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>`}
1404
+ ${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
1405
  <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>
1406
+ <div class="tname">${K(e, s, t.date)}<a href=${u(e.hrefs.school, { id: r.id })}>${r.name}</a></div>
1407
+ <div class="trec">${r.mascot || ""} · ${w(n)}${c?.conferenceId ? i` · ${w(n, !0)} conf` : p}</div>
1346
1408
  </div>
1347
1409
  </div>
1348
1410
  `;
@@ -1350,23 +1412,23 @@ class Re extends $ {
1350
1412
  renderLineScore(e, t, s) {
1351
1413
  const r = e.periodScores || [];
1352
1414
  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`
1415
+ return i`<p class="empty" style="text-align:center">Period scoring will appear once the game starts.</p>`;
1416
+ const o = Math.max(4, ...r.map((l) => l.period)), c = (l) => l <= 4 ? String(l) : `OT${l > 5 ? l - 4 : ""}`, n = (l, d) => {
1417
+ const m = r.find((f) => f.period === d);
1418
+ return m ? m[l] : e.state === "final" ? 0 : "·";
1419
+ }, h = (l, d, m) => i`
1358
1420
  <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>`)}
1421
+ <td class="teamcell">${C(l, 20)}${l?.abbr || "TBD"}</td>
1422
+ ${Array.from({ length: o }, (f, g) => i`<td class="num">${n(d, g + 1)}</td>`)}
1361
1423
  <td class="num" style="font-weight:700">${m}</td>
1362
1424
  </tr>`;
1363
- return l`
1425
+ return i`
1364
1426
  <div class="tablewrap" style="border-top:1px solid var(--hsot-gray-2)">
1365
1427
  <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>
1428
+ <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
1429
  <tbody>
1368
- ${d(t, "away", e.awayScore)}
1369
- ${d(s, "home", e.homeScore)}
1430
+ ${h(t, "away", e.awayScore)}
1431
+ ${h(s, "home", e.homeScore)}
1370
1432
  </tbody>
1371
1433
  </table>
1372
1434
  </div>
@@ -1374,37 +1436,217 @@ class Re extends $ {
1374
1436
  }
1375
1437
  renderContext(e, t, s) {
1376
1438
  if (!s) return p;
1377
- const r = e.records[t], o = G(this.data.games, t);
1378
- return l`
1439
+ const r = e.records[t], o = W(this.data.games, t);
1440
+ return i`
1379
1441
  <div class="card ctxcard">
1380
1442
  <div class="who">${C(s)}${s.name}</div>
1381
1443
  <div class="row">
1382
- <span>Last 5: ${V(e, t)}</span>
1383
- <span>Streak: <b>${r ? L(r.results) : "·"}</b></span>
1444
+ <span>Last 5: ${Q(e, t)}</span>
1445
+ <span>Streak: <b>${r ? N(r.results) : "·"}</b></span>
1384
1446
  <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>
1447
+ <span>Next: ${o ? i`${$(o.date, { month: "numeric", day: "numeric" })}
1448
+ ${o.homeTeamId === t ? "vs" : "at"} ${A(e, o.homeTeamId === t ? o.awayTeamId : o.homeTeamId)}` : "·"}</span>
1387
1449
  </div>
1388
1450
  </div>
1389
1451
  `;
1390
1452
  }
1391
1453
  }
1392
- globalThis?.customElements && !globalThis.customElements.get("hsot-boxscore") && globalThis.customElements.define("hsot-boxscore", Re);
1454
+ globalThis?.customElements && !globalThis.customElements.get("hsot-boxscore") && globalThis.customElements.define("hsot-boxscore", Le);
1455
+ const Ne = 250, Oe = 2;
1456
+ class He extends te {
1457
+ static properties = {
1458
+ api: { type: String },
1459
+ schoolHref: { type: String, attribute: "school-href" },
1460
+ limit: { type: Number },
1461
+ placeholder: { type: String },
1462
+ results: { state: !0 },
1463
+ open: { state: !0 },
1464
+ activeIndex: { state: !0 },
1465
+ searched: { state: !0 }
1466
+ };
1467
+ static styles = b`
1468
+ :host {
1469
+ display: block;
1470
+ position: relative;
1471
+ font-family: var(--font-family, sans-serif);
1472
+ }
1473
+ input {
1474
+ width: 100%;
1475
+ box-sizing: border-box;
1476
+ padding: 0.625rem 0.75rem;
1477
+ font-size: 1rem;
1478
+ font-family: inherit;
1479
+ color: var(--color-black, #000);
1480
+ background: var(--color-white, #fff);
1481
+ border: 1px solid var(--color-gray-4, #ccc);
1482
+ border-bottom: 3px solid var(--color-red, #b90100);
1483
+ border-radius: 2px;
1484
+ }
1485
+ input:focus {
1486
+ outline: 2px solid var(--color-red, #b90100);
1487
+ outline-offset: -1px;
1488
+ }
1489
+ ul {
1490
+ position: absolute;
1491
+ z-index: 10;
1492
+ left: 0;
1493
+ right: 0;
1494
+ margin: 0;
1495
+ padding: 0;
1496
+ list-style: none;
1497
+ max-height: 20rem;
1498
+ overflow-y: auto;
1499
+ background: var(--color-white, #fff);
1500
+ border: 1px solid var(--color-gray-4, #ccc);
1501
+ border-top: none;
1502
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
1503
+ }
1504
+ li {
1505
+ padding: 0.5rem 0.75rem;
1506
+ cursor: pointer;
1507
+ }
1508
+ li[aria-selected="true"], li:hover {
1509
+ background: var(--color-gray-1, #f9f9f9);
1510
+ }
1511
+ li .name {
1512
+ font-weight: 700;
1513
+ color: var(--color-black, #000);
1514
+ }
1515
+ li .where {
1516
+ display: block;
1517
+ font-size: 0.8rem;
1518
+ color: var(--color-gray-5, #666);
1519
+ }
1520
+ li.empty {
1521
+ cursor: default;
1522
+ color: var(--color-gray-5, #666);
1523
+ }
1524
+ li.empty:hover {
1525
+ background: none;
1526
+ }
1527
+ `;
1528
+ constructor() {
1529
+ 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;
1530
+ }
1531
+ disconnectedCallback() {
1532
+ super.disconnectedCallback(), clearTimeout(this.debounceTimer), this.abortController?.abort();
1533
+ }
1534
+ onInput(e) {
1535
+ const t = e.target.value.trim();
1536
+ if (clearTimeout(this.debounceTimer), t.length < Oe) {
1537
+ this.abortController?.abort(), this.results = [], this.open = !1, this.searched = !1;
1538
+ return;
1539
+ }
1540
+ this.debounceTimer = setTimeout(() => this.search(t), Ne);
1541
+ }
1542
+ async search(e) {
1543
+ this.abortController?.abort(), this.abortController = new AbortController();
1544
+ try {
1545
+ const t = `${this.api}/schools?q=${encodeURIComponent(e)}&limit=${this.limit}`, s = await fetch(t, {
1546
+ signal: this.abortController.signal
1547
+ });
1548
+ if (!s.ok)
1549
+ return;
1550
+ const r = await s.json();
1551
+ this.results = r.items || [], this.activeIndex = -1, this.searched = !0, this.open = !0;
1552
+ } catch (t) {
1553
+ t.name !== "AbortError" && console.warn("school search failed", t);
1554
+ }
1555
+ }
1556
+ onKeyDown(e) {
1557
+ if (e.key === "Escape") {
1558
+ this.open = !1;
1559
+ return;
1560
+ }
1561
+ if (!(!this.open || !this.results.length))
1562
+ if (e.key === "ArrowDown")
1563
+ e.preventDefault(), this.activeIndex = (this.activeIndex + 1) % this.results.length;
1564
+ else if (e.key === "ArrowUp") {
1565
+ e.preventDefault();
1566
+ const t = this.results.length;
1567
+ this.activeIndex = (this.activeIndex - 1 + t) % t;
1568
+ } else e.key === "Enter" && (e.preventDefault(), this.go(this.results[this.activeIndex] || this.results[0]));
1569
+ }
1570
+ onBlur() {
1571
+ setTimeout(() => {
1572
+ this.open = !1;
1573
+ }, 150);
1574
+ }
1575
+ onFocus() {
1576
+ this.results.length && (this.open = !0);
1577
+ }
1578
+ go(e) {
1579
+ e && (globalThis.location.href = this.schoolHref.replace("{id}", e.id));
1580
+ }
1581
+ where(e) {
1582
+ return [e.location, e.county && `${e.county} County`].filter(Boolean).join(" — ");
1583
+ }
1584
+ renderOption(e, t) {
1585
+ const s = this.where(e), r = (o) => {
1586
+ o.preventDefault(), this.go(e);
1587
+ };
1588
+ return i`
1589
+ <li
1590
+ id="school-option-${t}"
1591
+ role="option"
1592
+ aria-selected="${t === this.activeIndex ? "true" : "false"}"
1593
+ @pointerdown="${r}"
1594
+ @mousemove="${() => {
1595
+ this.activeIndex = t;
1596
+ }}"
1597
+ >
1598
+ <span class="name">${e.name}</span>
1599
+ ${s ? i`<span class="where">${s}</span>` : p}
1600
+ </li>
1601
+ `;
1602
+ }
1603
+ renderListbox() {
1604
+ const e = this.searched && !this.results.length, t = i`<li class="empty">No schools found</li>`;
1605
+ return i`
1606
+ <ul id="school-search-listbox" role="listbox" aria-label="Schools">
1607
+ ${this.results.map((s, r) => this.renderOption(s, r))}
1608
+ ${e ? t : p}
1609
+ </ul>
1610
+ `;
1611
+ }
1612
+ render() {
1613
+ const e = this.activeIndex >= 0 ? `school-option-${this.activeIndex}` : "";
1614
+ return i`
1615
+ <input
1616
+ type="text"
1617
+ role="combobox"
1618
+ aria-label="Find your school"
1619
+ aria-expanded="${this.open ? "true" : "false"}"
1620
+ aria-controls="school-search-listbox"
1621
+ aria-activedescendant="${e}"
1622
+ autocomplete="off"
1623
+ placeholder="${this.placeholder}"
1624
+ @input="${this.onInput}"
1625
+ @keydown="${this.onKeyDown}"
1626
+ @blur="${this.onBlur}"
1627
+ @focus="${this.onFocus}"
1628
+ >
1629
+ ${this.open ? this.renderListbox() : p}
1630
+ `;
1631
+ }
1632
+ }
1633
+ globalThis?.customElements && !globalThis.customElements.get("hsot-school-search") && globalThis.customElements.define("hsot-school-search", He);
1393
1634
  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,
1635
+ H as D,
1636
+ Le as H,
1637
+ Fe as a,
1638
+ Be as b,
1639
+ He as c,
1640
+ Se as d,
1641
+ Ce as e,
1642
+ z as f,
1643
+ ce as g,
1644
+ u as h,
1645
+ q as i,
1646
+ Me as j,
1647
+ N as k,
1648
+ Te as p,
1407
1649
  w as r,
1408
- J as s,
1409
- ee as t
1650
+ re as s,
1651
+ V as t
1410
1652
  };