/* =============================================================================
   NewslettersPage — the "Newsletters" tab: a team + date selector that renders
   Will's newsletter "scaffolding" for the chosen issue.

   FIDELITY: this is a faithful web port of Will's Ghost email build-sheet
   (design-source/newsletter/Synth Issue - Rams Oct 20.html — 11 inline-styled
   cards). Will's markup is table-based + inline-styled for email; on the website
   we reproduce the SAME visual design with the same values/colors/type, laid out
   with the same structure. Where a card is data-driven it reads from
   window.SYNTH_ISSUES (newsletter_issues.js). Charts render as static <img>
   slots (Will's rule: no interactive charts in the newsletter itself).

   Day-type variants (Aug 6 meeting note): full (Mon/Tue, full box score) /
   condensed (Wed/Thu, line score only) / preview (Fri/Sat, condensed + injury
   report) / bye (no game). Team Power + Coach Decision ranking cards are OMITTED
   for now (Will hasn't designed them) — marked slots left where they belong.
   ========================================================================== */

// ---- shared style constants (mirror Will's inline email values) ------------
const NL = {
  card:      { width:'100%', maxWidth:602, margin:'0 auto 18px', background:'#FFFFFF', border:'1px solid #E4DCCB', borderRadius:14, overflow:'hidden', boxSizing:'border-box' },
  plain:     { width:'100%', maxWidth:602, margin:'0 auto 14px', boxSizing:'border-box' },
  serif:     "'Newsreader', Georgia, serif",
  sans:      "'IBM Plex Sans', Helvetica, sans-serif",
  mono:      "'IBM Plex Mono', monospace",
  ink:       '#142B4D',
  ink2:      '#3B4A66',
  ink3:      '#566078',
  rule:      '#E4DCCB',
  ruleSoft:  '#EFE9DF',
  paper2:    '#F7F3EA',
};
function teamColor(abbr){ return (window.SYNTH_TEAM_COLORS||{})[abbr] || {p:'#142B4D', ink:'#FFFFFF'}; }

// ---- card chrome: eyebrow (dash + label) ----------------------------------
function Eyebrow({ label, color }) {
  return (
    <div>
      <span style={{ display:'inline-block', width:20, height:3, background:color, borderRadius:2, verticalAlign:'middle' }} />
      <span style={{ fontFamily:NL.mono, fontSize:11, fontWeight:600, letterSpacing:'.14em', textTransform:'uppercase', color, marginLeft:9, verticalAlign:'middle' }}>{label}</span>
    </div>
  );
}

// ---- 01 masthead -----------------------------------------------------------
function Masthead({ issue }) {
  const tc = teamColor(issue.team);
  const tn = (window.SYNTH_TEAM_NAMES||{})[issue.team] || {city:issue.team, name:''};
  const m = issue.masthead || {};
  return (
    <div style={NL.card}>
      <div style={{ height:6, background:tc.p }} />
      <div style={{ padding:'22px 26px 0', display:'flex', alignItems:'center', justifyContent:'space-between' }}>
        <span style={{ display:'flex', alignItems:'center' }}>
          <img src="../assets/synth-logo-mono-outline.svg" width="44" height="44" alt="Synth" style={{ width:44, height:44, verticalAlign:'middle' }} />
          <span style={{ fontFamily:NL.serif, fontWeight:700, fontSize:27, letterSpacing:'-0.03em', color:NL.ink, lineHeight:1, marginLeft:9, position:'relative', top:4 }}>Synth</span>
        </span>
        <span style={{ textAlign:'right', fontFamily:NL.mono, fontSize:11, letterSpacing:'.04em', color:NL.ink3, lineHeight:1.6 }}>
          {m.dateLine}<br/>{m.weekLabel} · {m.editionLabel}
        </span>
      </div>
      <div style={{ padding:'16px 26px 22px' }}>
        <div style={{ borderTop:`1px solid ${NL.rule}`, paddingTop:14 }}>
          <span style={{ display:'inline-block', fontFamily:NL.mono, fontSize:11, fontWeight:600, letterSpacing:'.1em', color:tc.ink, background:tc.p, padding:'4px 11px', borderRadius:999, verticalAlign:'middle' }}>{issue.team}</span>
          <span style={{ fontFamily:NL.serif, fontWeight:600, fontSize:21, letterSpacing:'-0.02em', color:NL.ink, verticalAlign:'middle', marginLeft:10 }}>{tn.city} {tn.name} edition</span>
        </div>
      </div>
    </div>
  );
}

// ---- 02 gamecard: box score (+ leaders when full/preview) + next game ------
function StatLeaders({ side, color }) {
  const tc = teamColor(side.abbr);
  return (
    <div>
      <div style={{ display:'flex', alignItems:'center', margin:'18px 0 6px' }}>
        <span style={{ display:'inline-block', fontFamily:NL.mono, fontSize:11, fontWeight:600, letterSpacing:'.1em', color:tc.ink, background:tc.p, padding:'3px 9px', borderRadius:999 }}>{side.abbr}</span>
        <span style={{ fontFamily:NL.sans, fontSize:12.5, color:NL.ink, marginLeft:9 }}>{side.city}</span>
      </div>
      <table style={{ width:'100%', borderCollapse:'collapse', tableLayout:'fixed' }}><tbody>
        {(side.leaders||[]).map((L,i)=>(
          <tr key={i}>
            <td style={{ width:'11%', fontFamily:NL.mono, fontSize:11, letterSpacing:'.08em', color:NL.ink3, padding:'7px 0', borderTop:i?`1px solid ${NL.ruleSoft}`:'none' }}>{L.pos}</td>
            <td style={{ width:'33%', fontFamily:NL.sans, fontSize:12, color:NL.ink2, padding:'7px 0', borderTop:i?`1px solid ${NL.ruleSoft}`:'none', whiteSpace:'nowrap' }}>{L.name}</td>
            {['a','b','c'].map((k,j)=>(
              <td key={k} style={{ width:'18.6%', fontFamily:NL.mono, fontSize:11, textAlign:'right', fontVariantNumeric:'tabular-nums', color:NL.ink2, padding:'7px 0', borderTop:i?`1px solid ${NL.ruleSoft}`:'none' }}>{L[k]}</td>
            ))}
          </tr>
        ))}
      </tbody></table>
    </div>
  );
}
function BoxScore({ bs, showLeaders }) {
  const homeC = teamColor(bs.home.abbr), awayC = teamColor(bs.away.abbr);
  const row = (side, tint) => (
    <tr>
      <td style={{ fontFamily:NL.mono, fontSize:12.5, fontWeight:side.win?600:400, color:side.win?NL.ink:NL.ink3, padding:'5px 0', borderTop:tint?`1px solid ${NL.ruleSoft}`:'none' }}>{side.abbr}</td>
      {side.line.map((q,i)=>(
        <td key={i} style={{ textAlign:'center', fontFamily:NL.mono, fontSize:13, color:q?NL.ink2:NL.ink3, padding:'5px 0', borderTop:tint?`1px solid ${NL.ruleSoft}`:'none', fontVariantNumeric:'tabular-nums' }}>{q}</td>
      ))}
      <td style={{ textAlign:'right', fontFamily:NL.sans, fontSize:22, fontWeight:side.win?700:500, color:side.win?teamColor(side.abbr).p:NL.ink3, padding:'5px 0', borderTop:tint?`1px solid ${NL.ruleSoft}`:'none', fontVariantNumeric:'tabular-nums' }}>{side.total}</td>
    </tr>
  );
  return (
    <div>
      <table style={{ width:'100%', borderCollapse:'collapse', tableLayout:'fixed' }}><tbody>
        <tr>
          <td style={{ width:74 }} />
          {['1','2','3','4'].map(n=>(<td key={n} style={{ textAlign:'center', fontFamily:NL.mono, fontSize:11, letterSpacing:'.08em', color:NL.ink3, padding:'0 0 2px' }}>{n}</td>))}
          <td style={{ width:66 }} />
        </tr>
        {row(bs.home, false)}
        {row(bs.away, true)}
      </tbody></table>
      {showLeaders && (<div>
        <StatLeaders side={bs.home} color={homeC.p} />
        <StatLeaders side={bs.away} color={awayC.p} />
      </div>)}
    </div>
  );
}
function NextGame({ ng }) {
  const hc = teamColor(ng.home.abbr), ac = teamColor(ng.away.abbr);
  const teamCol = (side, tc) => (
    <td style={{ width:'30%', verticalAlign:'top', padding:'2px 4px 0' }}>
      <div style={{ width:38, height:38, borderRadius:'50%', background:tc.p, margin:'0 auto', textAlign:'center', lineHeight:'38px', fontFamily:NL.mono, fontSize:11, letterSpacing:'.04em', color:tc.ink }}>{side.abbr}</div>
      <div style={{ fontFamily:NL.sans, fontSize:12, letterSpacing:'.06em', textTransform:'uppercase', color:NL.ink, textAlign:'center', marginTop:9, lineHeight:1.2 }}>{side.name}</div>
      <div style={{ fontFamily:NL.mono, fontSize:11, color:NL.ink3, textAlign:'center', marginTop:4 }}>{side.record}</div>
    </td>
  );
  return (
    <div style={{ padding:'14px 26px 18px', background:NL.paper2, borderTop:`1px solid ${NL.rule}` }}>
      <div style={{ display:'flex', justifyContent:'space-between', paddingBottom:12 }}>
        <span style={{ fontFamily:NL.mono, fontSize:11, fontWeight:600, letterSpacing:'.14em', textTransform:'uppercase', color:NL.ink3 }}>Next game</span>
        <span style={{ fontFamily:NL.mono, fontSize:11, letterSpacing:'.06em', color:NL.ink3 }}>{ng.weekLabel}</span>
      </div>
      <table style={{ width:'100%', borderCollapse:'collapse', tableLayout:'fixed' }}><tbody><tr>
        {teamCol(ng.home, hc)}
        <td style={{ width:'40%', verticalAlign:'top', textAlign:'center', padding:'6px 2px 0' }}>
          <div style={{ fontFamily:NL.mono, fontSize:11, letterSpacing:'.12em', textTransform:'uppercase', color:NL.ink3 }}>{ng.dayDate}</div>
          <div style={{ fontFamily:NL.serif, fontSize:19, fontWeight:600, letterSpacing:'-0.02em', color:NL.ink, margin:'5px 0', whiteSpace:'nowrap' }}>{ng.kickoff}</div>
          <div style={{ fontFamily:NL.mono, fontSize:11, letterSpacing:'.12em', textTransform:'uppercase', color:NL.ink3 }}>{ng.tv}</div>
        </td>
        {teamCol(ng.away, ac)}
      </tr></tbody></table>
      <div style={{ textAlign:'center', borderTop:`1px solid ${NL.rule}`, marginTop:14, paddingTop:12, fontFamily:NL.mono, fontSize:11, letterSpacing:'.1em', textTransform:'uppercase', color:NL.ink3 }}>
        {ng.location}{ ng.betting ? <React.Fragment> &nbsp;·&nbsp; <b style={{ color:NL.ink }}>{ng.betting}</b></React.Fragment> : '' }
      </div>
    </div>
  );
}
function GameCard({ issue }) {
  const bs = issue.boxScore, ng = issue.nextGame, dt = issue.dayType;
  if (dt === 'bye') {
    return (
      <div style={NL.card}>
        <div style={{ padding:'18px 26px', fontFamily:NL.mono, fontSize:11, letterSpacing:'.06em', color:NL.ink3, textAlign:'center' }}>Bye week — no game this week.</div>
        {ng && <NextGame ng={ng} />}
      </div>
    );
  }
  const showLeaders = (dt === 'full');  // condensed/preview drop player stats
  return (
    <div style={NL.card}>
      <div style={{ padding:'16px 26px 12px', background:NL.paper2, borderBottom:`1px solid ${NL.rule}`, display:'flex', justifyContent:'space-between' }}>
        <span style={{ fontFamily:NL.mono, fontSize:11, fontWeight:600, letterSpacing:'.14em', textTransform:'uppercase', color:NL.ink3 }}>{bs.status}</span>
        <span style={{ fontFamily:NL.mono, fontSize:11, letterSpacing:'.06em', color:NL.ink3 }}>{bs.location}</span>
      </div>
      <div style={{ padding:'18px 26px 16px' }}>
        <BoxScore bs={bs} showLeaders={showLeaders} />
      </div>
      {ng && <NextGame ng={ng} />}
    </div>
  );
}

// ---- 03 opening (drop-cap) -------------------------------------------------
function Opening({ issue }) {
  const tc = teamColor(issue.team);
  const txt = issue.opening || '';
  const first = txt.charAt(0), rest = txt.slice(1);
  const rule = <div style={{ height:3, background:tc.p, borderRadius:2 }} />;
  return (
    <div style={NL.plain}>
      <div style={{ padding:'10px 26px 16px' }}>
        <div style={{ marginBottom:16 }}>{rule}</div>
        <div style={{ fontFamily:NL.serif, fontSize:19, lineHeight:1.5, color:NL.ink, letterSpacing:'-0.005em' }}>
          <span style={{ float:'left', fontFamily:NL.serif, fontSize:56, lineHeight:0.8, fontWeight:600, color:tc.p, margin:'5px 9px 0 0' }}>{first}</span>{rest}
        </div>
        <div style={{ marginTop:16 }}>{rule}</div>
      </div>
    </div>
  );
}

// ---- 04 fan sentiment (ring + aspects) -------------------------------------
function SentimentRing({ score, delta, up, color }) {
  const r=42, c=2*Math.PI*r, pct=Math.max(0,Math.min(100, score||0));
  const dash = (pct/100)*c;
  return (
    <svg width="116" height="116" viewBox="0 0 100 100" style={{ display:'block' }}>
      <circle cx="50" cy="50" r={r} fill="none" stroke="#ECE5D6" strokeWidth="9" />
      <circle cx="50" cy="50" r={r} fill="none" stroke={color} strokeWidth="9" strokeLinecap="round"
        strokeDasharray={`${dash} ${c}`} transform="rotate(-90 50 50)" />
      <text x="50" y="49" textAnchor="middle" style={{ fontFamily:NL.serif, fontWeight:700, fontSize:27, fill:NL.ink }}>{score==null?'—':score}</text>
      <text x="50" y="66" textAnchor="middle" style={{ fontFamily:NL.mono, fontSize:10, fill: up?'#2E7D5B':'#B83A2D' }}>{delta||''}</text>
    </svg>
  );
}
function Sentiment({ issue }) {
  const tc = teamColor(issue.team), s = issue.sentiment || {};
  return (
    <div style={NL.card}>
      <div style={{ padding:'20px 26px 0' }}><Eyebrow label="Fan sentiment" color={tc.p} /></div>
      <div style={{ padding:'14px 26px 4px', display:'flex', alignItems:'center', gap:18 }}>
        <div style={{ flex:'0 0 auto' }}><SentimentRing score={s.score} delta={s.delta} up={s.up} color={tc.p} /></div>
        <div>
          <h3 style={{ margin:'0 0 6px', fontFamily:NL.serif, fontWeight:600, fontSize:20, letterSpacing:'-0.02em', color:NL.ink }}>{s.headline}</h3>
          <p style={{ margin:0, fontFamily:NL.sans, fontSize:14, lineHeight:1.6, color:NL.ink2 }}>{s.blurb}</p>
        </div>
      </div>
      <div style={{ padding:'14px 26px 20px' }}>
        <div style={{ fontFamily:NL.mono, fontSize:11, fontWeight:600, letterSpacing:'.14em', textTransform:'uppercase', color:NL.ink3, margin:'6px 0 8px' }}>Top aspects driving fan conversation</div>
        <ol style={{ margin:0, paddingLeft:18, fontFamily:NL.sans, fontSize:13.5, lineHeight:1.7, color:NL.ink2 }}>
          {(s.aspects||[]).map((a,i)=>(<li key={i}>{a}</li>))}
        </ol>
      </div>
      {/* Team Power Rankings slot (Wed/Thu only) — OMITTED for now (Will hasn't designed it). */}
    </div>
  );
}

// ---- inline markdown (**bold** → <strong>) ---------------------------------
function inlineMd(text) {
  const parts = String(text||'').split(/(\*\*.+?\*\*)/g);
  return parts.map((p,i)=> p.startsWith('**') && p.endsWith('**')
    ? <strong key={i}>{p.slice(2,-2)}</strong> : <React.Fragment key={i}>{p}</React.Fragment>);
}
// A card body block: paragraph | bullets | table. Bet disclaimer paras (leading *) render italic.
function Block({ block }) {
  if (block.kind === 'para') {
    const t = block.text || '';
    const isDisc = t.startsWith('*') && t.endsWith('*') && !t.startsWith('**');
    if (isDisc) return <p style={{ margin:'0 0 12px', fontFamily:NL.sans, fontSize:11, lineHeight:1.55, color:NL.ink3, fontStyle:'italic' }}>{t.slice(1,-1)}</p>;
    return <p style={{ margin:'0 0 12px', fontFamily:NL.sans, fontSize:15, lineHeight:1.65, color:NL.ink2 }}>{inlineMd(t)}</p>;
  }
  if (block.kind === 'bullets') {
    return <ul style={{ margin:'0 0 14px', paddingLeft:20, fontFamily:NL.sans, fontSize:14.5, lineHeight:1.7, color:NL.ink2 }}>
      {block.items.map((b,i)=>(<li key={i}>{inlineMd(b)}</li>))}
    </ul>;
  }
  if (block.kind === 'table') {
    const rows = block.rows || [];
    if (!rows.length) return null;
    const [head, ...body] = rows;
    return (
      <div style={{ overflowX:'auto', margin:'0 0 14px' }}>
        <table style={{ width:'100%', borderCollapse:'collapse', fontFamily:NL.mono, fontSize:12 }}><tbody>
          <tr>{head.map((c,i)=>(<td key={i} style={{ textAlign: i?'right':'left', padding:'6px 8px', borderBottom:`1px solid ${NL.rule}`, color:NL.ink3, fontWeight:600, letterSpacing:'.02em' }}>{c}</td>))}</tr>
          {body.map((r,ri)=>(<tr key={ri}>{r.map((c,ci)=>(<td key={ci} style={{ textAlign: ci?'right':'left', padding:'6px 8px', borderBottom:`1px solid ${NL.ruleSoft}`, color: ci?NL.ink:NL.ink2, fontVariantNumeric:'tabular-nums' }}>{c}</td>))}</tr>))}
        </tbody></table>
      </div>
    );
  }
  return null;
}
// ---- 05-09 content cards (Story / Stat / Bet from parsed rendered_body) -----
function ContentCard({ issue, card, dateLabel }) {
  const tc = teamColor(issue.team);
  const isBet = card.type === 'Bet';
  const cardStyle = Object.assign({}, NL.card, isBet ? { border:'1px solid #2E7D5B' } : {});
  return (
    <div style={cardStyle}>
      <div style={{ padding:'20px 26px 0', display:'flex', justifyContent:'space-between', alignItems:'center' }}>
        <Eyebrow label={card.type} color={tc.p} />
        <span style={{ fontFamily:NL.mono, fontSize:10.5, letterSpacing:'.08em', textTransform:'uppercase', color:NL.ink3 }}>{card.type.toLowerCase()} · {dateLabel} · {issue.team}</span>
      </div>
      {card.headline && (
        <div style={{ padding:'13px 26px 0' }}>
          <h3 style={{ margin:0, fontFamily:NL.serif, fontWeight:600, fontSize:24, lineHeight:1.18, letterSpacing:'-0.025em', color:NL.ink }}>{card.headline}</h3>
        </div>
      )}
      <div style={{ padding:'12px 26px 0' }}>
        {(card.blocks||[]).map((b,i)=>(<Block key={i} block={b} />))}
      </div>
      {card.chart && card.chart.src && (
        <div style={{ padding:'8px 26px 8px' }}>
          {/* bare transparent PNG: we render title/subtitle/source as text around it */}
          {card.chart.title && (
            <div style={{ fontFamily:NL.serif, fontWeight:600, fontSize:16, letterSpacing:'-0.01em', color:NL.ink, marginBottom: card.chart.subtitle?2:8 }}>{card.chart.title}</div>
          )}
          {card.chart.subtitle && (
            <div style={{ fontFamily:NL.sans, fontSize:12.5, color:NL.ink3, marginBottom:8 }}>{card.chart.subtitle}</div>
          )}
          <img src={card.chart.src} alt={card.chart.alt||''} style={{ width:'100%', maxWidth:600, height:'auto', display:'block' }} />
          {card.chart.source && (
            <div style={{ fontFamily:NL.mono, fontSize:10.5, letterSpacing:'.04em', color:NL.ink3, marginTop:6 }}>{card.chart.source}</div>
          )}
        </div>
      )}
      <div style={{ padding:'0 26px 18px' }} />
    </div>
  );
}
function NewsletterBody({ issue }) {
  const nl = issue.newsletter || {};
  const dateLabel = (issue.masthead && issue.masthead.dateLine) ? issue.masthead.dateLine.split(' · ').pop() : issue.date;
  if (nl.status !== 'present' || !nl.cards || nl.cards.length === 0) {
    return (
      <div style={Object.assign({}, NL.card, { borderStyle:'dashed' })}>
        <div style={{ padding:'40px 26px', textAlign:'center', fontFamily:NL.mono, fontSize:12, letterSpacing:'.04em', color:NL.ink3 }}>
          {nl.placeholder || 'Newsletter not generated yet for this date.'}<br/>
          <span style={{ fontSize:11, color:'#8A93A6' }}>The analysis-agent cards (Story / Stat / Bet) will appear here once produced.</span>
        </div>
      </div>
    );
  }
  return (<div>{nl.cards.map((c,i)=>(<ContentCard key={i} issue={issue} card={c} dateLabel={dateLabel} />))}</div>);
}

// ---- injury / availability (only when window_active, per the DB) -----------
function InjuryReport({ issue }) {
  const inj = issue.injury;
  if (!inj || !inj.active) return null;   // honor the analysis-side window_active flag
  const tc = teamColor(issue.team);
  const roster = inj.roster || [];
  return (
    <div style={NL.card}>
      <div style={{ padding:'20px 26px 0' }}><Eyebrow label="Injury report" color={tc.p} /></div>
      <div style={{ padding:'12px 26px 20px' }}>
        <div style={{ fontFamily:NL.mono, fontSize:10, letterSpacing:'.04em', color:'#8A93A6', marginBottom:10 }}>Roster status (IR/PUP/etc.). Weekly Questionable/Probable feed is deferred.</div>
        <table style={{ width:'100%', borderCollapse:'collapse' }}><tbody>
          {roster.map((r,i)=>(
            <tr key={i}>
              <td style={{ fontFamily:NL.sans, fontSize:13, color:NL.ink2, padding:'7px 0', borderTop:i?`1px solid ${NL.ruleSoft}`:'none' }}>{r.name}{r.position?<span style={{ color:NL.ink3, marginLeft:8, fontFamily:NL.mono, fontSize:11 }}>{r.position}</span>:''}</td>
              <td style={{ fontFamily:NL.mono, fontSize:11, letterSpacing:'.06em', textTransform:'uppercase', textAlign:'right', color:NL.ink3, padding:'7px 0', borderTop:i?`1px solid ${NL.ruleSoft}`:'none' }}>{r.status}</td>
            </tr>
          ))}
        </tbody></table>
      </div>
    </div>
  );
}

// ---- 10 around the league (real AFC/NFC standings tables) ------------------
function ConfTable({ conf, rows, focalTeam }) {
  const seeded = rows.seeded || [];
  const out = rows.out || [];
  const line = (label) => (
    <tr><td colSpan={3} style={{ padding:'6px 0 6px', borderTop:`1px solid ${NL.rule}`, borderBottom:`1px solid ${NL.rule}`, fontFamily:NL.mono, fontSize:9.5, letterSpacing:'.14em', textTransform:'uppercase', color:'#B0453B', fontWeight:600 }}>{label}</td></tr>
  );
  const teamRow = (r, seededRow) => {
    const tc = teamColor(r.key);
    const focal = r.key === focalTeam;
    return (
      <tr key={r.key} style={ focal ? { background:'rgba(0,0,0,0.03)' } : null }>
        <td style={{ padding:'7px 0', fontFamily:NL.mono, fontSize:11, color:NL.ink3, width:24, textAlign:'center' }}>{seededRow ? r.rank : '—'}</td>
        <td style={{ padding:'7px 0' }}>
          <span style={{ display:'inline-block', fontFamily:NL.mono, fontSize:10, fontWeight:600, letterSpacing:'.06em', color:tc.ink, background:tc.p, padding:'2px 7px', borderRadius:999, verticalAlign:'middle' }}>{r.key}</span>
          <span className="syn-standings-name" style={{ fontFamily:NL.sans, fontSize:12.5, color:NL.ink2, marginLeft:9, verticalAlign:'middle', fontWeight: focal?600:400 }}>{r.name}</span>
        </td>
        <td style={{ padding:'7px 0', textAlign:'right', fontFamily:NL.mono, fontSize:11.5, color:NL.ink, fontVariantNumeric:'tabular-nums' }}>
          {r.record}{ seededRow ? '' : (r.games_back!=null ? <span style={{ color:NL.ink3, marginLeft:8 }}>{r.games_back} GB</span> : '') }
        </td>
      </tr>
    );
  };
  return (
    <div style={{ flex:1, minWidth:0 }}>
      <div style={{ fontFamily:NL.mono, fontSize:11, fontWeight:600, letterSpacing:'.14em', textTransform:'uppercase', color:NL.ink3, paddingBottom:8, borderBottom:`1px solid ${NL.rule}`, marginBottom:6 }}>{conf}</div>
      <table style={{ width:'100%', borderCollapse:'collapse', tableLayout:'fixed' }}><tbody>
        {seeded.map(r=>teamRow(r, true))}
        {rows.playoff_line ? line('Playoff line') : null}
        {out.map(r=>teamRow(r, false))}
      </tbody></table>
    </div>
  );
}
function Standings({ issue }) {
  const tc = teamColor(issue.team), st = issue.standings;
  const conf = st && st.conferences;
  return (
    <div>
      <div style={NL.plain}>
        <div style={{ padding:'10px 26px 0' }}>
          <div style={{ height:3, background:tc.p, borderRadius:2, marginBottom:14 }} />
          <div style={{ fontFamily:NL.mono, fontSize:11, fontWeight:600, letterSpacing:'.14em', textTransform:'uppercase', color:tc.p }}>Around the league</div>
          <div style={{ fontFamily:NL.serif, fontWeight:600, fontSize:23, lineHeight:1.2, letterSpacing:'-0.02em', color:NL.ink, marginTop:8 }}>League standings through Week {st ? st.as_of_week : '—'}</div>
        </div>
      </div>
      <div style={Object.assign({}, NL.card, conf ? {} : { borderStyle:'dashed' })}>
        {conf ? (
          <div style={{ padding:'20px 26px', display:'flex', gap:34, flexWrap:'wrap' }}>
            <ConfTable conf="AFC" rows={conf.AFC||{}} focalTeam={issue.team} />
            <ConfTable conf="NFC" rows={conf.NFC||{}} focalTeam={issue.team} />
          </div>
        ) : (
          <div style={{ padding:'22px 26px', textAlign:'center', fontFamily:NL.mono, fontSize:11, letterSpacing:'.04em', color:NL.ink3 }}>Standings not available for this date.</div>
        )}
        {conf && (
          <div style={{ padding:'0 26px 18px', fontFamily:NL.mono, fontSize:10.5, color:NL.ink3 }}>
            <span style={{ textDecoration:'underline', textDecorationColor:'#A7A091', textUnderlineOffset:3 }}>NFL standings · through {st.as_of_date}</span>
          </div>
        )}
      </div>
      {/* Coach Decision Rankings slot (Wed/Thu, below Bet/standings) — OMITTED for now. */}
    </div>
  );
}

// ---- 11 footer -------------------------------------------------------------
function NLFooter() {
  return (
    <div style={{ width:'100%', maxWidth:602, margin:'0 auto' }}>
      <div style={{ padding:'20px 26px 8px', borderTop:'1px solid #DCD5C6', display:'flex', justifyContent:'space-between', alignItems:'baseline' }}>
        <span style={{ fontFamily:NL.serif, fontWeight:700, fontSize:17, letterSpacing:'-0.02em', color:NL.ink }}>Synth</span>
        <span style={{ fontFamily:NL.mono, fontSize:11, color:NL.ink3 }}>
          <a href="#newsletters" style={{ color:'#9A530F', textDecoration:'none' }}>Archive</a> &nbsp;·&nbsp;
          <a href="#onboarding" style={{ color:'#9A530F', textDecoration:'none' }}>Change team</a> &nbsp;·&nbsp;
          <a href="https://signup.readsynth.ca/unsubscribe" style={{ color:'#9A530F', textDecoration:'none' }}>Unsubscribe</a>
        </span>
      </div>
      <div style={{ padding:'0 26px 24px', fontFamily:NL.mono, fontSize:11, lineHeight:1.6, color:NL.ink3, marginTop:12 }}>
        The context engine for sports. Data in this newsletter is generated by AI, which can make mistakes. Please double-check responses. If you're going to gamble, play responsibly and according to laws in your local jurisdiction.<br/>Synth · Toronto, ON
      </div>
    </div>
  );
}

