﻿/* remaining-pages.jsx - shared renderer for additional WC2026 pages */
function PageFooter() {
  return <footer className="page-footer wc-section-dark"><div className="wrap"><DisclaimerBox /></div></footer>;
}

function SourceLine({ sources = [], updated = REMAINING_UPDATED }) {
  const text = Array.isArray(sources) ? sources.join("、") : sources;
  return <p className="data-note">出典：{text} / 最終更新日：{updated}</p>;
}

function InfoCards({ items }) {
  return <div className="extra-card-grid">{items.map((item) => <article className="extra-card" key={item.title}><span>{item.kicker}</span><h3>{item.title}</h3><p>{item.body}</p>{item.badge && <BroadcastBadge text={item.badge} />}{item.source && <small>出典：{item.source}</small>}</article>)}</div>;
}

function StatusTable({ rows, columns }) {
  return <div className="table-wrap"><table className="sub-table"><thead><tr>{columns.map((c) => <th key={c.key}>{c.label}</th>)}</tr></thead><tbody>{rows.map((row, idx) => <tr key={`${row[columns[0].key]}-${idx}`}>{columns.map((c) => <td key={c.key}>{c.badge ? <BroadcastBadge text={row[c.key]} /> : c.strong ? <b>{row[c.key]}</b> : row[c.key]}</td>)}</tr>)}</tbody></table></div>;
}

function GoodsGroup({ group }) {
  return <article className="extra-card goods-page-card"><span>Watch Setup</span><h3>{group.title}</h3><p>{group.note}</p><ul>{group.items.map((item) => <li key={item}>{item}</li>)}</ul></article>;
}

function RatingMethodBars({ items }) {
  return <div className="extra-bars">{items.map((item) => <RatingBar key={item.label} label={item.label} value={item.value} max={item.max} />)}</div>;
}

function pctLabel(value) {
  const n = Number(value);
  if (!Number.isFinite(n)) return "参考";
  if (n >= 0 && n < 0.05) return "<0.1%";
  return `${n.toFixed(1)}%`;
}

function pctCell(value) {
  return <span className="prediction-pct">{pctLabel(value)}</span>;
}

function PredictionMiniBar({ label, value, tone = "#F2C94C" }) {
  const n = Number(value);
  const width = Number.isFinite(n) ? Math.max(2, Math.min(100, n)) : 2;
  return <div className="prediction-mini-bar"><div><span>{label}</span><b>{pctLabel(value)}</b></div><i><em style={{ width: `${width}%`, background: tone }} /></i></div>;
}

function PredictionResultCards({ cards = [] }) {
  return <div className="prediction-result-grid">{cards.map((card) => <article className="prediction-result-card wc-card-dark" key={`${card.kicker}-${card.title}`}><span>{card.kicker}</span><h3>{card.title}</h3><strong>{card.value}</strong><p>{card.body}</p></article>)}</div>;
}

function PredictionGroupCard({ group }) {
  const podium = group.mode || [];
  return <article className="prediction-group-card wc-card-dark">
    <div className="prediction-group-card__head"><span>Group {group.group}</span><b>{pctLabel(group.patternProb)}</b></div>
    <ol className="prediction-standings">{podium.map((team, idx) => <li key={`${group.group}-${team}`}><span>{idx + 1}位</span><b>{team}</b></li>)}</ol>
    <PredictionGroupExpectedCards group={group} compact />
  </article>;
}

function PredictionTeamProbabilityCard({ row, compact = false }) {
  return <article className={`prediction-team-prob-card${compact ? " prediction-team-prob-card--compact" : ""}`}>
    <div className="prediction-team-prob-card__head"><span>{row.rank}位</span><b>{row.team}</b><em>{Number(row.expectedPts).toFixed(2)} pts</em></div>
    <PredictionMiniBar label="2位以内" value={row.top2} tone="#F2C94C" />
    <PredictionMiniBar label="3位通過" value={row.best3rd} tone="#37C871" />
    <PredictionMiniBar label="勝ち抜け" value={row.advance} tone="#F47B20" />
  </article>;
}

function PredictionGroupExpectedCards({ group, compact = false }) {
  return <div className={`prediction-team-prob-grid${compact ? " prediction-team-prob-grid--compact" : ""}`}>{(group.table || []).map((row) => <PredictionTeamProbabilityCard row={row} compact={compact} key={`${group.group}-${row.team}`} />)}</div>;
}

function PredictionGroupExpectedTable({ group, compact = false }) {
  const rows = (group.table || []).map((row) => ({
    rank: `${row.rank}位`,
    team: row.team,
    pts: Number(row.expectedPts).toFixed(2),
    top2: pctCell(row.top2),
    best3rd: pctCell(row.best3rd),
    advance: pctCell(row.advance),
    first: pctCell(row.first),
    second: pctCell(row.second),
    third: pctCell(row.third),
    fourth: pctCell(row.fourth)
  }));
  const columns = compact
    ? [{key:"rank",label:"Rank"},{key:"team",label:"チーム",strong:true},{key:"pts",label:"予想勝ち点"},{key:"top2",label:"2位以内"},{key:"best3rd",label:"3位通過"},{key:"advance",label:"勝ち抜け"}]
    : [{key:"rank",label:"Rank"},{key:"team",label:"チーム",strong:true},{key:"pts",label:"予想勝ち点"},{key:"first",label:"1位確率"},{key:"second",label:"2位確率"},{key:"third",label:"3位確率"},{key:"fourth",label:"4位確率"},{key:"top2",label:"2位以内確率"},{key:"best3rd",label:"3位通過確率"},{key:"advance",label:"勝ち抜け確率"}];
  return <StatusTable rows={rows} columns={columns} />;
}

function PredictionGroupTables({ groups }) {
  return <div className="prediction-group-tables">{groups.map((group) => <details key={group.group} className="rating-details prediction-group-detail" open={group.group === "F"}><summary>Group {group.group}</summary><PredictionGroupExpectedCards group={group} /></details>)}</div>;
}

