@wral/hsot-data 0.2.0 → 0.4.0

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,122 +1,85 @@
1
- import { LitElement as ie, html as n, css as $, nothing as p, svg as J } from "lit";
2
- const ye = 50;
3
- function $e(a = {}) {
4
- const e = Object.entries(a).filter(([, s]) => s != null && s !== "");
5
- if (!e.length) return "";
6
- const t = new URLSearchParams();
7
- return e.forEach(([s, o]) => t.set(s, String(o))), `?${t.toString()}`;
8
- }
9
- function we({ baseUrl: a, token: e = "", fetchFn: t } = {}) {
10
- if (!a) throw new Error("createClient requires a baseUrl");
11
- const s = a.replace(/\/+$/, ""), o = t || ((...i) => fetch(...i));
12
- async function r(i) {
13
- const h = { Accept: "application/json" };
14
- e && (h.Authorization = `Bearer ${e}`);
15
- const c = await o(`${s}${i}`, { headers: h });
16
- if (!c.ok) {
17
- const d = new Error(`api-hsot ${c.status} on ${i}`);
18
- throw d.status = c.status, d;
19
- }
20
- return c.json();
21
- }
22
- async function l(i, h = {}) {
23
- const c = [];
24
- let d = null;
25
- for (let m = 0; m < ye; m += 1) {
26
- const f = $e(d ? { ...h, cursor: d } : h), u = await r(`${i}${f}`);
27
- if (c.push(...u.items || []), d = u.nextCursor || null, !d) break;
28
- }
29
- return { items: c, total: c.length, nextCursor: null };
30
- }
31
- return {
32
- listSchools: (i) => l("/schools", i),
33
- getSchool: (i) => r(`/schools/${i}`),
34
- listTeams: (i) => l("/teams", i),
35
- getTeam: (i) => r(`/teams/${i}`),
36
- listConferences: (i) => l("/conferences", i),
37
- listPlayers: (i) => l("/players", i),
38
- listRosters: (i) => l("/rosters", i),
39
- listGames: (i) => l("/games", i),
40
- getGame: (i) => r(`/games/${i}`),
41
- listTournaments: (i) => l("/tournaments", i),
42
- listSeedings: (i, h) => l(`/tournaments/${i}/seedings`, h),
43
- listEdges: (i, h) => l(`/tournaments/${i}/edges`, h),
44
- listRankings: (i) => l("/rankings", i),
45
- listSports: () => r("/sports")
46
- };
47
- }
48
- const j = {
1
+ import { LitElement as le, html as n, css as w, nothing as p, svg as ee } from "lit";
2
+ import { createClient as ke } from "./client.mjs";
3
+ const E = {
49
4
  game: "/{sport}/game/{id}/",
50
5
  school: "/school/{id}/",
51
- section: "/{sport}/{view}/"
6
+ section: "/{sport}/{view}/",
7
+ // The "Report a Score" page; {id} is the game being reported on, and
8
+ // reportHref() drops the parameter when there is none.
9
+ report: "/report-a-score/?game={id}"
52
10
  };
53
11
  function g(a, e) {
54
12
  return String(a).replace(/\{(\w+)\}/g, (t, s) => e[s] !== void 0 && e[s] !== null ? String(e[s]) : t);
55
13
  }
56
14
  function z(a) {
57
15
  return {
58
- game: a.getAttribute("game-href") || j.game,
59
- school: a.getAttribute("school-href") || j.school,
60
- section: a.getAttribute("section-href") || j.section
16
+ game: a.getAttribute("game-href") || E.game,
17
+ school: a.getAttribute("school-href") || E.school,
18
+ section: a.getAttribute("section-href") || E.section,
19
+ report: a.getAttribute("report-href") || E.report
61
20
  };
62
21
  }
63
- const B = (a) => a ? a.charAt(0).toUpperCase() + a.slice(1) : "";
64
- function w(a, e) {
22
+ function ce(a, e = "") {
23
+ const t = g(a.report || E.report, { id: e || "" });
24
+ return e ? t : t.replace(/([?&])game=(?=&|$)/, "$1").replace(/[?&]$/, "").replace(/\?&/, "?");
25
+ }
26
+ const k = (a) => a ? a.charAt(0).toUpperCase() + a.slice(1) : "";
27
+ function x(a, e) {
65
28
  if (!a) return "TBD";
66
- const [t, s, o] = String(a).split("-").map(Number);
67
- return !t || !s || !o ? "TBD" : new Date(t, s - 1, o).toLocaleDateString("en-US", e || { weekday: "short", month: "short", day: "numeric" });
29
+ const [t, s, r] = String(a).split("-").map(Number);
30
+ return !t || !s || !r ? "TBD" : new Date(t, s - 1, r).toLocaleDateString("en-US", e || { weekday: "short", month: "short", day: "numeric" });
68
31
  }
69
- function q(a) {
32
+ function W(a) {
70
33
  if (!a) return "";
71
34
  const [e, t] = String(a).split(":").map(Number);
72
35
  if (Number.isNaN(e)) return "";
73
36
  const s = e >= 12 ? "PM" : "AM";
74
37
  return `${(e + 11) % 12 + 1}:${String(t || 0).padStart(2, "0")} ${s}`;
75
38
  }
76
- function xe(a) {
39
+ function Se(a) {
77
40
  return a ? `${Math.floor(a / 12)}-${a % 12}` : "·";
78
41
  }
79
- function ke(a) {
42
+ function Ie(a) {
80
43
  return (Array.isArray(a?.positions) ? a.positions : String(a?.position ?? "").split(/[/,]/)).map((t) => String(t ?? "").trim()).filter(Boolean).join("/");
81
44
  }
82
- function E(a = /* @__PURE__ */ new Date()) {
45
+ function _(a = /* @__PURE__ */ new Date()) {
83
46
  const e = a.getFullYear();
84
47
  return a.getMonth() >= 6 ? `${e}-${e + 1}` : `${e - 1}-${e}`;
85
48
  }
86
- function W(a = /* @__PURE__ */ new Date()) {
49
+ function V(a = /* @__PURE__ */ new Date()) {
87
50
  const e = (t) => String(t).padStart(2, "0");
88
51
  return `${a.getFullYear()}-${e(a.getMonth() + 1)}-${e(a.getDate())}`;
89
52
  }
90
- function Se(a, e = W()) {
53
+ function Te(a, e = V()) {
91
54
  const t = [...new Set((a || []).filter(Boolean))].sort();
92
55
  if (!t.length || t.includes(e)) return e;
93
- const s = t.filter((o) => o < e);
56
+ const s = t.filter((r) => r < e);
94
57
  return s.length ? s[s.length - 1] : t[0];
95
58
  }
96
- function V(a) {
59
+ function Y(a) {
97
60
  return a ? (a.abbr || a.name || "?").slice(0, 4).toUpperCase() : "?";
98
61
  }
99
- function N(a) {
62
+ function G(a) {
100
63
  if (!a || !/^#[0-9a-fA-F]{6}$/.test(a)) return "#FFFFFF";
101
- const e = parseInt(a.slice(1), 16), t = e >> 16 & 255, s = e >> 8 & 255, o = e & 255;
102
- return 0.299 * t + 0.587 * s + 0.114 * o > 150 ? "#0F1B33" : "#FFFFFF";
64
+ const e = parseInt(a.slice(1), 16), t = e >> 16 & 255, s = e >> 8 & 255, r = e & 255;
65
+ return 0.299 * t + 0.587 * s + 0.114 * r > 150 ? "#0F1B33" : "#FFFFFF";
103
66
  }
104
- const Ie = (a) => {
67
+ const Ce = (a) => {
105
68
  const e = ["th", "st", "nd", "rd"], t = a % 100;
106
69
  return a + (e[(t - 20) % 10] || e[t] || e[0]);
107
70
  };
108
- function ee(a, e) {
109
- const t = (r) => {
110
- const l = /^\d+/.exec(String(r ?? ""));
111
- return l ? Number(l[0]) : null;
112
- }, s = t(a), o = t(e);
113
- return s !== null && o !== null && s !== o ? o - s : s !== null && o === null ? -1 : s === null && o !== null ? 1 : String(a ?? "").localeCompare(String(e ?? ""), "en", { sensitivity: "base" });
114
- }
115
- function Te(a, e) {
71
+ function te(a, e) {
72
+ const t = (o) => {
73
+ const i = /^\d+/.exec(String(o ?? ""));
74
+ return i ? Number(i[0]) : null;
75
+ }, s = t(a), r = t(e);
76
+ return s !== null && r !== null && s !== r ? r - s : s !== null && r === null ? -1 : s === null && r !== null ? 1 : String(a ?? "").localeCompare(String(e ?? ""), "en", { sensitivity: "base" });
77
+ }
78
+ function De(a, e) {
116
79
  const t = (s) => String(s?.name ?? s ?? "");
117
80
  return t(a).localeCompare(t(e), "en", { numeric: !0, sensitivity: "base" });
118
81
  }
119
- function le(a) {
82
+ function de(a) {
120
83
  if (a.state === "live") {
121
84
  const e = [a.period, a.clock].filter(Boolean).join(" ");
122
85
  return { kind: "live", label: e ? `Live · ${e}` : "Live" };
@@ -125,54 +88,65 @@ function le(a) {
125
88
  const e = [];
126
89
  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(" · ")}` : ""}` };
127
90
  }
128
- return a.state === "postponed" ? { kind: "warn", label: "Postponed" } : a.state === "canceled" ? { kind: "warn", label: "Canceled" } : { kind: "sched", label: `${w(a.date, { month: "short", day: "numeric" })} · ${q(a.time)}`.replace(/ · $/, "") };
91
+ return a.state === "postponed" ? { kind: "warn", label: "Postponed" } : a.state === "canceled" ? { kind: "warn", label: "Canceled" } : { kind: "sched", label: `${x(a.date, { month: "short", day: "numeric" })} · ${W(a.time)}`.replace(/ · $/, "") };
92
+ }
93
+ const Be = ["boys", "girls"];
94
+ function he(a, e) {
95
+ return e ? a ? a.gender === e || a.gender === "coed" : !1 : !0;
129
96
  }
130
- const Ce = /* @__PURE__ */ new Set(["game", "story", "page", "forum", "video", "gallery"]);
131
- function S(a) {
97
+ function me(a, e) {
98
+ return e ? (a || []).filter((t) => he(t, e)) : a || [];
99
+ }
100
+ function q(a) {
101
+ const e = new Set((a || []).map((t) => t && t.gender));
102
+ return Be.filter((t) => e.has(t));
103
+ }
104
+ const Fe = (a) => q(a).length === 2, ze = /* @__PURE__ */ new Set(["game", "story", "page", "forum", "video", "gallery"]);
105
+ function I(a) {
132
106
  let e = String(a || "").replace(/^[a-z][a-z0-9+.-]*:\/\/[^/#?]*/i, "");
133
107
  const t = e.indexOf("#");
134
108
  let s = "";
135
109
  t !== -1 && (s = e.slice(t).split("?")[0], e = e.slice(0, t));
136
- let o = e.split("?")[0] + s;
137
- return o = o.replace(/([^:])\/{2,}/g, "$1/").replace(/^\/{2,}/, "/"), o = o.replace(/^\/(?=#)/, ""), o.length > 1 && (o = o.replace(/\/+$/, "")), o.toLowerCase();
110
+ let r = e.split("?")[0] + s;
111
+ return r = r.replace(/([^:])\/{2,}/g, "$1/").replace(/^\/{2,}/, "/"), r = r.replace(/^\/(?=#)/, ""), r.length > 1 && (r = r.replace(/\/+$/, "")), r.toLowerCase();
138
112
  }
139
- function ce() {
113
+ function pe() {
140
114
  const a = globalThis.location;
141
115
  if (!a) return "";
142
116
  const e = (a.hash || "").startsWith("#/") ? a.hash : "";
143
- return S((a.pathname || "") + e);
117
+ return I((a.pathname || "") + e);
144
118
  }
145
- function De(a, e, t) {
119
+ function Pe(a, e, t) {
146
120
  if (!t) return null;
147
- const s = S(a);
121
+ const s = I(a);
148
122
  if (!s) return null;
149
- const o = S(g(e.game, { sport: t, id: "" })), r = S(g(e.school, { id: "" }));
150
- if (s === o || s.startsWith(`${o}/`) || s === r || s.startsWith(`${r}/`)) return null;
151
- const l = S(g(e.section, { sport: t, view: "" }));
152
- if (s === l) return "";
153
- if (!s.startsWith(`${l}/`)) return null;
154
- const i = s.slice(l.length + 1), h = i.split("/");
155
- return h.length > 2 || h.some((c) => !/^[a-z][a-z-]*$/.test(c)) || Ce.has(h[0]) ? null : i;
156
- }
157
- function Be(a, e, t) {
158
- const s = (l) => g(t.section, { sport: a, view: l }).replace(/([^:])\/{2,}/g, "$1/"), r = new Set((e || []).map((l) => l && l.gender).filter((l) => l === "boys" || l === "girls")).size === 2 ? [
123
+ const r = I(g(e.game, { sport: t, id: "" })), o = I(g(e.school, { id: "" }));
124
+ if (s === r || s.startsWith(`${r}/`) || s === o || s.startsWith(`${o}/`)) return null;
125
+ const i = I(g(e.section, { sport: t, view: "" }));
126
+ if (s === i) return "";
127
+ if (!s.startsWith(`${i}/`)) return null;
128
+ const d = s.slice(i.length + 1), h = d.split("/");
129
+ return h.length > 2 || h.some((l) => !/^[a-z][a-z-]*$/.test(l)) || ze.has(h[0]) ? null : d;
130
+ }
131
+ function Ee(a, e, t) {
132
+ const s = (o) => g(t.section, { sport: a, view: o }).replace(/([^:])\/{2,}/g, "$1/"), r = Fe(e) ? [
159
133
  { label: "Boys Standings", href: s("boys/standings") },
160
134
  { label: "Girls Standings", href: s("girls/standings") }
161
135
  ] : [{ label: "Standings", href: s("standings") }];
162
136
  return [
163
- { label: `${B(a)} Home`, href: s("") },
137
+ { label: `${k(a)} Home`, href: s("") },
164
138
  { label: "Scores/Schedule", href: s("scores") },
165
139
  { label: "Playoff Brackets", href: s("brackets") },
166
140
  ...r,
167
141
  { label: "Polls & Rankings", href: s("rankings") }
168
142
  ];
169
143
  }
170
- function Fe(a, e = ce()) {
171
- const t = S(e);
144
+ function Ae(a, e = pe()) {
145
+ const t = I(e);
172
146
  for (const s of a.querySelectorAll(':scope > a[slot="nav"]'))
173
- t && S(s.getAttribute("href")) === t ? s.setAttribute("aria-current", "page") : s.removeAttribute("aria-current");
147
+ t && I(s.getAttribute("href")) === t ? s.setAttribute("aria-current", "page") : s.removeAttribute("aria-current");
174
148
  }
175
- class y extends ie {
149
+ class $ extends le {
176
150
  static properties = {
177
151
  api: { type: String },
178
152
  refreshInterval: { type: Number, attribute: "refresh-interval" },
@@ -191,7 +165,7 @@ class y extends ie {
191
165
  this._client = e, this.isConnected && this.load();
192
166
  }
193
167
  get client() {
194
- return this._client ? this._client : this.api ? we({ baseUrl: this.api }) : null;
168
+ return this._client ? this._client : this.api ? ke({ baseUrl: this.api }) : null;
195
169
  }
196
170
  connectedCallback() {
197
171
  super.connectedCallback(), this._setupInterval();
@@ -203,7 +177,7 @@ class y extends ie {
203
177
  this.load();
204
178
  }
205
179
  updated(e) {
206
- e.has("api") && e.get("api") !== void 0 && e.get("api") !== this.api && this.load(), e.has("refreshInterval") && this._setupInterval(), Fe(this);
180
+ e.has("api") && e.get("api") !== void 0 && e.get("api") !== this.api && this.load(), e.has("refreshInterval") && this._setupInterval(), Ae(this);
207
181
  }
208
182
  async load() {
209
183
  const e = this.client;
@@ -238,7 +212,7 @@ class y extends ie {
238
212
  return n``;
239
213
  }
240
214
  }
241
- const b = (a) => Object.fromEntries((a || []).map((e) => [e.id, e])), ze = $`
215
+ const b = (a) => Object.fromEntries((a || []).map((e) => [e.id, e])), _e = w`
242
216
  :host {
243
217
  --hsot-red: var(--color-red, #D1232A);
244
218
  --hsot-red-deep: var(--color-red-dark, #951C21);
@@ -276,7 +250,7 @@ const b = (a) => Object.fromEntries((a || []).map((e) => [e.id, e])), ze = $`
276
250
  outline-offset: 1px;
277
251
  }
278
252
  .mut { color: var(--hsot-gray-5); }
279
- `, Pe = $`
253
+ `, Ne = w`
280
254
  .band { background: var(--hsot-white); color: var(--hsot-black); }
281
255
  .band .inner { max-width: 1366px; margin: 0 auto; padding: 1.1rem 1.25rem 0; }
282
256
  .band h1, .band h2.bandtitle {
@@ -325,7 +299,7 @@ const b = (a) => Object.fromEntries((a || []).map((e) => [e.id, e])), ze = $`
325
299
  @media (max-width: 720px) {
326
300
  .band h1, .band h2.bandtitle, .band.section h1, .band.section h2.bandtitle { font-size: 1.8rem; }
327
301
  }
328
- `, Ae = $`
302
+ `, Re = w`
329
303
  .view { max-width: 1366px; margin: 0 auto; padding: 1.25rem; box-sizing: border-box; }
330
304
  /* Optional right rail (slot="rail" light-DOM children): a divided 300px
331
305
  column on desktop, stacked under the view content on smaller screens. */
@@ -389,7 +363,7 @@ const b = (a) => Object.fromEntries((a || []).map((e) => [e.id, e])), ze = $`
389
363
  .error { padding: 1.2rem 1rem; color: var(--hsot-red-deep); font-size: 0.9rem; }
390
364
  .note { font-size: 0.8125rem; color: var(--hsot-gray-5); margin: 0.6rem 0 0; }
391
365
  .loading { padding: 1.2rem; color: var(--hsot-gray-5); font-family: var(--hsot-heading-font); }
392
- `, Ee = $`
366
+ `, Ge = w`
393
367
  .pill {
394
368
  display: inline-block; font-family: var(--hsot-heading-font); font-weight: 700;
395
369
  font-size: 0.6875rem; text-transform: uppercase; letter-spacing: 0.04em;
@@ -404,7 +378,7 @@ const b = (a) => Object.fromEntries((a || []).map((e) => [e.id, e])), ze = $`
404
378
  .pill.champ { background: var(--hsot-straw); color: #6b5900; }
405
379
  @keyframes hsot-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.55; } }
406
380
  @media (prefers-reduced-motion: reduce) { .pill.live { animation: none; } }
407
- `, _e = $`
381
+ `, Me = w`
408
382
  .tablewrap { overflow-x: auto; }
409
383
  table.data { font-family: var(--hsot-heading-font); font-size: 14px; border-collapse: collapse; width: 100%; }
410
384
  table.data th {
@@ -422,7 +396,7 @@ const b = (a) => Object.fromEntries((a || []).map((e) => [e.id, e])), ze = $`
422
396
  table.data tbody tr.rowlink:hover { background: var(--hsot-gray-1); }
423
397
  table.data td.teamcell a { color: inherit; text-decoration: none; font-weight: 500; }
424
398
  table.data td.teamcell a:hover { text-decoration: underline; }
425
- `, Re = $`
399
+ `, Le = w`
426
400
  .swatch {
427
401
  display: inline-flex; align-items: center; justify-content: center;
428
402
  width: 26px; height: 26px; border-radius: 50%;
@@ -446,7 +420,7 @@ const b = (a) => Object.fromEntries((a || []).map((e) => [e.id, e])), ze = $`
446
420
  .dot.W { background: var(--hsot-win); }
447
421
  .dot.L { background: var(--hsot-loss); }
448
422
  .dot.T { background: var(--hsot-tie); }
449
- `, Ne = $`
423
+ `, Oe = w`
450
424
  ul.gamelist { list-style: none; margin: 0; padding: 0; }
451
425
  .gamelist li {
452
426
  display: flex; align-items: center; gap: 0.7rem; padding: 0.55rem 1rem;
@@ -496,183 +470,183 @@ const b = (a) => Object.fromEntries((a || []).map((e) => [e.id, e])), ze = $`
496
470
  .gamelist .ff { color: var(--hsot-gray-5); font-size: 0.78rem; font-style: italic; }
497
471
  .gamelist .where { color: var(--hsot-gray-5); font-size: 0.78rem; }
498
472
  .gamelist a.box { font-size: 0.78rem; }
499
- `, P = [ze, Pe, Ae, Ee, _e, Re, Ne];
500
- function O(a) {
473
+ `, P = [_e, Ne, Re, Ge, Me, Le, Oe];
474
+ function H(a) {
501
475
  return a.state !== "final" ? null : a.forfeit === "home" ? "away" : a.forfeit === "away" || a.homeScore > a.awayScore ? "home" : a.awayScore > a.homeScore ? "away" : a.tiebreakWinner && a.tiebreakWinner !== "none" ? a.tiebreakWinner : "tie";
502
476
  }
503
- function Me(a) {
477
+ function He(a) {
504
478
  return a && (a.forfeit === "home" || a.forfeit === "away") ? a.forfeit : null;
505
479
  }
506
- function _(a, e) {
507
- const t = {}, s = (r) => (t[r] = t[r] || { w: 0, l: 0, t: 0, cw: 0, cl: 0, ct: 0, pf: 0, pa: 0, results: [] }, t[r]), o = a.filter((r) => r.state === "final" && r.gameType !== "scrimmage" && (!e || r.date <= e)).sort((r, l) => String(r.date).localeCompare(String(l.date)));
508
- for (const r of o) {
509
- const l = O(r), i = r.gameType === "conference";
480
+ function N(a, e) {
481
+ 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, i) => String(o.date).localeCompare(String(i.date)));
482
+ for (const o of r) {
483
+ const i = H(o), d = o.gameType === "conference";
510
484
  for (const h of ["home", "away"]) {
511
- const c = h === "home" ? r.homeTeamId : r.awayTeamId;
512
- if (!c) continue;
513
- const d = s(c), m = h === "home" ? r.homeScore : r.awayScore, f = h === "home" ? r.awayScore : r.homeScore;
514
- d.pf += m, d.pa += f;
485
+ const l = h === "home" ? o.homeTeamId : o.awayTeamId;
486
+ if (!l) continue;
487
+ const c = s(l), m = h === "home" ? o.homeScore : o.awayScore, f = h === "home" ? o.awayScore : o.homeScore;
488
+ c.pf += m, c.pa += f;
515
489
  let u = "T";
516
- l === "tie" ? (d.t += 1, i && (d.ct += 1)) : l === h ? (d.w += 1, i && (d.cw += 1), u = "W") : (d.l += 1, i && (d.cl += 1), u = "L"), d.results.push({ gameId: r.id, date: r.date, mark: u, my: m, their: f, opp: h === "home" ? r.awayTeamId : r.homeTeamId, conf: i });
490
+ i === "tie" ? (c.t += 1, d && (c.ct += 1)) : i === h ? (c.w += 1, d && (c.cw += 1), u = "W") : (c.l += 1, d && (c.cl += 1), u = "L"), c.results.push({ gameId: o.id, date: o.date, mark: u, my: m, their: f, opp: h === "home" ? o.awayTeamId : o.homeTeamId, conf: d });
517
491
  }
518
492
  }
519
493
  return t;
520
494
  }
521
- function H(a) {
495
+ function U(a) {
522
496
  if (!a || !a.length) return "";
523
497
  const e = a[a.length - 1].mark;
524
498
  let t = 0;
525
499
  for (let s = a.length - 1; s >= 0 && a[s].mark === e; s -= 1) t += 1;
526
500
  return e + t;
527
501
  }
528
- const te = (a, e, t) => {
502
+ const se = (a, e, t) => {
529
503
  const s = a + e + t;
530
504
  return s ? (a + t / 2) / s : 0;
531
- }, se = (a) => a.toFixed(3).replace("0.", ".");
532
- function k(a, e = !1) {
505
+ }, ae = (a) => a.toFixed(3).replace("0.", ".");
506
+ function S(a, e = !1) {
533
507
  if (!a) return "0-0";
534
- const t = e ? a.cw : a.w, s = e ? a.cl : a.l, o = e ? a.ct : a.t;
535
- return `${t}-${s}${o ? `-${o}` : ""}`;
508
+ const t = e ? a.cw : a.w, s = e ? a.cl : a.l, r = e ? a.ct : a.t;
509
+ return `${t}-${s}${r ? `-${r}` : ""}`;
536
510
  }
537
- function de(a, e) {
511
+ function fe(a, e) {
538
512
  return a.map((t) => {
539
513
  const s = e[t.id] || { w: 0, l: 0, t: 0, cw: 0, cl: 0, ct: 0, pf: 0, pa: 0, results: [] };
540
- return { team: t, rec: s, confPct: te(s.cw, s.cl, s.ct), overallPct: te(s.w, s.l, s.t) };
514
+ return { team: t, rec: s, confPct: se(s.cw, s.cl, s.ct), overallPct: se(s.w, s.l, s.t) };
541
515
  }).sort((t, s) => s.confPct - t.confPct || s.overallPct - t.overallPct || s.rec.pf - s.rec.pa - (t.rec.pf - t.rec.pa));
542
516
  }
543
- function Y(a, e) {
517
+ function K(a, e) {
544
518
  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;
545
519
  }
546
- function ae(a, e) {
520
+ function re(a, e) {
547
521
  const t = a[e];
548
522
  return t && t.results.length ? t.results[t.results.length - 1] : null;
549
523
  }
550
- function $t(a, e, t, s = "") {
551
- let o = null;
552
- for (const r of a || [])
553
- r.sport === e && (t && r.effectiveDate > t || s && r.gender && r.gender !== s || (!o || r.effectiveDate > o.effectiveDate) && (o = r));
554
- return o;
524
+ function It(a, e, t, s = "") {
525
+ let r = null;
526
+ for (const o of a || [])
527
+ o.sport === e && (t && o.effectiveDate > t || s && o.gender && o.gender !== s || (!r || o.effectiveDate > r.effectiveDate) && (r = o));
528
+ return r;
555
529
  }
556
- function Q(a, e, t, s, o) {
557
- const r = e[t];
558
- if (!r) return null;
559
- const l = /* @__PURE__ */ new Map();
530
+ function Q(a, e, t, s, r) {
531
+ const o = e[t];
532
+ if (!o) return null;
533
+ const i = /* @__PURE__ */ new Map();
560
534
  for (const h of a || []) {
561
- if (h.sport !== s || o && h.effectiveDate > o || h.gender && r.gender !== h.gender && r.gender !== "coed") continue;
562
- const c = h.gender || "", d = l.get(c);
563
- (!d || h.effectiveDate > d.effectiveDate) && l.set(c, h);
535
+ if (h.sport !== s || r && h.effectiveDate > r || h.gender && o.gender !== h.gender && o.gender !== "coed") continue;
536
+ const l = h.gender || "", c = i.get(l);
537
+ (!c || h.effectiveDate > c.effectiveDate) && i.set(l, h);
564
538
  }
565
- let i = null;
566
- for (const h of l.values()) {
567
- const c = (h.teamIds || []).indexOf(t);
568
- c !== -1 && (!i || h.effectiveDate > i.effectiveDate) && (i = { poll: h, rank: c + 1 });
539
+ let d = null;
540
+ for (const h of i.values()) {
541
+ const l = (h.teamIds || []).indexOf(t);
542
+ l !== -1 && (!d || h.effectiveDate > d.effectiveDate) && (d = { poll: h, rank: l + 1 });
569
543
  }
570
- return i ? i.rank : null;
544
+ return d ? d.rank : null;
571
545
  }
572
- function Le(a, e, t) {
546
+ function Ue(a, e, t) {
573
547
  if (!a) return { kind: "none", delta: 0 };
574
548
  const s = (a.teamIds || []).indexOf(t) + 1;
575
549
  if (!s) return { kind: "none", delta: 0 };
576
550
  if (!e) return { kind: "same", delta: 0 };
577
- const o = (e.teamIds || []).indexOf(t) + 1;
578
- if (!o) return { kind: "new", delta: 0 };
579
- const r = o - s;
580
- return r > 0 ? { kind: "up", delta: r } : r < 0 ? { kind: "down", delta: -r } : { kind: "same", delta: 0 };
551
+ const r = (e.teamIds || []).indexOf(t) + 1;
552
+ if (!r) return { kind: "new", delta: 0 };
553
+ const o = r - s;
554
+ return o > 0 ? { kind: "up", delta: o } : o < 0 ? { kind: "down", delta: -o } : { kind: "same", delta: 0 };
581
555
  }
582
- function Ge(a) {
556
+ function je(a) {
583
557
  return /^https?:\/\//i.test(String(a || ""));
584
558
  }
585
- function he(a, { w: e, h: t } = {}) {
586
- if (!Ge(a)) return "";
559
+ function ue(a, { w: e, h: t } = {}) {
560
+ if (!je(a)) return "";
587
561
  const s = [];
588
562
  e && s.push(`w=${Math.max(1, Math.round(e))}`), t && s.push(`h=${Math.max(1, Math.round(t))}`), s.push("f=webp");
589
- const o = a.includes("?") ? "&" : "?";
590
- return `${a}${o}${s.join("&")}`;
563
+ const r = a.includes("?") ? "&" : "?";
564
+ return `${a}${r}${s.join("&")}`;
591
565
  }
592
566
  function M(a, e) {
593
567
  const t = e * 2;
594
- return he(a?.logoAssetId, { w: t, h: t });
568
+ return ue(a?.logoAssetId, { w: t, h: t });
595
569
  }
596
- function Oe(a, e) {
597
- return he(a?.photoAssetId, { w: e * 2 });
570
+ function qe(a, e) {
571
+ return ue(a?.photoAssetId, { w: e * 2 });
598
572
  }
599
- function U(a, e, { title: t, sub: s, teams: o }) {
600
- const r = ce(), i = !!a.querySelector(':scope > a[slot="nav"]') || De(r, e.hrefs, e.sport) !== null;
573
+ function j(a, e, { title: t, sub: s, teams: r }) {
574
+ const o = pe(), d = !!a.querySelector(':scope > a[slot="nav"]') || Pe(o, e.hrefs, e.sport) !== null;
601
575
  return n`
602
576
  <div class="band section">
603
577
  <div class="inner">
604
578
  <h1>${t}</h1>
605
579
  ${s ? n`<p class="sub">${s}</p>` : p}
606
580
  </div>
607
- ${i ? n`
608
- <nav class="sectionnav" aria-label="${B(e.sport)} section">
581
+ ${d ? n`
582
+ <nav class="sectionnav" aria-label="${k(e.sport)} section">
609
583
  <div class="navrow">
610
584
  <slot name="nav">
611
- ${Be(e.sport, o, e.hrefs).map((h) => n`<a href=${h.href}
612
- aria-current=${r && S(h.href) === r ? "page" : p}>${h.label}</a>`)}
585
+ ${Ee(e.sport, r, e.hrefs).map((h) => n`<a href=${h.href}
586
+ aria-current=${o && I(h.href) === o ? "page" : p}>${h.label}</a>`)}
613
587
  </slot>
614
588
  </div>
615
589
  </nav>` : p}
616
590
  </div>
617
591
  `;
618
592
  }
619
- const I = (a, e) => {
593
+ const T = (a, e) => {
620
594
  const t = a.teamsById[e];
621
595
  return t ? a.schoolsById[t.schoolId] : null;
622
- }, F = (a, e) => I(a, e)?.name || "TBD", L = (a, e) => I(a, e)?.abbr || "TBD";
623
- function T(a, e = 26) {
596
+ }, F = (a, e) => T(a, e)?.name || "TBD", L = (a, e) => T(a, e)?.abbr || "TBD";
597
+ function C(a, e = 26) {
624
598
  if (!a) return p;
625
599
  const t = M(a, e);
626
600
  if (t)
627
601
  return n`<img class="swatch logo" aria-hidden="true" alt="" loading="lazy"
628
602
  src=${t} style="width:${e}px;height:${e}px" />`;
629
- const s = a.colorPrimary || "#030711", o = N(s);
603
+ const s = a.colorPrimary || "#030711", r = G(s);
630
604
  return n`<span class="swatch" aria-hidden="true"
631
- style="width:${e}px;height:${e}px;background:${s};color:${o};font-size:${Math.max(8, e * 0.28)}px"
632
- >${V(a)}</span>`;
605
+ style="width:${e}px;height:${e}px;background:${s};color:${r};font-size:${Math.max(8, e * 0.28)}px"
606
+ >${Y(a)}</span>`;
633
607
  }
634
- function K(a, e, t) {
608
+ function X(a, e, t) {
635
609
  const s = Q(a.rankings, a.teamsById, e, a.sport, t);
636
610
  return s ? n`<span class="rankbadge">#${s}</span>` : p;
637
611
  }
638
- function G(a, e, t) {
639
- const s = I(a, e);
640
- return s ? n`${K(a, e, t)}<a href=${g(a.hrefs.school, { id: s.id })}>${s.name}</a>` : n`<span class="mut">TBD</span>`;
612
+ function O(a, e, t) {
613
+ const s = T(a, e);
614
+ return s ? n`${X(a, e, t)}<a href=${g(a.hrefs.school, { id: s.id })}>${s.name}</a>` : n`<span class="mut">TBD</span>`;
641
615
  }
642
- function X(a, e, t = 5) {
616
+ function Z(a, e, t = 5) {
643
617
  const s = a.records[e];
644
618
  if (!s || !s.results.length) return n`<span class="mut">·</span>`;
645
- const o = s.results.slice(-1 * t);
646
- return n`<span class="dots" role="img" aria-label="last ${o.length} results">
647
- ${o.map((r) => n`<a class="dot ${r.mark}"
648
- title="${r.mark} ${r.my}-${r.their} vs ${F(a, r.opp)}"
649
- href=${g(a.hrefs.game, { sport: a.sport, id: r.gameId })}>${r.mark}</a>`)}
619
+ const r = s.results.slice(-1 * t);
620
+ return n`<span class="dots" role="img" aria-label="last ${r.length} results">
621
+ ${r.map((o) => n`<a class="dot ${o.mark}"
622
+ title="${o.mark} ${o.my}-${o.their} vs ${F(a, o.opp)}"
623
+ href=${g(a.hrefs.game, { sport: a.sport, id: o.gameId })}>${o.mark}</a>`)}
650
624
  </span>`;
651
625
  }
652
- function C(a, e) {
626
+ function D(a, e) {
653
627
  return a.querySelector(':scope > [slot="rail"]') ? n`<div class="view withrail">
654
628
  <div class="viewmain">${e}</div>
655
629
  <aside class="viewrail"><slot name="rail"></slot></aside>
656
630
  </div>` : n`<div class="view">${e}</div>`;
657
631
  }
658
- function D(a) {
632
+ function B(a) {
659
633
  if (!a.promoImage) return p;
660
634
  const e = n`<img src=${a.promoImage} alt=${a.promoAlt || "Sponsor"}>`;
661
635
  return n`<div class="promo">${a.promoHref ? n`<a href=${a.promoHref} target="_blank" rel="sponsored noopener">${e}</a>` : e}</div>`;
662
636
  }
663
637
  function A(a) {
664
- const e = le(a);
638
+ const e = de(a);
665
639
  return n`<span class="pill ${e.kind}">${e.label}</span>`;
666
640
  }
667
- function me(a, e, t) {
641
+ function ge(a, e, t) {
668
642
  if (!e) return n`<span class="mut">·</span>`;
669
- const s = e.homeTeamId === t ? e.awayTeamId : e.homeTeamId, o = e.homeTeamId === t ? "vs" : "at";
670
- return n`${e.state === "live" ? n`<span class="pill live">Live</span> ` : n`${w(e.date, { month: "numeric", day: "numeric" })} `}${o} ${L(a, s)}`;
643
+ const s = e.homeTeamId === t ? e.awayTeamId : e.homeTeamId, r = e.homeTeamId === t ? "vs" : "at";
644
+ return n`${e.state === "live" ? n`<span class="pill live">Live</span> ` : n`${x(e.date, { month: "numeric", day: "numeric" })} `}${r} ${L(a, s)}`;
671
645
  }
672
- class He extends y {
646
+ class We extends $ {
673
647
  static styles = P;
674
648
  static properties = {
675
- ...y.properties,
649
+ ...$.properties,
676
650
  sport: { type: String },
677
651
  season: { type: String },
678
652
  date: { type: String }
@@ -688,57 +662,57 @@ class He extends y {
688
662
  this._datePinned = !!this.date;
689
663
  }
690
664
  async fetchData(e) {
691
- const t = this.season || E(), [s, o, r, l, i] = await Promise.all([
665
+ const t = this.season || _(), [s, r, o, i, d] = await Promise.all([
692
666
  e.listSchools(),
693
667
  e.listTeams({ sport: this.sport }),
694
668
  e.listConferences(),
695
669
  e.listGames({ sport: this.sport, season: t }),
696
670
  e.listRankings({ sport: this.sport })
697
671
  ]);
698
- return this._datePinned || (this.date = Se(l.items.map((h) => h.date)), this._datePinned = !0), {
672
+ return this._datePinned || (this.date = Te(i.items.map((h) => h.date)), this._datePinned = !0), {
699
673
  season: t,
700
674
  schools: s.items,
701
- teams: o.items,
702
- conferences: r.items,
703
- games: l.items,
704
- rankings: i.items
675
+ teams: r.items,
676
+ conferences: o.items,
677
+ games: i.items,
678
+ rankings: d.items
705
679
  };
706
680
  }
707
681
  get ctx() {
708
682
  return (!this._ctx || this._ctxData !== this.data) && (this._ctx = {
709
683
  teamsById: b(this.data.teams),
710
684
  schoolsById: b(this.data.schools),
711
- records: _(this.data.games),
685
+ records: N(this.data.games),
712
686
  rankings: this.data.rankings,
713
687
  hrefs: z(this),
714
688
  sport: this.sport
715
689
  }, this._ctxData = this.data), this._ctx;
716
690
  }
717
691
  renderView() {
718
- const e = this.ctx, t = b(this.data.conferences), s = [...new Set(this.data.games.map((c) => c.date).filter(Boolean))].sort(), o = Number.MAX_SAFE_INTEGER, r = (c) => {
719
- const d = [c.awayTeamId, c.homeTeamId].map((m) => Q(e.rankings, e.teamsById, m, this.sport, c.date)).filter(Boolean);
720
- return d.length ? Math.min(...d) : o;
721
- }, l = this.data.games.filter((c) => c.date === this.date), i = new Map(l.map((c) => [c, r(c)]));
722
- l.sort((c, d) => (c.state === "live" ? 0 : 1) - (d.state === "live" ? 0 : 1) || i.get(c) - i.get(d));
692
+ const e = this.ctx, t = b(this.data.conferences), s = [...new Set(this.data.games.map((l) => l.date).filter(Boolean))].sort(), r = Number.MAX_SAFE_INTEGER, o = (l) => {
693
+ const c = [l.awayTeamId, l.homeTeamId].map((m) => Q(e.rankings, e.teamsById, m, this.sport, l.date)).filter(Boolean);
694
+ return c.length ? Math.min(...c) : r;
695
+ }, i = this.data.games.filter((l) => l.date === this.date), d = new Map(i.map((l) => [l, o(l)]));
696
+ i.sort((l, c) => (l.state === "live" ? 0 : 1) - (c.state === "live" ? 0 : 1) || d.get(l) - d.get(c));
723
697
  const h = /* @__PURE__ */ new Map();
724
- return l.forEach((c) => {
725
- const d = c.gameType === "conference" && c.conferenceId ? t[c.conferenceId]?.name || "Conference" : c.gameType === "playoff" ? "Playoffs" : c.gameType === "scrimmage" ? "Scrimmages" : "Nonconference";
726
- h.has(d) || h.set(d, []), h.get(d).push(c);
698
+ return i.forEach((l) => {
699
+ const c = l.gameType === "conference" && l.conferenceId ? t[l.conferenceId]?.name || "Conference" : l.gameType === "playoff" ? "Playoffs" : l.gameType === "scrimmage" ? "Scrimmages" : "Nonconference";
700
+ h.has(c) || h.set(c, []), h.get(c).push(l);
727
701
  }), n`
728
- ${U(this, e, {
729
- title: n`${B(this.sport)} scores &amp; schedules`,
730
- sub: n`${w(this.date, { weekday: "long", month: "long", day: "numeric", year: "numeric" })} · ${l.length} games`,
702
+ ${j(this, e, {
703
+ title: n`${k(this.sport)} scores &amp; schedules`,
704
+ sub: n`${x(this.date, { weekday: "long", month: "long", day: "numeric", year: "numeric" })} · ${i.length} games`,
731
705
  teams: this.data.teams
732
706
  })}
733
- ${C(this, n`
734
- ${D(this)}
707
+ ${D(this, n`
708
+ ${B(this)}
735
709
  <div class="toolbar">
736
710
  <label class="asof" for="datesel">Date</label>
737
- <select id="datesel" @change=${(c) => {
738
- this.date = c.target.value;
711
+ <select id="datesel" @change=${(l) => {
712
+ this.date = l.target.value;
739
713
  }}>
740
- ${(s.includes(this.date) ? s : [...s, this.date].sort()).map((c) => n`<option value=${c} ?selected=${c === this.date}>
741
- ${w(c, { weekday: "short", month: "short", day: "numeric" })}${c === W() ? " · today" : ""}
714
+ ${(s.includes(this.date) ? s : [...s, this.date].sort()).map((l) => n`<option value=${l} ?selected=${l === this.date}>
715
+ ${x(l, { weekday: "short", month: "short", day: "numeric" })}${l === V() ? " · today" : ""}
742
716
  </option>`)}
743
717
  </select>
744
718
  <button class="chip" ?disabled=${s.indexOf(this.date) <= 0}
@@ -750,13 +724,13 @@ class He extends y {
750
724
  this.date = s[s.indexOf(this.date) + 1];
751
725
  }}>Next →</button>
752
726
  <span class="spacer"></span>
753
- <span class="asof">Live games first · report a score to see it update here</span>
727
+ <span class="asof">Live games first · <a href=${ce(e.hrefs)}>report a score</a> to see it update here</span>
754
728
  </div>
755
- ${l.length ? p : n`<p class="empty">No ${this.sport} games on this date.</p>`}
756
- ${[...h.entries()].map(([c, d]) => n`
757
- <div class="section-title">${c}</div>
729
+ ${i.length ? p : n`<p class="empty">No ${this.sport} games on this date.</p>`}
730
+ ${[...h.entries()].map(([l, c]) => n`
731
+ <div class="section-title">${l}</div>
758
732
  <div class="card"><ul class="gamelist">
759
- ${d.map((m) => this.renderGame(e, m))}
733
+ ${c.map((m) => this.renderGame(e, m))}
760
734
  </ul></div>
761
735
  `)}
762
736
  `)}
@@ -766,12 +740,12 @@ class He extends y {
766
740
  // a lone score column on the far right read as detached from the teams).
767
741
  // Scheduled games carry their start time on the status pill alone.
768
742
  renderGame(e, t) {
769
- const s = t.state === "final" || t.state === "live", o = (l, i, h = p) => n`<span class="side">${G(e, l, t.date)}${s ? n`<span class="score">${i}</span>` : p}${h}</span>`, r = Me(t);
743
+ const s = t.state === "final" || t.state === "live", r = (i, d, h = p) => n`<span class="side">${O(e, i, t.date)}${s ? n`<span class="score">${d}</span>` : p}${h}</span>`, o = He(t);
770
744
  return n`
771
745
  <li>
772
746
  ${A(t)}
773
- <span class="opp matchup">${o(t.awayTeamId, t.awayScore, n`<span class="at">at</span>`)}${o(t.homeTeamId, t.homeScore)}</span>
774
- ${r ? n`<span class="ff">${F(e, r === "home" ? t.homeTeamId : t.awayTeamId)} forfeited</span>` : p}
747
+ <span class="opp matchup">${r(t.awayTeamId, t.awayScore, n`<span class="at">at</span>`)}${r(t.homeTeamId, t.homeScore)}</span>
748
+ ${o ? n`<span class="ff">${F(e, o === "home" ? t.homeTeamId : t.awayTeamId)} forfeited</span>` : p}
775
749
  <span class="where">${t.venue || ""}</span>
776
750
  ${t.broadcast ? n`<span class="pill class">${t.broadcast}</span>` : p}
777
751
  <a class="box" href=${g(e.hrefs.game, { sport: this.sport, id: t.id })}>Box score →</a>
@@ -779,84 +753,116 @@ class He extends y {
779
753
  `;
780
754
  }
781
755
  }
782
- globalThis?.customElements && !globalThis.customElements.get("hsot-scores") && globalThis.customElements.define("hsot-scores", He);
783
- class Ue extends y {
756
+ globalThis?.customElements && !globalThis.customElements.get("hsot-scores") && globalThis.customElements.define("hsot-scores", We);
757
+ class Ve extends $ {
784
758
  static styles = P;
785
759
  static properties = {
786
- ...y.properties,
760
+ ...$.properties,
787
761
  sport: { type: String },
762
+ gender: { type: String },
788
763
  season: { type: String },
789
764
  classFilter: { state: !0 },
790
- query: { state: !0 }
765
+ query: { state: !0 },
766
+ pickedGender: { state: !0 }
791
767
  };
792
768
  constructor() {
793
- super(), this.sport = "football", this.season = "", this.classFilter = "All", this.query = "";
769
+ super(), this.sport = "football", this.gender = "", this.season = "", this.classFilter = "All", this.query = "", this.pickedGender = "";
770
+ }
771
+ /**
772
+ * The side the table shows: the pinned `gender`, else the reader's pick,
773
+ * else the first side fielded. '' only for a sport with one side, where
774
+ * there is nothing to scope.
775
+ */
776
+ get viewGender() {
777
+ if (this.gender) return this.gender;
778
+ const e = q(this.data?.teams);
779
+ return e.length < 2 ? "" : e.includes(this.pickedGender) ? this.pickedGender : e[0];
794
780
  }
795
781
  async fetchData(e) {
796
- const t = this.season || E(), [s, o, r, l, i] = await Promise.all([
782
+ const t = this.season || _(), [s, r, o, i, d] = await Promise.all([
797
783
  e.listConferences({ active: !0 }),
798
784
  e.listSchools(),
785
+ // Deliberately NOT gender-filtered: the sub-nav decides whether to
786
+ // offer Boys/Girls standings from the sides the sport fields, so it
787
+ // needs the whole sport. The table filters below.
799
788
  e.listTeams({ sport: this.sport }),
789
+ // Games carry no gender (it lives on the team they are played by),
790
+ // so this stays the sport's season. Records key off team ids, and a
791
+ // team only appears in its own side's games.
800
792
  e.listGames({ sport: this.sport, season: t }),
801
- e.listRankings({ sport: this.sport })
793
+ e.listRankings({ sport: this.sport, ...this.gender ? { gender: this.gender } : {} })
802
794
  ]);
803
795
  return {
804
796
  season: t,
805
797
  conferences: s.items,
806
- schools: o.items,
807
- teams: r.items,
808
- games: l.items,
809
- rankings: i.items
798
+ schools: r.items,
799
+ teams: o.items,
800
+ games: i.items,
801
+ rankings: d.items
810
802
  };
811
803
  }
812
804
  get ctx() {
813
- return (!this._ctx || this._ctxData !== this.data) && (this._ctx = {
805
+ return (!this._ctx || this._ctxData !== this.data || this._ctxGender !== this.viewGender) && (this._ctx = {
814
806
  teamsById: b(this.data.teams),
815
807
  schoolsById: b(this.data.schools),
816
- records: _(this.data.games),
808
+ records: N(this.data.games),
817
809
  rankings: this.data.rankings,
818
810
  hrefs: z(this),
819
- sport: this.sport
820
- }, this._ctxData = this.data), this._ctx;
811
+ sport: this.sport,
812
+ // The teams this view stands for — one side of a gendered
813
+ // sport, or all of them when the sport fields only one.
814
+ teams: me(this.data.teams, this.viewGender)
815
+ }, this._ctxData = this.data, this._ctxGender = this.viewGender), this._ctx;
821
816
  }
822
817
  renderView() {
823
- const e = this.ctx, t = ["All", ...[...new Set(this.data.conferences.flatMap((o) => o.classifications || []))].sort(ee)].slice(0, 9), s = this.data.conferences.filter((o) => o.active !== !1).filter((o) => this.classFilter === "All" || (o.classifications || []).includes(this.classFilter)).sort(Te);
818
+ const e = this.ctx, t = this.viewGender, s = this.gender ? [] : q(this.data.teams), r = ["All", ...[...new Set(this.data.conferences.flatMap((i) => i.classifications || []))].sort(te)].slice(0, 9), o = this.data.conferences.filter((i) => i.active !== !1).filter((i) => this.classFilter === "All" || (i.classifications || []).includes(this.classFilter)).sort(De);
824
819
  return n`
825
- ${U(this, e, {
826
- title: n`${B(this.sport)} standings`,
820
+ ${j(this, e, {
821
+ title: n`${t ? `${k(t)} ` : ""}${k(this.sport)} standings`,
827
822
  sub: n`${this.data.season} season · every conference, computed live from reported results`,
823
+ // The WHOLE sport, not this view's side: the sub-nav offers the
824
+ // Boys/Girls split only when both are fielded, and a
825
+ // gender-scoped list would always look like one side.
828
826
  teams: this.data.teams
829
827
  })}
830
- ${C(this, n`
831
- ${D(this)}
828
+ ${D(this, n`
829
+ ${B(this)}
832
830
  <div class="toolbar">
831
+ ${s.length === 2 ? n`
832
+ <div role="group" aria-label="Boys or girls standings">
833
+ ${s.map((i) => n`<button class="chip ${t === i ? "on" : ""}"
834
+ aria-pressed=${t === i ? "true" : "false"}
835
+ @click=${() => {
836
+ this.pickedGender = i;
837
+ }}>${k(i)}</button>`)}
838
+ </div>` : p}
833
839
  <div role="group" aria-label="Classification filter">
834
- ${t.map((o) => n`<button class="chip ${this.classFilter === o ? "on" : ""}"
840
+ ${r.map((i) => n`<button class="chip ${this.classFilter === i ? "on" : ""}"
835
841
  @click=${() => {
836
- this.classFilter = o;
837
- }}>${o}</button>`)}
842
+ this.classFilter = i;
843
+ }}>${i}</button>`)}
838
844
  </div>
839
845
  <input type="search" placeholder="Find a school…" aria-label="Find a school"
840
- .value=${this.query} @input=${(o) => {
841
- this.query = o.target.value;
846
+ .value=${this.query} @input=${(i) => {
847
+ this.query = i.target.value;
842
848
  }}>
843
849
  <span class="spacer"></span>
844
- <span class="asof">Records through ${w(W(), { month: "long", day: "numeric" })} · conference games count toward both records · scrimmages toward neither</span>
850
+ <span class="asof">Records through ${x(V(), { month: "long", day: "numeric" })} · conference games count toward both records · scrimmages toward neither</span>
845
851
  </div>
846
- ${s.map((o) => this.renderConference(e, o))}
852
+ ${o.map((i) => this.renderConference(e, i))}
847
853
  `)}
848
854
  `;
849
855
  }
850
856
  renderConference(e, t) {
851
- const s = this.data.teams.filter((l) => l.conferenceId === t.id);
857
+ const s = e.teams.filter((i) => i.conferenceId === t.id);
852
858
  if (!s.length) return p;
853
- const o = this.query.trim().toLowerCase(), r = de(s, e.records);
859
+ const r = this.query.trim().toLowerCase(), o = fe(s, e.records);
854
860
  return n`
855
861
  <div class="card">
856
862
  <div class="card-head">
857
863
  <h2>${t.name}</h2>
858
- ${[...t.classifications || []].sort(ee).map((l) => n`<span class="pill class">${l}</span>`)}
859
- <span class="meta">${r.length} teams · membership derives from teams</span>
864
+ ${[...t.classifications || []].sort(te).map((i) => n`<span class="pill class">${i}</span>`)}
865
+ <span class="meta">${o.length} teams · membership derives from teams</span>
860
866
  </div>
861
867
  <div class="tablewrap"><table class="data">
862
868
  <thead><tr>
@@ -865,43 +871,43 @@ class Ue extends y {
865
871
  <th>Streak</th><th>Last 5</th><th>Next</th>
866
872
  </tr></thead>
867
873
  <tbody>
868
- ${r.map((l, i) => this.renderRow(e, l, i, o))}
874
+ ${o.map((i, d) => this.renderRow(e, i, d, r))}
869
875
  </tbody>
870
876
  </table></div>
871
877
  </div>
872
878
  `;
873
879
  }
874
- renderRow(e, t, s, o) {
875
- const r = e.schoolsById[t.team.schoolId], l = r?.name || t.team.name || "TBD";
876
- if (o && !l.toLowerCase().includes(o)) return p;
877
- const i = t.rec.pf - t.rec.pa, h = Y(this.data.games, t.team.id), c = () => {
880
+ renderRow(e, t, s, r) {
881
+ const o = e.schoolsById[t.team.schoolId], i = o?.name || t.team.name || "TBD";
882
+ if (r && !i.toLowerCase().includes(r)) return p;
883
+ const d = t.rec.pf - t.rec.pa, h = K(this.data.games, t.team.id), l = () => {
878
884
  location.href = g(e.hrefs.school, { id: t.team.schoolId });
879
885
  };
880
886
  return n`
881
- <tr class="rowlink" @click=${(d) => {
882
- d.target.closest("a") || c();
887
+ <tr class="rowlink" @click=${(c) => {
888
+ c.target.closest("a") || l();
883
889
  }}>
884
890
  <td class="mut">${s + 1}</td>
885
891
  <td class="teamcell">
886
- ${T(r)}${K(e, t.team.id, null)}
887
- <a href=${g(e.hrefs.school, { id: t.team.schoolId })}>${l}</a>
892
+ ${C(o)}${X(e, t.team.id, null)}
893
+ <a href=${g(e.hrefs.school, { id: t.team.schoolId })}>${i}</a>
888
894
  </td>
889
- <td class="num">${k(t.rec, !0)}</td>
890
- <td class="num">${se(t.confPct)}</td>
891
- <td class="num">${k(t.rec)}</td>
892
- <td class="num">${se(t.overallPct)}</td>
895
+ <td class="num">${S(t.rec, !0)}</td>
896
+ <td class="num">${ae(t.confPct)}</td>
897
+ <td class="num">${S(t.rec)}</td>
898
+ <td class="num">${ae(t.overallPct)}</td>
893
899
  <td class="num">${t.rec.pf}</td>
894
900
  <td class="num">${t.rec.pa}</td>
895
- <td class="num" style="color:${i >= 0 ? "var(--hsot-win)" : "var(--hsot-loss)"}">${i > 0 ? "+" : ""}${i}</td>
896
- <td>${H(t.rec.results) || "·"}</td>
897
- <td>${X(e, t.team.id)}</td>
898
- <td>${me(e, h, t.team.id)}</td>
901
+ <td class="num" style="color:${d >= 0 ? "var(--hsot-win)" : "var(--hsot-loss)"}">${d > 0 ? "+" : ""}${d}</td>
902
+ <td>${U(t.rec.results) || "·"}</td>
903
+ <td>${Z(e, t.team.id)}</td>
904
+ <td>${ge(e, h, t.team.id)}</td>
899
905
  </tr>
900
906
  `;
901
907
  }
902
908
  }
903
- globalThis?.customElements && !globalThis.customElements.get("hsot-standings") && globalThis.customElements.define("hsot-standings", Ue);
904
- const je = $`
909
+ globalThis?.customElements && !globalThis.customElements.get("hsot-standings") && globalThis.customElements.define("hsot-standings", Ve);
910
+ const Ye = w`
905
911
  .hero1 {
906
912
  border-radius: var(--hsot-radius-md); color: var(--hsot-white);
907
913
  padding: 1.3rem 1.4rem; display: flex; align-items: center; gap: 1.2rem;
@@ -918,10 +924,10 @@ const je = $`
918
924
  .delta.new { background: var(--hsot-straw); color: #6b5900; border-radius: var(--hsot-radius-xs); padding: 0.1rem 0.3rem; font-size: 0.7rem; }
919
925
  .sparkline { vertical-align: middle; }
920
926
  `;
921
- class qe extends y {
922
- static styles = [...P, je];
927
+ class Ke extends $ {
928
+ static styles = [...P, Ye];
923
929
  static properties = {
924
- ...y.properties,
930
+ ...$.properties,
925
931
  sport: { type: String },
926
932
  gender: { type: String },
927
933
  season: { type: String },
@@ -936,73 +942,73 @@ class qe extends y {
936
942
  e && (this.pollDate = e);
937
943
  }
938
944
  async fetchData(e) {
939
- const t = this.season || E(), [s, o, r, l, i] = await Promise.all([
945
+ const t = this.season || _(), [s, r, o, i, d] = await Promise.all([
940
946
  e.listRankings({ sport: this.sport, ...this.gender ? { gender: this.gender } : {} }),
941
947
  e.listSchools(),
942
948
  e.listTeams({ sport: this.sport }),
943
949
  e.listConferences(),
944
950
  e.listGames({ sport: this.sport, season: t })
945
- ]), h = s.items.filter((c) => !this.gender || !c.gender || c.gender === this.gender).sort((c, d) => d.effectiveDate.localeCompare(c.effectiveDate));
951
+ ]), h = s.items.filter((l) => !this.gender || !l.gender || l.gender === this.gender).sort((l, c) => c.effectiveDate.localeCompare(l.effectiveDate));
946
952
  return {
947
953
  season: t,
948
954
  polls: h,
949
- schools: o.items,
950
- teams: r.items,
951
- conferences: l.items,
952
- games: i.items
955
+ schools: r.items,
956
+ teams: o.items,
957
+ conferences: i.items,
958
+ games: d.items
953
959
  };
954
960
  }
955
961
  get ctx() {
956
962
  return (!this._ctx || this._ctxData !== this.data) && (this._ctx = {
957
963
  teamsById: b(this.data.teams),
958
964
  schoolsById: b(this.data.schools),
959
- records: _(this.data.games),
965
+ records: N(this.data.games),
960
966
  rankings: this.data.polls,
961
967
  hrefs: z(this),
962
968
  sport: this.sport
963
969
  }, this._ctxData = this.data), this._ctx;
964
970
  }
965
971
  sparkline(e, t, s) {
966
- const i = t.map((m, f) => {
972
+ const d = t.map((m, f) => {
967
973
  const u = (m.teamIds || []).indexOf(e);
968
974
  if (u === -1) return null;
969
- const v = t.length === 1 ? 96 / 2 : f / (t.length - 1) * 90 + 3, x = 3 + u / 24 * 20;
970
- return { x: v, y: x };
975
+ const y = t.length === 1 ? 96 / 2 : f / (t.length - 1) * 90 + 3, v = 3 + u / 24 * 20;
976
+ return { x: y, y: v };
971
977
  }), h = [];
972
- let c = [];
973
- if (i.forEach((m) => {
974
- m ? c.push(m) : c.length && (h.push(c), c = []);
975
- }), c.length && h.push(c), !h.length) return p;
976
- const d = i[s];
978
+ let l = [];
979
+ if (d.forEach((m) => {
980
+ m ? l.push(m) : l.length && (h.push(l), l = []);
981
+ }), l.length && h.push(l), !h.length) return p;
982
+ const c = d[s];
977
983
  return n`<svg class="sparkline" width=${96} height=${26} viewBox="0 0 ${96} ${26}" role="img" aria-label="rank history">
978
- ${h.map((m) => J`<polyline fill="none" stroke="var(--hsot-red)" stroke-width="2"
984
+ ${h.map((m) => ee`<polyline fill="none" stroke="var(--hsot-red)" stroke-width="2"
979
985
  points=${m.map((f) => `${f.x.toFixed(1)},${f.y.toFixed(1)}`).join(" ")}></polyline>`)}
980
- ${d ? J`<circle cx=${d.x.toFixed(1)} cy=${d.y.toFixed(1)} r="3" fill="var(--hsot-black)"></circle>` : p}
986
+ ${c ? ee`<circle cx=${c.x.toFixed(1)} cy=${c.y.toFixed(1)} r="3" fill="var(--hsot-black)"></circle>` : p}
981
987
  </svg>`;
982
988
  }
983
989
  movement(e, t, s) {
984
- const o = Le(e, t, s);
985
- return o.kind === "up" ? n`<span class="delta up">▲ ${o.delta}</span>` : o.kind === "down" ? n`<span class="delta down">▼ ${o.delta}</span>` : o.kind === "new" ? n`<span class="delta new">NEW</span>` : o.kind === "same" ? n`<span class="delta same">—</span>` : n`<span class="delta same">·</span>`;
990
+ const r = Ue(e, t, s);
991
+ return r.kind === "up" ? n`<span class="delta up">▲ ${r.delta}</span>` : r.kind === "down" ? n`<span class="delta down">▼ ${r.delta}</span>` : r.kind === "new" ? n`<span class="delta new">NEW</span>` : r.kind === "same" ? n`<span class="delta same">—</span>` : n`<span class="delta same">·</span>`;
986
992
  }
987
993
  renderView() {
988
994
  const e = this.ctx, t = this.data.polls;
989
995
  if (!t.length) return n`<div class="view"><p class="empty">No ${this.sport} polls published yet this season.</p></div>`;
990
- const s = Math.max(0, t.findIndex((m) => m.effectiveDate === this.pollDate)), o = t[s] || t[0], r = t[s + 1] || null, l = t.slice().reverse(), i = l.indexOf(o), h = b(this.data.conferences), c = (o.teamIds || [])[0], d = c ? I(e, c) : null;
996
+ const s = Math.max(0, t.findIndex((m) => m.effectiveDate === this.pollDate)), r = t[s] || t[0], o = t[s + 1] || null, i = t.slice().reverse(), d = i.indexOf(r), h = b(this.data.conferences), l = (r.teamIds || [])[0], c = l ? T(e, l) : null;
991
997
  return n`
992
- ${U(this, e, {
993
- title: n`${B(this.sport)} Top 25`,
998
+ ${j(this, e, {
999
+ title: n`${k(this.sport)} Top 25`,
994
1000
  sub: n`The HighSchoolOT poll · updated weekly · ${t.length} polls this season`,
995
1001
  teams: this.data.teams
996
1002
  })}
997
- ${C(this, n`
998
- ${D(this)}
1003
+ ${D(this, n`
1004
+ ${B(this)}
999
1005
  <div class="toolbar">
1000
1006
  <label class="asof" for="pollsel">Poll of</label>
1001
1007
  <select id="pollsel" @change=${(m) => {
1002
1008
  this.pollDate = m.target.value;
1003
1009
  }}>
1004
- ${t.map((m, f) => n`<option value=${m.effectiveDate} ?selected=${m === o}>
1005
- ${w(m.effectiveDate, { month: "long", day: "numeric", year: "numeric" })}${f === 0 ? " · current" : ""}
1010
+ ${t.map((m, f) => n`<option value=${m.effectiveDate} ?selected=${m === r}>
1011
+ ${x(m.effectiveDate, { month: "long", day: "numeric", year: "numeric" })}${f === 0 ? " · current" : ""}
1006
1012
  </option>`)}
1007
1013
  </select>
1008
1014
  <button class="chip" ?disabled=${s >= t.length - 1}
@@ -1016,65 +1022,65 @@ class qe extends y {
1016
1022
  <span class="spacer"></span>
1017
1023
  <span class="asof">Movement vs. the previous poll · sparkline = season rank history</span>
1018
1024
  </div>
1019
- ${d ? this.renderHero(e, o, r, c, d, h) : p}
1025
+ ${c ? this.renderHero(e, r, o, l, c, h) : p}
1020
1026
  <div class="card"><div class="tablewrap"><table class="data">
1021
1027
  <thead><tr>
1022
1028
  <th class="num">Rk</th><th>Mvmt</th><th>Team</th><th class="num">Record</th>
1023
1029
  <th>Conference</th><th>Last result</th><th>Next</th><th>Season</th>
1024
1030
  </tr></thead>
1025
1031
  <tbody>
1026
- ${(o.teamIds || []).map((m, f) => f === 0 || !m ? p : this.renderRow(e, o, r, l, i, h, m, f + 1))}
1032
+ ${(r.teamIds || []).map((m, f) => f === 0 || !m ? p : this.renderRow(e, r, o, i, d, h, m, f + 1))}
1027
1033
  </tbody>
1028
1034
  </table></div></div>
1029
1035
  <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>
1030
1036
  `)}
1031
1037
  `;
1032
1038
  }
1033
- renderHero(e, t, s, o, r, l) {
1034
- const i = e.records[o], h = ae(e.records, o), c = l[e.teamsById[o]?.conferenceId], d = `linear-gradient(120deg, ${r.colorPrimary || "#030711"} 0%, var(--hsot-black) 85%)`;
1039
+ renderHero(e, t, s, r, o, i) {
1040
+ const d = e.records[r], h = re(e.records, r), l = i[e.teamsById[r]?.conferenceId], c = `linear-gradient(120deg, ${o.colorPrimary || "#030711"} 0%, var(--hsot-black) 85%)`;
1035
1041
  return n`
1036
- <div class="hero1" style="background:${d}">
1042
+ <div class="hero1" style="background:${c}">
1037
1043
  <div class="bigrank">#1</div>
1038
- ${T(r, 64)}
1044
+ ${C(o, 64)}
1039
1045
  <div>
1040
- <h2><a href=${g(e.hrefs.school, { id: r.id })}>${r.name} ${r.mascot || ""}</a></h2>
1046
+ <h2><a href=${g(e.hrefs.school, { id: o.id })}>${o.name} ${o.mascot || ""}</a></h2>
1041
1047
  <div class="facts">
1042
- ${k(i)} overall${c ? n` · ${k(i, !0)} ${c.name}` : p}
1043
- · streak ${H(i?.results) || "·"}
1048
+ ${S(d)} overall${l ? n` · ${S(d, !0)} ${l.name}` : p}
1049
+ · streak ${U(d?.results) || "·"}
1044
1050
  ${h ? n` · last: ${h.mark} ${h.my}-${h.their} vs ${L(e, h.opp)}` : p}
1045
- &nbsp;${this.movement(t, s, o)}
1051
+ &nbsp;${this.movement(t, s, r)}
1046
1052
  </div>
1047
1053
  </div>
1048
1054
  </div>
1049
1055
  `;
1050
1056
  }
1051
- renderRow(e, t, s, o, r, l, i, h) {
1052
- const c = I(e, i);
1053
- if (!c) return p;
1054
- const d = e.records[i], m = ae(e.records, i), f = Y(this.data.games, i), u = l[e.teamsById[i]?.conferenceId], v = () => {
1055
- location.href = g(e.hrefs.school, { id: c.id });
1057
+ renderRow(e, t, s, r, o, i, d, h) {
1058
+ const l = T(e, d);
1059
+ if (!l) return p;
1060
+ const c = e.records[d], m = re(e.records, d), f = K(this.data.games, d), u = i[e.teamsById[d]?.conferenceId], y = () => {
1061
+ location.href = g(e.hrefs.school, { id: l.id });
1056
1062
  };
1057
1063
  return n`
1058
- <tr class="rowlink" @click=${(x) => {
1059
- x.target.closest("a") || v();
1064
+ <tr class="rowlink" @click=${(v) => {
1065
+ v.target.closest("a") || y();
1060
1066
  }}>
1061
1067
  <td class="num" style="font-weight:700">${h}</td>
1062
- <td>${this.movement(t, s, i)}</td>
1063
- <td class="teamcell">${T(c)}<a href=${g(e.hrefs.school, { id: c.id })}>${c.name}</a>
1064
- <span class="mut" style="font-size:0.78rem">${c.mascot || ""}</span></td>
1065
- <td class="num">${k(d)}</td>
1068
+ <td>${this.movement(t, s, d)}</td>
1069
+ <td class="teamcell">${C(l)}<a href=${g(e.hrefs.school, { id: l.id })}>${l.name}</a>
1070
+ <span class="mut" style="font-size:0.78rem">${l.mascot || ""}</span></td>
1071
+ <td class="num">${S(c)}</td>
1066
1072
  <td class="mut">${u?.name || "Independent"}</td>
1067
1073
  <td>${m ? n`<a class="box" style="text-decoration:none" href=${g(e.hrefs.game, { sport: this.sport, id: m.gameId })}>
1068
1074
  <b style="color:${m.mark === "W" ? "var(--hsot-win)" : m.mark === "L" ? "var(--hsot-loss)" : "var(--hsot-tie)"}">${m.mark}</b>
1069
1075
  ${m.my}-${m.their} vs ${L(e, m.opp)}</a>` : n`<span class="mut">·</span>`}</td>
1070
- <td>${me(e, f, i)}</td>
1071
- <td>${this.sparkline(i, o, r)}</td>
1076
+ <td>${ge(e, f, d)}</td>
1077
+ <td>${this.sparkline(d, r, o)}</td>
1072
1078
  </tr>
1073
1079
  `;
1074
1080
  }
1075
1081
  }
1076
- globalThis?.customElements && !globalThis.customElements.get("hsot-rankings") && globalThis.customElements.define("hsot-rankings", qe);
1077
- const We = $`
1082
+ globalThis?.customElements && !globalThis.customElements.get("hsot-rankings") && globalThis.customElements.define("hsot-rankings", Ke);
1083
+ const Qe = w`
1078
1084
  .schoolhero { color: var(--hsot-white); padding: 1.6rem 1.25rem 1.3rem; }
1079
1085
  .schoolhero .inner { max-width: 1366px; margin: 0 auto; display: flex; gap: 1.2rem; align-items: center; flex-wrap: wrap; }
1080
1086
  .schoolhero .crest {
@@ -1128,77 +1134,83 @@ const We = $`
1128
1134
  table.data.roster .sub { display: block; font-weight: 400; font-size: 0.78rem; color: var(--hsot-gray-5); }
1129
1135
  }
1130
1136
  `;
1131
- class Ve extends y {
1132
- static styles = [...P, We];
1137
+ class Xe extends $ {
1138
+ static styles = [...P, Qe];
1133
1139
  static properties = {
1134
- ...y.properties,
1140
+ ...$.properties,
1135
1141
  schoolId: { type: String, attribute: "school-id" },
1136
1142
  sport: { type: String },
1143
+ gender: { type: String },
1137
1144
  season: { type: String },
1138
1145
  activeTeamId: { state: !0 }
1139
1146
  };
1140
1147
  constructor() {
1141
- super(), this.schoolId = "", this.sport = "", this.season = "", this.activeTeamId = "";
1148
+ super(), this.schoolId = "", this.sport = "", this.gender = "", this.season = "", this.activeTeamId = "";
1142
1149
  }
1143
1150
  connectedCallback() {
1144
1151
  super.connectedCallback();
1145
- const e = new URLSearchParams(globalThis.location?.search || "").get("sport");
1146
- e && !this.sport && (this.sport = e);
1152
+ const e = new URLSearchParams(globalThis.location?.search || ""), t = e.get("sport"), s = e.get("gender");
1153
+ t && !this.sport && (this.sport = t), s && !this.gender && (this.gender = s);
1147
1154
  }
1148
1155
  async fetchData(e) {
1149
- const t = this.season || E(), s = await e.getSchool(this.schoolId), r = (await e.listTeams({ schoolId: this.schoolId })).items, l = r.find((v) => v.sport === (this.sport || "football")) || r[0] || null, [i, h, c, d, m, f, u] = await Promise.all([
1150
- l ? e.listGames({ sport: l.sport, season: t }) : Promise.resolve({ items: [] }),
1151
- l ? e.listTeams({ sport: l.sport }) : Promise.resolve({ items: [] }),
1156
+ const t = this.season || _(), s = await e.getSchool(this.schoolId), o = (await e.listTeams({ schoolId: this.schoolId })).items, i = this.sport || "football", d = o.find((v) => v.id === this.activeTeamId) || o.find((v) => v.sport === i && he(v, this.gender)) || o.find((v) => v.sport === i) || o[0] || null, [h, l, c, m, f, u, y] = await Promise.all([
1157
+ d ? e.listGames({ sport: d.sport, season: t }) : Promise.resolve({ items: [] }),
1158
+ d ? e.listTeams({ sport: d.sport }) : Promise.resolve({ items: [] }),
1152
1159
  e.listSchools(),
1153
1160
  e.listConferences(),
1154
- l ? e.listRankings({ sport: l.sport }) : Promise.resolve({ items: [] }),
1155
- l ? e.listRosters({ teamId: l.id }) : Promise.resolve({ items: [] }),
1161
+ d ? e.listRankings({ sport: d.sport }) : Promise.resolve({ items: [] }),
1162
+ d ? e.listRosters({ teamId: d.id }) : Promise.resolve({ items: [] }),
1156
1163
  // teamId is the public surface's one players filter (roster
1157
1164
  // membership) — never fetch the whole collection.
1158
- l ? e.listPlayers({ teamId: l.id }) : Promise.resolve({ items: [] })
1165
+ d ? e.listPlayers({ teamId: d.id }) : Promise.resolve({ items: [] })
1159
1166
  ]);
1160
1167
  return {
1161
1168
  season: t,
1162
1169
  school: s,
1163
- teams: r,
1164
- active: l,
1165
- games: i.items,
1166
- allTeams: h.items,
1170
+ teams: o,
1171
+ active: d,
1172
+ games: h.items,
1173
+ allTeams: l.items,
1167
1174
  schools: c.items,
1168
- conferences: d.items,
1169
- rankings: m.items,
1170
- roster: f.items.find((v) => v.season === t) || null,
1171
- players: u.items
1175
+ conferences: m.items,
1176
+ rankings: f.items,
1177
+ roster: u.items.find((v) => v.season === t) || null,
1178
+ players: y.items
1172
1179
  };
1173
1180
  }
1174
1181
  get ctx() {
1175
1182
  return (!this._ctx || this._ctxData !== this.data) && (this._ctx = {
1176
1183
  teamsById: b(this.data.allTeams.length ? this.data.allTeams : this.data.teams),
1177
1184
  schoolsById: b(this.data.schools),
1178
- records: _(this.data.games),
1185
+ records: N(this.data.games),
1179
1186
  rankings: this.data.rankings,
1180
1187
  hrefs: z(this),
1181
1188
  sport: this.data.active?.sport || "football"
1182
1189
  }, this._ctxData = this.data), this._ctx;
1183
1190
  }
1184
- switchSport(e) {
1185
- this.sport = e, this.load();
1191
+ /**
1192
+ * Open a team's tab. The team id is what selects it — sport alone is
1193
+ * ambiguous on a gendered sport — with sport and gender kept in step so
1194
+ * the rest of the view and a shared ?sport=&gender= link agree with it.
1195
+ */
1196
+ switchTeam(e) {
1197
+ e && (this.activeTeamId = e.id, this.sport = e.sport, this.gender = e.gender || "", this.load());
1186
1198
  }
1187
1199
  renderView() {
1188
- const { school: e, teams: t, active: s, season: o } = this.data;
1200
+ const { school: e, teams: t, active: s, season: r } = this.data;
1189
1201
  if (!e) return n`<div class="view"><p class="empty">School not found.</p></div>`;
1190
- const r = this.ctx, l = N(e.colorPrimary || "#030711"), i = (e.adm || [])[0], h = b(this.data.conferences), c = s ? h[s.conferenceId] : null;
1202
+ const o = this.ctx, i = G(e.colorPrimary || "#030711"), d = (e.adm || [])[0], h = b(this.data.conferences), l = s ? h[s.conferenceId] : null;
1191
1203
  return n`
1192
- <div class="schoolhero" style="background:linear-gradient(115deg, ${e.colorPrimary || "#030711"} 0%, ${e.colorPrimary || "#030711"} 55%, var(--hsot-black) 100%);color:${l}">
1204
+ <div class="schoolhero" style="background:linear-gradient(115deg, ${e.colorPrimary || "#030711"} 0%, ${e.colorPrimary || "#030711"} 55%, var(--hsot-black) 100%);color:${i}">
1193
1205
  <div class="inner">
1194
- ${M(e, 84) ? n`<img class="crest logo" alt="" loading="lazy" src=${M(e, 84)} />` : n`<div class="crest" style="background:${e.colorSecondary || "#7C7C7C"};color:${N(e.colorSecondary || "#7C7C7C")}">${V(e)}</div>`}
1206
+ ${M(e, 84) ? n`<img class="crest logo" alt="" loading="lazy" src=${M(e, 84)} />` : n`<div class="crest" style="background:${e.colorSecondary || "#7C7C7C"};color:${G(e.colorSecondary || "#7C7C7C")}">${Y(e)}</div>`}
1195
1207
  <div style="min-width:260px">
1196
1208
  <h1>${e.name} <span class="mascot">${e.mascot || ""}</span></h1>
1197
1209
  <div class="facts">
1198
1210
  ${e.location ? n`<span><b>Location</b>${e.location}${e.county ? n` · ${e.county} County` : p}</span>` : p}
1199
1211
  ${e.association ? n`<span><b>League</b>${e.association}${e.classification ? n` · ${e.classification}` : p}</span>` : p}
1200
- ${c ? n`<span><b>Conference</b>${c.name}</span>` : p}
1201
- ${i ? n`<span><b>Enrollment</b>${i.value.toLocaleString()} (${i.season} ADM)</span>` : p}
1212
+ ${l ? n`<span><b>Conference</b>${l.name}</span>` : p}
1213
+ ${d ? n`<span><b>Enrollment</b>${d.value.toLocaleString()} (${d.season} ADM)</span>` : p}
1202
1214
  ${e.openingYear ? n`<span><b>Opened</b>${e.openingYear}</span>` : p}
1203
1215
  ${e.areaCode ? n`<span><b>Area</b>${e.areaCode}</span>` : p}
1204
1216
  </div>
@@ -1207,29 +1219,29 @@ class Ve extends y {
1207
1219
  </div>
1208
1220
  <div class="band">
1209
1221
  <nav class="tabs" aria-label="Teams">
1210
- ${t.map((d) => d.id === s?.id ? n`<a class="on" href="#" @click=${(m) => m.preventDefault()}>${d.name}</a>` : n`<a href="#" @click=${(m) => {
1211
- m.preventDefault(), this.switchSport(d.sport);
1212
- }}>${d.name}</a>`)}
1222
+ ${t.map((c) => c.id === s?.id ? n`<a class="on" href="#" aria-current="page" @click=${(m) => m.preventDefault()}>${c.name}</a>` : n`<a href="#" @click=${(m) => {
1223
+ m.preventDefault(), this.switchTeam(c);
1224
+ }}>${c.name}</a>`)}
1213
1225
  </nav>
1214
1226
  </div>
1215
- ${C(this, n`
1216
- ${D(this)}
1217
- ${s ? this.renderTeam(r, s, c, o) : n`<p class="empty">No teams recorded for this school yet.</p>`}
1227
+ ${D(this, n`
1228
+ ${B(this)}
1229
+ ${s ? this.renderTeam(o, s, l, r) : n`<p class="empty">No teams recorded for this school yet.</p>`}
1218
1230
  `)}
1219
1231
  `;
1220
1232
  }
1221
- renderTeam(e, t, s, o) {
1222
- const r = e.records[t.id] || { w: 0, l: 0, t: 0, cw: 0, cl: 0, ct: 0, pf: 0, pa: 0, results: [] }, l = r.w + r.l + r.t, i = s ? this.data.allTeams.filter((m) => m.conferenceId === s.id) : [], h = s ? de(i, e.records).findIndex((m) => m.team.id === t.id) + 1 : 0, c = Q(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)));
1233
+ renderTeam(e, t, s, r) {
1234
+ const o = e.records[t.id] || { w: 0, l: 0, t: 0, cw: 0, cl: 0, ct: 0, pf: 0, pa: 0, results: [] }, i = o.w + o.l + o.t, d = s ? me(this.data.allTeams.filter((m) => m.conferenceId === s.id), t.gender) : [], h = s ? fe(d, e.records).findIndex((m) => m.team.id === t.id) + 1 : 0, l = Q(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)));
1223
1235
  return n`
1224
1236
  <div class="tiles">
1225
- <div class="tile"><div class="k">Overall</div><div class="v">${k(r)}</div><div class="s">${l} games played</div></div>
1226
- <div class="tile"><div class="k">${s?.name || "Conference"}</div><div class="v">${k(r, !0)}</div>
1227
- <div class="s">${h ? `${Ie(h)} of ${i.length}` : "·"}</div></div>
1228
- <div class="tile"><div class="k">Points</div><div class="v">${l ? (r.pf / l).toFixed(1) : "0.0"}</div>
1229
- <div class="s">scored per game · ${l ? (r.pa / l).toFixed(1) : "0.0"} allowed</div></div>
1230
- <div class="tile"><div class="k">Streak</div><div class="v">${H(r.results) || "·"}</div>
1231
- <div class="s">last 5: ${X(e, t.id)}</div></div>
1232
- <div class="tile"><div class="k">HSOT Top 25</div><div class="v">${c ? `#${c}` : "NR"}</div>
1237
+ <div class="tile"><div class="k">Overall</div><div class="v">${S(o)}</div><div class="s">${i} games played</div></div>
1238
+ <div class="tile"><div class="k">${s?.name || "Conference"}</div><div class="v">${S(o, !0)}</div>
1239
+ <div class="s">${h ? `${Ce(h)} of ${d.length}` : "·"}</div></div>
1240
+ <div class="tile"><div class="k">Points</div><div class="v">${i ? (o.pf / i).toFixed(1) : "0.0"}</div>
1241
+ <div class="s">scored per game · ${i ? (o.pa / i).toFixed(1) : "0.0"} allowed</div></div>
1242
+ <div class="tile"><div class="k">Streak</div><div class="v">${U(o.results) || "·"}</div>
1243
+ <div class="s">last 5: ${Z(e, t.id)}</div></div>
1244
+ <div class="tile"><div class="k">HSOT Top 25</div><div class="v">${l ? `#${l}` : "NR"}</div>
1233
1245
  <div class="s"><a href=${g(e.hrefs.section, { sport: t.sport, view: "rankings" })}>full poll</a></div></div>
1234
1246
  </div>
1235
1247
  ${(t.championships || []).length ? n`
@@ -1240,31 +1252,31 @@ class Ve extends y {
1240
1252
  <div>
1241
1253
  <div class="section-title">Schedule &amp; results</div>
1242
1254
  <div class="card">
1243
- ${d.length ? n`<ul class="gamelist">${d.map((m) => this.renderGameRow(e, t, m))}</ul>` : n`<p class="empty">No ${t.sport} games recorded for ${o}.</p>`}
1255
+ ${c.length ? n`<ul class="gamelist">${c.map((m) => this.renderGameRow(e, t, m))}</ul>` : n`<p class="empty">No ${t.sport} games recorded for ${r}.</p>`}
1244
1256
  </div>
1245
1257
  </div>
1246
1258
  <div>
1247
- <div class="section-title">Roster · ${o}</div>
1248
- <div class="card">${this.renderRoster(t, o)}</div>
1259
+ <div class="section-title">Roster · ${r}</div>
1260
+ <div class="card">${this.renderRoster(t, r)}</div>
1249
1261
  </div>
1250
1262
  </div>
1251
1263
  `;
1252
1264
  }
1253
1265
  renderGameRow(e, t, s) {
1254
- const o = s.homeTeamId === t.id, r = o ? s.awayTeamId : s.homeTeamId, l = o ? s.homeScore : s.awayScore, i = o ? s.awayScore : s.homeScore;
1255
- let h = n`<span class="mut">${q(s.time)}</span>`;
1266
+ const r = s.homeTeamId === t.id, o = r ? s.awayTeamId : s.homeTeamId, i = r ? s.homeScore : s.awayScore, d = r ? s.awayScore : s.homeScore;
1267
+ let h = n`<span class="mut">${W(s.time)}</span>`;
1256
1268
  if (s.state === "final") {
1257
- const d = O(s), m = d === "tie" ? "T" : d === (o ? "home" : "away") ? "W" : "L";
1258
- h = n`<span class=${m}>${m}</span> ${l}-${i}${s.finish === "overtime" ? n` <span class="mut">OT</span>` : p}${s.forfeit && s.forfeit !== "none" ? n` <span class="mut">FF</span>` : p}`;
1259
- } else s.state === "live" && (h = n`<span style="color:var(--hsot-red)">${l}-${i}</span>`);
1260
- const c = s.gameType === "conference" ? "Conf" : s.gameType === "nonconference" ? "Non-conf" : s.gameType === "playoff" ? `Playoff${s.label ? ` · ${s.label}` : ""}` : "Scrimmage";
1269
+ const c = H(s), m = c === "tie" ? "T" : c === (r ? "home" : "away") ? "W" : "L";
1270
+ h = n`<span class=${m}>${m}</span> ${i}-${d}${s.finish === "overtime" ? n` <span class="mut">OT</span>` : p}${s.forfeit && s.forfeit !== "none" ? n` <span class="mut">FF</span>` : p}`;
1271
+ } else s.state === "live" && (h = n`<span style="color:var(--hsot-red)">${i}-${d}</span>`);
1272
+ const l = s.gameType === "conference" ? "Conf" : s.gameType === "nonconference" ? "Non-conf" : s.gameType === "playoff" ? `Playoff${s.label ? ` · ${s.label}` : ""}` : "Scrimmage";
1261
1273
  return n`
1262
1274
  <li>
1263
- <span class="d">${w(s.date)}</span>
1264
- ${le(s).kind === "sched" ? p : A(s)}
1275
+ <span class="d">${x(s.date)}</span>
1276
+ ${de(s).kind === "sched" ? p : A(s)}
1265
1277
  <span class="res">${h}</span>
1266
- <span class="opp">${o ? "vs" : "at"} ${G(e, r, s.date)}
1267
- <span class="pill type">${c}</span>
1278
+ <span class="opp">${r ? "vs" : "at"} ${O(e, o, s.date)}
1279
+ <span class="pill type">${l}</span>
1268
1280
  ${s.broadcast ? n`<span class="pill class">${s.broadcast}</span>` : p}
1269
1281
  </span>
1270
1282
  <span class="where">${s.venue || ""}</span>
@@ -1276,25 +1288,25 @@ class Ve extends y {
1276
1288
  const s = this.data.roster;
1277
1289
  if (!s)
1278
1290
  return n`<p class="empty">Roster not published for ${t}.</p>`;
1279
- const o = Oe(s, 560), r = this.data.school?.name || "", l = b(this.data.players), i = s.entries.slice().sort((c, d) => (c.number || 0) - (d.number || 0)), h = i.some((c) => l[c.playerId]?.college);
1291
+ const r = qe(s, 560), o = this.data.school?.name || "", i = b(this.data.players), d = s.entries.slice().sort((l, c) => (l.number || 0) - (c.number || 0)), h = d.some((l) => i[l.playerId]?.college);
1280
1292
  return n`
1281
- ${o ? n`<img class="rosterphoto" src=${o} loading="lazy" decoding="async"
1282
- alt="${r} ${e.name} ${t} team photo" />` : p}
1293
+ ${r ? n`<img class="rosterphoto" src=${r} loading="lazy" decoding="async"
1294
+ alt="${o} ${e.name} ${t} team photo" />` : p}
1283
1295
  <div class="tablewrap"><table class="data roster">
1284
1296
  <thead><tr><th class="num">No.</th><th>Player</th><th class="pos">Pos</th><th class="cls">Class</th><th class="num">Ht</th><th class="num">Wt</th>${h ? n`<th>College</th>` : p}</tr></thead>
1285
1297
  <tbody>
1286
- ${i.map((c) => {
1287
- const d = l[c.playerId];
1288
- if (!d) return p;
1289
- const m = ke(c), f = [m, d.classOf].filter(Boolean).join(" · ") || "·";
1298
+ ${d.map((l) => {
1299
+ const c = i[l.playerId];
1300
+ if (!c) return p;
1301
+ const m = Ie(l), f = [m, c.classOf].filter(Boolean).join(" · ") || "·";
1290
1302
  return n`<tr>
1291
- <td class="num mut">${c.number ?? "·"}</td>
1292
- <td class="player" style="font-weight:500">${d.firstName} ${d.lastName}<span class="sub">${f}</span></td>
1303
+ <td class="num mut">${l.number ?? "·"}</td>
1304
+ <td class="player" style="font-weight:500">${c.firstName} ${c.lastName}<span class="sub">${f}</span></td>
1293
1305
  <td class="pos">${m || "·"}</td>
1294
- <td class="cls mut">${d.classOf || "·"}</td>
1295
- <td class="num">${xe(d.heightIn)}</td>
1296
- <td class="num">${d.weightLb || "·"}</td>
1297
- ${h ? n`<td class="college">${d.college || "·"}</td>` : p}
1306
+ <td class="cls mut">${c.classOf || "·"}</td>
1307
+ <td class="num">${Se(c.heightIn)}</td>
1308
+ <td class="num">${c.weightLb || "·"}</td>
1309
+ ${h ? n`<td class="college">${c.college || "·"}</td>` : p}
1298
1310
  </tr>`;
1299
1311
  })}
1300
1312
  </tbody>
@@ -1302,8 +1314,8 @@ class Ve extends y {
1302
1314
  `;
1303
1315
  }
1304
1316
  }
1305
- globalThis?.customElements && !globalThis.customElements.get("hsot-school") && globalThis.customElements.define("hsot-school", Ve);
1306
- const pe = {
1317
+ globalThis?.customElements && !globalThis.customElements.get("hsot-school") && globalThis.customElements.define("hsot-school", Xe);
1318
+ const ve = {
1307
1319
  football: ["quarters", 4],
1308
1320
  flag_football: ["quarters", 4],
1309
1321
  basketball: ["quarters", 4],
@@ -1314,57 +1326,57 @@ const pe = {
1314
1326
  softball: ["innings", 7],
1315
1327
  volleyball: ["sets", 3]
1316
1328
  };
1317
- function fe(a) {
1318
- return (pe[a] || ["quarters", 4])[0];
1329
+ function be(a) {
1330
+ return (ve[a] || ["quarters", 4])[0];
1319
1331
  }
1320
- function Z(a) {
1321
- return (pe[a] || ["quarters", 4])[1];
1332
+ function J(a) {
1333
+ return (ve[a] || ["quarters", 4])[1];
1322
1334
  }
1323
- function Ye(a, e) {
1324
- const t = fe(a), s = Z(a);
1335
+ function Ze(a, e) {
1336
+ const t = be(a), s = J(a);
1325
1337
  if (e <= s || t === "innings" || t === "sets") return String(e);
1326
- const o = e - s;
1327
- return `OT${o > 1 ? o : ""}`;
1338
+ const r = e - s;
1339
+ return `OT${r > 1 ? r : ""}`;
1328
1340
  }
1329
- function Qe(a, e) {
1341
+ function Je(a, e) {
1330
1342
  const t = String(a ?? "").trim();
1331
1343
  let s;
1332
- return (s = /^(\d+)Q$/i.exec(t)) || (s = /^(\d+)H$/i.exec(t)) ? Number(s[1]) : /^half$/i.test(t) ? fe(e) === "halves" ? 1 : 2 : (s = /^(\d*)OT(\d*)$/i.exec(t)) ? Z(e) + Number(s[1] || s[2] || 1) : (s = /^[TB](\d+)$/i.exec(t)) || (s = /^(\d+)(?:st|nd|rd|th)\s*set$/i.exec(t)) || (s = /^set\s*(\d+)$/i.exec(t)) ? Number(s[1]) : null;
1344
+ return (s = /^(\d+)Q$/i.exec(t)) || (s = /^(\d+)H$/i.exec(t)) ? Number(s[1]) : /^half$/i.test(t) ? be(e) === "halves" ? 1 : 2 : (s = /^(\d*)OT(\d*)$/i.exec(t)) ? J(e) + Number(s[1] || s[2] || 1) : (s = /^[TB](\d+)$/i.exec(t)) || (s = /^(\d+)(?:st|nd|rd|th)\s*set$/i.exec(t)) || (s = /^set\s*(\d+)$/i.exec(t)) ? Number(s[1]) : null;
1333
1345
  }
1334
1346
  const R = (a) => Number.isInteger(a) && a >= 0 ? a : null;
1335
- function Ke(a) {
1347
+ function et(a) {
1336
1348
  const e = Array.isArray(a?.scoringPlays) ? a.scoringPlays : [];
1337
1349
  if (!e.length) return null;
1338
1350
  const t = a.sport, s = /* @__PURE__ */ new Map();
1339
1351
  for (const m of e) {
1340
- const f = Qe(m?.period, t), u = R(m?.homeScore), v = R(m?.awayScore);
1341
- if (!f || u === null || v === null) return null;
1342
- const x = s.get(f) || { home: 0, away: 0 };
1343
- x.home = Math.max(x.home, u), x.away = Math.max(x.away, v), s.set(f, x);
1352
+ const f = Je(m?.period, t), u = R(m?.homeScore), y = R(m?.awayScore);
1353
+ if (!f || u === null || y === null) return null;
1354
+ const v = s.get(f) || { home: 0, away: 0 };
1355
+ v.home = Math.max(v.home, u), v.away = Math.max(v.away, y), s.set(f, v);
1344
1356
  }
1345
- const o = Math.max(...s.keys()), r = [];
1346
- let l = !0, i = { home: 0, away: 0 };
1347
- for (let m = 1; m <= o; m += 1) {
1348
- const f = s.get(m) || i, u = f.home - i.home, v = f.away - i.away;
1349
- (u < 0 || v < 0) && (l = !1), r.push({ period: m, home: Math.max(u, 0), away: Math.max(v, 0) }), i = { home: Math.max(f.home, i.home), away: Math.max(f.away, i.away) };
1357
+ const r = Math.max(...s.keys()), o = [];
1358
+ let i = !0, d = { home: 0, away: 0 };
1359
+ for (let m = 1; m <= r; m += 1) {
1360
+ const f = s.get(m) || d, u = f.home - d.home, y = f.away - d.away;
1361
+ (u < 0 || y < 0) && (i = !1), o.push({ period: m, home: Math.max(u, 0), away: Math.max(y, 0) }), d = { home: Math.max(f.home, d.home), away: Math.max(f.away, d.away) };
1350
1362
  }
1351
- const h = R(a.homeScore) ?? 0, c = R(a.awayScore) ?? 0, d = l && i.home === h && i.away === c;
1352
- return l = l && i.home <= h && i.away <= c, { periods: r, reconciled: d, consistent: l };
1363
+ const h = R(a.homeScore) ?? 0, l = R(a.awayScore) ?? 0, c = i && d.home === h && d.away === l;
1364
+ return i = i && d.home <= h && d.away <= l, { periods: o, reconciled: c, consistent: i };
1353
1365
  }
1354
- function Xe(a) {
1366
+ function tt(a) {
1355
1367
  if (Array.isArray(a?.periodScores) && a.periodScores.length) return a.periodScores;
1356
- const e = Ke(a);
1368
+ const e = et(a);
1357
1369
  return e ? a.state === "final" ? e.reconciled ? e.periods : null : e.consistent ? e.periods : null : null;
1358
1370
  }
1359
- const Ze = "https://api.wral.com/search";
1360
- function Je(a) {
1371
+ const st = "https://api.wral.com/search";
1372
+ function at(a) {
1361
1373
  return a.map((e) => `uri:"${e}"`).join(" OR ");
1362
1374
  }
1363
- function et(a, e) {
1364
- const t = String(a || Ze).replace(/\/+$/, ""), s = new URLSearchParams({ query: Je(e), sort: "score", lang: "en" });
1375
+ function rt(a, e) {
1376
+ const t = String(a || st).replace(/\/+$/, ""), s = new URLSearchParams({ query: at(e), sort: "score", lang: "en" });
1365
1377
  return `${t}/v1/query?${s}`;
1366
1378
  }
1367
- function ue(a) {
1379
+ function ye(a) {
1368
1380
  try {
1369
1381
  const e = new URL(a);
1370
1382
  if (/(^|\.)smugmug\.com$/i.test(e.hostname)) {
@@ -1379,13 +1391,13 @@ function ue(a) {
1379
1391
  }
1380
1392
  return { uri: a, title: a };
1381
1393
  }
1382
- async function tt(a, e, t) {
1383
- const o = await ((...i) => fetch(...i))(et(a, e));
1384
- if (!o.ok) throw new Error(`search answered ${o.status}`);
1385
- const r = await o.json(), l = new Map((r.items || []).map((i) => [i.uri, i]));
1386
- return e.map((i) => l.get(i) || ue(i));
1394
+ async function ot(a, e, t) {
1395
+ const r = await ((...d) => fetch(...d))(rt(a, e));
1396
+ if (!r.ok) throw new Error(`search answered ${r.status}`);
1397
+ const o = await r.json(), i = new Map((o.items || []).map((d) => [d.uri, d]));
1398
+ return e.map((d) => i.get(d) || ye(d));
1387
1399
  }
1388
- const st = $`
1400
+ const nt = w`
1389
1401
  .breadcrumbs { font-size: 0.8125rem; margin: 0.9rem 0 0; color: var(--hsot-gray-5); }
1390
1402
  .breadcrumbs a { text-decoration: none; }
1391
1403
  .scorehead { display: grid; grid-template-columns: 1fr auto 1fr; gap: 1rem; align-items: center; padding: 1.4rem 1rem; }
@@ -1428,6 +1440,9 @@ const st = $`
1428
1440
  table.plays-table td.play { white-space: normal; min-width: 12rem; }
1429
1441
  /* Game notes are typed with line breaks the desk means to keep. */
1430
1442
  .gamenote { padding: 0 1rem 0.9rem; text-align: center; white-space: pre-line; }
1443
+ /* The embed's way out to everything it drops (Coverage, season context,
1444
+ head to head) — the data page still renders all of it. */
1445
+ .fullbox { margin: 0.9rem 0 0; text-align: center; font-size: 0.875rem; }
1431
1446
  .cols { display: grid; grid-template-columns: 1fr 1fr; gap: 1.25rem; }
1432
1447
  .ctxcard { padding: 0.85rem 1rem; }
1433
1448
  .ctxcard .who { font-family: var(--hsot-heading-font); font-weight: 700; margin-bottom: 0.4rem; }
@@ -1438,22 +1453,28 @@ const st = $`
1438
1453
  .cols { grid-template-columns: 1fr; }
1439
1454
  }
1440
1455
  `;
1441
- class at extends y {
1442
- static styles = [...P, st];
1456
+ class it extends $ {
1457
+ static styles = [...P, nt];
1443
1458
  static properties = {
1444
- ...y.properties,
1459
+ ...$.properties,
1445
1460
  gameId: { type: String, attribute: "game-id" },
1446
1461
  // The public site search that resolves Game.coverageUrls into cards
1447
1462
  // (DEV-1236). Shared cross-stage by design — see the studio host's
1448
1463
  // registry — so the prod default is right everywhere; the attribute
1449
1464
  // exists for the same reason the href templates do.
1450
- searchApi: { type: String, attribute: "search-api" }
1465
+ searchApi: { type: String, attribute: "search-api" },
1466
+ // Story pages embed the box score in the article column, where the page
1467
+ // chrome (breadcrumbs, the report-a-score line) and the cross-links
1468
+ // (Coverage, Season context, head-to-head) belong to the data page, not
1469
+ // the recap. `embed` keeps the score head, line score and scoring plays,
1470
+ // and links out to the full box score for the rest.
1471
+ embed: { type: Boolean }
1451
1472
  };
1452
1473
  constructor() {
1453
- super(), this.gameId = "", this.searchApi = "";
1474
+ super(), this.gameId = "", this.searchApi = "", this.embed = !1;
1454
1475
  }
1455
1476
  async fetchData(e) {
1456
- const t = await e.getGame(this.gameId), s = Array.isArray(t.coverageUrls) ? t.coverageUrls : [], [o, r, l, i, h, c] = await Promise.all([
1477
+ const t = await e.getGame(this.gameId), s = Array.isArray(t.coverageUrls) ? t.coverageUrls : [], [r, o, i, d, h, l] = await Promise.all([
1457
1478
  e.listSchools(),
1458
1479
  e.listTeams({ sport: t.sport }),
1459
1480
  e.listConferences(),
@@ -1461,23 +1482,25 @@ class at extends y {
1461
1482
  e.listGames({ sport: t.sport, season: t.season }),
1462
1483
  // A search outage must not blank the box score — degrade to bare
1463
1484
  // links (fetchCoverage already degrades per-URL index misses).
1464
- s.length ? tt(this.searchApi, s).catch(() => s.map(ue)) : Promise.resolve([])
1485
+ // The embed drops the Coverage grid, so it skips the search
1486
+ // round-trip entirely rather than fetching cards it will not render.
1487
+ s.length && !this.embed ? ot(this.searchApi, s).catch(() => s.map(ye)) : Promise.resolve([])
1465
1488
  ]);
1466
1489
  return {
1467
1490
  game: t,
1468
- schools: o.items,
1469
- teams: r.items,
1470
- conferences: l.items,
1471
- rankings: i.items,
1491
+ schools: r.items,
1492
+ teams: o.items,
1493
+ conferences: i.items,
1494
+ rankings: d.items,
1472
1495
  games: h.items,
1473
- coverage: c
1496
+ coverage: l
1474
1497
  };
1475
1498
  }
1476
1499
  get ctx() {
1477
1500
  return (!this._ctx || this._ctxData !== this.data) && (this._ctx = {
1478
1501
  teamsById: b(this.data.teams),
1479
1502
  schoolsById: b(this.data.schools),
1480
- records: _(this.data.games),
1503
+ records: N(this.data.games),
1481
1504
  rankings: this.data.rankings,
1482
1505
  hrefs: z(this),
1483
1506
  sport: this.data.game.sport
@@ -1486,50 +1509,59 @@ class at extends y {
1486
1509
  renderView() {
1487
1510
  const e = this.data.game;
1488
1511
  if (!e) return n`<div class="view"><p class="empty">Game not found.</p></div>`;
1489
- const t = this.ctx, s = b(this.data.conferences), o = t.teamsById[e.awayTeamId] ? t.schoolsById[t.teamsById[e.awayTeamId].schoolId] : null, r = t.teamsById[e.homeTeamId] ? t.schoolsById[t.teamsById[e.homeTeamId].schoolId] : null, l = O(e), i = (d) => e.state === "final" && l !== d && l !== "tie" ? "opacity:0.45" : "", h = e.conferenceId ? s[e.conferenceId] : null, c = 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));
1512
+ const t = this.ctx, s = b(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, i = H(e), d = (c) => e.state === "final" && i !== c && i !== "tie" ? "opacity:0.45" : "", h = e.conferenceId ? s[e.conferenceId] : null, l = 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));
1490
1513
  return n`
1491
- ${C(this, n`
1492
- ${D(this)}
1493
- <p class="breadcrumbs">
1494
- <a href=${g(t.hrefs.section, { sport: e.sport, view: "scores" })}>${B(e.sport)}</a> /
1495
- <a href=${g(t.hrefs.section, { sport: e.sport, view: "scores" })}>Scores/Schedules</a> /
1496
- ${F(t, e.awayTeamId)} at ${F(t, e.homeTeamId)}
1497
- </p>
1514
+ ${D(this, n`
1515
+ ${B(this)}
1516
+ ${this.embed ? p : n`
1517
+ <p class="breadcrumbs">
1518
+ <a href=${g(t.hrefs.section, { sport: e.sport, view: "scores" })}>${k(e.sport)}</a> /
1519
+ <a href=${g(t.hrefs.section, { sport: e.sport, view: "scores" })}>Scores/Schedules</a> /
1520
+ ${F(t, e.awayTeamId)} at ${F(t, e.homeTeamId)}
1521
+ </p>`}
1498
1522
  <div class="card">
1499
1523
  <div class="scorehead">
1500
- ${this.teamBlock(t, e, e.awayTeamId, o, !1)}
1524
+ ${this.teamBlock(t, e, e.awayTeamId, r, !1)}
1501
1525
  <div class="mid">
1502
1526
  <div class="bigscore">
1503
- <span style=${i("away")}>${e.awayScore}</span>
1527
+ <span style=${d("away")}>${e.awayScore}</span>
1504
1528
  <span class="mut" style="font-size:1.6rem">–</span>
1505
- <span style=${i("home")}>${e.homeScore}</span>
1529
+ <span style=${d("home")}>${e.homeScore}</span>
1506
1530
  </div>
1507
1531
  <div class="status">${A(e)}</div>
1508
- <div class="status">${w(e.date, { weekday: "short", month: "short", day: "numeric", year: "numeric" })}${e.state === "scheduled" && e.time ? n` · ${q(e.time)}` : p} · ${e.venue || "Venue TBD"}
1532
+ <div class="status">${x(e.date, { weekday: "short", month: "short", day: "numeric", year: "numeric" })}${e.state === "scheduled" && e.time ? n` · ${W(e.time)}` : p} · ${e.venue || "Venue TBD"}
1509
1533
  ${e.broadcast ? n` · <span class="pill class">${e.broadcast}</span>` : p}</div>
1510
1534
  <div class="status">
1511
1535
  <span class="pill type">${e.gameType === "conference" ? `${h?.name || "Conference"} game` : e.gameType}</span>
1512
1536
  ${e.label ? n`<span class="pill type">Bracket ${e.label}</span>` : p}
1513
- ${(e.tags || []).map((d) => n`<span class="pill type">${d}</span>`)}
1537
+ ${(e.tags || []).map((c) => n`<span class="pill type">${c}</span>`)}
1514
1538
  </div>
1539
+ ${this.embed ? p : n`
1540
+ <div class="status">
1541
+ <a href=${ce(t.hrefs, e.id)}>Report a score for this game</a>
1542
+ </div>`}
1515
1543
  </div>
1516
- ${this.teamBlock(t, e, e.homeTeamId, r, !0)}
1544
+ ${this.teamBlock(t, e, e.homeTeamId, o, !0)}
1517
1545
  </div>
1518
- ${this.renderLineScore(e, o, r)}
1519
- ${this.renderScoringPlays(e, o, r)}
1546
+ ${this.renderLineScore(e, r, o)}
1547
+ ${this.renderScoringPlays(e, r, o)}
1520
1548
  ${e.notes ? n`<p class="note gamenote">${e.notes}</p>` : p}
1521
1549
  </div>
1550
+ ${this.embed ? n`
1551
+ <p class="fullbox">
1552
+ <a href=${g(t.hrefs.game, { sport: e.sport, id: e.id })}>Full box score &rarr;</a>
1553
+ </p>` : n`
1522
1554
  ${(this.data.coverage || []).length ? n`
1523
1555
  <div class="section-title">Coverage</div>
1524
1556
  <div class="covgrid">
1525
- ${this.data.coverage.map((d) => n`
1526
- <a class="card covcard" href=${d.uri}>
1527
- ${d.image ? n`<img class="covimg" src=${d.image} alt="" loading="lazy" />` : p}
1557
+ ${this.data.coverage.map((c) => n`
1558
+ <a class="card covcard" href=${c.uri}>
1559
+ ${c.image ? n`<img class="covimg" src=${c.image} alt="" loading="lazy" />` : p}
1528
1560
  <div class="covbody">
1529
- <div class="covtitle">${d.videoDuration ? n`<span class="pill live" style="animation:none">Video</span> ` : p}${d.photos ? n`<span class="pill live" style="animation:none">Photos</span> ` : p}${d.title || d.uri}</div>
1530
- ${d.description ? n`<p class="covdesc">${d.description}</p>` : p}
1531
- ${d.author || d.publishedTime ? n`
1532
- <div class="covmeta">${[d.author, d.publishedTime ? new Date(d.publishedTime).toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" }) : ""].filter(Boolean).join(" · ")}</div>
1561
+ <div class="covtitle">${c.videoDuration ? n`<span class="pill live" style="animation:none">Video</span> ` : p}${c.photos ? n`<span class="pill live" style="animation:none">Photos</span> ` : p}${c.title || c.uri}</div>
1562
+ ${c.description ? n`<p class="covdesc">${c.description}</p>` : p}
1563
+ ${c.author || c.publishedTime ? n`
1564
+ <div class="covmeta">${[c.author, c.publishedTime ? new Date(c.publishedTime).toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" }) : ""].filter(Boolean).join(" · ")}</div>
1533
1565
  ` : p}
1534
1566
  </div>
1535
1567
  </a>
@@ -1537,50 +1569,50 @@ class at extends y {
1537
1569
  </div>` : p}
1538
1570
  <div class="section-title">Season context</div>
1539
1571
  <div class="cols">
1540
- ${[[e.awayTeamId, o], [e.homeTeamId, r]].map(([d, m]) => this.renderContext(t, d, m))}
1572
+ ${[[e.awayTeamId, r], [e.homeTeamId, o]].map(([c, m]) => this.renderContext(t, c, m))}
1541
1573
  </div>
1542
- ${c.length ? n`
1574
+ ${l.length ? n`
1543
1575
  <div class="section-title">Head to head this season</div>
1544
1576
  <div class="card"><ul class="gamelist">
1545
- ${c.map((d) => n`<li>
1546
- <span class="d">${w(d.date)}</span>${A(d)}
1547
- <span class="opp">${F(t, d.awayTeamId)} ${d.awayScore}, ${F(t, d.homeTeamId)} ${d.homeScore}</span>
1548
- <a class="box" href=${g(t.hrefs.game, { sport: e.sport, id: d.id })}>Box score →</a>
1577
+ ${l.map((c) => n`<li>
1578
+ <span class="d">${x(c.date)}</span>${A(c)}
1579
+ <span class="opp">${F(t, c.awayTeamId)} ${c.awayScore}, ${F(t, c.homeTeamId)} ${c.homeScore}</span>
1580
+ <a class="box" href=${g(t.hrefs.game, { sport: e.sport, id: c.id })}>Box score →</a>
1549
1581
  </li>`)}
1550
- </ul></div>` : p}
1582
+ </ul></div>` : p}`}
1551
1583
  `)}
1552
1584
  `;
1553
1585
  }
1554
- teamBlock(e, t, s, o, r) {
1555
- if (!o) return n`<div class="teamblock ${r ? "right" : ""}"><div class="tname">TBD</div></div>`;
1556
- const l = e.teamsById[s], i = e.records[s], h = M(o, 58);
1586
+ teamBlock(e, t, s, r, o) {
1587
+ if (!r) return n`<div class="teamblock ${o ? "right" : ""}"><div class="tname">TBD</div></div>`;
1588
+ const i = e.teamsById[s], d = e.records[s], h = M(r, 58);
1557
1589
  return n`
1558
- <div class="teamblock ${r ? "right" : ""}">
1559
- ${h ? n`<img class="crest logo" alt="" loading="lazy" src=${h} />` : n`<span class="crest" style="background:${o.colorPrimary || "#030711"};color:${N(o.colorPrimary || "#030711")}">${V(o)}</span>`}
1590
+ <div class="teamblock ${o ? "right" : ""}">
1591
+ ${h ? n`<img class="crest logo" alt="" loading="lazy" src=${h} />` : n`<span class="crest" style="background:${r.colorPrimary || "#030711"};color:${G(r.colorPrimary || "#030711")}">${Y(r)}</span>`}
1560
1592
  <div>
1561
- <div class="tname">${K(e, s, t.date)}<a href=${g(e.hrefs.school, { id: o.id })}>${o.name}</a></div>
1562
- <div class="trec">${o.mascot || ""} · ${k(i)}${l?.conferenceId ? n` · ${k(i, !0)} conf` : p}</div>
1593
+ <div class="tname">${X(e, s, t.date)}<a href=${g(e.hrefs.school, { id: r.id })}>${r.name}</a></div>
1594
+ <div class="trec">${r.mascot || ""} · ${S(d)}${i?.conferenceId ? n` · ${S(d, !0)} conf` : p}</div>
1563
1595
  </div>
1564
1596
  </div>
1565
1597
  `;
1566
1598
  }
1567
1599
  renderLineScore(e, t, s) {
1568
- const o = Xe(e);
1569
- if (!o)
1600
+ const r = tt(e);
1601
+ if (!r)
1570
1602
  return e.state === "scheduled" ? n`<p class="empty" style="text-align:center">Period scoring will appear once the game starts.</p>` : p;
1571
- const r = Math.max(Z(e.sport), ...o.map((c) => c.period)), l = (c) => Ye(e.sport, c), i = (c, d) => {
1572
- const m = o.find((f) => f.period === d);
1573
- return m ? m[c] : e.state === "final" ? 0 : "·";
1574
- }, h = (c, d, m) => n`
1603
+ const o = Math.max(J(e.sport), ...r.map((l) => l.period)), i = (l) => Ze(e.sport, l), d = (l, c) => {
1604
+ const m = r.find((f) => f.period === c);
1605
+ return m ? m[l] : e.state === "final" ? 0 : "·";
1606
+ }, h = (l, c, m) => n`
1575
1607
  <tr>
1576
- <td class="teamcell">${T(c, 20)}${c?.abbr || "TBD"}</td>
1577
- ${Array.from({ length: r }, (f, u) => n`<td class="num">${i(d, u + 1)}</td>`)}
1608
+ <td class="teamcell">${C(l, 20)}${l?.abbr || "TBD"}</td>
1609
+ ${Array.from({ length: o }, (f, u) => n`<td class="num">${d(c, u + 1)}</td>`)}
1578
1610
  <td class="num" style="font-weight:700">${m}</td>
1579
1611
  </tr>`;
1580
1612
  return n`
1581
1613
  <div class="tablewrap" style="border-top:1px solid var(--hsot-gray-2)">
1582
1614
  <table class="data" style="max-width:560px;margin:0.6rem auto 0.9rem">
1583
- <thead><tr><th>Team</th>${Array.from({ length: r }, (c, d) => n`<th class="num">${l(d + 1)}</th>`)}<th class="num">T</th></tr></thead>
1615
+ <thead><tr><th>Team</th>${Array.from({ length: o }, (l, c) => n`<th class="num">${i(c + 1)}</th>`)}<th class="num">T</th></tr></thead>
1584
1616
  <tbody>
1585
1617
  ${h(t, "away", e.awayScore)}
1586
1618
  ${h(s, "home", e.homeScore)}
@@ -1590,9 +1622,9 @@ class at extends y {
1590
1622
  `;
1591
1623
  }
1592
1624
  renderScoringPlays(e, t, s) {
1593
- const o = Array.isArray(e.scoringPlays) ? e.scoringPlays : [];
1594
- if (!o.length) return p;
1595
- const r = (l) => [l.period, l.clock].filter(Boolean).join(" ");
1625
+ const r = Array.isArray(e.scoringPlays) ? e.scoringPlays : [];
1626
+ if (!r.length) return p;
1627
+ const o = (i) => [i.period, i.clock].filter(Boolean).join(" ");
1596
1628
  return n`
1597
1629
  <div class="plays">
1598
1630
  <div class="plays-title">Scoring plays</div>
@@ -1603,11 +1635,11 @@ class at extends y {
1603
1635
  <th class="num">${t?.abbr || "Away"}</th><th class="num">${s?.abbr || "Home"}</th>
1604
1636
  </tr></thead>
1605
1637
  <tbody>
1606
- ${o.map((l) => n`<tr>
1607
- <td class="when">${r(l) || "·"}</td>
1608
- <td class="play">${l.description || "·"}</td>
1609
- <td class="num">${l.awayScore}</td>
1610
- <td class="num">${l.homeScore}</td>
1638
+ ${r.map((i) => n`<tr>
1639
+ <td class="when">${o(i) || "·"}</td>
1640
+ <td class="play">${i.description || "·"}</td>
1641
+ <td class="num">${i.awayScore}</td>
1642
+ <td class="num">${i.homeScore}</td>
1611
1643
  </tr>`)}
1612
1644
  </tbody>
1613
1645
  </table>
@@ -1617,24 +1649,24 @@ class at extends y {
1617
1649
  }
1618
1650
  renderContext(e, t, s) {
1619
1651
  if (!s) return p;
1620
- const o = e.records[t], r = Y(this.data.games, t);
1652
+ const r = e.records[t], o = K(this.data.games, t);
1621
1653
  return n`
1622
1654
  <div class="card ctxcard">
1623
- <div class="who">${T(s)}${s.name}</div>
1655
+ <div class="who">${C(s)}${s.name}</div>
1624
1656
  <div class="row">
1625
- <span>Last 5: ${X(e, t)}</span>
1626
- <span>Streak: <b>${o ? H(o.results) : "·"}</b></span>
1627
- <span>PF/PA: <b>${o ? `${o.pf} / ${o.pa}` : "·"}</b></span>
1628
- <span>Next: ${r ? n`${w(r.date, { month: "numeric", day: "numeric" })}
1629
- ${r.homeTeamId === t ? "vs" : "at"} ${L(e, r.homeTeamId === t ? r.awayTeamId : r.homeTeamId)}` : "·"}</span>
1657
+ <span>Last 5: ${Z(e, t)}</span>
1658
+ <span>Streak: <b>${r ? U(r.results) : "·"}</b></span>
1659
+ <span>PF/PA: <b>${r ? `${r.pf} / ${r.pa}` : "·"}</b></span>
1660
+ <span>Next: ${o ? n`${x(o.date, { month: "numeric", day: "numeric" })}
1661
+ ${o.homeTeamId === t ? "vs" : "at"} ${L(e, o.homeTeamId === t ? o.awayTeamId : o.homeTeamId)}` : "·"}</span>
1630
1662
  </div>
1631
1663
  </div>
1632
1664
  `;
1633
1665
  }
1634
1666
  }
1635
- globalThis?.customElements && !globalThis.customElements.get("hsot-boxscore") && globalThis.customElements.define("hsot-boxscore", at);
1636
- const ot = 250, rt = 2;
1637
- class nt extends ie {
1667
+ globalThis?.customElements && !globalThis.customElements.get("hsot-boxscore") && globalThis.customElements.define("hsot-boxscore", it);
1668
+ const lt = 250, ct = 2;
1669
+ class dt extends le {
1638
1670
  static properties = {
1639
1671
  api: { type: String },
1640
1672
  schoolHref: { type: String, attribute: "school-href" },
@@ -1645,7 +1677,7 @@ class nt extends ie {
1645
1677
  activeIndex: { state: !0 },
1646
1678
  searched: { state: !0 }
1647
1679
  };
1648
- static styles = $`
1680
+ static styles = w`
1649
1681
  :host {
1650
1682
  display: block;
1651
1683
  position: relative;
@@ -1714,11 +1746,11 @@ class nt extends ie {
1714
1746
  }
1715
1747
  onInput(e) {
1716
1748
  const t = e.target.value.trim();
1717
- if (clearTimeout(this.debounceTimer), t.length < rt) {
1749
+ if (clearTimeout(this.debounceTimer), t.length < ct) {
1718
1750
  this.abortController?.abort(), this.results = [], this.open = !1, this.searched = !1;
1719
1751
  return;
1720
1752
  }
1721
- this.debounceTimer = setTimeout(() => this.search(t), ot);
1753
+ this.debounceTimer = setTimeout(() => this.search(t), lt);
1722
1754
  }
1723
1755
  async search(e) {
1724
1756
  this.abortController?.abort(), this.abortController = new AbortController();
@@ -1728,8 +1760,8 @@ class nt extends ie {
1728
1760
  });
1729
1761
  if (!s.ok)
1730
1762
  return;
1731
- const o = await s.json();
1732
- this.results = o.items || [], this.activeIndex = -1, this.searched = !0, this.open = !0;
1763
+ const r = await s.json();
1764
+ this.results = r.items || [], this.activeIndex = -1, this.searched = !0, this.open = !0;
1733
1765
  } catch (t) {
1734
1766
  t.name !== "AbortError" && console.warn("school search failed", t);
1735
1767
  }
@@ -1763,15 +1795,15 @@ class nt extends ie {
1763
1795
  return [e.location, e.county && `${e.county} County`].filter(Boolean).join(" — ");
1764
1796
  }
1765
1797
  renderOption(e, t) {
1766
- const s = this.where(e), o = (r) => {
1767
- r.preventDefault(), this.go(e);
1798
+ const s = this.where(e), r = (o) => {
1799
+ o.preventDefault(), this.go(e);
1768
1800
  };
1769
1801
  return n`
1770
1802
  <li
1771
1803
  id="school-option-${t}"
1772
1804
  role="option"
1773
1805
  aria-selected="${t === this.activeIndex ? "true" : "false"}"
1774
- @pointerdown="${o}"
1806
+ @pointerdown="${r}"
1775
1807
  @mousemove="${() => {
1776
1808
  this.activeIndex = t;
1777
1809
  }}"
@@ -1785,7 +1817,7 @@ class nt extends ie {
1785
1817
  const e = this.searched && !this.results.length, t = n`<li class="empty">No schools found</li>`;
1786
1818
  return n`
1787
1819
  <ul id="school-search-listbox" role="listbox" aria-label="Schools">
1788
- ${this.results.map((s, o) => this.renderOption(s, o))}
1820
+ ${this.results.map((s, r) => this.renderOption(s, r))}
1789
1821
  ${e ? t : p}
1790
1822
  </ul>
1791
1823
  `;
@@ -1811,111 +1843,111 @@ class nt extends ie {
1811
1843
  `;
1812
1844
  }
1813
1845
  }
1814
- globalThis?.customElements && !globalThis.customElements.get("hsot-school-search") && globalThis.customElements.define("hsot-school-search", nt);
1815
- function ge(a, e) {
1816
- const t = new Map(a.map((h) => [h.id, h])), s = /* @__PURE__ */ new Map(), o = /* @__PURE__ */ new Map();
1846
+ globalThis?.customElements && !globalThis.customElements.get("hsot-school-search") && globalThis.customElements.define("hsot-school-search", dt);
1847
+ function $e(a, e) {
1848
+ const t = new Map(a.map((h) => [h.id, h])), s = /* @__PURE__ */ new Map(), r = /* @__PURE__ */ new Map();
1817
1849
  for (const h of e || [])
1818
- h.outcome === "winner" && (s.has(h.targetGameId) || s.set(h.targetGameId, []), s.get(h.targetGameId).push(h), o.has(h.sourceGameId) || o.set(h.sourceGameId, []), o.get(h.sourceGameId).push(h));
1819
- const r = a.filter((h) => !o.has(h.id)), l = (h) => h.targetSlot === "home" ? 0 : 1;
1820
- function i(h) {
1821
- const c = t.get(h);
1822
- if (!c) return null;
1823
- const m = [...s.get(h) || []].sort((f, u) => l(f) - l(u)).map((f) => i(f.sourceGameId)).filter(Boolean);
1824
- return { game: c, children: m, bracketGroup: c.bracketGroup };
1850
+ h.outcome === "winner" && (s.has(h.targetGameId) || s.set(h.targetGameId, []), s.get(h.targetGameId).push(h), r.has(h.sourceGameId) || r.set(h.sourceGameId, []), r.get(h.sourceGameId).push(h));
1851
+ const o = a.filter((h) => !r.has(h.id)), i = (h) => h.targetSlot === "home" ? 0 : 1;
1852
+ function d(h) {
1853
+ const l = t.get(h);
1854
+ if (!l) return null;
1855
+ const m = [...s.get(h) || []].sort((f, u) => i(f) - i(u)).map((f) => d(f.sourceGameId)).filter(Boolean);
1856
+ return { game: l, children: m, bracketGroup: l.bracketGroup };
1825
1857
  }
1826
- return r.length === 1 ? i(r[0].id) : r.map((h) => i(h.id));
1858
+ return o.length === 1 ? d(o[0].id) : o.map((h) => d(h.id));
1827
1859
  }
1828
- function ve(a, e = [], t = 0) {
1860
+ function we(a, e = [], t = 0) {
1829
1861
  if (!a) return e;
1830
1862
  e[t] || (e[t] = []), e[t].push(a.game);
1831
- for (const s of a.children || []) ve(s, e, t + 1);
1863
+ for (const s of a.children || []) we(s, e, t + 1);
1832
1864
  return e;
1833
1865
  }
1834
- const it = (a) => Math.max(1, Math.round(Math.log2(a || 2)));
1835
- function lt({ round: a, perGroup: e, groupCount: t = 1 }) {
1836
- const s = it(e), r = (t === 4 ? s + 2 : t === 2 ? s + 1 : s) - a;
1837
- return r === 0 ? t > 1 ? "Championship" : "Final" : r === 1 ? "Semifinal" : `Round ${a}`;
1866
+ const ht = (a) => Math.max(1, Math.round(Math.log2(a || 2)));
1867
+ function mt({ round: a, perGroup: e, groupCount: t = 1 }) {
1868
+ const s = ht(e), o = (t === 4 ? s + 2 : t === 2 ? s + 1 : s) - a;
1869
+ return o === 0 ? t > 1 ? "Championship" : "Final" : o === 1 ? "Semifinal" : `Round ${a}`;
1838
1870
  }
1839
- function ct(a) {
1871
+ function pt(a) {
1840
1872
  if (!a || !a.length) return "setup";
1841
1873
  const e = Math.max(...a.map((s) => s.round ?? 0)), t = a.filter((s) => (s.round ?? 0) === e);
1842
1874
  return t.length && t.every((s) => s.state === "final") ? "complete" : a.some((s) => s.state !== "scheduled" || s.homeScore || s.awayScore || s.round === 1 && (s.homeTeamId || s.awayTeamId)) ? "active" : "setup";
1843
1875
  }
1844
- function dt(a, e) {
1876
+ function ft(a, e) {
1845
1877
  const t = a?.groupNames || [];
1846
1878
  if (t.length >= 2) {
1847
- const o = t.map((r) => ({ key: r, name: r }));
1848
- return (e || []).some((r) => r.bracketGroup === "Championship") && o.push({ key: "Championship", name: "Championship" }), o;
1879
+ const r = t.map((o) => ({ key: o, name: o }));
1880
+ return (e || []).some((o) => o.bracketGroup === "Championship") && r.push({ key: "Championship", name: "Championship" }), r;
1849
1881
  }
1850
- const s = [...new Set((e || []).map((o) => o.bracketGroup).filter(Boolean))];
1882
+ const s = [...new Set((e || []).map((r) => r.bracketGroup).filter(Boolean))];
1851
1883
  return [{ key: null, name: s.length === 1 ? s[0] : "Bracket" }];
1852
1884
  }
1853
- const ht = (a, e) => e?.key == null ? [...a || []] : (a || []).filter((t) => t.bracketGroup === e.key), oe = (a) => {
1885
+ const ut = (a, e) => e?.key == null ? [...a || []] : (a || []).filter((t) => t.bracketGroup === e.key), oe = (a) => {
1854
1886
  const e = /(\d+)\s*$/.exec(a.label || "");
1855
1887
  return e ? Number(e[1]) : 1 / 0;
1856
- }, re = (a, e) => oe(a) - oe(e) || String(a.id).localeCompare(String(e.id));
1857
- function mt(a, e) {
1858
- if (a.every((o) => Number.isInteger(o.round))) return (o) => o.round;
1859
- const t = ge(a, e), s = /* @__PURE__ */ new Map();
1860
- for (const o of Array.isArray(t) ? t : [t]) {
1861
- const r = ve(o), l = r.length - 1;
1862
- r.forEach((i, h) => i.forEach((c) => s.set(c.id, l - h + 1)));
1863
- }
1864
- return (o) => Number.isInteger(o.round) ? o.round : s.get(o.id) || 1;
1865
- }
1866
- function pt(a, e, t) {
1867
- const s = ht(a, t);
1888
+ }, ne = (a, e) => oe(a) - oe(e) || String(a.id).localeCompare(String(e.id));
1889
+ function gt(a, e) {
1890
+ if (a.every((r) => Number.isInteger(r.round))) return (r) => r.round;
1891
+ const t = $e(a, e), s = /* @__PURE__ */ new Map();
1892
+ for (const r of Array.isArray(t) ? t : [t]) {
1893
+ const o = we(r), i = o.length - 1;
1894
+ o.forEach((d, h) => d.forEach((l) => s.set(l.id, i - h + 1)));
1895
+ }
1896
+ return (r) => Number.isInteger(r.round) ? r.round : s.get(r.id) || 1;
1897
+ }
1898
+ function vt(a, e, t) {
1899
+ const s = ut(a, t);
1868
1900
  if (!s.length) return [];
1869
- const o = mt(a || [], e || []), r = /* @__PURE__ */ new Map();
1870
- for (const c of s) {
1871
- const d = o(c);
1872
- r.has(d) || r.set(d, []), r.get(d).push(c);
1873
- }
1874
- const l = /* @__PURE__ */ new Map();
1875
- for (const c of e || [])
1876
- c.outcome === "winner" && (l.has(c.targetGameId) || l.set(c.targetGameId, []), l.get(c.targetGameId).push(c.sourceGameId));
1877
- const i = [];
1901
+ const r = gt(a || [], e || []), o = /* @__PURE__ */ new Map();
1902
+ for (const l of s) {
1903
+ const c = r(l);
1904
+ o.has(c) || o.set(c, []), o.get(c).push(l);
1905
+ }
1906
+ const i = /* @__PURE__ */ new Map();
1907
+ for (const l of e || [])
1908
+ l.outcome === "winner" && (i.has(l.targetGameId) || i.set(l.targetGameId, []), i.get(l.targetGameId).push(l.sourceGameId));
1909
+ const d = [];
1878
1910
  let h = null;
1879
- for (const c of [...r.keys()].sort((d, m) => d - m)) {
1880
- let d = [...r.get(c)];
1911
+ for (const l of [...o.keys()].sort((c, m) => c - m)) {
1912
+ let c = [...o.get(l)];
1881
1913
  if (h) {
1882
1914
  const m = (f) => {
1883
- const u = (l.get(f.id) || []).map((v) => h.get(v)).filter((v) => v !== void 0);
1915
+ const u = (i.get(f.id) || []).map((y) => h.get(y)).filter((y) => y !== void 0);
1884
1916
  return u.length ? Math.min(...u) : 1 / 0;
1885
1917
  };
1886
- d.sort((f, u) => m(f) - m(u) || re(f, u));
1918
+ c.sort((f, u) => m(f) - m(u) || ne(f, u));
1887
1919
  } else
1888
- d.sort(re);
1889
- h = new Map(d.map((m, f) => [m.id, f])), i.push({ round: c, games: d });
1920
+ c.sort(ne);
1921
+ h = new Map(c.map((m, f) => [m.id, f])), d.push({ round: l, games: c });
1890
1922
  }
1891
- return i;
1923
+ return d;
1892
1924
  }
1893
- function ft(a, e, t) {
1894
- const s = a[`${e}TeamId`] || null, o = (t || []).find((l) => l.gameId === a.id && l.slot === e), r = a[`${e}Seed`] ?? o?.seed ?? null;
1895
- return { teamId: s, seed: r, bye: !s && !!o?.isBye };
1925
+ function bt(a, e, t) {
1926
+ const s = a[`${e}TeamId`] || null, r = (t || []).find((i) => i.gameId === a.id && i.slot === e), o = a[`${e}Seed`] ?? r?.seed ?? null;
1927
+ return { teamId: s, seed: o, bye: !s && !!r?.isBye };
1896
1928
  }
1897
- function be(a) {
1898
- const e = O(a);
1929
+ function xe(a) {
1930
+ const e = H(a);
1899
1931
  return e === "home" || e === "away" ? e : null;
1900
1932
  }
1901
- function ut(a, e) {
1902
- const t = ge(a || [], e || []);
1933
+ function yt(a, e) {
1934
+ const t = $e(a || [], e || []);
1903
1935
  if (!t || Array.isArray(t)) return null;
1904
- const s = be(t.game);
1936
+ const s = xe(t.game);
1905
1937
  return s && t.game[`${s}TeamId`] || null;
1906
1938
  }
1907
- const ne = { active: 0, setup: 1, complete: 2 };
1908
- function gt(a, { id: e, param: t } = {}) {
1939
+ const ie = { active: 0, setup: 1, complete: 2 };
1940
+ function $t(a, { id: e, param: t } = {}) {
1909
1941
  const s = a || [];
1910
1942
  if (!s.length) return null;
1911
- for (const o of [e, t]) {
1912
- if (!o) continue;
1913
- const r = s.find((l) => l.id === o);
1914
- if (r) return r;
1943
+ for (const r of [e, t]) {
1944
+ if (!r) continue;
1945
+ const o = s.find((i) => i.id === r);
1946
+ if (o) return o;
1915
1947
  }
1916
- return [...s].sort((o, r) => (ne[o.status] ?? 3) - (ne[r.status] ?? 3) || String(o.name || "").localeCompare(String(r.name || "")))[0];
1948
+ return [...s].sort((r, o) => (ie[r.status] ?? 3) - (ie[o.status] ?? 3) || String(r.name || "").localeCompare(String(o.name || "")))[0];
1917
1949
  }
1918
- const vt = $`
1950
+ const wt = w`
1919
1951
  .bracket { display: flex; gap: 1rem; align-items: stretch; overflow-x: auto; padding-bottom: 0.5rem; }
1920
1952
  .round { flex: 0 0 250px; display: flex; flex-direction: column; min-width: 0; }
1921
1953
  .roundhead {
@@ -1961,10 +1993,10 @@ const vt = $`
1961
1993
  .champ .tname a { color: inherit; text-decoration: none; font-weight: 700; }
1962
1994
  @media (max-width: 720px) { .round { flex-basis: 215px; } }
1963
1995
  `;
1964
- class bt extends y {
1965
- static styles = [P, vt];
1996
+ class xt extends $ {
1997
+ static styles = [P, wt];
1966
1998
  static properties = {
1967
- ...y.properties,
1999
+ ...$.properties,
1968
2000
  sport: { type: String },
1969
2001
  season: { type: String },
1970
2002
  tournamentId: { type: String, attribute: "tournament-id" },
@@ -1975,24 +2007,24 @@ class bt extends y {
1975
2007
  super(), this.sport = "football", this.season = "", this.tournamentId = "", this.picked = "", this.group = null;
1976
2008
  }
1977
2009
  async fetchData(e) {
1978
- const t = this.season || E(), s = (await e.listTournaments({ sport: this.sport, season: t })).items, o = new URLSearchParams(globalThis.location?.search || "").get("tournament"), r = gt(s, { id: this.picked || this.tournamentId, param: o });
1979
- if (!r) return { season: t, tournaments: s, tournament: null };
1980
- const [l, i, h, c, d] = await Promise.all([
1981
- e.listSeedings(r.id),
1982
- e.listEdges(r.id),
1983
- e.listGames({ tournamentId: r.id }),
2010
+ const t = this.season || _(), s = (await e.listTournaments({ sport: this.sport, season: t })).items, r = new URLSearchParams(globalThis.location?.search || "").get("tournament"), o = $t(s, { id: this.picked || this.tournamentId, param: r });
2011
+ if (!o) return { season: t, tournaments: s, tournament: null };
2012
+ const [i, d, h, l, c] = await Promise.all([
2013
+ e.listSeedings(o.id),
2014
+ e.listEdges(o.id),
2015
+ e.listGames({ tournamentId: o.id }),
1984
2016
  e.listSchools(),
1985
2017
  e.listTeams({ sport: this.sport })
1986
2018
  ]);
1987
2019
  return {
1988
2020
  season: t,
1989
2021
  tournaments: s,
1990
- tournament: r,
1991
- seedings: l.items,
1992
- edges: i.items,
2022
+ tournament: o,
2023
+ seedings: i.items,
2024
+ edges: d.items,
1993
2025
  games: h.items,
1994
- schools: c.items,
1995
- teams: d.items
2026
+ schools: l.items,
2027
+ teams: c.items
1996
2028
  };
1997
2029
  }
1998
2030
  get ctx() {
@@ -2018,46 +2050,46 @@ class bt extends y {
2018
2050
  }
2019
2051
  }
2020
2052
  renderView() {
2021
- const e = this.data, t = this.ctx, s = U(this, t, {
2022
- title: n`${B(this.sport)} playoff brackets`,
2053
+ const e = this.data, t = this.ctx, s = j(this, t, {
2054
+ title: n`${k(this.sport)} playoff brackets`,
2023
2055
  sub: e.tournament ? n`${e.tournament.name} · ${e.season} season` : n`${e.season} season`,
2024
2056
  teams: e.teams
2025
2057
  });
2026
2058
  if (!e.tournament)
2027
- return n`${s}${C(this, n`
2028
- ${D(this)}
2059
+ return n`${s}${D(this, n`
2060
+ ${B(this)}
2029
2061
  <div class="card"><div class="empty">No ${this.sport} brackets have been published for the ${e.season} season yet.</div></div>
2030
2062
  `)}`;
2031
- const o = dt(e.tournament, e.games), r = o.find((m) => m.key === this.group) || o[0], l = (e.tournament.groupNames || []).length >= 2 ? e.tournament.groupNames.length : 1, i = (Number(e.tournament.size) || 0) / l, h = pt(e.games, e.edges, r), c = ct(e.games), d = ut(e.games, e.edges);
2063
+ const r = ft(e.tournament, e.games), o = r.find((m) => m.key === this.group) || r[0], i = (e.tournament.groupNames || []).length >= 2 ? e.tournament.groupNames.length : 1, d = (Number(e.tournament.size) || 0) / i, h = vt(e.games, e.edges, o), l = pt(e.games), c = yt(e.games, e.edges);
2032
2064
  return n`
2033
2065
  ${s}
2034
- ${C(this, n`
2035
- ${D(this)}
2066
+ ${D(this, n`
2067
+ ${B(this)}
2036
2068
  <div class="toolbar">
2037
2069
  ${e.tournaments.length > 1 ? n`
2038
2070
  <div role="group" aria-label="Tournament">
2039
2071
  ${e.tournaments.map((m) => n`<button class="chip ${m.id === e.tournament.id ? "on" : ""}"
2040
2072
  @click=${() => this.pick(m.id)}>${m.name}</button>`)}
2041
2073
  </div>` : p}
2042
- ${o.length > 1 ? n`
2074
+ ${r.length > 1 ? n`
2043
2075
  <div role="tablist" aria-label="Bracket group">
2044
- ${o.map((m) => n`<button class="chip ${m.key === r.key ? "on" : ""}" role="tab"
2045
- aria-selected=${m.key === r.key ? "true" : "false"}
2076
+ ${r.map((m) => n`<button class="chip ${m.key === o.key ? "on" : ""}" role="tab"
2077
+ aria-selected=${m.key === o.key ? "true" : "false"}
2046
2078
  @click=${() => {
2047
2079
  this.group = m.key;
2048
2080
  }}>${m.name}</button>`)}
2049
2081
  </div>` : p}
2050
2082
  <span class="spacer"></span>
2051
- <span class="pill ${c === "complete" ? "final" : c === "active" ? "class" : "type"}">${c === "complete" ? "Complete" : c === "active" ? "In progress" : "Bracket set"}</span>
2083
+ <span class="pill ${l === "complete" ? "final" : l === "active" ? "class" : "type"}">${l === "complete" ? "Complete" : l === "active" ? "In progress" : "Bracket set"}</span>
2052
2084
  <span class="asof">${e.tournament.size}-team ${String(e.tournament.format || "").replace(/_/g, " ")}</span>
2053
2085
  </div>
2054
- ${d ? n`<div class="champ"><span class="pill champ">Champion</span>
2055
- ${T(I(t, d), 26)}<span class="tname">${G(t, d)}</span></div>` : p}
2086
+ ${c ? n`<div class="champ"><span class="pill champ">Champion</span>
2087
+ ${C(T(t, c), 26)}<span class="tname">${O(t, c)}</span></div>` : p}
2056
2088
  ${h.length ? n`
2057
- <div class="bracket" role="region" aria-label="${r.name} bracket">
2089
+ <div class="bracket" role="region" aria-label="${o.name} bracket">
2058
2090
  ${h.map((m) => n`
2059
2091
  <section class="round">
2060
- <h3 class="roundhead">${lt({ round: m.round, perGroup: i, groupCount: l })}</h3>
2092
+ <h3 class="roundhead">${mt({ round: m.round, perGroup: d, groupCount: i })}</h3>
2061
2093
  <div class="games">${m.games.map((f) => this.renderMatchup(t, f))}</div>
2062
2094
  </section>`)}
2063
2095
  </div>` : n`<div class="card"><div class="empty">This bracket has no games yet.</div></div>`}
@@ -2080,41 +2112,40 @@ class bt extends y {
2080
2112
  `;
2081
2113
  }
2082
2114
  renderSlot(e, t, s) {
2083
- const { teamId: o, seed: r, bye: l } = ft(t, s, this.data.seedings), i = be(t), h = t.state === "live" || t.state === "final";
2115
+ const { teamId: r, seed: o, bye: i } = bt(t, s, this.data.seedings), d = xe(t), h = t.state === "live" || t.state === "final";
2084
2116
  return n`
2085
- <div class="slot ${i ? i === s ? "winner" : "loser" : ""}">
2086
- <span class="seed">${r ?? ""}</span>
2087
- ${o ? n`${T(I(e, o), 22)}<span class="tname">${G(e, o, t.date)}</span>` : l ? n`<span class="tname bye">Bye</span>` : n`<span class="tname mut">TBD</span>`}
2117
+ <div class="slot ${d ? d === s ? "winner" : "loser" : ""}">
2118
+ <span class="seed">${o ?? ""}</span>
2119
+ ${r ? n`${C(T(e, r), 22)}<span class="tname">${O(e, r, t.date)}</span>` : i ? n`<span class="tname bye">Bye</span>` : n`<span class="tname mut">TBD</span>`}
2088
2120
  ${h ? n`<span class="score">${t[`${s}Score`] ?? 0}</span>` : p}
2089
2121
  </div>
2090
2122
  `;
2091
2123
  }
2092
2124
  }
2093
- globalThis?.customElements && !globalThis.customElements.get("hsot-brackets") && globalThis.customElements.define("hsot-brackets", bt);
2125
+ globalThis?.customElements && !globalThis.customElements.get("hsot-brackets") && globalThis.customElements.define("hsot-brackets", xt);
2094
2126
  export {
2095
- j as D,
2096
- at as H,
2097
- bt as a,
2098
- qe as b,
2099
- Ve as c,
2100
- nt as d,
2101
- He as e,
2102
- Ue as f,
2103
- dt as g,
2104
- ge as h,
2105
- ut as i,
2106
- _ as j,
2107
- ct as k,
2108
- we as l,
2109
- g as m,
2110
- O as n,
2111
- $t as o,
2112
- Le as p,
2113
- lt as q,
2114
- k as r,
2115
- pt as s,
2116
- de as t,
2117
- H as u,
2118
- Q as v,
2119
- ve as w
2127
+ E as D,
2128
+ it as H,
2129
+ xt as a,
2130
+ Ke as b,
2131
+ Xe as c,
2132
+ dt as d,
2133
+ We as e,
2134
+ Ve as f,
2135
+ ft as g,
2136
+ $e as h,
2137
+ yt as i,
2138
+ N as j,
2139
+ pt as k,
2140
+ g as l,
2141
+ H as m,
2142
+ It as n,
2143
+ mt as o,
2144
+ Ue as p,
2145
+ vt as q,
2146
+ S as r,
2147
+ fe as s,
2148
+ U as t,
2149
+ Q as u,
2150
+ we as v
2120
2151
  };