My Mexica Aztec Calendar

By: Mr. Philip S. Wathen Jr.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Mexica 365-Day Calendar</title>
<style>
:root{
--bg:#0e0d0c; --panel:#1a1817; --line:#332f2c;
--ink:#e8e2d9; --dim:#8d857c; --acc:#c8553d; --gold:#d4a24c;
}
*{box-sizing:border-box}
body{margin:0;padding:24px;background:var(--bg);color:var(--ink);
font:14px/1.5 ui-monospace,SFMono-Regular,Menlo,monospace}
h1{font-size:20px;margin:0 0 4px;letter-spacing:.06em;font-weight:600}
.sub{color:var(--dim);font-size:12px;margin-bottom:24px}
.today{background:var(--panel);border:1px solid var(--line);border-left:3px solid var(--acc);
padding:18px 20px;margin-bottom:24px}
.today .big{font-size:26px;color:var(--gold);letter-spacing:.02em}
.today .row{color:var(--dim);font-size:12px;margin-top:8px}
.controls{display:flex;gap:12px;flex-wrap:wrap;align-items:center;margin-bottom:20px}
input[type=date]{background:var(--panel);border:1px solid var(--line);color:var(--ink);
padding:6px 10px;font:inherit;border-radius:3px}
button{background:var(--panel);border:1px solid var(--line);color:var(--ink);
padding:6px 14px;font:inherit;border-radius:3px;cursor:pointer}
button:hover{border-color:var(--acc)}
.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:8px}
.v{background:var(--panel);border:1px solid var(--line);padding:10px 12px;border-radius:3px}
.v.current{border-color:var(--gold);box-shadow:0 0 0 1px var(--gold) inset}
.v .nm{font-size:12px;color:var(--gold);letter-spacing:.03em}
.v .pos{font-size:10px;color:var(--dim)}
.v .days{display:flex;flex-wrap:wrap;gap:2px;margin-top:8px}
.d{width:16px;height:16px;font-size:9px;display:flex;align-items:center;
justify-content:center;background:#221f1d;color:var(--dim);border-radius:2px}
.d.ev{background:var(--acc);color:#fff;font-weight:700}
.d.today{background:var(--gold);color:#000;font-weight:700}
.nem{grid-column:1/-1;border-style:dashed}
.evlist{margin-top:24px;background:var(--panel);border:1px solid var(--line);padding:16px 20px}
.evlist h2{font-size:13px;color:var(--gold);margin:0 0 10px;letter-spacing:.05em}
.evlist div{font-size:12px;color:var(--dim);padding:3px 0;border-bottom:1px solid #262322}
.evlist div span{color:var(--ink)}
footer{margin-top:32px;color:var(--dim);font-size:11px;line-height:1.7}
</style>
</head>
<body>
<h1>MEXICA 365-DAY CALENDAR</h1>
<div class="sub">18 veintenas × 20 days + 5 Nemontemi · structural layer</div>
<div class="today">
<div class="big" id="todayName">—</div>
<div class="row" id="todayDetail">—</div>
</div>
<div class="controls">
<input type="date" id="picker">
<button onclick="setToday()">Today</button>
</div>
<div class="grid" id="grid"></div>
<div class="evlist">
<h2>RITUAL EVENTS — CURRENT YEAR</h2>
<div id="events">—</div>
</div>
<footer>
Epoch A₀ = 13 Feb 1519 Julian (JDN 2275916) = Atlcahualo day 1.<br>
365-day recurrence. No leap day encoded. Intercalation is a separate hypothesis.<br>
Blank day slots indicate no secure ordinalized event — not absence of ritual.
</footer>
<script>
const EPOCH = 2275916; // 13 Feb 1519 Julian = Atlcahualo day 1
const VEINTENAS = [
[1,"Atlcahualo","Cuauhtlehua, Xilomanaliztli"],
[2,"Tlacaxipehualiztli",""],
[3,"Tozoztontli","Tozoztli"],
[4,"Huey Tozoztli","Hueytozoztli"],
[5,"Tóxcatl","Tepopochhuiliztli"],
[6,"Etzalcualiztli",""],
[7,"Tecuilhuitontli","Tecuilhuitl, Tecuilhuitzintli"],
[8,"Huey Tecuilhuitl",""],
[9,"Tlaxochimaco","Miccailhuitl, Miccailhuitontli"],
[10,"Xócotl Huetzi","Huey Miccailhuitl"],
[11,"Ochpaniztli",""],
[12,"Teotleco","Pachtli, Pachtontli"],
[13,"Tepeilhuitl","Huey Pachtli"],
[14,"Quecholli",""],
[15,"Panquetzaliztli",""],
[16,"Atemoztli",""],
[17,"Tititl",""],
[18,"Izcalli",""]
];
const EVENTS = {
1:{}, 2:{20:"Principal concluding ceremony"},
3:{1:"Tlaloc festival"}, 4:{1:"Cinteotl / maize festival"},
5:{}, 6:{4:"Fasting complex — 4th day"},
7:{}, 8:{1:"Xilonen festival",10:"Xilonen impersonator sacrifice"},
9:{1:"Huitzilopochtli / flower festival"},
10:{1:"Xiuhtecuhtli / xocotl ceremony"},
11:{1:"Toci / Teteoinnan festival"},
12:{16:"Teotleco interval begins",17:"Teotleco interval",
18:"Teotleco interval",19:"Teotleco interval",20:"Teotleco interval ends"},
13:{}, 14:{10:"Zacatepec journey",11:"Hunt"},
15:{2:"Songs and dances begin",9:"Victims prepared",
16:"Slave owners fast",19:"Serpent dance"},
16:{4:"Nexpixolo — closes Panquetzaliztli sequence"},
17:{}, 18:{10:"New Fire, midnight"},
N:{1:"Nemontemi",2:"Nemontemi",3:"Nemontemi",4:"Nemontemi",5:"Nemontemi"}
};
function toJDN(y,m,d){
const a = Math.floor((14-m)/12), yy = y+4800-a, mm = m+12*a-3;
return d + Math.floor((153*mm+2)/5) + 365*yy
+ Math.floor(yy/4) - Math.floor(yy/100) + Math.floor(yy/400) - 32045;
}
function convert(y,m,d){
const jdn = toJDN(y,m,d);
const since = jdn - EPOCH;
const n = ((since % 365) + 365) % 365;
const year = Math.floor(since/365) + 1;
if(n < 360){
const pos = Math.floor(n/20) + 1;
return {pos, day:(n%20)+1, year, n};
}
return {pos:"N", day:n-359, year, n};
}
function name(pos){
if(pos==="N") return "Nemontemi";
return VEINTENAS[pos-1][1];
}
let current = null;
function render(){
const grid = document.getElementById("grid");
grid.innerHTML = "";
for(let p=1;p<=18;p++){
const el = document.createElement("div");
el.className = "v" + (current.pos===p ? " current":"");
let days = "";
for(let d=1;d<=20;d++){
const isToday = (current.pos===p && current.day===d);
const isEv = EVENTS[p] && EVENTS[p][d];
days += `<div class="d${isEv?" ev":""}${isToday?" today":""}">${d}</div>`;
}
el.innerHTML = `<div class="pos">POSITION ${p}</div>
<div class="nm">${VEINTENAS[p-1][1]}</div>
<div class="days">${days}</div>`;
grid.appendChild(el);
}
const nem = document.createElement("div");
nem.className = "v nem" + (current.pos==="N" ? " current":"");
let nd = "";
for(let d=1;d<=5;d++){
const isToday = (current.pos==="N" && current.day===d);
nd += `<div class="d ev${isToday?" today":""}">${d}</div>`;
}
nem.innerHTML = `<div class="pos">TERMINAL</div><div class="nm">Nemontemi</div>
<div class="days">${nd}</div>`;
grid.appendChild(nem);
const box = document.getElementById("events");
let html = "";
const list = EVENTS[current.pos] || {};
const keys = Object.keys(list).map(Number).sort((a,b)=>a-b);
if(!keys.length){
html = `<div>No secure ordinalized event for this veintena <span>(month-level evidence only)</span></div>`;
} else {
keys.forEach(d=>{
html += `<div>${name(current.pos)} day ${d} — <span>${list[d]}</span></div>`;
});
}
box.innerHTML = html;
}
function show(y,m,d){
current = convert(y,m,d);
document.getElementById("todayName").textContent =
name(current.pos) + " day " + current.day;
const jdn = toJDN(y,m,d);
document.getElementById("todayDetail").textContent =
`${y}-${String(m).padStart(2,"0")}-${String(d).padStart(2,"0")} · JDN ${jdn} · `
+ `day ${current.n} of year · year ${current.year} of the count`;
render();
}
function setToday(){
const t = new Date();
show(t.getFullYear(), t.getMonth()+1, t.getDate());
document.getElementById("picker").value =
`${t.getFullYear()}-${String(t.getMonth()+1).padStart(2,"0")}-${String(t.getDate()).padStart(2,"0")}`;
}
document.getElementById("picker").addEventListener("change", e=>{
const [y,m,d] = e.target.value.split("-").map(Number);
if(y) show(y,m,d);
});
setToday();
</script>
</body>
</html>


Comments