Last active
March 22, 2026 11:39
-
-
Save leonmak/9a3b8adc757bb8cf20152ded5c504cd3 to your computer and use it in GitHub Desktop.
Bayes one-pager
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <html lang="en"> | |
| <head> | |
| <style> | |
| :root { | |
| --bg: #ffffff; | |
| --bg2: #f5f4f0; | |
| --bg3: #eae9e4; | |
| --tx: #1a1a18; | |
| --tx2: #5f5e5a; | |
| --tx3: #888780; | |
| --bd: rgba(0, 0, 0, 0.12); | |
| --bd2: rgba(0, 0, 0, 0.06); | |
| --purple-50: #eeedfe; | |
| --purple-100: #cecbf6; | |
| --purple-200: #afa9ec; | |
| --purple-400: #7f77dd; | |
| --purple-600: #534ab7; | |
| --purple-800: #3c3489; | |
| --purple-900: #26215c; | |
| --teal-50: #e1f5ee; | |
| --teal-100: #9fe1cb; | |
| --teal-200: #5dcaa5; | |
| --teal-400: #1d9e75; | |
| --teal-600: #0f6e56; | |
| --teal-800: #085041; | |
| --teal-900: #04342c; | |
| --coral-50: #faece7; | |
| --coral-100: #f5c4b3; | |
| --coral-200: #f0997b; | |
| --coral-400: #d85a30; | |
| --coral-600: #993c1d; | |
| --coral-800: #712b13; | |
| --blue-50: #e6f1fb; | |
| --blue-100: #b5d4f4; | |
| --blue-200: #85b7eb; | |
| --blue-400: #378add; | |
| --blue-600: #185fa5; | |
| --blue-800: #0c447c; | |
| --amber-50: #faeeda; | |
| --amber-100: #fac775; | |
| --amber-200: #ef9f27; | |
| --amber-400: #ba7517; | |
| --amber-600: #854f0b; | |
| --amber-800: #633806; | |
| --green-50: #eaf3de; | |
| --green-100: #c0dd97; | |
| --green-200: #97c459; | |
| --green-600: #3b6d11; | |
| --green-800: #27500a; | |
| --red-50: #fcebeb; | |
| --red-100: #f7c1c1; | |
| --red-200: #f09595; | |
| --red-400: #e24b4a; | |
| --red-600: #a32d2d; | |
| --red-800: #791f1f; | |
| --gray-50: #f1efe8; | |
| --gray-100: #d3d1c7; | |
| --gray-200: #b4b2a9; | |
| --gray-400: #888780; | |
| --gray-600: #5f5e5a; | |
| --gray-800: #444441; | |
| --pink-50: #fbeaf0; | |
| --pink-100: #f4c0d1; | |
| --pink-200: #ed93b1; | |
| --pink-600: #993556; | |
| --pink-800: #72243e; | |
| --font: | |
| "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; | |
| --mono: "SF Mono", "Fira Code", "Consolas", monospace; | |
| --radius: 8px; | |
| --radius-lg: 12px; | |
| } | |
| @media (prefers-color-scheme: dark) { | |
| :root { | |
| --bg: #1a1a18; | |
| --bg2: #2c2c2a; | |
| --bg3: #3d3d3a; | |
| --tx: #66614c; | |
| --tx2: #b4b2a9; | |
| --tx3: #888780; | |
| --bd: rgba(255, 255, 255, 0.12); | |
| --bd2: rgba(255, 255, 255, 0.06); | |
| } | |
| } | |
| * { | |
| margin: 0; | |
| padding: 0; | |
| box-sizing: border-box; | |
| } | |
| body { | |
| font-family: var(--font); | |
| background: var(--bg); | |
| color: var(--tx); | |
| line-height: 1.7; | |
| font-size: 15px; | |
| } | |
| .page { | |
| max-width: 780px; | |
| margin: 0 auto; | |
| padding: 2rem 1.5rem 4rem; | |
| } | |
| h1 { | |
| font-size: 28px; | |
| font-weight: 600; | |
| margin-bottom: 0.25rem; | |
| letter-spacing: -0.5px; | |
| } | |
| h2 { | |
| font-size: 20px; | |
| font-weight: 500; | |
| margin: 3rem 0 0.75rem; | |
| padding-top: 2rem; | |
| border-top: 0.5px solid var(--bd); | |
| } | |
| h3 { | |
| font-size: 16px; | |
| font-weight: 500; | |
| margin: 1.5rem 0 0.5rem; | |
| } | |
| p, | |
| .prose { | |
| color: var(--tx2); | |
| margin-bottom: 1rem; | |
| } | |
| .subtitle { | |
| font-size: 15px; | |
| color: var(--tx3); | |
| margin-bottom: 2.5rem; | |
| } | |
| .formula-bar { | |
| background: var(--bg2); | |
| border-radius: var(--radius); | |
| padding: 14px 20px; | |
| font-family: var(--mono); | |
| font-size: 15px; | |
| margin: 1rem 0 1.5rem; | |
| text-align: center; | |
| border: 0.5px solid var(--bd2); | |
| } | |
| .formula-bar .hl-post { | |
| color: var(--purple-600); | |
| font-weight: 600; | |
| } | |
| .formula-bar .hl-like { | |
| color: var(--teal-600); | |
| font-weight: 600; | |
| } | |
| .formula-bar .hl-prior { | |
| color: var(--blue-600); | |
| font-weight: 600; | |
| } | |
| .formula-bar .hl-evid { | |
| color: var(--amber-600); | |
| font-weight: 600; | |
| } | |
| /* Section cards */ | |
| .section-card { | |
| background: var(--bg2); | |
| border-radius: var(--radius-lg); | |
| padding: 1.25rem 1.5rem; | |
| margin: 1rem 0; | |
| border: 0.5px solid var(--bd2); | |
| } | |
| /* Grid viz */ | |
| .grid { | |
| display: grid; | |
| grid-template-columns: repeat(20, 1fr); | |
| gap: 3px; | |
| margin: 1rem 0; | |
| } | |
| .dot { | |
| width: 100%; | |
| aspect-ratio: 1; | |
| border-radius: 3px; | |
| transition: background 0.4s; | |
| } | |
| .legend { | |
| display: flex; | |
| flex-wrap: wrap; | |
| gap: 14px; | |
| font-size: 12px; | |
| color: var(--tx2); | |
| margin: 0.5rem 0; | |
| } | |
| .legend-item { | |
| display: flex; | |
| align-items: center; | |
| gap: 6px; | |
| } | |
| .legend-swatch { | |
| width: 12px; | |
| height: 12px; | |
| border-radius: 3px; | |
| } | |
| .stat-row { | |
| display: grid; | |
| grid-template-columns: repeat(4, minmax(0, 1fr)); | |
| gap: 10px; | |
| margin: 1rem 0; | |
| } | |
| .stat { | |
| background: var(--bg); | |
| border-radius: var(--radius); | |
| padding: 10px 12px; | |
| border: 0.5px solid var(--bd2); | |
| } | |
| .stat-label { | |
| font-size: 10px; | |
| text-transform: uppercase; | |
| letter-spacing: 0.5px; | |
| margin-bottom: 2px; | |
| } | |
| .stat-val { | |
| font-size: 18px; | |
| font-weight: 500; | |
| } | |
| .eq-line { | |
| font-family: var(--mono); | |
| font-size: 14px; | |
| color: var(--tx2); | |
| text-align: center; | |
| margin: 0.5rem 0; | |
| } | |
| .slider-row { | |
| display: flex; | |
| align-items: center; | |
| gap: 12px; | |
| margin: 6px 0; | |
| } | |
| .slider-row label { | |
| font-size: 12px; | |
| color: var(--tx2); | |
| min-width: 140px; | |
| } | |
| .slider-row input[type="range"] { | |
| flex: 1; | |
| } | |
| .slider-row span { | |
| font-size: 12px; | |
| color: var(--tx2); | |
| min-width: 32px; | |
| text-align: right; | |
| } | |
| /* Tabs */ | |
| .tab-row { | |
| display: flex; | |
| gap: 6px; | |
| margin: 0 0 1rem; | |
| flex-wrap: wrap; | |
| } | |
| .tab-btn { | |
| cursor: pointer; | |
| padding: 6px 14px; | |
| font-size: 12px; | |
| border-radius: var(--radius); | |
| background: var(--bg); | |
| color: var(--tx2); | |
| border: 0.5px solid var(--bd); | |
| transition: all 0.2s; | |
| } | |
| .tab-btn.active { | |
| background: var(--blue-50); | |
| color: var(--blue-800); | |
| border-color: var(--blue-200); | |
| } | |
| @media (prefers-color-scheme: dark) { | |
| .tab-btn.active { | |
| background: var(--blue-800); | |
| color: var(--blue-100); | |
| border-color: var(--blue-600); | |
| } | |
| } | |
| .tab-panel { | |
| display: none; | |
| } | |
| .tab-panel.active { | |
| display: block; | |
| } | |
| /* Evidence cards */ | |
| .ev-card { | |
| background: var(--bg); | |
| border-radius: var(--radius); | |
| padding: 8px 12px; | |
| margin: 5px 0; | |
| display: flex; | |
| align-items: center; | |
| gap: 10px; | |
| cursor: pointer; | |
| border: 0.5px solid var(--bd2); | |
| transition: opacity 0.3s; | |
| } | |
| .ev-card.off { | |
| opacity: 0.3; | |
| } | |
| .ev-check { | |
| width: 16px; | |
| height: 16px; | |
| border-radius: 3px; | |
| border: 0.5px solid var(--bd); | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| font-size: 11px; | |
| color: var(--blue-600); | |
| flex-shrink: 0; | |
| } | |
| .ev-card.on .ev-check { | |
| background: var(--blue-50); | |
| border-color: var(--blue-200); | |
| } | |
| @media (prefers-color-scheme: dark) { | |
| .ev-card.on .ev-check { | |
| background: var(--blue-800); | |
| border-color: var(--blue-600); | |
| color: var(--blue-100); | |
| } | |
| } | |
| .ev-label { | |
| font-size: 12px; | |
| color: var(--tx); | |
| flex: 1; | |
| } | |
| .ev-lr { | |
| font-size: 11px; | |
| font-family: var(--mono); | |
| min-width: 40px; | |
| text-align: right; | |
| } | |
| .bar-bg { | |
| height: 24px; | |
| background: var(--bg3); | |
| border-radius: 12px; | |
| overflow: hidden; | |
| margin: 4px 0; | |
| } | |
| .bar-fill { | |
| height: 100%; | |
| border-radius: 12px; | |
| transition: | |
| width 0.5s, | |
| background 0.5s; | |
| } | |
| .bar-labels { | |
| display: flex; | |
| justify-content: space-between; | |
| font-size: 11px; | |
| color: var(--tx3); | |
| } | |
| .belief-val { | |
| font-size: 22px; | |
| font-weight: 500; | |
| margin: 2px 0; | |
| } | |
| .belief-label { | |
| font-size: 11px; | |
| color: var(--tx3); | |
| } | |
| .step-log { | |
| font-size: 11px; | |
| font-family: var(--mono); | |
| color: var(--tx3); | |
| line-height: 1.7; | |
| margin: 0.5rem 0; | |
| max-height: 120px; | |
| overflow-y: auto; | |
| } | |
| /* Domain rows */ | |
| .domain-row { | |
| display: flex; | |
| align-items: center; | |
| gap: 8px; | |
| margin: 6px 0; | |
| } | |
| .domain-tag { | |
| font-size: 10px; | |
| padding: 2px 8px; | |
| border-radius: var(--radius); | |
| min-width: 60px; | |
| text-align: center; | |
| } | |
| .domain-text { | |
| font-size: 12px; | |
| color: var(--tx2); | |
| flex: 1; | |
| } | |
| .domain-lr { | |
| font-size: 11px; | |
| font-family: var(--mono); | |
| padding: 2px 8px; | |
| border-radius: var(--radius); | |
| } | |
| /* Expandable cards */ | |
| .exp-card { | |
| background: var(--bg); | |
| border-radius: var(--radius-lg); | |
| padding: 12px 16px; | |
| margin: 8px 0; | |
| border: 0.5px solid var(--bd2); | |
| cursor: pointer; | |
| transition: all 0.2s; | |
| } | |
| .exp-card.active { | |
| border-color: var(--blue-200); | |
| } | |
| @media (prefers-color-scheme: dark) { | |
| .exp-card.active { | |
| border-color: var(--blue-600); | |
| } | |
| } | |
| .exp-head { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| } | |
| .exp-title { | |
| font-size: 13px; | |
| font-weight: 500; | |
| color: var(--tx); | |
| } | |
| .exp-tag { | |
| font-size: 10px; | |
| padding: 2px 8px; | |
| border-radius: var(--radius); | |
| } | |
| .exp-body { | |
| display: none; | |
| margin-top: 10px; | |
| font-size: 12px; | |
| color: var(--tx2); | |
| line-height: 1.65; | |
| } | |
| .exp-card.active .exp-body { | |
| display: block; | |
| } | |
| .example-box { | |
| background: var(--bg2); | |
| border-radius: var(--radius); | |
| padding: 8px 12px; | |
| margin: 6px 0; | |
| border: 0.5px solid var(--bd2); | |
| } | |
| .example-box .elabel { | |
| font-size: 10px; | |
| color: var(--tx3); | |
| margin-bottom: 2px; | |
| } | |
| .echain { | |
| font-family: var(--mono); | |
| font-size: 11px; | |
| color: var(--tx3); | |
| margin: 4px 0; | |
| } | |
| .eresult { | |
| font-size: 12px; | |
| font-weight: 500; | |
| margin-top: 4px; | |
| } | |
| .note { | |
| font-size: 12px; | |
| color: var(--tx3); | |
| line-height: 1.6; | |
| margin-top: 0.5rem; | |
| } | |
| svg text.th { | |
| font-family: var(--font); | |
| font-size: 14px; | |
| font-weight: 500; | |
| fill: var(--tx); | |
| } | |
| svg text.ts { | |
| font-family: var(--font); | |
| font-size: 12px; | |
| fill: var(--tx2); | |
| } | |
| svg text.t { | |
| font-family: var(--font); | |
| font-size: 14px; | |
| fill: var(--tx); | |
| } | |
| .odds-chain { | |
| font-family: var(--mono); | |
| font-size: 12px; | |
| color: var(--tx2); | |
| margin: 6px 0; | |
| display: flex; | |
| align-items: center; | |
| gap: 6px; | |
| flex-wrap: wrap; | |
| } | |
| .odds-chain .op { | |
| color: var(--tx3); | |
| } | |
| .big-result { | |
| font-size: 18px; | |
| font-weight: 500; | |
| color: var(--tx); | |
| margin: 0.75rem 0 0; | |
| } | |
| .toc { | |
| list-style: none; | |
| padding: 0; | |
| margin: 1rem 0 2rem; | |
| } | |
| .toc li { | |
| margin: 4px 0; | |
| } | |
| .toc a { | |
| font-size: 14px; | |
| color: var(--blue-600); | |
| text-decoration: none; | |
| } | |
| .toc a:hover { | |
| text-decoration: underline; | |
| } | |
| @media (prefers-color-scheme: dark) { | |
| .toc a { | |
| color: var(--blue-200); | |
| } | |
| } | |
| </style> | |
| <meta charset="UTF-8" /> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | |
| <title>Bayes' Theorem — A Visual Guide</title> | |
| </head> | |
| <body> | |
| <div class="page"> | |
| <h1>Bayes' Theorem</h1> | |
| <p class="subtitle"> | |
| A visual, interactive guide — from formula to real-world reasoning | |
| </p> | |
| <div class="formula-bar"> | |
| <span class="hl-post">P(cause | data)</span> = | |
| <span class="hl-like">P(data | cause)</span> × | |
| <span class="hl-prior">P(cause)</span> / | |
| <span class="hl-evid">P(data)</span> | |
| </div> | |
| <nav> | |
| <ol class="toc"> | |
| <li> | |
| <a href="#s1">1. The population grid — Bayes is just counting</a> | |
| </li> | |
| <li> | |
| <a href="#s2">2. The three terms — a tug of war on your belief</a> | |
| </li> | |
| <li> | |
| <a href="#s3" | |
| >3. The rectangle is a population, not a Venn diagram</a | |
| > | |
| </li> | |
| <li> | |
| <a href="#s4" | |
| >4. Likelihood vs. probability — same formula, different | |
| question</a | |
| > | |
| </li> | |
| <li> | |
| <a href="#s5" | |
| >5. Sequential updating — ratcheting belief with each signal</a | |
| > | |
| </li> | |
| <li><a href="#s6">6. Each signal pulls from its own space</a></li> | |
| <li><a href="#s7">7. Where the numbers come from in practice</a></li> | |
| <li><a href="#s8">8. When Bayes is most valuable</a></li> | |
| </ol> | |
| </nav> | |
| <!-- ============================================================ --> | |
| <h2 id="s1">1. The population grid</h2> | |
| <p> | |
| Each square is one person out of 200. The question "what's | |
| P(cause|data)?" is just: of all the squares that show the data (purple + | |
| coral), what fraction actually have the cause (purple only)? | |
| </p> | |
| <div class="section-card"> | |
| <div class="legend" id="leg1"> | |
| <div class="legend-item"> | |
| <div | |
| class="legend-swatch" | |
| style="background: var(--purple-200)" | |
| ></div> | |
| Cause + data (TP) | |
| </div> | |
| <div class="legend-item"> | |
| <div | |
| class="legend-swatch" | |
| style="background: var(--teal-200)" | |
| ></div> | |
| Cause, no data (FN) | |
| </div> | |
| <div class="legend-item"> | |
| <div | |
| class="legend-swatch" | |
| style="background: var(--coral-200)" | |
| ></div> | |
| No cause, but data (FP) | |
| </div> | |
| <div class="legend-item"> | |
| <div | |
| class="legend-swatch" | |
| style="background: var(--gray-100)" | |
| ></div> | |
| Neither (TN) | |
| </div> | |
| </div> | |
| <div class="grid" id="grid1"></div> | |
| <div class="stat-row"> | |
| <div class="stat"> | |
| <div class="stat-label" style="color: var(--purple-600)"> | |
| P(cause|data) | |
| </div> | |
| <div class="stat-val" id="v1-post" style="color: var(--purple-600)"> | |
| — | |
| </div> | |
| </div> | |
| <div class="stat"> | |
| <div class="stat-label" style="color: var(--teal-600)"> | |
| P(data|cause) | |
| </div> | |
| <div class="stat-val" id="v1-like" style="color: var(--teal-600)"> | |
| — | |
| </div> | |
| </div> | |
| <div class="stat"> | |
| <div class="stat-label" style="color: var(--blue-600)"> | |
| P(cause) | |
| </div> | |
| <div class="stat-val" id="v1-prior" style="color: var(--blue-600)"> | |
| — | |
| </div> | |
| </div> | |
| <div class="stat"> | |
| <div class="stat-label" style="color: var(--amber-600)"> | |
| P(data) | |
| </div> | |
| <div class="stat-val" id="v1-evid" style="color: var(--amber-600)"> | |
| — | |
| </div> | |
| </div> | |
| </div> | |
| <div class="eq-line" id="eq1"></div> | |
| <div class="slider-row"> | |
| <label>P(cause) = <span id="l1a">10%</span></label | |
| ><input | |
| type="range" | |
| min="1" | |
| max="50" | |
| value="10" | |
| step="1" | |
| id="s1a" | |
| oninput="updateGrid()" | |
| /><span></span> | |
| </div> | |
| <div class="slider-row"> | |
| <label>P(data|cause) = <span id="l1b">90%</span></label | |
| ><input | |
| type="range" | |
| min="5" | |
| max="100" | |
| value="90" | |
| step="1" | |
| id="s1b" | |
| oninput="updateGrid()" | |
| /><span></span> | |
| </div> | |
| <div class="slider-row"> | |
| <label>P(data|¬cause) = <span id="l1c">5%</span></label | |
| ><input | |
| type="range" | |
| min="0" | |
| max="50" | |
| value="5" | |
| step="1" | |
| id="s1c" | |
| oninput="updateGrid()" | |
| /><span></span> | |
| </div> | |
| <div class="note"> | |
| Drag sliders to see how the posterior shifts. A 90%-accurate test | |
| gives only ~17% posterior when the cause is rare (10%). | |
| </div> | |
| </div> | |
| <!-- ============================================================ --> | |
| <h2 id="s2">2. The three terms</h2> | |
| <p> | |
| The prior anchors your starting belief. The likelihood amplifies it (how | |
| well does the cause explain the data?). The marginal dampens it (how | |
| common is the data anyway?). The posterior is where the balance settles. | |
| </p> | |
| <div class="section-card"> | |
| <svg | |
| width="100%" | |
| viewBox="0 0 680 290" | |
| xmlns="http://www.w3.org/2000/svg" | |
| > | |
| <rect | |
| x="40" | |
| y="20" | |
| width="170" | |
| height="50" | |
| rx="8" | |
| fill="var(--blue-50)" | |
| stroke="var(--blue-200)" | |
| stroke-width="0.5" | |
| /> | |
| <text | |
| class="th" | |
| x="125" | |
| y="38" | |
| text-anchor="middle" | |
| dominant-baseline="central" | |
| fill="var(--blue-800)" | |
| > | |
| Prior P(cause) | |
| </text> | |
| <text | |
| class="ts" | |
| x="125" | |
| y="56" | |
| text-anchor="middle" | |
| dominant-baseline="central" | |
| fill="var(--blue-600)" | |
| > | |
| What you believed before | |
| </text> | |
| <rect | |
| x="255" | |
| y="20" | |
| width="170" | |
| height="50" | |
| rx="8" | |
| fill="var(--teal-50)" | |
| stroke="var(--teal-200)" | |
| stroke-width="0.5" | |
| /> | |
| <text | |
| class="th" | |
| x="340" | |
| y="38" | |
| text-anchor="middle" | |
| dominant-baseline="central" | |
| fill="var(--teal-800)" | |
| > | |
| Likelihood P(d|c) | |
| </text> | |
| <text | |
| class="ts" | |
| x="340" | |
| y="56" | |
| text-anchor="middle" | |
| dominant-baseline="central" | |
| fill="var(--teal-600)" | |
| > | |
| How well cause fits data | |
| </text> | |
| <rect | |
| x="470" | |
| y="20" | |
| width="170" | |
| height="50" | |
| rx="8" | |
| fill="var(--amber-50)" | |
| stroke="var(--amber-200)" | |
| stroke-width="0.5" | |
| /> | |
| <text | |
| class="th" | |
| x="555" | |
| y="38" | |
| text-anchor="middle" | |
| dominant-baseline="central" | |
| fill="var(--amber-800)" | |
| > | |
| Marginal P(data) | |
| </text> | |
| <text | |
| class="ts" | |
| x="555" | |
| y="56" | |
| text-anchor="middle" | |
| dominant-baseline="central" | |
| fill="var(--amber-600)" | |
| > | |
| How common is this data? | |
| </text> | |
| <text | |
| class="ts" | |
| x="125" | |
| y="90" | |
| text-anchor="middle" | |
| fill="var(--blue-600)" | |
| > | |
| anchors belief | |
| </text> | |
| <text | |
| class="ts" | |
| x="340" | |
| y="90" | |
| text-anchor="middle" | |
| fill="var(--teal-600)" | |
| > | |
| amplifies belief | |
| </text> | |
| <text | |
| class="ts" | |
| x="555" | |
| y="90" | |
| text-anchor="middle" | |
| fill="var(--amber-600)" | |
| > | |
| dampens belief | |
| </text> | |
| <rect | |
| x="170" | |
| y="108" | |
| width="340" | |
| height="44" | |
| rx="8" | |
| fill="var(--purple-50)" | |
| stroke="var(--purple-200)" | |
| stroke-width="0.5" | |
| /> | |
| <text | |
| class="th" | |
| x="340" | |
| y="134" | |
| text-anchor="middle" | |
| dominant-baseline="central" | |
| fill="var(--purple-800)" | |
| > | |
| Posterior P(cause|data) — updated belief | |
| </text> | |
| <!-- Balance visual --> | |
| <polygon points="340,218 322,244 358,244" fill="var(--gray-200)" /> | |
| <line | |
| x1="170" | |
| y1="218" | |
| x2="510" | |
| y2="218" | |
| stroke="var(--gray-400)" | |
| stroke-width="1.5" | |
| /> | |
| <rect | |
| x="120" | |
| y="178" | |
| width="100" | |
| height="34" | |
| rx="6" | |
| fill="var(--teal-50)" | |
| stroke="var(--teal-200)" | |
| stroke-width="0.5" | |
| /> | |
| <text | |
| class="ts" | |
| x="170" | |
| y="198" | |
| text-anchor="middle" | |
| dominant-baseline="central" | |
| fill="var(--teal-800)" | |
| > | |
| Likelihood | |
| </text> | |
| <text | |
| class="ts" | |
| x="170" | |
| y="260" | |
| text-anchor="middle" | |
| fill="var(--teal-600)" | |
| > | |
| Pulls UP | |
| </text> | |
| <rect | |
| x="460" | |
| y="178" | |
| width="100" | |
| height="34" | |
| rx="6" | |
| fill="var(--amber-50)" | |
| stroke="var(--amber-200)" | |
| stroke-width="0.5" | |
| /> | |
| <text | |
| class="ts" | |
| x="510" | |
| y="198" | |
| text-anchor="middle" | |
| dominant-baseline="central" | |
| fill="var(--amber-800)" | |
| > | |
| Marginal | |
| </text> | |
| <text | |
| class="ts" | |
| x="510" | |
| y="260" | |
| text-anchor="middle" | |
| fill="var(--amber-600)" | |
| > | |
| Pulls DOWN | |
| </text> | |
| <text class="ts" x="340" y="280" text-anchor="middle"> | |
| The posterior is where the balance settles | |
| </text> | |
| </svg> | |
| </div> | |
| <!-- ============================================================ --> | |
| <h2 id="s3">3. The rectangle is a population</h2> | |
| <p> | |
| The standard Venn diagram is misleading — cancer isn't a "subset" of | |
| symptoms. They're different dimensions: hidden state (rows) vs. | |
| observable data (columns). Each person falls into one of four cells. | |
| </p> | |
| <div class="section-card"> | |
| <div class="tab-row"> | |
| <div class="tab-btn active" onclick="showTab('t3', 0)"> | |
| Misleading Venn | |
| </div> | |
| <div class="tab-btn" onclick="showTab('t3', 1)"> | |
| Correct: 2D table | |
| </div> | |
| <div class="tab-btn" onclick="showTab('t3', 2)">Why it matters</div> | |
| </div> | |
| <div class="tab-panel active" data-group="t3"> | |
| <svg | |
| width="100%" | |
| viewBox="0 0 680 220" | |
| xmlns="http://www.w3.org/2000/svg" | |
| > | |
| <rect | |
| x="40" | |
| y="20" | |
| width="300" | |
| height="180" | |
| rx="4" | |
| fill="none" | |
| stroke="var(--bd)" | |
| stroke-width="0.5" | |
| /> | |
| <text class="ts" x="50" y="38">All possible outcomes</text> | |
| <ellipse | |
| cx="170" | |
| cy="120" | |
| rx="90" | |
| ry="65" | |
| fill="var(--blue-50)" | |
| stroke="var(--blue-200)" | |
| stroke-width="0.5" | |
| /> | |
| <text | |
| class="th" | |
| x="160" | |
| y="112" | |
| text-anchor="middle" | |
| fill="var(--blue-800)" | |
| > | |
| Symptoms | |
| </text> | |
| <ellipse | |
| cx="210" | |
| cy="115" | |
| rx="45" | |
| ry="35" | |
| fill="var(--purple-50)" | |
| stroke="var(--purple-200)" | |
| stroke-width="0.5" | |
| /> | |
| <text | |
| class="ts" | |
| x="210" | |
| y="118" | |
| text-anchor="middle" | |
| fill="var(--purple-800)" | |
| > | |
| Cancer | |
| </text> | |
| <text class="ts" x="400" y="60" fill="var(--red-600)"> | |
| This implies cancer is a | |
| </text> | |
| <text class="ts" x="400" y="78" fill="var(--red-600)"> | |
| subset of symptoms | |
| </text> | |
| <text class="ts" x="400" y="110"> | |
| But cancer is a hidden cause. | |
| </text> | |
| <text class="ts" x="400" y="128">Symptoms are observations.</text> | |
| <text class="ts" x="400" y="146"> | |
| Different categories entirely. | |
| </text> | |
| </svg> | |
| </div> | |
| <div class="tab-panel" data-group="t3"> | |
| <svg | |
| width="100%" | |
| viewBox="0 0 680 280" | |
| xmlns="http://www.w3.org/2000/svg" | |
| > | |
| <text class="th" x="340" y="22" text-anchor="middle"> | |
| Two independent dimensions per person | |
| </text> | |
| <text | |
| class="ts" | |
| x="60" | |
| y="100" | |
| text-anchor="middle" | |
| fill="var(--purple-800)" | |
| > | |
| Cancer | |
| </text> | |
| <text | |
| class="ts" | |
| x="60" | |
| y="190" | |
| text-anchor="middle" | |
| fill="var(--teal-800)" | |
| > | |
| No cancer | |
| </text> | |
| <text | |
| class="ts" | |
| x="220" | |
| y="54" | |
| text-anchor="middle" | |
| fill="var(--amber-800)" | |
| > | |
| Symptom + | |
| </text> | |
| <text | |
| class="ts" | |
| x="420" | |
| y="54" | |
| text-anchor="middle" | |
| fill="var(--gray-600)" | |
| > | |
| Symptom - | |
| </text> | |
| <rect | |
| x="110" | |
| y="66" | |
| width="200" | |
| height="70" | |
| rx="4" | |
| fill="var(--purple-50)" | |
| stroke="var(--purple-200)" | |
| stroke-width="0.5" | |
| /> | |
| <text | |
| class="th" | |
| x="210" | |
| y="96" | |
| text-anchor="middle" | |
| fill="var(--purple-800)" | |
| > | |
| True positive | |
| </text> | |
| <text | |
| class="ts" | |
| x="210" | |
| y="114" | |
| text-anchor="middle" | |
| fill="var(--purple-600)" | |
| > | |
| Cancer + symptoms | |
| </text> | |
| <rect | |
| x="330" | |
| y="66" | |
| width="200" | |
| height="70" | |
| rx="4" | |
| fill="var(--teal-50)" | |
| stroke="var(--teal-200)" | |
| stroke-width="0.5" | |
| /> | |
| <text | |
| class="th" | |
| x="430" | |
| y="96" | |
| text-anchor="middle" | |
| fill="var(--teal-800)" | |
| > | |
| False negative | |
| </text> | |
| <text | |
| class="ts" | |
| x="430" | |
| y="114" | |
| text-anchor="middle" | |
| fill="var(--teal-600)" | |
| > | |
| Cancer, no symptoms | |
| </text> | |
| <rect | |
| x="110" | |
| y="152" | |
| width="200" | |
| height="70" | |
| rx="4" | |
| fill="var(--coral-50)" | |
| stroke="var(--coral-200)" | |
| stroke-width="0.5" | |
| /> | |
| <text | |
| class="th" | |
| x="210" | |
| y="182" | |
| text-anchor="middle" | |
| fill="var(--coral-800)" | |
| > | |
| False positive | |
| </text> | |
| <text | |
| class="ts" | |
| x="210" | |
| y="200" | |
| text-anchor="middle" | |
| fill="var(--coral-600)" | |
| > | |
| No cancer, but symptoms | |
| </text> | |
| <rect | |
| x="330" | |
| y="152" | |
| width="200" | |
| height="70" | |
| rx="4" | |
| fill="var(--gray-50)" | |
| stroke="var(--gray-100)" | |
| stroke-width="0.5" | |
| /> | |
| <text | |
| class="th" | |
| x="430" | |
| y="182" | |
| text-anchor="middle" | |
| fill="var(--gray-800)" | |
| > | |
| True negative | |
| </text> | |
| <text | |
| class="ts" | |
| x="430" | |
| y="200" | |
| text-anchor="middle" | |
| fill="var(--gray-600)" | |
| > | |
| No cancer, no symptoms | |
| </text> | |
| <text | |
| class="ts" | |
| x="340" | |
| y="258" | |
| text-anchor="middle" | |
| fill="var(--teal-600)" | |
| > | |
| Each cell = people with that combination of state + observation | |
| </text> | |
| </svg> | |
| </div> | |
| <div class="tab-panel" data-group="t3"> | |
| <svg | |
| width="100%" | |
| viewBox="0 0 680 200" | |
| xmlns="http://www.w3.org/2000/svg" | |
| > | |
| <rect | |
| x="40" | |
| y="20" | |
| width="44" | |
| height="160" | |
| rx="0" | |
| fill="var(--purple-200)" | |
| opacity="0.6" | |
| /> | |
| <text | |
| class="ts" | |
| x="62" | |
| y="12" | |
| text-anchor="middle" | |
| fill="var(--purple-600)" | |
| > | |
| Cancer (1%) | |
| </text> | |
| <rect | |
| x="84" | |
| y="20" | |
| width="556" | |
| height="160" | |
| rx="0" | |
| fill="var(--gray-50)" | |
| /> | |
| <text | |
| class="ts" | |
| x="362" | |
| y="12" | |
| text-anchor="middle" | |
| fill="var(--gray-600)" | |
| > | |
| No cancer (99%) | |
| </text> | |
| <rect | |
| x="40" | |
| y="20" | |
| width="44" | |
| height="144" | |
| fill="var(--purple-200)" | |
| /> | |
| <text | |
| class="ts" | |
| x="62" | |
| y="96" | |
| text-anchor="middle" | |
| fill="var(--purple-800)" | |
| > | |
| TP: 9 | |
| </text> | |
| <rect | |
| x="40" | |
| y="164" | |
| width="44" | |
| height="16" | |
| fill="var(--teal-100)" | |
| /> | |
| <rect | |
| x="84" | |
| y="20" | |
| width="92" | |
| height="160" | |
| fill="var(--coral-100)" | |
| /> | |
| <text | |
| class="ts" | |
| x="130" | |
| y="96" | |
| text-anchor="middle" | |
| fill="var(--coral-800)" | |
| > | |
| FP: 45 | |
| </text> | |
| <rect | |
| x="176" | |
| y="20" | |
| width="464" | |
| height="160" | |
| fill="var(--gray-50)" | |
| /> | |
| <text | |
| class="ts" | |
| x="408" | |
| y="96" | |
| text-anchor="middle" | |
| fill="var(--gray-600)" | |
| > | |
| TN: 855 | |
| </text> | |
| <rect | |
| x="40" | |
| y="20" | |
| width="600" | |
| height="160" | |
| rx="0" | |
| fill="none" | |
| stroke="var(--bd)" | |
| stroke-width="0.5" | |
| /> | |
| <text class="th" x="340" y="200" text-anchor="middle"> | |
| P(cancer|symptom+) = 9 / (9 + 45) = 17% | |
| </text> | |
| </svg> | |
| <div class="note"> | |
| The Venn diagram hides the enormous no-cancer population producing | |
| false alarms. The contingency table makes the coral zone visible. | |
| </div> | |
| </div> | |
| </div> | |
| <!-- ============================================================ --> | |
| <h2 id="s4">4. Likelihood vs. probability</h2> | |
| <p> | |
| P(data|cause) looks like one thing but plays two different roles | |
| depending on which variable you're moving. Probability sweeps over data | |
| (sums to 1). Likelihood sweeps over causes (does NOT sum to 1). | |
| </p> | |
| <div class="section-card"> | |
| <div class="tab-row"> | |
| <div class="tab-btn active" onclick="showTab('t4', 0)"> | |
| Probability (fix cause) | |
| </div> | |
| <div class="tab-btn" onclick="showTab('t4', 1)"> | |
| Likelihood (fix data) | |
| </div> | |
| <div class="tab-btn" onclick="showTab('t4', 2)">Side by side</div> | |
| </div> | |
| <div class="tab-panel active" data-group="t4"> | |
| <svg | |
| width="100%" | |
| viewBox="0 0 680 240" | |
| xmlns="http://www.w3.org/2000/svg" | |
| > | |
| <text class="th" x="340" y="22" text-anchor="middle"> | |
| Fix the cause, ask "what data do I expect?" | |
| </text> | |
| <rect | |
| x="50" | |
| y="42" | |
| width="110" | |
| height="38" | |
| rx="6" | |
| fill="var(--purple-50)" | |
| stroke="var(--purple-200)" | |
| stroke-width="0.5" | |
| /> | |
| <text | |
| class="th" | |
| x="105" | |
| y="64" | |
| text-anchor="middle" | |
| dominant-baseline="central" | |
| fill="var(--purple-800)" | |
| > | |
| Cancer | |
| </text> | |
| <text | |
| class="ts" | |
| x="105" | |
| y="96" | |
| text-anchor="middle" | |
| fill="var(--purple-600)" | |
| > | |
| Locked in | |
| </text> | |
| <rect | |
| x="220" | |
| y="36" | |
| width="190" | |
| height="40" | |
| rx="6" | |
| fill="var(--teal-50)" | |
| stroke="var(--teal-200)" | |
| stroke-width="0.5" | |
| /> | |
| <text | |
| class="ts" | |
| x="315" | |
| y="52" | |
| text-anchor="middle" | |
| fill="var(--teal-800)" | |
| > | |
| P(fever|cancer) = 0.60 | |
| </text> | |
| <text | |
| class="ts" | |
| x="315" | |
| y="66" | |
| text-anchor="middle" | |
| fill="var(--teal-600)" | |
| > | |
| Fever? | |
| </text> | |
| <rect | |
| x="220" | |
| y="86" | |
| width="190" | |
| height="40" | |
| rx="6" | |
| fill="var(--teal-50)" | |
| stroke="var(--teal-200)" | |
| stroke-width="0.5" | |
| /> | |
| <text | |
| class="ts" | |
| x="315" | |
| y="102" | |
| text-anchor="middle" | |
| fill="var(--teal-800)" | |
| > | |
| P(weight loss|cancer) = 0.40 | |
| </text> | |
| <text | |
| class="ts" | |
| x="315" | |
| y="116" | |
| text-anchor="middle" | |
| fill="var(--teal-600)" | |
| > | |
| Weight loss? | |
| </text> | |
| <rect | |
| x="220" | |
| y="136" | |
| width="190" | |
| height="40" | |
| rx="6" | |
| fill="var(--teal-50)" | |
| stroke="var(--teal-200)" | |
| stroke-width="0.5" | |
| /> | |
| <text | |
| class="ts" | |
| x="315" | |
| y="152" | |
| text-anchor="middle" | |
| fill="var(--teal-800)" | |
| > | |
| P(fatigue|cancer) = 0.70 | |
| </text> | |
| <text | |
| class="ts" | |
| x="315" | |
| y="166" | |
| text-anchor="middle" | |
| fill="var(--teal-600)" | |
| > | |
| Fatigue? | |
| </text> | |
| <rect | |
| x="470" | |
| y="86" | |
| width="170" | |
| height="40" | |
| rx="6" | |
| fill="var(--amber-50)" | |
| stroke="var(--amber-200)" | |
| stroke-width="0.5" | |
| /> | |
| <text | |
| class="th" | |
| x="555" | |
| y="104" | |
| text-anchor="middle" | |
| dominant-baseline="central" | |
| fill="var(--amber-800)" | |
| > | |
| Must sum to 1 | |
| </text> | |
| <text | |
| class="ts" | |
| x="555" | |
| y="150" | |
| text-anchor="middle" | |
| fill="var(--amber-600)" | |
| > | |
| Sweeping over all data | |
| </text> | |
| <text | |
| class="ts" | |
| x="555" | |
| y="166" | |
| text-anchor="middle" | |
| fill="var(--amber-600)" | |
| > | |
| for one fixed cause | |
| </text> | |
| </svg> | |
| <div class="note"> | |
| Probability mode: "I <em>know</em> the patient has cancer. What | |
| symptoms should I expect?" Generates predictions forward. | |
| </div> | |
| </div> | |
| <div class="tab-panel" data-group="t4"> | |
| <svg | |
| width="100%" | |
| viewBox="0 0 680 240" | |
| xmlns="http://www.w3.org/2000/svg" | |
| > | |
| <text class="th" x="340" y="22" text-anchor="middle"> | |
| Fix the data, ask "which cause explains it best?" | |
| </text> | |
| <rect | |
| x="50" | |
| y="42" | |
| width="110" | |
| height="38" | |
| rx="6" | |
| fill="var(--teal-50)" | |
| stroke="var(--teal-200)" | |
| stroke-width="0.5" | |
| /> | |
| <text | |
| class="th" | |
| x="105" | |
| y="64" | |
| text-anchor="middle" | |
| dominant-baseline="central" | |
| fill="var(--teal-800)" | |
| > | |
| Fever | |
| </text> | |
| <text | |
| class="ts" | |
| x="105" | |
| y="96" | |
| text-anchor="middle" | |
| fill="var(--teal-600)" | |
| > | |
| Locked in | |
| </text> | |
| <rect | |
| x="220" | |
| y="36" | |
| width="190" | |
| height="40" | |
| rx="6" | |
| fill="var(--purple-50)" | |
| stroke="var(--purple-200)" | |
| stroke-width="0.5" | |
| /> | |
| <text | |
| class="ts" | |
| x="315" | |
| y="52" | |
| text-anchor="middle" | |
| fill="var(--purple-800)" | |
| > | |
| L(cancer) = 0.60 | |
| </text> | |
| <text | |
| class="ts" | |
| x="315" | |
| y="66" | |
| text-anchor="middle" | |
| fill="var(--purple-600)" | |
| > | |
| Cancer? | |
| </text> | |
| <rect | |
| x="220" | |
| y="86" | |
| width="190" | |
| height="40" | |
| rx="6" | |
| fill="var(--purple-50)" | |
| stroke="var(--purple-200)" | |
| stroke-width="0.5" | |
| /> | |
| <text | |
| class="ts" | |
| x="315" | |
| y="102" | |
| text-anchor="middle" | |
| fill="var(--purple-800)" | |
| > | |
| L(flu) = 0.85 | |
| </text> | |
| <text | |
| class="ts" | |
| x="315" | |
| y="116" | |
| text-anchor="middle" | |
| fill="var(--purple-600)" | |
| > | |
| Flu? | |
| </text> | |
| <rect | |
| x="220" | |
| y="136" | |
| width="190" | |
| height="40" | |
| rx="6" | |
| fill="var(--purple-50)" | |
| stroke="var(--purple-200)" | |
| stroke-width="0.5" | |
| /> | |
| <text | |
| class="ts" | |
| x="315" | |
| y="152" | |
| text-anchor="middle" | |
| fill="var(--purple-800)" | |
| > | |
| L(infection) = 0.75 | |
| </text> | |
| <text | |
| class="ts" | |
| x="315" | |
| y="166" | |
| text-anchor="middle" | |
| fill="var(--purple-600)" | |
| > | |
| Infection? | |
| </text> | |
| <rect | |
| x="470" | |
| y="86" | |
| width="170" | |
| height="40" | |
| rx="6" | |
| fill="var(--red-50)" | |
| stroke="var(--red-200)" | |
| stroke-width="0.5" | |
| /> | |
| <text | |
| class="th" | |
| x="555" | |
| y="104" | |
| text-anchor="middle" | |
| dominant-baseline="central" | |
| fill="var(--red-800)" | |
| > | |
| Do NOT sum to 1 | |
| </text> | |
| <text | |
| class="ts" | |
| x="555" | |
| y="150" | |
| text-anchor="middle" | |
| fill="var(--red-600)" | |
| > | |
| Sweeping over all causes | |
| </text> | |
| <text | |
| class="ts" | |
| x="555" | |
| y="166" | |
| text-anchor="middle" | |
| fill="var(--red-600)" | |
| > | |
| for one fixed observation | |
| </text> | |
| </svg> | |
| <div class="note"> | |
| Likelihood mode: "I <em>see</em> fever. Which cause fits best?" | |
| These are scores, not probabilities. 0.85 + 0.60 + 0.75 = 2.20, and | |
| that's fine. | |
| </div> | |
| </div> | |
| <div class="tab-panel" data-group="t4"> | |
| <div | |
| style=" | |
| display: grid; | |
| grid-template-columns: 1fr 1fr; | |
| gap: 12px; | |
| margin-top: 8px; | |
| " | |
| > | |
| <div | |
| style=" | |
| background: var(--teal-50); | |
| border-radius: var(--radius-lg); | |
| padding: 14px; | |
| border: 0.5px solid var(--teal-200); | |
| " | |
| > | |
| <div | |
| style=" | |
| font-weight: 500; | |
| font-size: 14px; | |
| color: var(--teal-800); | |
| margin-bottom: 8px; | |
| " | |
| > | |
| Probability | |
| </div> | |
| <div | |
| style=" | |
| font-size: 12px; | |
| color: var(--teal-600); | |
| line-height: 1.6; | |
| " | |
| > | |
| Fix: cause<br />Sweep: data<br />Sums to 1<br />"Given cancer, | |
| what will I see?"<br />Forward: cause generates data | |
| </div> | |
| </div> | |
| <div | |
| style=" | |
| background: var(--purple-50); | |
| border-radius: var(--radius-lg); | |
| padding: 14px; | |
| border: 0.5px solid var(--purple-200); | |
| " | |
| > | |
| <div | |
| style=" | |
| font-weight: 500; | |
| font-size: 14px; | |
| color: var(--purple-800); | |
| margin-bottom: 8px; | |
| " | |
| > | |
| Likelihood | |
| </div> | |
| <div | |
| style=" | |
| font-size: 12px; | |
| color: var(--purple-600); | |
| line-height: 1.6; | |
| " | |
| > | |
| Fix: data<br />Sweep: cause<br />Does NOT sum to 1<br />"Given | |
| fever, which cause fits?"<br />Backward: data interrogates | |
| causes | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- ============================================================ --> | |
| <h2 id="s5">5. Sequential updating</h2> | |
| <p> | |
| Each piece of evidence is its own mini Bayes update. Yesterday's | |
| posterior becomes today's prior. In odds form: | |
| <code>posterior odds = prior odds × likelihood ratio</code>. | |
| </p> | |
| <div class="section-card"> | |
| <div class="tab-row"> | |
| <div class="tab-btn active" onclick="showTab('t5', 0)"> | |
| Is she into me? | |
| </div> | |
| <div class="tab-btn" onclick="showTab('t5', 1)"> | |
| Is USA bombing Iran? | |
| </div> | |
| </div> | |
| <div class="tab-panel active" data-group="t5"> | |
| <div style="font-size: 12px; color: var(--tx3); margin-bottom: 6px"> | |
| Click each signal to observe it. Watch your belief update. | |
| </div> | |
| <div id="ev0"></div> | |
| <div style="margin-top: 12px"> | |
| <div class="belief-label">P(she's into me | all evidence)</div> | |
| <div class="belief-val" id="bv0">30%</div> | |
| <div class="bar-bg"> | |
| <div | |
| class="bar-fill" | |
| id="bf0" | |
| style="width: 30%; background: var(--purple-200)" | |
| ></div> | |
| </div> | |
| <div class="bar-labels"> | |
| <span>Not interested</span><span>Definitely interested</span> | |
| </div> | |
| </div> | |
| <div class="step-log" id="log0"><div>Prior: 30%</div></div> | |
| </div> | |
| <div class="tab-panel" data-group="t5"> | |
| <div style="font-size: 12px; color: var(--tx3); margin-bottom: 6px"> | |
| Click each intelligence signal. Watch the estimate shift. | |
| </div> | |
| <div id="ev1"></div> | |
| <div style="margin-top: 12px"> | |
| <div class="belief-label"> | |
| P(USA strikes Iran | all intelligence) | |
| </div> | |
| <div class="belief-val" id="bv1">5%</div> | |
| <div class="bar-bg"> | |
| <div | |
| class="bar-fill" | |
| id="bf1" | |
| style="width: 5%; background: var(--red-200)" | |
| ></div> | |
| </div> | |
| <div class="bar-labels"> | |
| <span>Posturing</span><span>Imminent strike</span> | |
| </div> | |
| </div> | |
| <div class="step-log" id="log1"><div>Prior: 5%</div></div> | |
| </div> | |
| </div> | |
| <!-- ============================================================ --> | |
| <h2 id="s6">6. Each signal pulls from its own space</h2> | |
| <p> | |
| The likelihood ratio for "she leans in" is computed entirely within the | |
| body language domain. "Fast replies" lives in texting. They combine | |
| multiplicatively — evidence from unrelated domains converges onto one | |
| belief. | |
| </p> | |
| <div class="section-card"> | |
| <div class="domain-row"> | |
| <div | |
| class="domain-tag" | |
| style="background: var(--purple-50); color: var(--purple-800)" | |
| > | |
| Body | |
| </div> | |
| <div class="domain-text"> | |
| "Leaning in" — how often do interested vs. uninterested people lean | |
| in? | |
| </div> | |
| <div | |
| class="domain-lr" | |
| style="background: var(--purple-50); color: var(--purple-800)" | |
| > | |
| 2x | |
| </div> | |
| </div> | |
| <div class="domain-row"> | |
| <div | |
| class="domain-tag" | |
| style="background: var(--teal-50); color: var(--teal-800)" | |
| > | |
| Texting | |
| </div> | |
| <div class="domain-text"> | |
| "Fast replies" — how often do interested vs. uninterested people | |
| reply fast? | |
| </div> | |
| <div | |
| class="domain-lr" | |
| style="background: var(--teal-50); color: var(--teal-800)" | |
| > | |
| 2.5x | |
| </div> | |
| </div> | |
| <div class="domain-row"> | |
| <div | |
| class="domain-tag" | |
| style="background: var(--amber-50); color: var(--amber-800)" | |
| > | |
| Social | |
| </div> | |
| <div class="domain-text"> | |
| "Friends tease" — how often with vs. without interest? | |
| </div> | |
| <div | |
| class="domain-lr" | |
| style="background: var(--amber-50); color: var(--amber-800)" | |
| > | |
| 3.5x | |
| </div> | |
| </div> | |
| <div class="domain-row"> | |
| <div | |
| class="domain-tag" | |
| style="background: var(--coral-50); color: var(--coral-800)" | |
| > | |
| Verbal | |
| </div> | |
| <div class="domain-text"> | |
| "Mentions boyfriend" — how often with vs. without interest? | |
| </div> | |
| <div | |
| class="domain-lr" | |
| style="background: var(--coral-50); color: var(--coral-800)" | |
| > | |
| 0.05x | |
| </div> | |
| </div> | |
| <h3 style="margin-top: 1rem">Multiplication chain (odds form)</h3> | |
| <div class="odds-chain"> | |
| <span>Prior 30:70</span> <span class="op">×</span> | |
| <span style="color: var(--purple-600)">2</span> | |
| <span class="op">×</span> | |
| <span style="color: var(--teal-600)">2.5</span> | |
| <span class="op">×</span> | |
| <span style="color: var(--amber-600)">3.5</span> | |
| <span class="op">×</span> | |
| <span style="color: var(--coral-600)">0.05</span> | |
| <span class="op">=</span> | |
| <span>0.375 : 1 → P = 27%</span> | |
| </div> | |
| <div class="big-result"> | |
| Three positive signals wiped out by one strong negative | |
| </div> | |
| <div class="note"> | |
| But beware: if "leans in," "fast replies," and "laughs a lot" all stem | |
| from one hidden trait (she's naturally warm), they're correlated — | |
| multiplying them as independent evidence over-counts. The test: could | |
| one hidden variable explain all of them? | |
| </div> | |
| </div> | |
| <!-- ============================================================ --> | |
| <h2 id="s7">7. Where the numbers come from</h2> | |
| <p> | |
| The prior can range from hard data to a pure guess. The framework | |
| doesn't require precision — it requires explicitness. An explicit bad | |
| guess is more correctable than an invisible one. | |
| </p> | |
| <div class="section-card"> | |
| <div class="tab-row"> | |
| <div class="tab-btn active" onclick="showTab('t7', 0)"> | |
| Source spectrum | |
| </div> | |
| <div class="tab-btn" onclick="showTab('t7', 1)">Correlation trap</div> | |
| <div class="tab-btn" onclick="showTab('t7', 2)"> | |
| Why it still works | |
| </div> | |
| </div> | |
| <div class="tab-panel active" data-group="t7"> | |
| <div style="display: flex; flex-direction: column; gap: 6px"> | |
| <div | |
| style=" | |
| background: var(--teal-50); | |
| padding: 10px 14px; | |
| border-radius: var(--radius); | |
| border: 0.5px solid var(--teal-200); | |
| " | |
| > | |
| <div | |
| style=" | |
| font-weight: 500; | |
| font-size: 13px; | |
| color: var(--teal-800); | |
| " | |
| > | |
| Hard data | |
| </div> | |
| <div style="font-size: 12px; color: var(--teal-600)"> | |
| Clinical trials, large datasets — P(positive|cancer)=0.90 from | |
| 50,000 patients | |
| </div> | |
| </div> | |
| <div | |
| style=" | |
| background: var(--blue-50); | |
| padding: 10px 14px; | |
| border-radius: var(--radius); | |
| border: 0.5px solid var(--blue-200); | |
| " | |
| > | |
| <div | |
| style=" | |
| font-weight: 500; | |
| font-size: 13px; | |
| color: var(--blue-800); | |
| " | |
| > | |
| Reference classes | |
| </div> | |
| <div style="font-size: 12px; color: var(--blue-600)"> | |
| Historical frequency — P(strike|buildup)=0.08 from 50 past | |
| buildups | |
| </div> | |
| </div> | |
| <div | |
| style=" | |
| background: var(--amber-50); | |
| padding: 10px 14px; | |
| border-radius: var(--radius); | |
| border: 0.5px solid var(--amber-200); | |
| " | |
| > | |
| <div | |
| style=" | |
| font-weight: 500; | |
| font-size: 13px; | |
| color: var(--amber-800); | |
| " | |
| > | |
| Expert elicitation | |
| </div> | |
| <div style="font-size: 12px; color: var(--amber-600)"> | |
| Average of 10 domain experts — P(recession|yield curve)=0.35 | |
| </div> | |
| </div> | |
| <div | |
| style=" | |
| background: var(--coral-50); | |
| padding: 10px 14px; | |
| border-radius: var(--radius); | |
| border: 0.5px solid var(--coral-200); | |
| " | |
| > | |
| <div | |
| style=" | |
| font-weight: 500; | |
| font-size: 13px; | |
| color: var(--coral-800); | |
| " | |
| > | |
| Calibrated gut | |
| </div> | |
| <div style="font-size: 12px; color: var(--coral-600)"> | |
| Your estimate, checked against track record — P(she's into | |
| me)=0.30 | |
| </div> | |
| </div> | |
| <div | |
| style=" | |
| background: var(--gray-50); | |
| padding: 10px 14px; | |
| border-radius: var(--radius); | |
| border: 0.5px solid var(--gray-100); | |
| " | |
| > | |
| <div | |
| style=" | |
| font-weight: 500; | |
| font-size: 13px; | |
| color: var(--gray-800); | |
| " | |
| > | |
| Pure guess | |
| </div> | |
| <div style="font-size: 12px; color: var(--gray-600)"> | |
| No basis, but at least it's explicit and updatable | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="tab-panel" data-group="t7"> | |
| <svg | |
| width="100%" | |
| viewBox="0 0 680 260" | |
| xmlns="http://www.w3.org/2000/svg" | |
| > | |
| <rect | |
| x="180" | |
| y="20" | |
| width="320" | |
| height="38" | |
| rx="6" | |
| fill="var(--coral-50)" | |
| stroke="var(--coral-200)" | |
| stroke-width="0.5" | |
| /> | |
| <text | |
| class="th" | |
| x="340" | |
| y="42" | |
| text-anchor="middle" | |
| dominant-baseline="central" | |
| fill="var(--coral-800)" | |
| > | |
| Hidden variable: she's naturally warm | |
| </text> | |
| <line | |
| x1="260" | |
| y1="58" | |
| x2="130" | |
| y2="90" | |
| stroke="var(--coral-200)" | |
| stroke-width="0.5" | |
| /> | |
| <line | |
| x1="340" | |
| y1="58" | |
| x2="340" | |
| y2="90" | |
| stroke="var(--coral-200)" | |
| stroke-width="0.5" | |
| /> | |
| <line | |
| x1="420" | |
| y1="58" | |
| x2="550" | |
| y2="90" | |
| stroke="var(--coral-200)" | |
| stroke-width="0.5" | |
| /> | |
| <rect | |
| x="55" | |
| y="92" | |
| width="150" | |
| height="34" | |
| rx="6" | |
| fill="var(--purple-50)" | |
| stroke="var(--purple-200)" | |
| stroke-width="0.5" | |
| /> | |
| <text | |
| class="ts" | |
| x="130" | |
| y="112" | |
| text-anchor="middle" | |
| dominant-baseline="central" | |
| fill="var(--purple-800)" | |
| > | |
| Leans in | |
| </text> | |
| <rect | |
| x="265" | |
| y="92" | |
| width="150" | |
| height="34" | |
| rx="6" | |
| fill="var(--purple-50)" | |
| stroke="var(--purple-200)" | |
| stroke-width="0.5" | |
| /> | |
| <text | |
| class="ts" | |
| x="340" | |
| y="112" | |
| text-anchor="middle" | |
| dominant-baseline="central" | |
| fill="var(--purple-800)" | |
| > | |
| Fast replies | |
| </text> | |
| <rect | |
| x="475" | |
| y="92" | |
| width="150" | |
| height="34" | |
| rx="6" | |
| fill="var(--purple-50)" | |
| stroke="var(--purple-200)" | |
| stroke-width="0.5" | |
| /> | |
| <text | |
| class="ts" | |
| x="550" | |
| y="112" | |
| text-anchor="middle" | |
| dominant-baseline="central" | |
| fill="var(--purple-800)" | |
| > | |
| Laughs a lot | |
| </text> | |
| <text | |
| class="ts" | |
| x="340" | |
| y="155" | |
| text-anchor="middle" | |
| fill="var(--red-600)" | |
| > | |
| You think: 2x × 2.5x × 2x = 10x boost | |
| </text> | |
| <text | |
| class="ts" | |
| x="340" | |
| y="173" | |
| text-anchor="middle" | |
| fill="var(--red-600)" | |
| > | |
| Reality: all three stem from one trait — effective ~2.5x | |
| </text> | |
| <line | |
| x1="40" | |
| y1="194" | |
| x2="640" | |
| y2="194" | |
| stroke="var(--bd)" | |
| stroke-width="0.5" | |
| /> | |
| <text | |
| class="ts" | |
| x="340" | |
| y="216" | |
| text-anchor="middle" | |
| fill="var(--teal-600)" | |
| > | |
| Truly independent: body language + direct action + third-party | |
| source | |
| </text> | |
| <text | |
| class="ts" | |
| x="340" | |
| y="234" | |
| text-anchor="middle" | |
| fill="var(--teal-600)" | |
| > | |
| Test: if I learned the cause of signal A, would it change my | |
| expectation of B? | |
| </text> | |
| </svg> | |
| </div> | |
| <div class="tab-panel" data-group="t7"> | |
| <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 10px"> | |
| <div | |
| style=" | |
| background: var(--red-50); | |
| padding: 12px; | |
| border-radius: var(--radius); | |
| border: 0.5px solid var(--red-100); | |
| " | |
| > | |
| <div | |
| style=" | |
| font-weight: 500; | |
| font-size: 13px; | |
| color: var(--red-800); | |
| margin-bottom: 6px; | |
| " | |
| > | |
| Without Bayes | |
| </div> | |
| <div | |
| style="font-size: 12px; color: var(--red-600); line-height: 1.5" | |
| > | |
| Priors are hidden<br />Correlations ignored<br />Base rates | |
| forgotten<br />One vivid signal dominates | |
| </div> | |
| </div> | |
| <div | |
| style=" | |
| background: var(--teal-50); | |
| padding: 12px; | |
| border-radius: var(--radius); | |
| border: 0.5px solid var(--teal-100); | |
| " | |
| > | |
| <div | |
| style=" | |
| font-weight: 500; | |
| font-size: 13px; | |
| color: var(--teal-800); | |
| margin-bottom: 6px; | |
| " | |
| > | |
| With Bayes (even imperfect) | |
| </div> | |
| <div | |
| style=" | |
| font-size: 12px; | |
| color: var(--teal-600); | |
| line-height: 1.5; | |
| " | |
| > | |
| Priors explicit, challengeable<br />Self-correcting with data<br />Base | |
| rates anchored<br />Degrades gracefully | |
| </div> | |
| </div> | |
| </div> | |
| <div class="note" style="margin-top: 10px"> | |
| The framework's main value isn't producing a precise number. It's | |
| forcing you to ask "what's my base rate?", "how diagnostic is this | |
| signal really?", and "am I double-counting correlated evidence?" | |
| </div> | |
| </div> | |
| </div> | |
| <!-- ============================================================ --> | |
| <h2 id="s8">8. When Bayes is most valuable</h2> | |
| <p> | |
| The prior doesn't need to be low — Bayes catches a different cognitive | |
| mistake at each end of the spectrum. | |
| </p> | |
| <div class="section-card" style="padding-bottom: 0.5rem"> | |
| <div class="exp-card active" onclick="toggleExp(this)"> | |
| <div class="exp-head"> | |
| <div class="exp-title"> | |
| Low prior: rare disease, rare crime, rare event | |
| </div> | |
| <div | |
| class="exp-tag" | |
| style="background: var(--purple-50); color: var(--purple-800)" | |
| > | |
| Base rate neglect | |
| </div> | |
| </div> | |
| <div class="exp-body"> | |
| Your gut overweights the positive test and forgets how rare the | |
| disease is. | |
| <div class="example-box"> | |
| <div class="elabel">Medical screening</div> | |
| Test is 95% accurate. Disease affects 1 in 1000. | |
| <div class="echain">Prior: 0.1% × LR: 19x = Posterior: ~1.9%</div> | |
| <div class="eresult" style="color: var(--purple-600)"> | |
| Gut says 95%. Bayes says 1.9%. | |
| </div> | |
| </div> | |
| <div class="example-box"> | |
| <div class="elabel">Startup investing</div> | |
| Great pitch, strong team. But 90% of startups fail. | |
| <div class="echain">Prior: 10% × LR ~3x = Posterior: ~25%</div> | |
| <div class="eresult" style="color: var(--purple-600)"> | |
| Impressive pitch doesn't overcome the base rate. | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="exp-card" onclick="toggleExp(this)"> | |
| <div class="exp-head"> | |
| <div class="exp-title"> | |
| High prior: when disconfirming signals compound | |
| </div> | |
| <div | |
| class="exp-tag" | |
| style="background: var(--teal-50); color: var(--teal-800)" | |
| > | |
| Confirmation bias | |
| </div> | |
| </div> | |
| <div class="exp-body"> | |
| When you're already confident, you dismiss warning signs one by one | |
| — but they multiply. | |
| <div class="example-box"> | |
| <div class="elabel">Your company is "doing well"</div> | |
| Prior: 85% healthy. But churn up, NPS drops, key hire leaves. | |
| <div class="echain">85% × 0.4 × 0.5 × 0.6 = ~40%</div> | |
| <div class="eresult" style="color: var(--teal-600)"> | |
| Each alone is dismissible. Together they're a pattern. | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="exp-card" onclick="toggleExp(this)"> | |
| <div class="exp-head"> | |
| <div class="exp-title"> | |
| Many hypotheses: which explanation wins? | |
| </div> | |
| <div | |
| class="exp-tag" | |
| style="background: var(--amber-50); color: var(--amber-800)" | |
| > | |
| Narrative fallacy | |
| </div> | |
| </div> | |
| <div class="exp-body"> | |
| Your gut picks the most dramatic story and ignores boring | |
| alternatives. | |
| <div class="example-box"> | |
| <div class="elabel">Server is slow</div> | |
| DDoS (exciting, 2% prior), memory leak (boring, 30% prior), | |
| traffic spike (50% prior). | |
| <div class="echain"> | |
| DDoS: 2%×3x=6% | Leak: 30%×4x=67% | Traffic: 50%×1.5x=27% | |
| </div> | |
| <div class="eresult" style="color: var(--amber-600)"> | |
| The boring explanation almost always wins. | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="exp-card" onclick="toggleExp(this)"> | |
| <div class="exp-head"> | |
| <div class="exp-title"> | |
| Noisy signals: when evidence is ambiguous | |
| </div> | |
| <div | |
| class="exp-tag" | |
| style="background: var(--coral-50); color: var(--coral-800)" | |
| > | |
| Overconfidence | |
| </div> | |
| </div> | |
| <div class="exp-body"> | |
| Some evidence is consistent with many hypotheses — it barely | |
| discriminates. | |
| <div class="example-box"> | |
| <div class="elabel">Hiring interviews</div> | |
| P(great answers|strong hire): 70%. P(great answers|weak hire): | |
| 50%. | |
| <div class="echain"> | |
| LR = 70/50 = 1.4x — barely moves the needle | |
| </div> | |
| <div class="eresult" style="color: var(--coral-600)"> | |
| Interviews feel informative but LR is ~1.4x. A work sample test | |
| might be 5x. | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <p | |
| style=" | |
| margin-top: 2rem; | |
| font-size: 13px; | |
| color: var(--tx3); | |
| text-align: center; | |
| " | |
| > | |
| interactive Bayes' theorem guide | |
| </p> | |
| </div> | |
| <script> | |
| // === Section 1: Grid === | |
| const N = 200, | |
| grid = document.getElementById("grid1"); | |
| for (let i = 0; i < N; i++) { | |
| const d = document.createElement("div"); | |
| d.className = "dot"; | |
| grid.appendChild(d); | |
| } | |
| const dots = grid.children; | |
| function updateGrid() { | |
| const pC = parseInt(document.getElementById("s1a").value) / 100; | |
| const pDC = parseInt(document.getElementById("s1b").value) / 100; | |
| const pDN = parseInt(document.getElementById("s1c").value) / 100; | |
| document.getElementById("l1a").textContent = Math.round(pC * 100) + "%"; | |
| document.getElementById("l1b").textContent = | |
| Math.round(pDC * 100) + "%"; | |
| document.getElementById("l1c").textContent = | |
| Math.round(pDN * 100) + "%"; | |
| const nC = Math.round(N * pC), | |
| nN = N - nC; | |
| const nTP = Math.round(nC * pDC), | |
| nFN = nC - nTP; | |
| const nFP = Math.round(nN * pDN), | |
| nTN = nN - nFP; | |
| let idx = 0; | |
| for (let i = 0; i < nTP; i++) | |
| dots[idx++].style.background = "var(--purple-200)"; | |
| for (let i = 0; i < nFN; i++) | |
| dots[idx++].style.background = "var(--teal-200)"; | |
| for (let i = 0; i < nFP; i++) | |
| dots[idx++].style.background = "var(--coral-200)"; | |
| for (let i = 0; i < nTN; i++) | |
| dots[idx++].style.background = "var(--gray-100)"; | |
| const pD = (nTP + nFP) / N; | |
| const post = pD > 0 ? nTP / (nTP + nFP) : 0; | |
| document.getElementById("v1-post").textContent = | |
| Math.round(post * 100) + "%"; | |
| document.getElementById("v1-like").textContent = | |
| Math.round(pDC * 100) + "%"; | |
| document.getElementById("v1-prior").textContent = | |
| Math.round(pC * 100) + "%"; | |
| document.getElementById("v1-evid").textContent = | |
| Math.round(pD * 100) + "%"; | |
| document.getElementById("eq1").innerHTML = | |
| `<span class="hl-post">${Math.round(post * 100)}%</span> = <span class="hl-like">${Math.round(pDC * 100)}%</span> × <span class="hl-prior">${Math.round(pC * 100)}%</span> / <span class="hl-evid">${Math.round(pD * 100)}%</span>`; | |
| } | |
| updateGrid(); | |
| // === Tab system === | |
| function showTab(group, i) { | |
| document | |
| .querySelectorAll(`[data-group="${group}"]`) | |
| .forEach((p, j) => p.classList.toggle("active", j === i)); | |
| const btns = document | |
| .querySelectorAll(`[data-group="${group}"]`)[0] | |
| ?.parentElement.querySelectorAll(".tab-btn"); | |
| if (!btns) { | |
| let el = document.querySelectorAll(`[data-group="${group}"]`)[0] | |
| ?.parentElement; | |
| el?.querySelectorAll(".tab-btn").forEach((b, j) => | |
| b.classList.toggle("active", j === i), | |
| ); | |
| } | |
| const card = document | |
| .querySelectorAll(`[data-group="${group}"]`)[0] | |
| ?.closest(".section-card"); | |
| if (card) | |
| card | |
| .querySelectorAll(".tab-btn") | |
| .forEach((b, j) => b.classList.toggle("active", j === i)); | |
| } | |
| // === Section 5: Sequential updating === | |
| const scenes = [ | |
| { | |
| prior: 0.3, | |
| evidence: [ | |
| { label: "She laughs at your bad jokes", lr: 2.5 }, | |
| { label: "She initiates texting first", lr: 3.0 }, | |
| { label: "She mentions her boyfriend", lr: 0.05 }, | |
| { label: "She suggests hanging out 1-on-1", lr: 4.0 }, | |
| { label: "She takes hours to reply", lr: 0.5 }, | |
| { label: "She remembers small details about you", lr: 2.0 }, | |
| { label: "Her friends seem to know about you", lr: 3.5 }, | |
| { label: "She avoids physical proximity", lr: 0.3 }, | |
| ], | |
| colors: [ | |
| "var(--purple-200)", | |
| "var(--purple-400)", | |
| "var(--purple-600)", | |
| ], | |
| fillId: "bf0", | |
| valId: "bv0", | |
| logId: "log0", | |
| evId: "ev0", | |
| }, | |
| { | |
| prior: 0.05, | |
| evidence: [ | |
| { label: "Carrier group moves to Persian Gulf", lr: 3.0 }, | |
| { label: "Satellite shows ammo depot buildup", lr: 2.5 }, | |
| { label: "Diplomatic backchannel opens", lr: 0.3 }, | |
| { label: "Military families told to leave region", lr: 5.0 }, | |
| { label: "President makes conciliatory speech", lr: 0.4 }, | |
| { label: "Cyber attacks on Iranian infrastructure", lr: 4.0 }, | |
| { label: "Congress briefed on classified war plans", lr: 6.0 }, | |
| { label: "UN announces emergency summit", lr: 0.6 }, | |
| ], | |
| colors: ["var(--red-200)", "var(--red-400)", "var(--red-600)"], | |
| fillId: "bf1", | |
| valId: "bv1", | |
| logId: "log1", | |
| evId: "ev1", | |
| }, | |
| ]; | |
| let state = [ | |
| { active: new Array(8).fill(false) }, | |
| { active: new Array(8).fill(false) }, | |
| ]; | |
| function renderCards(si) { | |
| const s = scenes[si], | |
| container = document.getElementById(s.evId); | |
| container.innerHTML = ""; | |
| s.evidence.forEach((e, i) => { | |
| const on = state[si].active[i]; | |
| const card = document.createElement("div"); | |
| card.className = "ev-card " + (on ? "on" : "off"); | |
| const c = e.lr > 1 ? "var(--teal-600)" : "var(--red-600)"; | |
| card.innerHTML = `<div class="ev-check">${on ? "✓" : ""}</div><div class="ev-label">${e.label}</div><div class="ev-lr" style="color:${c}">LR ${e.lr}x</div>`; | |
| card.onclick = () => { | |
| state[si].active[i] = !state[si].active[i]; | |
| recalc(si); | |
| }; | |
| container.appendChild(card); | |
| }); | |
| } | |
| function recalc(si) { | |
| const s = scenes[si]; | |
| renderCards(si); | |
| let belief = s.prior; | |
| const log = document.getElementById(s.logId); | |
| log.innerHTML = `<div>Prior: ${Math.round(s.prior * 100)}%</div>`; | |
| state[si].active.forEach((a, i) => { | |
| if (!a) return; | |
| const e = s.evidence[i], | |
| old = belief; | |
| const odds = (belief / (1 - belief)) * e.lr; | |
| belief = Math.max(0.001, Math.min(0.999, odds / (1 + odds))); | |
| const ar = e.lr > 1 ? "↑" : "↓"; | |
| log.innerHTML += `<div>${ar} "${e.label}" (${e.lr}x): ${Math.round(old * 100)}%→${Math.round(belief * 100)}%</div>`; | |
| }); | |
| const pct = Math.round(belief * 100); | |
| document.getElementById(s.valId).textContent = pct + "%"; | |
| const bar = document.getElementById(s.fillId); | |
| bar.style.width = pct + "%"; | |
| bar.style.background = | |
| pct > 70 ? s.colors[2] : pct > 40 ? s.colors[1] : s.colors[0]; | |
| log.scrollTop = log.scrollHeight; | |
| } | |
| renderCards(0); | |
| renderCards(1); | |
| // === Section 8: Expandable cards === | |
| function toggleExp(el) { | |
| const was = el.classList.contains("active"); | |
| el.parentElement | |
| .querySelectorAll(".exp-card") | |
| .forEach((c) => c.classList.remove("active")); | |
| if (!was) el.classList.add("active"); | |
| } | |
| </script> | |
| </body> | |
| </html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment