The howto called the CASE object the single source of truth. It was not. The rendered .md
was hand-written — 356 of its 500 lines were the shared glossary widget pasted in verbatim,
and it carried editorial prose (the balance, the closing) that the contract never modelled.
A generator run against the old contract would have DELETED that prose: the exact
work-in-the-generated-tree shape adr-070 names.
So the contract was extended first (balance / balance_outro / closing, additive — every
existing case validates unchanged), the prose was rescued into it, and only then was
gen-expediente.nu written. The glossary widget is now injected from its single source
instead of retyped. `just expedientes-check` asserts every .md body reproduces from its .ncl:
edit the source, never the render.
The generator dropped the hero and the "show full expediente" CTA on its first run — half an
hour after the ADR that forbids exactly that. It was caught only because the output was
diffed against the previous render instead of trusted because it printed a green tick. Both
are emitted from data now, and the check is why we know.
New case, clinical skin: 69/58 — "the mirror that reverted its own work". The tool reported
"index.json with 69 posts" while the disk held 58; eleven ADRs (059..069) were written and
never published; zero content reached production for four weeks; 214 lines of template work
sat one command from deletion with no witness anywhere. Every number in its ledger traces to
a log or an artifact, per the mode's own rule — none is recalled.
Its verdict is the one the series exists to ask and rarely gets: "with ontoref, would it not
have gone like this?" — and here the answer is NO. It happened INSIDE ontoref, with ADR-066
("the check decides, never the reporter") accepted a week earlier and proven by an eight-path
falsación run. The protocol did not fail. Difusión was the blind spot: the one surface the
protocol did not govern. Every mechanism that would have caught every one of these failures
already existed and was already accepted in this very repo. None of them was pointed here.
Also: adr-070's pages (the ADR projection now runs in the build chain).
317 lines
19 KiB
HTML
317 lines
19 KiB
HTML
<!doctype html>
|
||
<html lang="{{LANG}}"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
||
<title>{{TITLE}}</title>
|
||
<style>
|
||
/* ── PALETAS por skin × tema ─────────────────────────────────────────── */
|
||
:root, :root[data-skin="detective"]{
|
||
--paper:#F6F1E4; --paper-edge:#E4DAC2; --ink:#1C1810; --ink-faded:#5A5240;
|
||
--desk:#33302A; --stamp:#9C2D25; --accent:#8A6014; --rule:#CDBF9C; --code:#26231D;
|
||
}
|
||
:root[data-skin="detective"][data-theme="dark"]{
|
||
--paper:#D9CBA6; --paper-edge:#C7B78E; --ink:#231D14; --ink-faded:#574F3B;
|
||
--desk:#100E0A; --stamp:#CF4133; --accent:#C89338; --rule:#B6A67E; --code:#0A0805;
|
||
}
|
||
:root[data-skin="clinical"]{
|
||
--paper:#F5F9FA; --paper-edge:#DBE7EA; --ink:#132630; --ink-faded:#51666E;
|
||
--desk:#17282E; --stamp:#C0272B; --accent:#0C7A83; --rule:#D2E0E4; --code:#0C1A20;
|
||
}
|
||
:root[data-skin="clinical"][data-theme="dark"]{
|
||
--paper:#D7E4E7; --paper-edge:#BFD2D6; --ink:#0F2028; --ink-faded:#4A5F67;
|
||
--desk:#081217; --stamp:#E24A44; --accent:#2FA7B0; --rule:#A9C2C8; --code:#050D11;
|
||
}
|
||
|
||
*{box-sizing:border-box}
|
||
html{-webkit-text-size-adjust:100%}
|
||
body{margin:0; min-height:100vh;
|
||
background:radial-gradient(120% 80% at 82% -12%, color-mix(in srgb,var(--accent) 20%,transparent), transparent 60%), var(--desk);
|
||
color:var(--ink); font-family:Georgia,"Iowan Old Style","Times New Roman",serif; line-height:1.6;
|
||
padding:0 1rem 4rem; display:flex; flex-direction:column; align-items:center;
|
||
--mono:"Courier New",ui-monospace,"Cascadia Mono",monospace}
|
||
|
||
/* ── Barra de navegación del sitio (logo + volver) ───────────────────── */
|
||
.sitebar{width:100%; max-width:52rem; display:flex; align-items:center; justify-content:space-between;
|
||
gap:1rem; padding:.9rem .2rem; margin-bottom:.4rem}
|
||
.sitebar a{color:var(--paper); text-decoration:none; font-family:var(--mono); font-size:.76rem; letter-spacing:.04em}
|
||
.sitebar .brand{display:flex; align-items:center; gap:.55rem; font-weight:700}
|
||
.sitebar .brand img{height:24px; width:auto; display:block}
|
||
.sitebar .back{border:1px solid color-mix(in srgb,var(--paper) 45%,transparent); padding:.34rem .7rem; border-radius:.4rem}
|
||
.sitebar .back:hover{border-color:var(--paper); background:color-mix(in srgb,var(--paper) 12%,transparent)}
|
||
|
||
/* ── Conmutador de expedientes ───────────────────────────────────────── */
|
||
.switch{width:100%; max-width:52rem; display:flex; align-items:center; gap:.6rem; flex-wrap:wrap;
|
||
padding:.55rem .8rem; margin-bottom:.9rem; border-radius:.5rem; font-family:var(--mono);
|
||
background:color-mix(in srgb,var(--paper) 12%,transparent); color:var(--paper)}
|
||
.switch .idx{font-size:.72rem; letter-spacing:.1em; opacity:.85; white-space:nowrap}
|
||
.switch .tabs{display:flex; gap:.4rem; flex:1; flex-wrap:wrap}
|
||
.switch .tab{font-size:.72rem; letter-spacing:.03em; background:transparent; color:var(--paper);
|
||
border:1px solid color-mix(in srgb,var(--paper) 40%,transparent); padding:.3rem .6rem; border-radius:.35rem; cursor:pointer}
|
||
.switch .tab[aria-current="true"]{background:var(--paper); color:var(--desk); font-weight:700; border-color:var(--paper)}
|
||
.switch .nav{display:flex; gap:.35rem}
|
||
.switch .nav button{font-size:.72rem; background:transparent; color:var(--paper);
|
||
border:1px solid color-mix(in srgb,var(--paper) 40%,transparent); padding:.3rem .55rem; border-radius:.35rem; cursor:pointer}
|
||
.switch .nav button:disabled{opacity:.35; cursor:default}
|
||
|
||
.file{width:100%; max-width:52rem; background:var(--paper); border:1px solid var(--paper-edge);
|
||
box-shadow:0 1px 0 color-mix(in srgb,#fff 30%,transparent) inset, 0 24px 60px -20px rgba(0,0,0,.6);
|
||
padding:clamp(1.25rem,4.5vw,3rem); position:relative; overflow:hidden;
|
||
background-image:repeating-linear-gradient(0deg, transparent 0 27px, color-mix(in srgb,var(--rule) 20%,transparent) 27px 28px);
|
||
background-attachment:local}
|
||
.file::before{content:""; position:absolute; left:15px; top:0; bottom:0; width:14px;
|
||
background:radial-gradient(circle at 50% 60px,var(--desk) 5px,transparent 6px),
|
||
radial-gradient(circle at 50% 160px,var(--desk) 5px,transparent 6px),
|
||
radial-gradient(circle at 50% 260px,var(--desk) 5px,transparent 6px);
|
||
background-repeat:no-repeat; opacity:.45}
|
||
|
||
.mono{font-family:var(--mono)} a{color:var(--stamp)}
|
||
header{border-bottom:2px solid var(--ink); padding-bottom:1rem; margin-bottom:1.7rem}
|
||
.kicker{font-family:var(--mono); font-weight:700; font-size:.74rem; letter-spacing:.18em; text-transform:uppercase; color:var(--ink-faded)}
|
||
h1{font-family:var(--mono); font-weight:700; font-size:clamp(1.55rem,5.4vw,2.6rem); line-height:1.05;
|
||
margin:.4rem 0 .2rem; text-wrap:balance; letter-spacing:-.01em}
|
||
h1 .red{color:var(--stamp)}
|
||
.logline{font-style:italic; max-width:44ch; margin:.6rem 0 0}
|
||
.meta{display:flex; flex-wrap:wrap; gap:.4rem .5rem; margin-top:1.1rem; font-family:var(--mono); font-size:.68rem}
|
||
.tag{border:1px solid var(--ink); padding:.22rem .5rem; letter-spacing:.1em; text-transform:uppercase}
|
||
.tag b{color:var(--stamp)} .tag.closed{background:var(--ink); color:var(--paper)}
|
||
|
||
.glossary{border:1px dashed var(--ink); padding:.8rem 1rem; margin:1.5rem 0 0; background:color-mix(in srgb,var(--accent) 8%,var(--paper))}
|
||
.gl-title{font-family:var(--mono); font-weight:700; font-size:.66rem; letter-spacing:.14em; text-transform:uppercase; color:var(--ink-faded); margin-bottom:.5rem}
|
||
.glossary dl{margin:0; display:grid; grid-template-columns:max-content 1fr; gap:.35rem .9rem}
|
||
.glossary dt{font-family:var(--mono); font-weight:700; color:var(--stamp)}
|
||
.glossary dd{margin:0; font-size:.9rem}
|
||
.glossary .more{font-family:var(--mono); font-size:.72rem; margin-top:.55rem}
|
||
|
||
section{margin:2.1rem 0}
|
||
.exhibit{font-family:var(--mono); font-weight:700; font-size:.74rem; letter-spacing:.14em; text-transform:uppercase;
|
||
color:var(--stamp); display:flex; align-items:center; gap:.6rem; margin-bottom:.7rem}
|
||
.exhibit::after{content:""; flex:1; height:1px; background:var(--rule)}
|
||
h2{font-family:var(--mono); font-size:1.22rem; margin:.1rem 0 .6rem; letter-spacing:-.01em}
|
||
p{margin:.7rem 0}
|
||
|
||
.sheet{overflow-x:auto; border:1px solid var(--ink); background:color-mix(in srgb,var(--paper) 80%,#fff)}
|
||
table{width:100%; border-collapse:collapse; font-family:var(--mono); font-size:.82rem; min-width:30rem}
|
||
caption{font-family:var(--mono); font-weight:700; font-size:.68rem; letter-spacing:.13em; text-transform:uppercase; color:var(--ink-faded);
|
||
text-align:left; padding:.5rem .7rem; border-bottom:1px solid var(--rule)}
|
||
td{padding:.5rem .7rem; border-bottom:1px dashed var(--rule)}
|
||
td:last-child{text-align:right; font-variant-numeric:tabular-nums; font-weight:700; white-space:nowrap}
|
||
tr:last-child td{border-bottom:none}
|
||
tr.big td{background:color-mix(in srgb,var(--stamp) 10%,transparent)}
|
||
tr.big td:last-child{color:var(--stamp); font-size:1.05rem}
|
||
.unit{color:var(--ink-faded); font-weight:400}
|
||
|
||
.lineup{display:grid; grid-template-columns:repeat(auto-fill,minmax(13.5rem,1fr)); gap:.8rem; margin-top:1rem}
|
||
.card{border:1px solid var(--ink); background:color-mix(in srgb,var(--paper) 86%,#fff); padding:.7rem .8rem}
|
||
.card .no{font-family:var(--mono); font-size:.66rem; color:var(--ink-faded); letter-spacing:.14em; font-weight:700}
|
||
.card h3{font-family:var(--mono); font-size:.9rem; margin:.15rem 0 .35rem}
|
||
.card p{font-size:.86rem; margin:.2rem 0; font-style:italic}
|
||
.vtag{font-family:var(--mono); font-size:.62rem; letter-spacing:.12em; text-transform:uppercase; display:inline-block;
|
||
margin-top:.45rem; padding:.12rem .4rem; border:1px solid var(--stamp); color:var(--stamp)}
|
||
|
||
pre{font-family:var(--mono); font-size:.78rem; line-height:1.5; overflow-x:auto; background:var(--code); color:#E9DFC6;
|
||
border:1px solid #000; padding:.9rem 1rem; margin:.8rem 0; box-shadow:0 8px 20px -12px rgba(0,0,0,.7)}
|
||
pre .c{color:#8a8570} pre .k{color:var(--accent)} pre .r{color:var(--stamp); font-weight:700} pre .g{color:#89a05a}
|
||
.caplabel{font-family:var(--mono); font-weight:700; font-size:.66rem; letter-spacing:.12em; text-transform:uppercase; color:var(--ink-faded)}
|
||
|
||
.stamp{position:absolute; top:6.6rem; right:1.4rem; transform:rotate(-9deg); border:.32rem solid var(--stamp); color:var(--stamp);
|
||
font-family:var(--mono); font-weight:700; padding:.42rem 1rem; text-align:center; line-height:1.05; opacity:.96; border-radius:7px;
|
||
background:color-mix(in srgb,var(--paper) 78%,transparent); box-shadow:0 0 0 2px color-mix(in srgb,var(--stamp) 26%,transparent);
|
||
pointer-events:none; letter-spacing:.06em}
|
||
.stamp b{font-size:1.2rem; display:block; letter-spacing:.14em} .stamp span{font-size:.64rem; letter-spacing:.2em}
|
||
@media (max-width:34rem){.stamp{animation:none; top:auto; bottom:1rem; right:.8rem; transform:rotate(-8deg); padding:.32rem .7rem} .stamp b{font-size:1rem}}
|
||
|
||
.verdict{border:2px solid var(--ink); padding:1.1rem 1.2rem; background:color-mix(in srgb,var(--accent) 9%,var(--paper))}
|
||
.verdict h2{color:var(--stamp)}
|
||
.cont{width:100%; border-collapse:collapse; margin-top:.6rem; font-size:.92rem}
|
||
.cont td{padding:.5rem .6rem; border-bottom:1px solid var(--rule); vertical-align:top}
|
||
.cont td:first-child{width:52%; font-style:italic}
|
||
.cont td:last-child{font-family:var(--mono); font-size:.8rem}
|
||
.kicknum{font-family:var(--mono); color:var(--stamp); font-weight:700}
|
||
|
||
.filefoot{display:flex; align-items:center; justify-content:space-between; gap:1rem; flex-wrap:wrap; margin-top:1.4rem}
|
||
.printlink{font-family:var(--mono); font-size:.72rem; color:var(--stamp); text-decoration:none;
|
||
border:1px solid var(--stamp); padding:.34rem .7rem; border-radius:.4rem; background:transparent; cursor:pointer}
|
||
.printlink:hover{background:color-mix(in srgb,var(--stamp) 12%,transparent)}
|
||
.pager{display:flex; gap:.4rem; font-family:var(--mono)}
|
||
.pager button{font-size:.72rem; background:var(--paper); color:var(--ink); border:1px solid var(--ink);
|
||
padding:.34rem .6rem; border-radius:.4rem; cursor:pointer}
|
||
.pager button:disabled{opacity:.35; cursor:default}
|
||
|
||
footer{margin-top:2.1rem; border-top:1px solid var(--rule); padding-top:.9rem; font-family:var(--mono); font-size:.68rem;
|
||
color:var(--ink-faded); display:flex; justify-content:space-between; flex-wrap:wrap; gap:.5rem}
|
||
|
||
.controls{position:fixed; top:.7rem; right:.7rem; display:flex; gap:.35rem; z-index:20; font-family:var(--mono)}
|
||
.controls button{font-size:.66rem; letter-spacing:.06em; background:var(--paper); color:var(--ink); border:1px solid var(--ink);
|
||
padding:.35rem .55rem; cursor:pointer; border-radius:4px}
|
||
.controls button[aria-pressed="true"]{background:var(--ink); color:var(--paper)}
|
||
.controls button:focus-visible, a:focus-visible, .tab:focus-visible, .pager button:focus-visible{outline:2px solid var(--stamp); outline-offset:2px}
|
||
|
||
@keyframes thunk{0%{transform:rotate(-9deg) scale(2.4); opacity:0} 70%{transform:rotate(-9deg) scale(.94); opacity:1} 100%{transform:rotate(-9deg) scale(1); opacity:.96}}
|
||
.stamp{animation:thunk .5s cubic-bezier(.2,1.3,.4,1) .35s both}
|
||
@media (prefers-reduced-motion:reduce){.stamp{animation:none}}
|
||
|
||
/* Archival/print: hide site chrome, keep the file. */
|
||
@media print{
|
||
.sitebar,.switch,.controls,.filefoot{display:none!important}
|
||
body{background:#fff;padding:0;display:block}
|
||
.file{box-shadow:none;border:none;max-width:none}
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<div class="controls">
|
||
<button id="sk-det" aria-pressed="true"></button>
|
||
<button id="sk-cli" aria-pressed="false"></button>
|
||
<button id="tg"></button>
|
||
</div>
|
||
|
||
<nav class="sitebar" aria-label="ontoref">
|
||
<a class="brand" href="/"><img src="/images/ontoref-logo.svg" alt="ontoref"><span>ontoref</span></a>
|
||
<a class="back" id="sw-back" href="#"></a>
|
||
</nav>
|
||
|
||
<div class="switch" role="tablist" id="sw-bar">
|
||
<span class="idx" id="sw-idx"></span>
|
||
<div class="tabs" id="sw-tabs"></div>
|
||
<div class="nav">
|
||
<button id="sw-prev">‹</button>
|
||
<button id="sw-next">›</button>
|
||
</div>
|
||
</div>
|
||
|
||
<article class="file" id="file"></article>
|
||
|
||
<script>
|
||
(function(){
|
||
"use strict";
|
||
|
||
/* ══ DATA ══ Projected by scripts/build/gen-informe.nu from the typed CASEs under
|
||
site/content/expedientes. DO NOT EDIT THIS FILE — edit the .ncl.
|
||
This viewer was hand-kept for two cases and drifted from the articles it shares a
|
||
source with (deriva's ledger: 6 rows there, 8 here). */
|
||
|
||
{{DATA}}
|
||
|
||
/* ══ RENDER ══ */
|
||
var skinKey = "detective";
|
||
var idx = 0;
|
||
|
||
function render(){
|
||
var c = CASES[idx], s = c.skins[skinKey] || c.skins[c.skin];
|
||
document.documentElement.setAttribute("data-skin", skinKey);
|
||
document.title = UI.doc_title.replace("{case_no}", c.caseNo);
|
||
// A case may legitimately have one skin. Better a dead button, plainly dead, than
|
||
// prose invented to fill the other genre.
|
||
var det = document.getElementById("sk-det"), cli = document.getElementById("sk-cli");
|
||
det.setAttribute("aria-pressed", skinKey==="detective");
|
||
cli.setAttribute("aria-pressed", skinKey==="clinical");
|
||
det.disabled = !c.skins.detective; det.title = c.skins.detective ? "" : UI.skin_missing;
|
||
cli.disabled = !c.skins.clinical; cli.title = c.skins.clinical ? "" : UI.skin_missing;
|
||
|
||
// Switcher chrome
|
||
document.getElementById("sw-idx").textContent = UI.counter + " " + (idx+1) + "/" + CASES.length;
|
||
document.getElementById("sw-prev").disabled = (idx===0);
|
||
document.getElementById("sw-next").disabled = (idx===CASES.length-1);
|
||
document.getElementById("sw-tabs").innerHTML = CASES.map(function(x,i){
|
||
return "<button class='tab' role='tab' data-go='"+i+"' aria-current='"+(i===idx)+"'>"+x.tab+"</button>";
|
||
}).join("");
|
||
|
||
var cost = c.cost.map(function(r){
|
||
return "<tr"+(r[2]?" class='big'":"")+"><td>"+r[0]+"</td><td>"+r[1]
|
||
.replace("<i>","<span class='unit'>").replace("</i>","</span>")+"</td></tr>";
|
||
}).join("");
|
||
var susp = c.suspectsTech.map(function(h,i){
|
||
var n=(i+1<10?"0":"")+(i+1);
|
||
return "<div class='card'><div class='no'>"+s.no.toUpperCase()+" "+n+"</div><h3>"+h+
|
||
"</h3><p>"+s.alibis[i]+"</p><span class='vtag'>"+s.tags[i]+"</span></div>";
|
||
}).join("");
|
||
var gloss = c.glossary.map(function(g){return "<dt>"+g.t+"</dt><dd>"+g.d+"</dd>";}).join("");
|
||
var cont = c.contain.map(function(r){return "<tr><td>"+r[0]+"</td><td>"+r[1]+"</td></tr>";}).join("");
|
||
var yieldTbl = "";
|
||
if(c.yielded && c.yielded.length){
|
||
var yrows = c.yielded.map(function(r){
|
||
return "<tr"+(r[2]?" class='big'":"")+"><td>"+r[0]+"</td><td>"+r[1]
|
||
.replace("<i>","<span class='unit'>").replace("</i>","</span>")+"</td></tr>";
|
||
}).join("");
|
||
yieldTbl = "<div class='sheet'><table><caption>"+c.yieldedTitle+"</caption><tbody>"+yrows+"</tbody></table></div>";
|
||
}
|
||
|
||
document.getElementById("file").innerHTML =
|
||
"<div class='stamp' aria-hidden='true'><b>"+s.stamp[0]+"</b><span>"+s.stamp[1]+"</span></div>"+
|
||
"<header><div class='kicker'>"+s.kicker+"</div>"+
|
||
"<h1>"+s.h1[0]+"<span class='red'>"+s.h1[1]+"</span></h1>"+
|
||
"<p class='logline'>"+s.logline+"</p>"+
|
||
"<div class='meta'>"+
|
||
"<span class='tag'>"+s.meta[0]+" <b>"+c.caseNo+"</b></span>"+
|
||
"<span class='tag'>"+s.meta[1]+": <b>"+c.classification+"</b></span>"+
|
||
"<span class='tag'>"+s.meta[2]+"</span>"+
|
||
"<span class='tag closed'>"+s.meta[3]+"</span></div>"+
|
||
"<aside class='glossary'><div class='gl-title'>"+UI.gloss_title+"</div>"+
|
||
"<dl>"+gloss+"</dl><div class='more'>"+c.glossaryMore+"</div></aside>"+
|
||
"</header>"+
|
||
"<section><div class='exhibit'>"+s.ex[0]+"</div><h2>"+s.h2[0]+"</h2><p>"+s.lead2+"</p>"+
|
||
"<div class='sheet'><table><caption>"+c.costCaption+"</caption><tbody>"+cost+"</tbody></table></div>"+yieldTbl+"</section>"+
|
||
"<section><div class='exhibit'>"+s.ex[1]+"</div><h2>"+s.h2[1]+"</h2><p>"+s.lead3+"</p>"+
|
||
"<div class='lineup'>"+susp+"</div></section>"+
|
||
"<section><div class='exhibit'>"+s.ex[2]+"</div><h2>"+s.h2[2]+"</h2>"+
|
||
"<span class='caplabel'>"+s.weaponCap+"</span><pre>"+c.weaponCode+"</pre><p>"+s.weaponAfter+"</p></section>"+
|
||
"<section><div class='exhibit'>"+s.ex[3]+"</div><h2>"+s.h2[3]+"</h2>"+
|
||
"<span class='caplabel'>"+s.fixCap+"</span><pre>"+c.fixCode+"</pre><p>"+s.fixAfter+"</p></section>"+
|
||
"<section class='verdict'><div class='exhibit'>"+s.ex[4]+"</div><h2>"+s.h2[4]+"</h2>"+
|
||
"<p>"+s.verdictLead+"</p><table class='cont'><tbody>"+cont+"</tbody></table>"+
|
||
"<p style='margin-bottom:0'>"+c.verdictClose+"</p></section>"+
|
||
"<div class='filefoot'>"+
|
||
"<button type='button' class='printlink' data-print>"+UI.print+"</button>"+
|
||
"<div class='pager'>"+
|
||
"<button data-step='-1'"+(idx===0?" disabled":"")+">"+UI.pager_prev+"</button>"+
|
||
"<button data-step='1'"+(idx===CASES.length-1?" disabled":"")+">"+UI.pager_next+"</button>"+
|
||
"</div></div>"+
|
||
"<footer><span>"+s.footL+"</span><span>"+s.footR+"</span></footer>";
|
||
}
|
||
|
||
function goto(i){
|
||
if(i<0||i>=CASES.length) return;
|
||
idx=i;
|
||
var id=CASES[idx].id;
|
||
if(location.hash.slice(1)!==id) history.replaceState(null,"","#"+id);
|
||
render();
|
||
}
|
||
|
||
var root=document.documentElement;
|
||
root.setAttribute("data-theme", matchMedia("(prefers-color-scheme:dark)").matches?"dark":"light");
|
||
document.getElementById("sk-det").textContent = UI.skin_detective;
|
||
document.getElementById("sk-cli").textContent = UI.skin_clinical;
|
||
document.getElementById("tg").setAttribute("aria-label", UI.theme);
|
||
document.getElementById("tg").textContent = "☀ / ☾";
|
||
var back = document.getElementById("sw-back");
|
||
back.textContent = UI.back; back.setAttribute("href", UI.back_href);
|
||
document.getElementById("sw-bar").setAttribute("aria-label", UI.switch_label);
|
||
document.getElementById("sw-prev").setAttribute("aria-label", UI.prev_label);
|
||
document.getElementById("sw-next").setAttribute("aria-label", UI.next_label);
|
||
document.getElementById("sk-det").onclick=function(){skinKey="detective";render();};
|
||
document.getElementById("sk-cli").onclick=function(){skinKey="clinical";render();};
|
||
document.getElementById("tg").onclick=function(){
|
||
root.setAttribute("data-theme", root.getAttribute("data-theme")==="dark"?"light":"dark");
|
||
};
|
||
document.getElementById("sw-prev").onclick=function(){goto(idx-1);};
|
||
document.getElementById("sw-next").onclick=function(){goto(idx+1);};
|
||
// Delegated: tab clicks + pager buttons inside #file.
|
||
document.addEventListener("click",function(ev){
|
||
var t=ev.target.closest && ev.target.closest("[data-go],[data-step],[data-print]");
|
||
if(!t) return;
|
||
if(t.hasAttribute("data-print")){ window.print(); return; }
|
||
if(t.hasAttribute("data-go")) goto(parseInt(t.getAttribute("data-go"),10));
|
||
else goto(idx+parseInt(t.getAttribute("data-step"),10));
|
||
});
|
||
window.addEventListener("hashchange",function(){
|
||
var i=CASES.findIndex(function(x){return x.id===location.hash.slice(1);});
|
||
if(i>=0 && i!==idx) goto(i);
|
||
});
|
||
|
||
// Open on the deep-linked case if the hash names one.
|
||
var start=CASES.findIndex(function(x){return x.id===location.hash.slice(1);});
|
||
idx = start>=0 ? start : 0;
|
||
render();
|
||
})();
|
||
</script>
|
||
|
||
</body></html>
|