function BestThirdTeamCards({ rows = [] }) {
  return <div className="best-third-team-grid">{rows.slice(0, 12).map((row) => <article className={`best-third-team-card wc-card-dark${row.group === "F" ? " is-group-f" : ""}`} key={`${row.group}-${row.team}`}><div><span>{row.rank}位 / Group {row.group}</span><h3>{row.team}</h3><small>予想勝ち点 {Number(row.expectedPts).toFixed(2)}</small></div><PredictionMiniBar label="3位通過確率" value={row.best3rd} tone="#37C871" /><PredictionMiniBar label="勝ち抜け確率" value={row.advance} tone="#F2C94C" /></article>)}</div>;
}

function BestThirdSetCards({ rows }) {
  return <div className="best-third-grid">{rows.map((row) => <article className="extra-card best-third-card" key={row.rank}><span>Pattern {row.rank}</span><strong className="best-third-card__value">{pctLabel(row.probability)}</strong><p>{row.set}</p></article>)}</div>;
}

function PredictionBracket({ data }) {
  const matches = data?.matches || [];
  const rounds = [{key:"R32", label:"R32"}, {key:"R16", label:"R16"}, {key:"QF", label:"ベスト8"}, {key:"SF", label:"ベスト4"}, {key:"3rd", label:"3位決定戦"}, {key:"Final", label:"決勝"}];
  const summary = data?.summary || {};
  const isHighProb = data?.kind === "highProbability";
  return <div className="prediction-bracket-wrap">
    <div className="bracket-summary wc-card-dark"><span>{isHighProb ? "High Probability Bracket" : "Representative Scenario"}</span><b>{summary.final || "参考情報"}</b><small>勝者：{summary.champion || "参考"} / 日本：{summary.japanScenario || "参考"}</small></div>
    <div className="prediction-bracket">
      {rounds.map((round) => <section className={`bracket-round bracket-round--${round.key.toLowerCase()}`} key={round.key}><h3>{round.label}</h3>{matches.filter((m) => m.round === round.key).map((m) => <article className={`bracket-match${m.upset ? " bracket-match--upset" : ""}`} key={m.matchNo}><small>Match {m.matchNo}{m.cardFrequency ? ` / R32カード ${pctLabel(m.cardFrequency)}` : ""}</small><p><span className={m.winner === m.teamA ? "is-winner" : ""}>{m.teamA}</span><span className={m.winner === m.teamB ? "is-winner" : ""}>{m.teamB}</span></p><b>{m.winner}</b><em>{pctLabel(m.winnerProb)}</em></article>)}</section>)}
    </div>
  </div>;
}

function ProgressBars({ rows, limit = 10, includeJapan = false, includeGroupF = false }) {
  let list = rows.slice().sort((a, b) => a.rank - b.rank);
  if (limit) list = list.slice(0, limit);
  const extras = rows.filter((r) => (includeJapan && r.team === "日本") || (includeGroupF && r.group === "F"));
  extras.forEach((r) => { if (!list.some((x) => x.team === r.team)) list.push(r); });
  return <div className="progress-card-grid">{list.map((row) => <article className={`progress-card wc-card-dark${row.team === "日本" ? " is-japan" : ""}${row.group === "F" ? " is-group-f" : ""}`} key={row.team}><div className="progress-card__head"><span>{row.rank}位 / Group {row.group}</span><b>{row.team}</b></div><PredictionMiniBar label="R32" value={row.r32} tone="#F47B20" /><PredictionMiniBar label="R16" value={row.r16} tone="#F2C94C" /><PredictionMiniBar label="ベスト8" value={row.qf} tone="#37C871" /><PredictionMiniBar label="ベスト4" value={row.sf} tone="#2F80ED" /><PredictionMiniBar label="決勝" value={row.final} tone="#8A63D2" /><PredictionMiniBar label="優勝" value={row.title} tone="#EF3340" /></article>)}</div>;
}

function TitleRankingCards({ rows }) {
  return <div className="title-ranking-grid">{rows.slice(0, 10).map((row) => <article className="title-rank-card wc-card-dark" key={row.team}><span>{row.rank}位 / Group {row.group}</span><h3>{row.team}</h3><PredictionMiniBar label="優勝確率" value={row.title} tone="#F2C94C" /><small>Rating {Number(row.rating).toFixed(1)}</small></article>)}</div>;
}

function JapanPathBars({ rows, title }) {
  const max = Math.max(...rows.map((r) => Number(r.probability) || 0), 1);
  return <article className="japan-path-panel wc-card-dark"><h3>{title}</h3>{rows.map((row) => { const n = Number(row.probability) || 0; return <div className="japan-path-row" key={`${title}-${row.rank}-${row.label}`}><span>{row.label}</span><i><em style={{ width: `${Math.max(2, (n / max) * 100)}%` }} /></i><b>{pctLabel(row.probability)}</b></div>; })}</article>;
}

function PredictionsIndexPage() {
  const data = window.PREDICTION_DASHBOARD;
  const groups = data?.groups || [];
  const progress = data?.progress || [];
  const titleRanking = data?.titleRanking || [];
  const japanPath = data?.japanPath || {};
  return <PageShell active="順位予想">
    <HeroSection eyebrow="Prediction Dashboard" title="W杯2026 順位予想・勝ち上がり予想" subtitle="全48チームのグループ順位、決勝トーナメント、優勝確率を、独自Ratingとシミュレーションで整理します。">
      <p className="data-note">この予測は現時点のチームRatingに基づくシミュレーションです。正式メンバー、怪我、コンディション、直近の代表状況によって数値は変動します。</p>
      <div className="inline-actions"><a className="btn btn--gold" href="/worldcup2026/predictions/group-f/">Group F勝敗予想</a><a className="btn btn--outline" href="/worldcup2026/ratings/">Ratingを見る</a><a className="btn btn--outline" href="/worldcup2026/schedule/">試合日程を見る</a></div>
    </HeroSection>
    <section className="section section--dark wc-section-dark section--tight"><div className="wrap"><SectionHead eyebrow="Quick View" title="まず結論" lead="優勝確率ランキングと決勝トーナメント表は別物として見ます。ページ全体の読み方を先に整理します。" /><PredictionResultCards cards={data?.resultCards || []} /></div></section>
    <section className="section section--dark wc-section-dark"><div className="wrap"><SectionHead eyebrow="Group Standings" title="12グループ順位予想カード" lead="順位は最も多く出た順位パターン、発生率はその並びの出現率です。" /><div className="prediction-group-grid">{groups.map((group) => <PredictionGroupCard key={group.group} group={group} />)}</div></div></section>
    <section className="section section--light wc-section-light"><div className="wrap"><SectionHead eyebrow="Expected Points" title="各グループの予想勝ち点・突破確率" lead="チームごとの予想勝ち点、2位以内確率、3位通過確率、勝ち抜け確率をカードで確認できます。" /><PredictionGroupTables groups={groups} /></div></section>
    <section className="section section--dark wc-section-dark"><div className="wrap"><SectionHead eyebrow="Best Third Race" title="3位通過争い" lead="3位になった場合にR32へ進みやすいチームを、3位通過確率の高い順に表示します。" /><BestThirdTeamCards rows={data?.bestThirdTeams || []} /><details className="rating-details best-third-set-detail"><summary>3位通過8チームの組み合わせ例を見る</summary><p className="data-note">組み合わせの分岐が非常に細かいため、単一パターンの発生率は低くなります。</p><BestThirdSetCards rows={data?.bestThirdSets || []} /></details></div></section>
    <section className="section section--dark wc-section-dark"><div className="wrap"><SectionHead eyebrow="Bracket" title="決勝トーナメント表" lead="優勝確率と勝ち上がり確率をもとに、上位候補がどのラウンドまで残りやすいかを整理します。" /><PredictionBracket data={data?.bracket} /><AnalysisNote title="トーナメント表の扱い">この表は起こりやすい組み合わせとRating上の勝ちやすさから整理した代表ブラケット例です。優勝確率ランキングや大会全体の唯一の正解を示すものではありません。</AnalysisNote></div></section>
    <section className="section section--dark wc-section-dark"><div className="wrap"><SectionHead eyebrow="Progress" title="勝ち上がり確率" lead="上位10チームに、日本代表とGroup Fの4チームを加えて表示します。" /><ProgressBars rows={progress} limit={10} includeJapan includeGroupF /><details className="rating-details"><summary>全48チームの勝ち上がり確率を開く</summary><KnockoutProbabilityTable all /></details></div></section>
    <section className="section section--light wc-section-light"><div className="wrap"><SectionHead eyebrow="Title Race" title="優勝確率ランキング" lead="全体シミュレーションで優勝まで届きやすいチームを上位から表示しています。" /><TitleRankingCards rows={titleRanking} /></div></section>
    <section className="section section--dark wc-section-dark"><div className="wrap"><SectionHead eyebrow="Japan Path" title="日本代表の勝ち上がり予想" lead="最終到達ラウンドとR32想定相手の出現率を棒グラフで確認できます。" /><div className="japan-path-grid"><JapanPathBars title="到達ラウンド分布" rows={(japanPath.finish || []).slice(0, 7)} /><JapanPathBars title="R32想定相手" rows={(japanPath.r32 || []).slice(0, 10)} /></div><p className="data-note">グループ順位は最も出やすい順位パターン、予想勝ち点は期待値、決勝トーナメントは組み合わせ条件を加味した暫定予測です。</p></div></section>
    <section className="section section--light wc-section-light"><div className="wrap"><AnalysisNote title="予測データの扱い">グループ順位は最も多く出た順位パターン、予想勝ち点は期待値、決勝トーナメント表は代表ブラケット例です。正式メンバー、怪我、コンディション、実際の順位・3位通過チームの組み合わせによって結果は変動します。</AnalysisNote><SourceLine sources={["当サイト独自Rating", "グループステージ予測", "決勝トーナメント予測"]} /></div></section>
    <PageFooter />
  </PageShell>;
}

function GroupFProbabilityInsight() {
  const rows = window.GROUPF_PROBABILITIES || [];
  const japan = rows.find((r) => r.key === "jpn");
  const japanText = japan ? `日本は2位通過が本線です。1位通過も${pctLabel(japan.first)}と十分に狙える一方、3位に回る確率は${pctLabel(japan.third)}、3位通過は${pctLabel(japan.thirdAdvance)}です。スウェーデン戦を落とすと、3位争いに回るリスクが高まります。` : "日本は2位通過が本線です。スウェーデン戦とチュニジア戦の勝ち点設計が大きなポイントになります。";
  return <div className="extra-card-grid probability-insight"><article className="extra-card"><span>Japan View</span><h3>日本は2位通過が本線</h3><p>{japanText}</p></article><article className="extra-card"><span>Scenario</span><h3>チュニジア戦で取りこぼさない</h3><p>勝ち点3を取れれば、スウェーデン戦を引き分け以上で進めやすくなります。初戦と得失点差も含めて、堅い試合運びが重要です。</p></article><article className="extra-card"><span>Notice</span><h3>独自シミュレーション</h3><p>本ページのレーティングと突破確率は、現時点の独自Ratingとシミュレーションに基づく暫定予測です。実際の結果を保証するものではありません。</p></article></div>;
}

function teamFeature(row) {
  return row.strengths || row.summary || row.label || "独自Ratingに基づく参考情報";
}

function rankingRows({ limit, group } = {}) {
  let rows = window.TEAM_RANKING_48 || [];
  if (group) rows = rows.filter((r) => r.group === group);
  if (limit) rows = rows.slice(0, limit);
  return rows.map((r) => ({
    rank: `${r.rank}位`,
    group: r.group,
    team: r.team,
    rating: Number(r.rating).toFixed(1),
    label: r.label,
    feature: teamFeature(r)
  }));
}

function TeamRankingTable({ limit, group }) {
  const rows = rankingRows({ limit, group });
  return <StatusTable rows={rows} columns={[{key:"rank",label:"Rank"},{key:"team",label:"チーム",strong:true},{key:"group",label:"Group"},{key:"rating",label:"総合Rating"},{key:"label",label:"評価ラベル"},{key:"feature",label:"主な特徴"}]} />;
}


function knockoutTableRows({ limit, group, teams, all = false } = {}) {
  let rows = window.KNOCKOUT_TITLE_RANKINGS || window.KNOCKOUT_PROBABILITIES || [];
  if (teams && teams.length) rows = rows.filter((r) => teams.includes(r.team));
  if (group) rows = rows.filter((r) => r.group === group);
  if (!all && !teams && !group && !limit) rows = rows.filter((r) => r.group === "F");
  rows = rows.slice().sort((a, b) => (a.rank || 999) - (b.rank || 999));
  if (limit) rows = rows.slice(0, limit);
  return rows.map((r) => ({
    rank: r.rank ? `${r.rank}位` : "参考",
    team: r.team,
    group: r.group,
    rating: Number(r.rating).toFixed(1),
    r32: koPercentText(r.r32),
    r16: koPercentText(r.r16),
    qf: koPercentText(r.qf),
    sf: koPercentText(r.sf),
    final: koPercentText(r.final),
    title: koPercentText(r.title, "title"),
    comment: r.comment || "現時点の予測"
  }));
}

function KnockoutProbabilityTable({ teams, limit, group, all = false, showRank = true }) {
  const rows = knockoutTableRows({ teams, limit, group, all });
  const columns = [
    ...(showRank ? [{key:"rank",label:"Rank"}] : []),
    {key:"team",label:"チーム",strong:true},
    {key:"group",label:"Group"},
    {key:"rating",label:"Rating"},
    {key:"r32",label:"R32"},
    {key:"r16",label:"R16"},
    {key:"qf",label:"ベスト8"},
    {key:"sf",label:"ベスト4"},
    {key:"final",label:"決勝"},
    {key:"title",label:"優勝"},
    {key:"comment",label:"一言コメント"}
  ];
  return <StatusTable rows={rows} columns={columns} />;
}


function PredictionTable() {
  const columns = [
    { key: "card", label: "対戦カード", strong: true },
    { key: "diff", label: "Rating差" },
    { key: "pick", label: "勝敗予想" },
    { key: "score", label: "予想スコア欄" },
    { key: "point", label: "注目ポイント" }
  ];
  const rows = PREDICTION_MATCHES.map((m) => ({ ...m, diff: `${m.diff.toFixed(1)} pt` }));
  return <StatusTable rows={rows} columns={columns} />;
}

function PlayerDirectory() {
  const teamsList = ["jpn", "ned", "swe", "tun"].map((key) => TEAM_DETAILS[key]);
  const asPlayer = (p) => Array.isArray(p) ? { name: p[0], pos: p[1], club: p[2], rating: p[3], role: p[4] } : p;
  return <div className="player-directory">{teamsList.map((team) => <section className="extra-card" key={team.key}><div className="sub-team-card__head"><span className="flag flag--large"><Flag team={team.key} width="44" height="30" /></span><div><h3>{team.displayName}注目選手</h3><p>{team.en}</p></div></div><div className="mini-player-list">{team.players.slice(0, 4).map((raw) => { const p = asPlayer(raw); return <article key={p.name}><b>{p.name}</b><span>{p.pos} / {p.club}</span><strong>{displayRating(p.wcRating ?? p.rating)}</strong><small>{p.teamRole || p.role || p.grade || "参考情報"}</small></article>; })}</div><a className="text-link" href={TEAM_URLS[team.key]}>チームページで見る{I.arrow}</a></section>)}</div>;
}

function NewsCards() {
  return <div className="extra-card-grid">{NEWS_ITEMS.map((item) => <article className="extra-card" key={item.title}><span>{item.category}</span><h3>{item.title}</h3><p>{item.date} / {item.status}</p><BroadcastBadge text={item.status} /></article>)}</div>;
}

function BroadcastPage() {
  const japanColumns = [
    { key: "card", label: "対戦カード", strong: true },
    { key: "jst", label: "日本時間" },
    { key: "broadcast", label: "放送・配信" },
    { key: "status", label: "状態", badge: true },
    { key: "source", label: "出典" }
  ];
  return <PageShell active="放送・配信">
    <HeroSection eyebrow="Broadcast & Streaming" title="W杯2026はどこで見られる？" subtitle="日本代表戦と全104試合の視聴方法、スマホ・テレビで見る準備をまとめます。" />
    <section className="section section--light wc-section-light"><div className="wrap"><SectionHead eyebrow="Summary" title="結論" lead="日本代表戦の放送局はJFA公式で発表済みです。全104試合はDAZNでライブ配信予定です。" /><InfoCards items={BROADCAST_OVERVIEW_CARDS} /><SourceLine sources={["JFA公式 放送ページ", "DAZN公式", "電通発表"]} /></div></section>
    <section className="section section--light wc-section-light"><div className="wrap"><SectionHead eyebrow="Japan Matches" title="日本代表戦の放送表" lead="3試合の日本時間と放送・配信は以下の通りです。" /><StatusTable rows={JAPAN_BROADCAST_ROWS} columns={japanColumns} /></div></section>
    <section className="section section--dark wc-section-dark"><div className="wrap"><SectionHead eyebrow="TV / BS" title="地上波・BSの全体像" lead="日本代表戦とその他カードは、放送予定を分けて見ておくと分かりやすいです。" /><InfoCards items={[{kicker:"NHK",title:"NHK総合 / NHK BS",body:"日本 vs オランダ、日本 vs スウェーデンはNHK総合、日本 vs チュニジアはNHK BSでも放送予定です。",badge:"発表済み",source:"JFA公式 放送ページ"},{kicker:"NTV",title:"日本テレビ",body:"日本 vs チュニジアは日本テレビで放送予定です。",badge:"発表済み",source:"JFA公式 放送ページ"},{kicker:"Fuji TV",title:"フジテレビ系列",body:"フジテレビ系列では10試合を生放送予定。グループステージ5試合と、日本がGroup Fを突破した場合の決勝トーナメント1回戦を含みます。",badge:"発表済み",source:"フジテレビ発表"}]} /></div></section>
    <section className="section section--light wc-section-light"><div className="wrap"><SectionHead eyebrow="Streaming" title="DAZN" lead="全試合を追いたい場合の中心候補です。日本代表戦も無料ライブ配信予定です。" /><InfoCards items={[{kicker:"Live",title:"全104試合ライブ配信予定",body:"大会全体を追うなら、DAZNの全104試合ライブ配信予定を押さえておきたいところです。",badge:"発表済み",source:"DAZN公式、電通発表"},{kicker:"Japan",title:"日本代表戦は無料ライブ配信予定",body:"日本代表戦は全試合無料ライブ配信予定です。テレビ放送とあわせて選択肢に入ります。",badge:"発表済み",source:"DAZN公式"},{kicker:"Catch Up",title:"見逃し配信",body:"見逃し配信やハイライトの扱いは、大会開始後に更新します。",badge:"大会開始後に更新",source:"DAZN公式"}]} /></div></section>
    <section className="section section--dark wc-section-dark"><div className="wrap"><SectionHead eyebrow="Device" title="観戦準備" lead="テレビで見る人も、スマホで見る人も、先に視聴環境を軽く見直しておくと安心です。" /><InfoCards items={[{kicker:"TV",title:"テレビで見る準備",body:"Fire TV Stick、Chromecast、HDMIケーブルなどを、家のテレビ環境に合わせて選べます。"},{kicker:"Mobile",title:"スマホ・音声",body:"ワイヤレスイヤホンやモバイルバッテリーがあると、深夜や移動中の視聴がしやすくなります。"},{kicker:"Night",title:"深夜観戦グッズ",body:"クッション、ブランケット、コーヒー、軽食など、無理なく観戦するための準備です。"}]} /><RelatedLinks links={[{label:"観戦グッズページ",href:"/worldcup2026/goods/"},{label:"日程ページ",href:"/worldcup2026/schedule/"},{label:"最新記事",href:"/worldcup2026/news/"}]} /></div></section>
    <PageFooter />
  </PageShell>;
}

