/* CalibrationLedger.jsx — the integrity instrument
   Every load-bearing coefficient in this document, classified into:
     CALIBRATED   — sourced from a published reference or live data feed
     ASSERTED     — reasoned assumption with explicit justification
     PROVISIONAL  — placeholder named as a gap, awaiting calibration

   Naming the gap is the discipline. A model whose coefficients are all
   "CALIBRATED" is either lucky or lying; the proportion in each column
   is the honest measure of where the work still needs to happen.
*/

const LEDGER = [
  /* ===== Inverse Design ===== */
  { section: 'Inverse design',
    rows: [
      { name: 'Coverage-line forward-map matrix (PER_LINE, 6×4)',
        status: 'ASSERTED',
        note: 'Direction (sign) is the load-bearing claim — primary retention is the most expensive and most cap-intensive line; cat reinsurance the cheapest with the strongest tail-transfer and regulatory credit. Magnitudes asserted from NZ commercial-lines treaty structure; full calibration pending a comparable reinsurance book.' },
      { name: 'Cost-of-cover baseline (BASELINE_PREMIUM = 0.62)',
        status: 'ASSERTED',
        note: 'Cost units of an "all-primary plus quota-share" prior-year stack at a typical NZ commercial line. The optimiser maps premium reductions against this point. A real engagement re-anchors per client.' },
      { name: 'Constitutional score formulas (5 × R(∂))',
        status: 'ASSERTED',
        note: 'Each score is a continuous monotone proxy for a regulatory floor. Coefficients chosen so that pathological allocations (all-primary, all-alt) breach floors, and well-spread allocations satisfy them. Per-coefficient calibration would require a regulator-supplied template; none exists publicly.' },
      { name: 'Regulatory floors (rbnz=0.55, ifrs=0.50, xrb=0.45, cap=0.50, eth=0.55)',
        status: 'PROVISIONAL',
        note: 'Asserted thresholds for the demo. Real floors are firm-specific and live in private regulatory correspondence. The framework is the deliverable; the floors are the customer\'s.' },
      { name: 'Loss weight λ = 1.5 on R(∂) penalty',
        status: 'ASSERTED',
        note: 'Sets how aggressively the optimiser pulls the configuration into the feasible region. Tuned so floors dominate at typical B*; lower values let target precision win at the cost of compliance margin.' },
      { name: 'Optimiser learning rate / max iters / convergence threshold',
        status: 'CALIBRATED',
        note: 'Standard projected-gradient defaults with backtracking line search. Empirically: monotone non-increasing loss across all tested seeds; convergence in 30–60 iters at typical B*.' },
      { name: 'Grade thresholds (A>0.85, B+>0.75, B>0.65, C>0.55, else D)',
        status: 'ASSERTED',
        note: 'Pedagogical bands for the visual grade. No statutory mapping; an actuary would replace with a firm-specific scoring rubric.' },
    ],
  },

  /* ===== Tempos ===== */
  { section: 'Tempos',
    rows: [
      { name: 'Event timeline (24 events × time t)',
        status: 'ASSERTED',
        note: 'Timing of each event roughly matches the public April 2026 sequencing of Hormuz-related supply-chain effects. Exact days are illustrative; trajectory shape is the load-bearing claim.' },
      { name: 'Tempo gap = N(physical) / N(government) at scrub time',
        status: 'PROVISIONAL',
        note: 'A count-ratio stand-in for a real arrival-rate ratio. Patrick will notice the difference; the right replacement is λ_phys / λ_gov derived from the underlying timestamps. Future calibration target.' },
      { name: 'Lane speed labels (days, hours, quarters, months)',
        status: 'ASSERTED',
        note: 'Order-of-magnitude descriptors of each tempo\'s characteristic time-constant. Defensible to a generalist; not fitted to a process model.' },
    ],
  },

  /* ===== PumpAbsorption ===== */
  { section: 'Pump-price absorption',
    rows: [
      { name: 'Crude-shock path: spike(amp=0.85, σ=0.18, μ=0.4) + tail(slope=0.25 from t=0.5)',
        status: 'ASSERTED',
        note: 'Stylised crude-spike profile consistent with major-strait disruption episodes. Not fit to any single historical event.' },
      { name: 'Absorber magnitudes (hedge=0.55, cargo=0.18, credit=0.12, BI=0.08, buffer=0.07)',
        status: 'PROVISIONAL',
        note: 'Asserted to sum to 1.00 for illustrative balance under maximum activation. A real calibration would back out per-layer contribution from listed-entity hedge-disclosure regression and treaty pricing data — significant project on its own.' },
      { name: 'EMA smoothing α = 0.18',
        status: 'ASSERTED',
        note: 'Effective lag ≈ 5 weeks, consistent with the rolling-tranche structure of NZ pump pricing. Documented in petrol-pricing-monitor reports.' },
      { name: 'Additive absorption: total = Σ enabled mags',
        status: 'PROVISIONAL',
        note: 'Treats absorbers as independent; reality has cross-layer correlation (shocks that break a hedge counterparty also stress trade credit). The right model is a 5×5 layer correlation matrix; held back from this document deliberately to preserve scope.' },
    ],
  },

  /* ===== Pressures ===== */
  { section: 'Pressures',
    rows: [
      { name: 'Six structural pressures (XRB, IFRS 17, cyber, AVF, Marsden, cascade)',
        status: 'CALIBRATED',
        note: 'Each pressure traces to public regulatory or industry context (XRB CS 1/2/3; RBNZ IPSA; published cat-modelling literature; industry commentary on Marsden Pt). Selection reflects current Aotearoa market conditions.' },
      { name: 'Initial (immediacy, magnitude) coordinates',
        status: 'ASSERTED',
        note: 'Asserted placement reflecting Axiom Intelligence\'s read of urgency and stakes. Patrick is invited to drag dots; the disagreement is itself useful data.' },
      { name: 'Priority = immediacy × magnitude',
        status: 'ASSERTED',
        note: 'Simplest defensible aggregator. A more sophisticated treatment would weight by stakeholder perspective and time-decay; not required for this section\'s purpose.' },
    ],
  },

  /* ===== Cascade ===== */
  { section: 'Cascade scenarios',
    rows: [
      { name: 'Six scenarios × seven sectors weight matrix (42 cells)',
        status: 'ASSERTED',
        note: 'Each weight in [0,1] reflects qualitative consensus across NZ-domain readings. Hormuz, Wellington fault, AVF, MPI biosecurity, cloud-supply-chain cyber, Hawkes Bay — all current candidate-scenario peg points for Aotearoa cat modelling.' },
      { name: 'Sector base-exposure values (banks=4.1, agri=2.6, infra=2.2, retail=1.8, fuel=1.4, transport=1.2, marae=0.9)',
        status: 'ASSERTED',
        note: 'Relative-magnitude order matches NZ insurance market structure (regional banks largest correlated exposure; iwi assets smallest in $-terms). Absolute scale chosen so totals sit in single-digit-billion-NZD range characteristic of large NZ events.' },
      { name: 'Vendor coverage multiplier (0.55)',
        status: 'PROVISIONAL',
        note: 'Single coefficient stand-in for a 7-sector × 6-scenario vendor coverage matrix. The right replacement is per-cell calibration — each cell saying which sectors a vendor model handles well and which it misses for that scenario. Held back from this document deliberately.' },
      { name: 'Correlation graph edge threshold (0.15)',
        status: 'ASSERTED',
        note: 'Visual threshold below which an edge is suppressed for legibility. Not a structural feature of the cascade.' },
    ],
  },

  /* ===== Offerings ===== */
  { section: 'Offerings',
    rows: [
      { name: 'Five offerings × five investability-axis scores (25 cells)',
        status: 'ASSERTED',
        note: 'Each score is Axiom Intelligence\'s own honest read of the offering against the axis. Patrick is invited to disagree; reasoning per cell is available on request and would migrate to per-cell explainers in a deeper revision.' },
      { name: 'Default investor weights (warmth=0.30, capital=0.25, scale=0.20, regulatory=0.15, mission=0.10)',
        status: 'ASSERTED',
        note: 'A plausible weighting for a first-time NZ investor in this category. Patrick re-weights live; ranking re-sorts.' },
      { name: 'Composite = Σ (score × weight)',
        status: 'CALIBRATED',
        note: 'Standard linear weighted sum. Honest, simple, defensible — no pretence of sophistication where none is needed.' },
    ],
  },
];

