prototype slide 07: 3 layout variants (?variant=A|B|C) — three columns / editorial bands / ontology+why-panel; all EN-primary per foreign audience

This commit is contained in:
Codex
2026-09-07 22:52:06 +02:00
parent 67d96a44de
commit 8df9535afa
@@ -0,0 +1,251 @@
<!doctype html>
<!-- PROTOTYPE (throwaway) — Slide 07 "The clinical ontology": three variants, switchable
via ?variant=A|B|C + floating bar (← → keys too).
Question: how to present 11+5 categories so the slide is more readable, livelier,
and with ENGLISH more prominent than Italian (audience mostly foreign).
A = three columns of 5-6 pills (user's idea) · B = editorial bands, EN-first pills
· C = split: ontology left, "why the order matters" panel right. -->
<html lang="en">
<head>
<meta charset="utf-8">
<title>PROTOTYPE · Slide 07 "The clinical ontology" — 3 layout variants</title>
<link rel="stylesheet" href="/deck/fonts.css">
<style>
:root {
--bordeaux: #cb333b; --bordeaux-deep: #8f1204; --bordeaux-tint: #f4dfe1;
--surface: #fdfcfc; --surface-alt: #f6f5f5; --surface-sunken: #ecebeb;
--ink: #2a2426; --ink-muted: #6b6568;
--line: #e3e0e1; --line-strong: #c9c5c6;
--sans: 'Source Sans 3', system-ui, sans-serif;
--display: 'Source Serif 4', Georgia, serif;
--mono: ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
}
* { box-sizing: border-box; }
body { margin: 0; background: #e9e7e7; font-family: var(--sans); padding: 26px 0 90px; }
.proto-head { text-align: center; margin: 0 0 14px; }
.proto-head b { font: 700 12px/1 var(--mono); letter-spacing: .14em; text-transform: uppercase; color: var(--bordeaux); }
.proto-head span { display: block; margin-top: 6px; font: 400 13px/1.4 var(--sans); color: var(--ink-muted); }
/* ---- slide frame (deck-like, 1200×690) ---- */
.frame { width: 1200px; height: 690px; margin: 0 auto; background: var(--surface);
display: flex; flex-direction: column; box-shadow: 0 8px 30px rgba(42,36,38,.18); overflow: hidden; }
.head { flex: 0 0 74px; display: flex; align-items: center; justify-content: space-between;
padding: 0 40px; border-bottom: 1px solid var(--line); }
.head img { height: 54px; display: block; }
.head-org { font: 700 11px/1 var(--sans); letter-spacing: .14em; text-transform: uppercase; color: var(--ink-muted); }
.band { flex: 0 0 42px; display: flex; align-items: center; justify-content: space-between;
padding: 0 40px; background: var(--bordeaux); color: var(--surface); }
.band b { font: 700 12.5px/1 var(--sans); letter-spacing: .14em; text-transform: uppercase; }
.band .jump { font: 700 11px/1 var(--mono); letter-spacing: .1em; }
.sbody { flex: 1; min-height: 0; display: flex; flex-direction: column;
padding: 22px 48px 16px; text-align: left; }
.vwrap { margin: auto 0; width: 100%; }
.foot { flex: 0 0 30px; display: flex; align-items: center; justify-content: space-between; gap: 24px;
padding: 0 40px; border-top: 1px solid var(--line);
font: 600 9.5px/1.4 var(--sans); letter-spacing: .03em; color: var(--ink-muted); }
.kicker { font: 700 11.5px/1 var(--sans); letter-spacing: .16em; text-transform: uppercase; color: var(--bordeaux); margin-bottom: 10px; }
h2 { font: 700 27px/1.15 var(--sans); letter-spacing: -.01em; color: var(--ink); margin: 0 0 14px; }
/* ---- shared: EN-first pills (EN bold dark = primary, IT gloss = secondary) ---- */
.pill { display: inline-flex; align-items: baseline; gap: 7px; border: 1px solid var(--bordeaux);
border-radius: 9999px; padding: 6px 13px; background: #fff; white-space: nowrap; }
.pill .en { font: 700 13px/1 var(--sans); color: var(--ink); }
.pill .it { font: 400 11px/1 var(--sans); color: var(--ink-muted); }
.pill.fill { background: var(--bordeaux-tint); }
.col-h { display: flex; align-items: center; gap: 8px; font: 700 10px/1 var(--mono);
letter-spacing: .14em; text-transform: uppercase; color: var(--bordeaux-deep); margin-bottom: 9px; }
.col-h .n { margin-left: auto; font: 700 9px/1 var(--mono); color: var(--bordeaux);
border: 1px solid var(--bordeaux); border-radius: 9999px; padding: 2px 7px; letter-spacing: .08em; }
/* ---- shared: numbered points ---- */
.pt .num { flex: 0 0 22px; font: 700 11px/1.6 var(--mono); color: var(--bordeaux); }
.pt b { font: 700 13px/1.35 var(--sans); color: var(--ink); }
.pt span.d { font: 400 12.5px/1.45 var(--sans); color: var(--ink-muted); }
code { font: 700 11.5px/1 var(--mono); color: var(--bordeaux-deep); background: var(--bordeaux-tint);
padding: 2px 6px; border-radius: 4px; }
/* ================= VARIANT A — three columns (user's idea) ================= */
.va-grid { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 0 26px; align-items: start; }
.va-col + .va-col { border-left: 1px solid var(--line); padding-left: 26px; }
.va-col .stack { display: flex; flex-direction: column; gap: 7px; align-items: stretch; }
.va-col .pill { display: flex; justify-content: flex-start; }
.va-points { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 26px; margin-top: 20px;
padding-top: 14px; border-top: 1px solid var(--line); }
.va-points .pt { display: flex; gap: 10px; }
/* ================= VARIANT B — editorial bands ================= */
.vb-band { display: flex; gap: 20px; align-items: flex-start; padding: 13px 0 15px; border-bottom: 1px solid var(--line); }
.vb-band:first-of-type { padding-top: 4px; }
.vb-num { flex: 0 0 96px; }
.vb-num b { display: block; font: 800 30px/1 var(--sans); letter-spacing: -.02em; color: var(--bordeaux); }
.vb-num span { display: block; margin-top: 5px; font: 700 9px/1.4 var(--mono); letter-spacing: .12em;
text-transform: uppercase; color: var(--ink-muted); }
.vb-chips { display: flex; flex-wrap: wrap; gap: 8px; align-content: flex-start; }
.vb-points { margin-top: 16px; }
.vb-points .pt { display: flex; gap: 10px; padding: 8px 0; border-bottom: 1px solid var(--line); }
.vb-points .pt:last-child { border-bottom: none; }
/* ================= VARIANT C — split: ontology / why order matters ================= */
.vc-split { display: grid; grid-template-columns: 1.42fr 1fr; gap: 26px; align-items: start; flex: 1; min-height: 0; }
.vc-tier { margin-bottom: 16px; }
.vc-tier .col-h { margin-bottom: 10px; }
.vc-chips { display: flex; flex-wrap: wrap; gap: 8px; }
.vc-why { border: 1px solid var(--bordeaux); background: var(--bordeaux-tint); border-radius: 10px;
padding: 15px 18px 8px; }
.vc-why-h { font: 700 10px/1 var(--mono); letter-spacing: .14em; text-transform: uppercase;
color: var(--bordeaux-deep); margin-bottom: 4px; }
.vc-why .pt { display: flex; gap: 10px; padding: 10px 0; border-bottom: 1px solid rgba(143,18,4,.18); }
.vc-why .pt:last-child { border-bottom: none; }
.vc-why .pt .num { color: var(--bordeaux-deep); }
/* ---- floating switcher (not part of the design) ---- */
.switcher { position: fixed; left: 50%; bottom: 18px; transform: translateX(-50%); z-index: 99;
display: flex; align-items: center; gap: 10px; background: #1d1a1b; color: #fff;
border-radius: 9999px; padding: 8px 10px; box-shadow: 0 6px 22px rgba(0,0,0,.35); }
.switcher button { all: unset; cursor: pointer; width: 30px; height: 30px; border-radius: 9999px;
display: grid; place-items: center; background: rgba(255,255,255,.14); font: 700 14px/1 var(--sans); }
.switcher button:hover { background: rgba(255,255,255,.28); }
.switcher .lbl { font: 700 12px/1 var(--mono); letter-spacing: .06em; min-width: 240px; text-align: center; }
</style>
</head>
<body>
<div class="proto-head">
<b>PROTOTYPE · slide 07 — the clinical ontology</b>
<span>Three layout variants · EN primary (bold dark) over IT gloss (secondary) · A = three columns (your idea) · B = editorial bands · C = ontology + "why order matters" panel</span>
</div>
<div class="frame">
<header class="head">
<img src="/deck/logo.png" alt="">
<span class="head-org">AritmoLab · Policlinico San Donato</span>
</header>
<nav class="band"><b>Text analysis</b><span class="jump">07 · The clinical ontology</span></nav>
<div class="sbody" id="sbody"></div>
<footer class="foot">
<span>Role of AI in the Analysis of Unstructured Clinical Databases</span>
<span>Dr. Marco Pancotti - MultiPhysixLab</span>
<span>Dr. Sara Paratico - Gruppo San Donato</span>
<span>San Donato Milanese, Milan, Italy · 2–3 October 2026</span>
<span>07 / 14</span>
</footer>
</div>
<div class="switcher">
<button id="prev" aria-label="previous variant">←</button>
<span class="lbl" id="lbl"></span>
<button id="next" aria-label="next variant">→</button>
</div>
<script>
// ---- data (EN-first: EN bold primary, IT gloss secondary) ----
const T1 = [
{ en: 'AF', it: 'FA' },
{ en: 'Brugada', it: '' },
{ en: 'Flutter', it: '' },
{ en: 'AT', it: 'TA' },
{ en: 'AVNRT', it: 'TRN' },
{ en: 'PSVT', it: 'WPW / TPSV' },
{ en: 'VT', it: 'TV' },
{ en: 'VF', it: 'FV' },
{ en: 'Ventricular ectopy', it: 'Extrasistolia V.' },
{ en: 'Syncope', it: 'Sincope' },
{ en: 'Long QT', it: 'QT lungo' },
];
const T2 = [
{ en: 'AV block', it: 'Blocco AV' },
{ en: 'Bundle branch block', it: 'Blocco di branca' },
{ en: 'Cardiomyopathy', it: 'Cardiomiopatia' },
{ en: 'Heart failure', it: 'Scompenso' },
{ en: 'Valvular disease', it: 'Valvulopatia' },
];
const pill = (c, fill) =>
`<span class="pill${fill ? ' fill' : ''}"><span class="en">${c.en}</span>${c.it ? `<span class="it">${c.it}</span>` : ''}</span>`;
const POINTS = [
{ n: '01', b: 'Order encodes clinical precedence', d: '“Brugada” is matched before “TV”, so “substrato per TV” <span style="color:var(--bordeaux-deep)">("substrate for VT")</span> can\'t mask a Brugada pattern' },
{ n: '02', b: 'Synonyms live inline', d: 'FA / f.a. / fib. atriale / atrial fibrillation → one canonical label' },
{ n: '03', b: 'Versioned like software', d: 'semver for the pattern library, <code>pattern_version</code> on every extracted row' },
];
// ---- variant A: three columns of pills (user's idea) ----
function variantA() {
const col = (h, count, items, fill) => `
<div class="va-col">
<div class="col-h">${h}<span class="n">${count}</span></div>
<div class="stack">${items.map(c => pill(c, fill)).join('')}</div>
</div>`;
return `
<div class="va-grid">
${col('Tier 1 · arrhythmic — 1/2', '6 of 11', T1.slice(0, 6), true)}
${col('Tier 1 · arrhythmic — 2/2', '5 of 11', T1.slice(6), true)}
${col('Tier 2 · structural', '5 of 5', T2, false)}
</div>
<div class="va-points">${POINTS.map(p => `
<div class="pt"><span class="num">${p.n}</span><div><b>${p.b}</b> <span class="d">— ${p.d}</span></div></div>`).join('')}
</div>`;
}
// ---- variant B: editorial bands with big numerals ----
function variantB() {
const band = (num, name, count, items, fill) => `
<div class="vb-band">
<div class="vb-num"><b>${num}</b><span>${name} · ${count} categories</span></div>
<div class="vb-chips">${items.map(c => pill(c, fill)).join('')}</div>
</div>`;
return `
${band('01', 'Arrhythmic', 11, T1, true)}
${band('02', 'Structural', 5, T2, false)}
<div class="vb-points">${POINTS.map(p => `
<div class="pt"><span class="num">${p.n}</span><div><b>${p.b}</b> <span class="d">— ${p.d}</span></div></div>`).join('')}
</div>`;
}
// ---- variant C: ontology left, "why the order matters" right ----
function variantC() {
return `
<div class="vc-split">
<div>
<div class="vc-tier">
<div class="col-h">Tier 1 · arrhythmic<span class="n">11</span></div>
<div class="vc-chips">${T1.map(c => pill(c, true)).join('')}</div>
</div>
<div class="vc-tier" style="margin-bottom:0">
<div class="col-h">Tier 2 · structural<span class="n">5</span></div>
<div class="vc-chips">${T2.map(c => pill(c, false)).join('')}</div>
</div>
</div>
<div class="vc-why">
<div class="vc-why-h">Why one clinical order matters</div>
${POINTS.map(p => `
<div class="pt"><span class="num">${p.n}</span><div><b>${p.b}</b> <span class="d">— ${p.d}</span></div></div>`).join('')}
</div>
</div>`;
}
// ---- switcher ----
const VARIANTS = [
{ key: 'A', name: 'Three columns (5-6 per column)', render: variantA },
{ key: 'B', name: 'Editorial bands, big numerals', render: variantB },
{ key: 'C', name: 'Ontology + why-order panel', render: variantC },
];
function current() {
const k = (location.search.match(/variant=([ABC])/) || [])[1] || 'A';
return Math.max(0, VARIANTS.findIndex(v => v.key === k));
}
function show(i) {
const v = VARIANTS[i];
document.getElementById('sbody').innerHTML =
'<div class="vwrap"><div class="kicker">The clinical ontology</div><h2>Two tiers, one clinical order</h2>' + v.render() + '</div>';
document.getElementById('lbl').textContent = `${v.key} · ${v.name}`;
history.replaceState(null, '', location.pathname + '?variant=' + v.key);
}
document.getElementById('prev').onclick = () => show((current() + VARIANTS.length - 1) % VARIANTS.length);
document.getElementById('next').onclick = () => show((current() + 1) % VARIANTS.length);
addEventListener('keydown', e => {
if (e.key === 'ArrowLeft') document.getElementById('prev').click();
if (e.key === 'ArrowRight') document.getElementById('next').click();
});
show(current());
</script>
</body>
</html>