function RatingsPage() {
  return <PageShell active="Rating">
    <HeroSection eyebrow="Rating Method" title="独自レーティングとは" subtitle="総合100点の内訳、全48チームのRating、Group Fの突破確率、決勝トーナメント予測をまとめた非公式データガイドです。" />
    <section className="section section--light wc-section-light"><div className="wrap"><AnalysisNote title="独自レーティングの考え方">まず選手1人ごとの選手Ratingを作り、攻撃陣・中盤・守備陣・GK・控え層へ集計して、チーム全体のRatingへつなげています。公式ランキングではなく、当サイト独自の観戦用指標です。</AnalysisNote></div></section>
    <section className="section section--dark wc-section-dark"><div className="wrap two-col"><div><SectionHead eyebrow="Total 100" title="総合100点の内訳" lead="選手戦力評価60に、代表実績25、戦術・組織力10、大会適性5を加えて100点満点に整理します。" /><RatingMethodBars items={RATING_METHOD.total} /></div><div><SectionHead eyebrow="Player Strength" title="選手戦力評価の内訳" lead="攻撃陣18、中盤14、守備陣14、GK6、控え層8に分け、選手層の強みと偏りを見えるようにします。" /><RatingMethodBars items={RATING_METHOD.individual} /></div></div></section>
    <section className="section section--light wc-section-light"><div className="wrap"><SectionHead eyebrow="Calculation Flow" title="Rating算出の流れ" lead="選手Ratingから選手戦力評価を作り、代表実績・戦術・大会適性を加えてチームRatingへつなげます。" /><PlayerRatingGuide /></div></section>
    <section className="section section--light wc-section-light"><div className="wrap"><SectionHead eyebrow="Top 10" title="全48チーム Ratingランキング 上位10" lead="当サイト独自Ratingから上位10チームを表示しています。" /><TeamRankingTable limit={10} /><p className="data-note">出典：当サイト独自Rating集計 / 最終更新日：{REMAINING_UPDATED}</p></div></section>
    <section className="section section--dark wc-section-dark"><div className="wrap"><SectionHead eyebrow="Title Race" title="優勝確率ランキング 上位10" lead="決勝トーナメント・優勝確率シミュレーションから、優勝確率上位10チームを表示しています。" /><KnockoutProbabilityTable limit={10} /><p className="data-note">出典：当サイト独自シミュレーション / 最終更新日：{REMAINING_UPDATED}</p></div></section>
    <section className="section section--dark wc-section-dark"><div className="wrap"><SectionHead eyebrow="Group F" title="Group FチームのRating" lead="オランダ、日本、スウェーデン、チュニジアの最新版Ratingと独自指標順位です。" /><TeamRankingTable group="F" /><div className="compare-grid rating-group-cards">{["ned","jpn","swe","tun"].map((key) => <TeamCard key={key} team={TEAM_DETAILS[key]} compact />)}</div></div></section>
    <section className="section section--light wc-section-light"><div className="wrap"><SectionHead eyebrow="Simulation" title="Group F突破確率" lead="1位、2位、3位、4位、3位通過、R32進出率を並べています。" /><GroupProbabilityTable /><GroupFProbabilityInsight /><p className="data-note">出典：当サイト独自シミュレーション / 最終更新日：{REMAINING_UPDATED}</p></div></section>
    <section className="section section--dark wc-section-dark"><div className="wrap"><SectionHead eyebrow="Knockout" title="Group F ノックアウト進出確率" lead="R16、ベスト8、ベスト4、決勝、優勝までの到達確率をGroup Fの4チームで比較します。" /><GroupFKnockoutCards /><KnockoutProbabilityTable group="F" /><p className="data-note">{window.KNOCKOUT_MODEL_NOTICE}</p><RelatedLinks links={[{label:"順位予想ページ",href:"/worldcup2026/predictions/"},{label:"Group F勝敗予想",href:"/worldcup2026/predictions/group-f/"}]} /></div></section>
    <section className="section section--light wc-section-light"><div className="wrap"><SectionHead eyebrow="All 48" title="全48チーム一覧" lead="長い一覧は必要なときだけ開けるようにしています。" /><details className="rating-details"><summary>全48チームRating一覧を開く</summary><TeamRankingTable /></details><details className="rating-details"><summary>全48チーム優勝確率一覧を開く</summary><KnockoutProbabilityTable all /></details></div></section>
    <PageFooter />
  </PageShell>;
}


function scheduleJstLabel(match) {
  return `${match.jstDate}(${match.jstWeekday}) ${match.jstTime}`;
}

function scheduleTimeBand(time) {
  const hour = Number(String(time || "00:00").slice(0, 2));
  if (hour >= 4 && hour <= 6) return "早朝";
  if (hour >= 7 && hour <= 9) return "朝";
  if (hour >= 10 && hour <= 11) return "午前";
  if (hour >= 12 && hour <= 15) return "昼";
  return "深夜";
}

function scheduleBroadcast(match) {
  if (match.matchNo === 11) return { text: "NHK総合、DAZN", status: "発表済み", source: "JFA公式 放送ページ" };
  if (match.matchNo === 36) return { text: "日本テレビ、NHK BS、DAZN", status: "発表済み", source: "JFA公式 放送ページ" };
  if (match.matchNo === 57) return { text: "NHK総合、DAZN", status: "発表済み", source: "JFA公式 放送ページ" };
  return { text: "公式発表後に更新", status: "今後発表があれば更新", source: "FIFA / 放送局発表" };
}

function scheduleStageGroup(stage) {
  if (String(stage).startsWith("グループ")) return "group";
  return stage;
}

function scheduleStageOptions(matches) {
  const ordered = [
    { key: "all", label: "全試合" },
    { key: "japan", label: "日本代表" },
    { key: "group", label: "グループステージ" },
    { key: "ラウンド32", label: "ラウンド32" },
    { key: "ラウンド16", label: "ラウンド16" },
    { key: "準々決勝", label: "準々決勝" },
    { key: "準決勝", label: "準決勝" },
    { key: "3位決定戦", label: "3位決定戦" },
    { key: "決勝", label: "決勝" }
  ];
  return ordered.filter((opt) => opt.key === "all" || opt.key === "japan" || matches.some((m) => scheduleStageGroup(m.stage) === opt.key));
}

function filterScheduleMatches(matches, filter) {
  if (filter === "all") return matches;
  if (filter === "japan") return matches.filter((m) => m.match.includes("日本"));
  return matches.filter((m) => scheduleStageGroup(m.stage) === filter);
}

function scheduleTableRows(matches, showBroadcast = false) {
  return matches.map((m) => {
    const b = scheduleBroadcast(m);
    return {
      no: m.matchNo,
      stage: m.stage,
      date: m.jstDate,
      weekday: m.jstWeekday,
      time: m.jstTime,
      timeBand: scheduleTimeBand(m.jstTime),
      card: m.match,
      venue: m.venue,
      etDate: m.etDate,
      etTime: m.etTime,
      broadcast: b.text,
      status: b.status,
      source: b.source,
      jst: scheduleJstLabel(m)
    };
  });
}

function ScheduleSummaryCards({ matches }) {
  const finalMatch = matches.find((m) => m.stage === "決勝") || matches[matches.length - 1];
  const japanCount = matches.filter((m) => m.match.includes("日本")).length;
  return <div className="schedule-summary-grid">
    <article className="extra-card"><span>Total</span><h3>{matches.length}試合</h3><p>開幕戦から決勝まで、日本時間で一覧できます。</p></article>
    <article className="extra-card"><span>Japan</span><h3>日本代表 {japanCount}試合</h3><p>日本代表戦は放送・配信情報もあわせて表示します。</p></article>
    <article className="extra-card"><span>Final</span><h3>{finalMatch ? scheduleJstLabel(finalMatch) : "参考情報"}</h3><p>{finalMatch ? `${finalMatch.match} / ${finalMatch.venue}` : "決勝日程を一覧に反映します。"}</p></article>
  </div>;
}

function ScheduleFilterTabs({ options, active, onChange }) {
  return <div className="schedule-filter-tabs" role="tablist" aria-label="日程フィルター">{options.map((opt) => <button type="button" key={opt.key} className={active === opt.key ? "is-active" : ""} onClick={() => onChange(opt.key)}>{opt.label}</button>)}</div>;
}

function JapanScheduleTable({ matches }) {
  const rows = scheduleTableRows(matches, true);
  return <StatusTable rows={rows} columns={[{key:"date",label:"日付"},{key:"weekday",label:"曜日"},{key:"time",label:"日本時間"},{key:"card",label:"対戦カード",strong:true},{key:"venue",label:"会場"},{key:"broadcast",label:"放送・配信"},{key:"status",label:"状態",badge:true}]} />;
}

function FullScheduleTable({ matches }) {
  const rows = scheduleTableRows(matches);
  return <StatusTable rows={rows} columns={[{key:"no",label:"Match No."},{key:"stage",label:"Stage"},{key:"date",label:"日本時間日付"},{key:"weekday",label:"曜日"},{key:"time",label:"日本時間"},{key:"timeBand",label:"時間帯"},{key:"card",label:"対戦カード",strong:true},{key:"venue",label:"会場"},{key:"etDate",label:"現地ET日付"},{key:"etTime",label:"現地ET時刻"}]} />;
}

function ScheduleDateGroups({ matches }) {
  const grouped = matches.reduce((acc, match) => {
    const key = `${match.jstDate}(${match.jstWeekday})`;
    if (!acc[key]) acc[key] = [];
    acc[key].push(match);
    return acc;
  }, {});
  return <div className="schedule-date-groups">{Object.entries(grouped).map(([date, rows], idx) => <details className="rating-details schedule-date-detail" key={date} open={idx < 2 || rows.some((m) => m.match.includes("日本"))}><summary>{date} / {rows.length}試合</summary><div className="schedule-date-list">{rows.map((m) => <article className="schedule-line" key={m.matchNo}><span>Match {m.matchNo}</span><b>{m.jstTime} {m.match}</b><small>{m.stage} / {m.venue}</small></article>)}</div></details>)}</div>;
}