const STATUS_STYLE = {
  CALIBRATED:  { bg: 'rgba(31, 138, 58, 0.14)',   color: '#1f8a3a', border: '#1f8a3a' },
  ASSERTED:    { bg: 'rgba(196, 136, 31, 0.14)',  color: '#a06a14', border: '#c4881f' },
  PROVISIONAL: { bg: 'rgba(139, 26, 26, 0.12)',   color: '#8b1a1a', border: '#8b1a1a' },
};

function CalibrationLedger() {
  // Tally — make the proportion visible
  const tally = { CALIBRATED: 0, ASSERTED: 0, PROVISIONAL: 0 };
  let total = 0;
  for (const sec of LEDGER) for (const r of sec.rows) { tally[r.status]++; total++; }

  const pct = (n) => total === 0 ? 0 : Math.round(n / total * 100);

  return (
    <section id="ledger" style={{ background: 'var(--tint)' }}>
      <div className="container">
        <div className="section-tag">
          <span className="num">07 / 07</span>
          <span>The integrity instrument</span>
          <span className="rule" />
        </div>
        <h2 style={{ marginBottom: 16 }}>
          <Explain term="calibration-status">Calibration ledger</Explain>.
        </h2>
        <p className="lede" style={{ maxWidth: '64ch' }}>
          Every load-bearing coefficient in this document, classified.
          A model whose coefficients are all sourced is either lucky or lying.
          The proportion in each column is the honest measure of where the work still needs to happen.
        </p>

        {/* Tally row */}
        <div style={{
          display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 16,
          margin: '28px 0 32px',
        }}>
          {['CALIBRATED', 'ASSERTED', 'PROVISIONAL'].map((s) => {
            const sty = STATUS_STYLE[s];
            return (
              <div key={s} style={{
                background: 'var(--bg-card)', border: '1px solid var(--rule)',
                borderRadius: 4, padding: '18px 20px',
                borderLeft: `3px solid ${sty.border}`,
              }}>
                <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 8 }}>
                  <span style={{
                    fontSize: 10, letterSpacing: '.16em', fontWeight: 700,
                    padding: '3px 8px', borderRadius: 2,
                    background: sty.bg, color: sty.color,
                  }}>
                    {s}
                  </span>
                </div>
                <div style={{ fontFamily: 'Source Serif 4', fontSize: 36, lineHeight: 1, letterSpacing: '-.02em' }}>
                  {tally[s]}<span style={{ fontSize: 18, color: 'var(--muted)', marginLeft: 4 }}>/{total}</span>
                </div>
                <div className="mono" style={{ fontSize: 12, color: 'var(--muted)', marginTop: 6 }}>
                  {pct(tally[s])}% of coefficients
                </div>
                <div style={{ fontSize: 12, color: 'var(--muted)', marginTop: 8, lineHeight: 1.5 }}>
                  {s === 'CALIBRATED' && 'Sourced from a published reference or live data feed.'}
                  {s === 'ASSERTED'   && 'Reasoned assumption with explicit justification.'}
                  {s === 'PROVISIONAL'&& 'Placeholder named as a gap, awaiting calibration.'}
                </div>
              </div>
            );
          })}
        </div>

        {/* Frame */}
        <div style={{
          padding: '14px 18px',
          borderLeft: '2px solid var(--ink)', background: 'var(--bg-card)',
          fontSize: 13.5, color: 'var(--ink-soft)', lineHeight: 1.6,
          maxWidth: '72ch', marginBottom: 32,
        }}>
          <strong>How to read this:</strong> the page above is a methodology demonstration, not a
          production system. CALIBRATED rows are points where the math touches public reality;
          ASSERTED rows are where we make a defensible call; PROVISIONAL rows are where we have
          named the gap rather than papered over it. A first engagement converts ASSERTED into
          CALIBRATED for the client's specific book; a longer one converts PROVISIONAL.
        </div>

        {/* Per-section ledger */}
        <div className="flex-col" style={{ gap: 28 }}>
          {LEDGER.map((sec) => (
            <div key={sec.section}>
              <div style={{
                fontSize: 11, letterSpacing: '.16em', textTransform: 'uppercase',
                color: 'var(--muted-2)', fontWeight: 700, marginBottom: 10,
                paddingBottom: 6, borderBottom: '1px solid var(--rule)',
              }}>
                {sec.section}
              </div>

              <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 13 }}>
                <tbody>
                  {sec.rows.map((r, i) => {
                    const sty = STATUS_STYLE[r.status];
                    return (
                      <tr key={i}>
                        <td style={{
                          padding: '14px 14px 14px 0',
                          borderBottom: '1px solid var(--rule)',
                          width: 130, verticalAlign: 'top',
                        }}>
                          <span style={{
                            fontSize: 9.5, letterSpacing: '.14em', fontWeight: 700,
                            padding: '3px 7px', borderRadius: 2, whiteSpace: 'nowrap',
                            background: sty.bg, color: sty.color,
                          }}>
                            {r.status}
                          </span>
                        </td>
                        <td style={{
                          padding: '14px 14px',
                          borderBottom: '1px solid var(--rule)',
                          verticalAlign: 'top',
                          minWidth: 200, maxWidth: 320,
                          fontWeight: 500, color: 'var(--ink)',
                        }}>
                          {r.name}
                        </td>
                        <td style={{
                          padding: '14px 0',
                          borderBottom: '1px solid var(--rule)',
                          verticalAlign: 'top',
                          color: 'var(--ink-soft)', lineHeight: 1.55,
                        }}>
                          {r.note}
                        </td>
                      </tr>
                    );
                  })}
                </tbody>
              </table>
            </div>
          ))}
        </div>

        <div style={{
          marginTop: 36, padding: '18px 22px',
          background: '#fff', border: '1px solid var(--rule)', borderRadius: 4,
          fontSize: 13, color: 'var(--ink-soft)', lineHeight: 1.65, maxWidth: '72ch',
        }}>
          <em>
            The discipline is to update this ledger every time a coefficient changes status.
            A first calibration engagement on a client book converts most of the ASSERTED rows
            in the Inverse Design section into CALIBRATED. A longer engagement does the same
            for the PROVISIONAL rows in PumpAbsorption and Cascade. The ledger is therefore the
            roadmap, not just an audit.
          </em>
        </div>
      </div>
    </section>
  );
}

window.CalibrationLedger = CalibrationLedger;