// ---- the scaffolding (11 sections, top to bottom) --------------------------
function Scaffolding({ issue }) {
  return (
    <div style={{ maxWidth:648, margin:'0 auto', padding:'0 8px' }}>
      <Masthead issue={issue} />
      <GameCard issue={issue} />
      <InjuryReport issue={issue} />
      <Opening issue={issue} />
      <Sentiment issue={issue} />
      <NewsletterBody issue={issue} />
      <Standings issue={issue} />
      <NLFooter />
    </div>
  );
}

// ---- the page: team + date selector ----------------------------------------
function NewslettersPage() {
  const teams = window.SYNTH_ISSUE_TEAMS || ['LAR','NYG'];
  const dates = window.SYNTH_ISSUE_DATES || [];
  const [team, setTeam] = React.useState(teams[0]);
  const [date, setDate] = React.useState(dates[0]);
  const key = team + '_' + date;
  const issue = (window.SYNTH_ISSUES || {})[key];
  const nameOf = (t) => { const n=(window.SYNTH_TEAM_NAMES||{})[t]; return n ? `${n.city} ${n.name}` : t; };
  const labelDate = (d) => new Date(d+'T12:00:00').toLocaleDateString('en-US',{weekday:'short', month:'short', day:'numeric', year:'numeric'});

  const sel = {
    fontFamily:NL.sans, fontSize:15, color:NL.ink, background:'#FFFFFF',
    border:'1px solid var(--syn-border-strong, #C9BFA8)', borderRadius:10,
    padding:'11px 14px', outline:'none', cursor:'pointer', minWidth:200,
  };
  const lbl = { fontFamily:NL.mono, fontSize:11, letterSpacing:'.12em', textTransform:'uppercase', color:NL.ink3, display:'block', marginBottom:7 };

  return (
    <main style={{ background:'var(--syn-paper, #FBF7F1)', minHeight:'calc(100vh - 64px)' }}>
      <div style={{ maxWidth:1120, margin:'0 auto', padding:'56px 48px 24px' }}>
        <div style={{ fontFamily:NL.mono, fontSize:12, letterSpacing:'.16em', textTransform:'uppercase', color:NL.ink3, fontWeight:500, marginBottom:16 }}>Newsletters</div>
        <h1 style={{ fontFamily:NL.serif, fontSize:44, fontWeight:600, letterSpacing:'-0.03em', lineHeight:1.04, color:NL.ink, margin:'0 0 10px' }}>The daily issue, by team and date.</h1>
        <p style={{ fontFamily:NL.serif, fontSize:18, lineHeight:1.45, color:'#4A4A4A', maxWidth:640, margin:'0 0 32px', fontWeight:400 }}>Pick a team and a date to read that day's Synth issue.</p>
        <div style={{ display:'flex', gap:20, flexWrap:'wrap', alignItems:'flex-end' }}>
          <div>
            <label style={lbl}>Team</label>
            <select value={team} onChange={e=>setTeam(e.target.value)} style={sel}>
              {teams.map(t=>(<option key={t} value={t}>{nameOf(t)}</option>))}
            </select>
          </div>
          <div>
            <label style={lbl}>Date</label>
            <select value={date} onChange={e=>setDate(e.target.value)} style={sel}>
              {dates.map(d=>(<option key={d} value={d}>{labelDate(d)}</option>))}
            </select>
          </div>
        </div>
      </div>
      <div style={{ borderTop:`1px solid ${NL.rule}`, padding:'32px 16px 96px' }}>
        {issue ? <Scaffolding issue={issue} />
               : <div style={{ textAlign:'center', fontFamily:NL.mono, color:NL.ink3, padding:'60px 0' }}>No issue found for {nameOf(team)} · {labelDate(date)}.</div>}
      </div>
    </main>
  );
}
window.NewslettersPage = NewslettersPage;