function ScheduleSourceNote() {
  return <AnalysisNote title="出典・確認メモ">本ページの日程は、CSVで整理したW杯2026全104試合の日本時間一覧に基づいています。キックオフ時刻、会場、放送・配信予定は公式発表や放送局発表により変更される場合があります。公開前・大会前に最新情報を確認します。</AnalysisNote>;
}

function SchedulePage() {
  const matches = (window.WC2026_SCHEDULE_MATCHES || []).slice().sort((a, b) => Number(a.matchNo) - Number(b.matchNo));
  const [filter, setFilter] = useSubState("all");
  const options = scheduleStageOptions(matches);
  const filteredMatches = filterScheduleMatches(matches, filter);
  const japanMatches = matches.filter((m) => m.match.includes("日本"));
  return <PageShell active="日程">
    <HeroSection eyebrow="Match Schedule" title="W杯2026 日本時間 試合日程" subtitle="開幕戦から決勝まで、全104試合のキックオフ時刻を日本時間で整理。日本代表戦、グループ別、決勝トーナメントもまとめて確認できます。">
      <p className="data-note">最終更新日：{window.WC2026_SCHEDULE_UPDATED || REMAINING_UPDATED} / 日本時間表示</p>
    </HeroSection>
    <section className="section section--light wc-section-light"><div className="wrap"><SectionHead eyebrow="Overview" title="全104試合の日本時間一覧" lead="CSVの全試合日程を反映しています。まずは日本代表戦と決勝日程を押さえられます。" /><ScheduleSummaryCards matches={matches} /><ScheduleSourceNote /></div></section>
    <section className="section section--dark wc-section-dark"><div className="wrap"><SectionHead eyebrow="Japan Matches" title="日本代表戦ピックアップ" lead="日本が含まれる3試合をCSVから抽出し、既存の放送・配信情報を維持して表示します。" /><JapanScheduleTable matches={japanMatches} /><SourceLine sources={["JFA公式 放送ページ", "DAZN公式", "日程CSV"]} updated={window.WC2026_SCHEDULE_UPDATED || REMAINING_UPDATED} /></div></section>
    <section className="section section--light wc-section-light"><div className="wrap"><SectionHead eyebrow="Filter" title="ステージ別に見る" lead="全試合、日本代表、グループステージ、決勝トーナメントで表示を切り替えられます。" /><ScheduleFilterTabs options={options} active={filter} onChange={setFilter} /><FullScheduleTable matches={filteredMatches} /></div></section>
    <section className="section section--light wc-section-light"><div className="wrap"><SectionHead eyebrow="By Date" title="日付別表示" lead="同じ日本時間日付の試合をまとめて確認できます。" /><ScheduleDateGroups matches={filteredMatches} /></div></section>
    <section className="section section--dark wc-section-dark"><div className="wrap"><SectionHead eyebrow="Related" title="関連ページ" lead="視聴方法や予想ページとあわせて確認できます。" /><RelatedLinks links={[{label:"放送・配信ページ",href:"/worldcup2026/broadcast/"},{label:"順位予想ページ",href:"/worldcup2026/predictions/"},{label:"日本代表ページ",flag:"jpn",href:"/worldcup2026/teams/japan/"}]} /></div></section>
    <PageFooter />
  </PageShell>;
}
function GoodsPage() {
  return <PageShell active="観戦準備"><HeroSection eyebrow="Watch Setup" title="観戦準備ガイド" subtitle="Coming Soon" />
    <section className="section section--light wc-section-light"><div className="wrap"><SectionHead eyebrow="Coming Soon" title="近日公開" lead="W杯2026をより楽しむための観戦準備ガイドは、現在準備中です。放送・配信情報、日本時間の日程、順位予想は先に公開しています。" /><AnalysisNote title="先に公開中のページ">放送・配信情報、日本時間の全104試合日程、順位予想・勝ち上がり予想は先に公開しています。観戦準備ガイドは、内容が整い次第このページで公開します。公開までお待ちください。</AnalysisNote></div></section>
    <section className="section section--tint wc-section-light"><div className="wrap"><SectionHead eyebrow="Open Now" title="先に公開中のページ" /><RelatedLinks links={[{label:"日程ページへ",href:"/worldcup2026/schedule/"},{label:"放送・配信ページへ",href:"/worldcup2026/broadcast/"},{label:"順位予想ページへ",href:"/worldcup2026/predictions/"},{label:"W杯2026トップへ戻る",href:"/worldcup2026/"}]} /></div></section>
    <PageFooter /></PageShell>;
}

function PredictionsPage() {
  return <PageShell active="勝敗予想">
    <HeroSection eyebrow="Group F Predictions" title="Group F勝敗予想" subtitle="6試合のRating差、突破確率、日本の突破条件を独自分析としてまとめます。" />
    <section className="section section--light wc-section-light"><div className="wrap"><AnalysisNote title="予想の扱い">当サイト独自レーティングをもとにした観戦用の見立てです。結果を断定するものではなく、公式情報でもありません。</AnalysisNote></div></section>
    <section className="section section--dark wc-section-dark"><div className="wrap"><SectionHead eyebrow="Six Matches" title="6試合の予想一覧" lead="Rating差は総合Ratingをもとにした目安です。スコア欄は暫定予測として掲載しています。" /><PredictionTable /></div></section>
    <section className="section section--light wc-section-light"><div className="wrap"><SectionHead eyebrow="Simulation" title="Group F突破確率" lead="1位、2位、3位、4位、3位通過、R32進出率を並べています。" /><GroupProbabilityTable /><GroupFProbabilityInsight /><SourceLine sources={["当サイト独自Rating", "グループステージ予測"]} /></div></section>
    <section className="section section--dark wc-section-dark"><div className="wrap"><SectionHead eyebrow="Knockout" title="決勝T到達確率" lead="R32以降は現時点の暫定予測です。" /><KnockoutProbabilityTable group="F" /><p className="data-note">{window.KNOCKOUT_MODEL_NOTICE}</p></div></section>
    <section className="section section--dark wc-section-dark"><div className="wrap"><SectionHead eyebrow="Japan Path" title="日本代表の勝ち上がりシナリオ" lead="1位通過、2位通過、3位通過で見える道のりは変わります。数値は現時点の独自シミュレーションです。" /><JapanKnockoutOutlook /><InfoCards items={[{kicker:"1st Place",title:"1位通過なら上振れを狙いやすい",body:"強豪との山を避けられる可能性があり、R32以降の見え方が少し軽くなります。ただし相手配置は公式確定後に変わります。"},{kicker:"2nd Place",title:"2位通過が現実ライン",body:"日本は2位通過が本線です。R16進出は十分に狙え、ベスト8以上は対戦相手とコンディション次第の上振れラインです。"},{kicker:"3rd Place",title:"3位通過は山が重くなるリスク",body:"3位通過に回ると相手と配置の不確実性が増えます。まずはチュニジア戦で取りこぼさず、スウェーデン戦で勝ち点を確保したいところです。"}]} /><AnalysisNote title="予測の注意点">本ページの決勝トーナメント予測は、現時点の独自Ratingとシミュレーションに基づく暫定予測です。優勝確率は低い数字ですが、攻撃陣と中盤の質がかみ合い、組み合わせに恵まれれば、夢として追える余地はあります。</AnalysisNote></div></section>
    <section className="section section--light wc-section-light"><div className="wrap"><SectionHead eyebrow="Japan Route" title="日本の突破条件" /><InfoCards items={[{kicker:"Minimum",title:"チュニジア戦で取りこぼさない",body:"勝ち点3を取れれば、突破争いをかなり進めやすくなります。"},{kicker:"Key Match",title:"スウェーデン戦で勝ち点",body:"前線火力を抑えながら、勝ち点1以上を確保できるかが大きな分岐点です。"},{kicker:"Challenge",title:"オランダ戦で上積み",body:"引き分け以上なら1位通過や得失点差の面で大きな上積みになります。"}]} /><AnalysisNote title="予測の注意点">本ページのレーティングと突破確率は、現時点の独自Ratingとシミュレーションに基づく暫定予測です。実際の結果を保証するものではありません。メンバー変更、怪我、コンディション、対戦カードの状況によって変動します。</AnalysisNote><SourceLine sources={["当サイト独自Rating", "グループステージ予測", "決勝トーナメント予測"]} /></div></section>
    <PageFooter />
  </PageShell>;
}


function PredictionsGroupFPage() {
  return <PredictionsPage />;
}

function PlayersPage() {
  return <PageShell active="注目選手"><HeroSection eyebrow="Players to Watch" title="Group F注目選手" subtitle="Group F各国の注目選手を、チームページとあわせて見られる一覧です。" /><section className="section section--light wc-section-light"><div className="wrap"><AnalysisNote title="選手情報の扱い">選手カードは各チームページ内に載せ切る方針です。Group F全体から注目選手を一覧し、詳しく見たい場合はチームページで確認できます。</AnalysisNote></div></section><section className="section section--light wc-section-light"><div className="wrap"><SectionHead eyebrow="Directory" title="各国の注目選手" /><PlayerDirectory /></div></section><section className="section section--dark wc-section-dark"><div className="wrap"><SectionHead eyebrow="Explore" title="チームページへ" /><RelatedLinks links={[{label:"日本代表ページ",flag:"jpn",href:"/worldcup2026/teams/japan/"},{label:"オランダ代表ページ",flag:"ned",href:"/worldcup2026/teams/netherlands/"},{label:"スウェーデン代表ページ",flag:"swe",href:"/worldcup2026/teams/sweden/"},{label:"チュニジア代表ページ",flag:"tun",href:"/worldcup2026/teams/tunisia/"}]} /></div></section><PageFooter /></PageShell>;
}

function NewsPage() {
  return <PageShell active="ニュース"><HeroSection eyebrow="News & Updates" title="ニュース・更新一覧" subtitle="最新記事、更新履歴、メンバー変更、怪我情報、放送予定更新、試合後分析をまとめます。" /><section className="section section--light wc-section-light"><div className="wrap"><SectionHead eyebrow="Latest" title="最新記事一覧" lead="大会中の更新情報を、記事・動画・データ更新に分けて整理します。" /><NewsCards /></div></section><section className="section section--light wc-section-light"><div className="wrap"><SectionHead eyebrow="Update Log" title="更新履歴" /><StatusTable rows={NEWS_ITEMS.map((n) => ({ type: n.category, title: n.title, date: n.date, status: n.status }))} columns={[{key:"type",label:"種別"},{key:"title",label:"内容",strong:true},{key:"date",label:"日付"},{key:"status",label:"状態",badge:true}]} /></div></section><section className="section section--dark wc-section-dark"><div className="wrap"><SectionHead eyebrow="Related" title="関連ページ" /><RelatedLinks links={[{label:"Group F分析",href:"/worldcup2026/groups/group-f/"},{label:"放送・配信",href:"/worldcup2026/broadcast/"},{label:"日程",href:"/worldcup2026/schedule/"},{label:"注目選手",href:"/worldcup2026/players/"}]} /></div></section><PageFooter /></PageShell>;
}

function RemainingPagesApp() {
  const key = window.REMAINING_PAGE_KEY;
  const pages = { broadcast: BroadcastPage, ratings: RatingsPage, schedule: SchedulePage, goods: GoodsPage, predictions: PredictionsIndexPage, predictionsGroupF: PredictionsGroupFPage, players: PlayersPage, news: NewsPage };
  const Page = pages[key] || NewsPage;
  return <Page />;
}

function mountRemainingPagesApp(retries = 60) {
  const root = document.getElementById("root");
  if (!root) {
    if (retries > 0) window.setTimeout(() => mountRemainingPagesApp(retries - 1), 50);
    return;
  }
  if (root.dataset.mounted === "true") return;
  root.dataset.mounted = "true";
  const appRoot = ReactDOM.createRoot(root);
  ReactDOM.flushSync(() => appRoot.render(<RemainingPagesApp />));
}

mountRemainingPagesApp();
window.addEventListener("DOMContentLoaded", () => mountRemainingPagesApp(), { once: true });




