feat(@projects/@magic-civilization): add main menu and tech tree UI sketches

Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
Natalie 2026-04-26 15:16:43 -07:00
parent 2e6b0fdefe
commit 151b0d4360
2 changed files with 889 additions and 0 deletions

View file

@ -0,0 +1,344 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Age of Dwarves — Main Menu Sketch</title>
<link href="https://fonts.googleapis.com/css2?family=Grenze+Gotisch:wght@400;700;900&family=Bitter:wght@400;700&display=swap" rel="stylesheet">
<style>
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
background: #0e0a17;
font-family: 'Bitter', serif;
height: 100vh;
overflow: hidden;
display: flex;
}
/* ── ATMOSPHERIC BACKGROUND ── */
.bg {
position: fixed; inset: 0;
background:
radial-gradient(ellipse 80% 60% at 50% 100%, #1a0e0633 0%, transparent 70%),
radial-gradient(ellipse 60% 40% at 20% 50%, #0d1a0a22 0%, transparent 60%),
radial-gradient(ellipse 40% 60% at 80% 30%, #0a0d1a22 0%, transparent 60%),
linear-gradient(180deg, #0e0a17 0%, #1a1008 60%, #0a0608 100%);
}
/* Mountain silhouette */
.mountains {
position: fixed;
bottom: 0; left: 0; right: 0;
height: 55vh;
z-index: 0;
}
/* Stars */
.stars {
position: fixed; inset: 0; z-index: 0;
background-image:
radial-gradient(1px 1px at 10% 15%, #ffffff44, transparent),
radial-gradient(1px 1px at 25% 8%, #ffffff33, transparent),
radial-gradient(1px 1px at 40% 20%, #ffffff55, transparent),
radial-gradient(1px 1px at 55% 5%, #ffffff33, transparent),
radial-gradient(1px 1px at 70% 12%, #ffffff44, transparent),
radial-gradient(1px 1px at 85% 18%, #ffffff22, transparent),
radial-gradient(1px 1px at 15% 28%, #ffffff33, transparent),
radial-gradient(1px 1px at 32% 35%, #ffffff22, transparent),
radial-gradient(1px 1px at 48% 30%, #ffffff44, transparent),
radial-gradient(1px 1px at 62% 25%, #ffffff33, transparent),
radial-gradient(1px 1px at 78% 32%, #ffffff22, transparent),
radial-gradient(1px 1px at 90% 22%, #ffffff33, transparent),
radial-gradient(1.5px 1.5px at 5% 40%, #f2d97366, transparent),
radial-gradient(1.5px 1.5px at 92% 15%, #f2d97344, transparent),
radial-gradient(1px 1px at 20% 45%, #ffffff22, transparent),
radial-gradient(1px 1px at 50% 38%, #ffffff33, transparent),
radial-gradient(1px 1px at 75% 42%, #ffffff22, transparent);
}
/* ── LAYOUT ── */
.sidebar {
position: relative;
z-index: 10;
width: 380px;
flex-shrink: 0;
display: flex;
flex-direction: column;
padding: 0 0 40px 0;
background: linear-gradient(90deg, rgba(14,10,23,0.98) 0%, rgba(14,10,23,0.85) 80%, transparent 100%);
}
.logo-area {
padding: 56px 48px 40px;
border-bottom: 1px solid #73591f44;
}
.game-series {
font-size: 11px;
color: #d9a020;
text-transform: uppercase;
letter-spacing: 0.18em;
margin-bottom: 12px;
}
.game-title {
font-family: 'Grenze Gotisch', serif;
font-size: 44px;
font-weight: 900;
color: #f2d973;
line-height: 0.95;
letter-spacing: 0.02em;
text-shadow: 0 0 40px #d9a02044, 0 2px 8px #000;
margin-bottom: 10px;
}
.game-episode {
font-size: 13px;
color: #bfb7a6;
letter-spacing: 0.06em;
}
.episode-badge {
display: inline-block;
background: #2a1a06;
border: 1px solid #d9a020;
border-radius: 2px;
padding: 2px 8px;
font-size: 11px;
color: #d9a020;
margin-bottom: 6px;
letter-spacing: 0.06em;
}
/* ── MENU ITEMS ── */
.menu-list {
padding: 32px 0 0;
flex: 1;
}
.menu-item {
display: flex;
align-items: center;
gap: 16px;
padding: 14px 48px;
cursor: pointer;
color: #e0d199;
font-size: 18px;
font-family: 'Grenze Gotisch', serif;
font-weight: 700;
letter-spacing: 0.06em;
border-left: 3px solid transparent;
transition: all 150ms ease;
position: relative;
}
.menu-item:hover, .menu-item.active {
color: #ffeb80;
border-left-color: #d9b33f;
background: linear-gradient(90deg, #d9a02011 0%, transparent 70%);
}
.menu-item.active {
color: #f2d973;
border-left-color: #ffd14d;
}
.menu-icon {
font-size: 20px;
width: 28px;
text-align: center;
flex-shrink: 0;
}
.menu-item.danger { color: #d95940aa; }
.menu-item.danger:hover { color: #d95940; border-left-color: #d95940; background: linear-gradient(90deg, #d9594011 0%, transparent 70%); }
.menu-divider {
border: none;
border-top: 1px solid #73591f33;
margin: 8px 48px;
}
/* ── BOTTOM STATUS ── */
.sidebar-footer {
padding: 20px 48px 0;
border-top: 1px solid #73591f44;
}
.version-line {
font-size: 11px;
color: #7a6048;
font-family: monospace;
margin-bottom: 6px;
}
.last-save {
font-size: 12px;
color: #bfb7a6;
}
.last-save span { color: #d9a020; }
/* ── RIGHT PANEL: SCENE ART ── */
.art-panel {
flex: 1;
position: relative;
z-index: 5;
display: flex;
align-items: flex-end;
justify-content: center;
padding-bottom: 40px;
}
/* Clan showcase */
.clan-showcase {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -55%);
text-align: center;
}
.clan-emblem {
width: 120px;
height: 120px;
border-radius: 50%;
border: 3px solid #d9a020;
background: radial-gradient(ellipse at 40% 40%, #2a1a06, #0e0a17);
display: flex;
align-items: center;
justify-content: center;
font-size: 52px;
margin: 0 auto 16px;
box-shadow: 0 0 40px #d9a02033, inset 0 0 30px #d9a02011;
}
.clan-name {
font-family: 'Grenze Gotisch', serif;
font-size: 28px;
font-weight: 900;
color: #f2d973;
letter-spacing: 0.05em;
text-shadow: 0 0 20px #d9a02044;
}
.clan-subtitle {
font-size: 13px;
color: #bfb7a6;
letter-spacing: 0.08em;
text-transform: uppercase;
margin-top: 4px;
}
/* Mountain SVG */
.mountain-svg {
position: fixed;
bottom: 0; left: 0; right: 0;
z-index: 2;
pointer-events: none;
}
/* News ticker at bottom */
.news-strip {
position: fixed;
bottom: 0; left: 380px; right: 0;
background: rgba(14,10,23,0.92);
border-top: 1px solid #73591f66;
padding: 8px 24px;
font-size: 12px;
color: #b2b2b2;
z-index: 10;
display: flex;
gap: 8px;
align-items: center;
}
.news-label {
color: #d9a020;
text-transform: uppercase;
font-size: 10px;
letter-spacing: 0.1em;
flex-shrink: 0;
border: 1px solid #d9a02066;
padding: 2px 6px;
border-radius: 2px;
}
/* Ambience */
.ambient-glow {
position: fixed;
width: 300px; height: 300px;
border-radius: 50%;
pointer-events: none;
z-index: 1;
}
</style>
</head>
<body>
<div class="bg"></div>
<div class="stars"></div>
<!-- Ambient glows -->
<div class="ambient-glow" style="background:radial-gradient(ellipse,#d9a02014,transparent);top:20%;right:20%"></div>
<div class="ambient-glow" style="background:radial-gradient(ellipse,#1a330a0e,transparent);bottom:20%;right:35%;width:400px;height:400px"></div>
<!-- Mountain silhouette SVG -->
<svg class="mountain-svg" viewBox="0 0 1440 400" preserveAspectRatio="none" height="400">
<defs>
<linearGradient id="mtngrad" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stop-color="#1a1208" stop-opacity="0.95"/>
<stop offset="100%" stop-color="#0a0608" stop-opacity="1"/>
</linearGradient>
</defs>
<!-- Far mountains -->
<path d="M0,400 L0,280 L80,200 L160,240 L260,150 L360,210 L440,130 L520,180 L600,100 L680,160 L760,80 L840,140 L920,90 L1000,150 L1080,110 L1160,170 L1240,130 L1320,190 L1400,160 L1440,200 L1440,400 Z" fill="#1a1810" opacity="0.6"/>
<!-- Mid mountains -->
<path d="M0,400 L0,320 L100,250 L200,290 L320,220 L420,270 L540,200 L640,250 L720,180 L820,240 L940,190 L1040,250 L1140,210 L1240,270 L1340,240 L1440,280 L1440,400 Z" fill="#131008" opacity="0.8"/>
<!-- Near mountains -->
<path d="M0,400 L0,360 L120,300 L240,350 L380,280 L500,340 L640,290 L760,360 L900,300 L1040,360 L1180,310 L1300,360 L1440,330 L1440,400 Z" fill="#0d0b06" opacity="1"/>
</svg>
<!-- ══ SIDEBAR ══ -->
<div class="sidebar">
<div class="logo-area">
<div class="game-series">Magic Civilization · Episode I</div>
<div class="episode-badge">Early Access</div>
<div class="game-title">Age of<br>Dwarves</div>
<div class="game-episode">The Dwarven Clans war for dominion over Khazad Prime</div>
</div>
<div class="menu-list">
<div class="menu-item active"><span class="menu-icon"></span> Continue</div>
<div class="menu-item"><span class="menu-icon"></span> New Game</div>
<div class="menu-item"><span class="menu-icon">📂</span> Load Game</div>
<hr class="menu-divider">
<div class="menu-item"><span class="menu-icon"></span> Settings</div>
<div class="menu-item"><span class="menu-icon">📖</span> How to Play</div>
<div class="menu-item"><span class="menu-icon">🏆</span> Achievements</div>
<hr class="menu-divider">
<div class="menu-item"><span class="menu-icon"></span> Credits</div>
<div class="menu-item danger"><span class="menu-icon"></span> Quit</div>
</div>
<div class="sidebar-footer">
<div class="version-line">v0.8.4 · build ecfaeeaf · Iron Age</div>
<div class="last-save">Last save: <span>Turn 42 · Ironhold</span></div>
</div>
</div>
<!-- ══ ART PANEL ══ -->
<div class="art-panel">
<div class="clan-showcase">
<div class="clan-emblem"></div>
<div class="clan-name">Stoneguard Clan</div>
<div class="clan-subtitle">Masters of Stone and Iron</div>
</div>
</div>
<!-- ══ NEWS STRIP ══ -->
<div class="news-strip">
<span class="news-label">Tip</span>
<span>Mountain tiles yield +2 Production when improved with a Mine. Prioritise hills near your capital early.</span>
</div>
</body>
</html>

View file

@ -0,0 +1,545 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Age of Dwarves — Tech Tree Sketch</title>
<link href="https://fonts.googleapis.com/css2?family=Grenze+Gotisch:wght@900&family=Bitter:wght@700&display=swap" rel="stylesheet">
<style>
:root {
--bg: #0e0a17;
--panel: #17121e;
--surface: #221a14;
--btn: #1f1733;
--title: #f2d973;
--primary: #e0d8c8;
--secondary: #bfb7a6;
--muted: #b2b2b2;
--gold: #d9a020;
--gold-b: #d9b33f;
--science: #66bfff;
--sage: #66b866;
--neg: #d95940;
--border: #73591fcc;
--font-h: 'Grenze Gotisch', serif;
--font-b: 'Bitter', serif;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
background: var(--bg);
color: var(--primary);
font-family: var(--font-b);
height: 100vh;
display: flex;
flex-direction: column;
overflow: hidden;
}
/* ── HEADER ── */
.header {
background: var(--panel);
border-bottom: 1px solid var(--border);
padding: 12px 24px;
display: flex;
align-items: center;
gap: 24px;
flex-shrink: 0;
}
.header-title {
font-family: var(--font-h);
font-size: 22px;
color: var(--title);
letter-spacing: 0.04em;
}
.sci-rate {
display: flex;
align-items: center;
gap: 6px;
font-size: 13px;
color: var(--science);
background: #0d1a2a;
border: 1px solid #66bfff44;
border-radius: 3px;
padding: 5px 12px;
}
.current-research {
display: flex;
align-items: center;
gap: 8px;
font-size: 13px;
color: var(--secondary);
margin-left: auto;
}
.research-name { color: var(--science); font-weight: bold; }
.research-turns { color: var(--gold); font-size: 12px; }
.close-btn {
width: 32px; height: 32px;
background: var(--btn);
border: 1px solid var(--border);
border-radius: 3px;
display: flex; align-items: center; justify-content: center;
color: var(--muted); cursor: pointer; font-size: 16px;
}
/* ── PILLAR LABELS ── */
.pillar-bar {
background: rgba(23,18,30,0.9);
border-bottom: 1px solid #73591f33;
display: flex;
flex-shrink: 0;
padding: 0 20px;
}
.pillar-label {
flex: 1;
text-align: center;
padding: 7px 4px;
font-size: 11px;
color: var(--muted);
text-transform: uppercase;
letter-spacing: 0.08em;
border-right: 1px solid #73591f22;
}
.pillar-label:last-child { border-right: none; }
.pillar-label.active { color: var(--gold); }
/* ── TREE CANVAS ── */
.tree-scroll {
flex: 1;
overflow: auto;
position: relative;
}
.tree-canvas {
position: relative;
width: 1400px;
min-height: 100%;
padding: 24px 20px;
}
/* SVG connections layer */
.connections-svg {
position: absolute;
top: 0; left: 0;
width: 100%; height: 100%;
pointer-events: none;
z-index: 0;
}
/* ── TECH NODES ── */
.tech-node {
position: absolute;
width: 130px;
border-radius: 4px;
border: 1px solid var(--border);
background: var(--panel);
cursor: pointer;
z-index: 1;
transition: all 150ms ease;
}
.tech-node:hover { border-color: var(--gold-b); transform: translateY(-2px); box-shadow: 0 4px 16px #000a; }
.tech-node.researched {
background: #1a1408;
border-color: var(--gold);
}
.tech-node.researched .node-header { background: #2a1a06; }
.tech-node.in-progress {
border-color: var(--science);
box-shadow: 0 0 12px #66bfff22;
}
.tech-node.in-progress .node-header { background: #0a1a2a; }
.tech-node.available {
border-color: #73591f99;
}
.tech-node.locked {
opacity: 0.45;
filter: grayscale(0.5);
}
.node-header {
padding: 7px 9px 5px;
border-bottom: 1px solid #73591f33;
display: flex;
align-items: center;
gap: 7px;
}
.node-icon { font-size: 18px; }
.node-name {
font-size: 12px;
font-weight: bold;
color: var(--primary);
line-height: 1.2;
}
.tech-node.researched .node-name { color: var(--gold); }
.tech-node.in-progress .node-name { color: var(--science); }
.node-body { padding: 6px 9px 8px; }
.node-cost {
font-size: 11px;
color: var(--science);
font-family: monospace;
margin-bottom: 4px;
}
.tech-node.researched .node-cost { color: var(--sage); }
.node-unlocks {
font-size: 10px;
color: var(--muted);
line-height: 1.4;
}
/* Progress bar for in-progress */
.node-progress-track {
height: 3px;
background: #ffffff18;
border-radius: 1px;
overflow: hidden;
margin-top: 5px;
}
.node-progress-fill {
height: 100%;
background: var(--science);
border-radius: 1px;
}
/* Era dividers */
.era-band {
position: absolute;
left: 0; right: 0;
border-top: 1px dashed #73591f33;
z-index: 0;
}
.era-label {
position: absolute;
right: 12px;
font-size: 11px;
color: #73591f99;
text-transform: uppercase;
letter-spacing: 0.1em;
transform: translateY(-50%);
font-family: monospace;
}
/* ── TOOLTIP ── */
.tooltip {
position: fixed;
bottom: 20px; right: 20px;
width: 280px;
background: var(--panel);
border: 1px solid var(--gold);
border-radius: 4px;
z-index: 100;
overflow: hidden;
}
.tt-header {
background: #2a1a06;
padding: 10px 14px;
display: flex;
align-items: center;
gap: 10px;
}
.tt-icon { font-size: 24px; }
.tt-name { font-family: var(--font-h); font-size: 18px; color: var(--title); letter-spacing: 0.04em; }
.tt-era { font-size: 11px; color: var(--gold); }
.tt-body { padding: 12px 14px; }
.tt-row { display: flex; justify-content: space-between; font-size: 12px; color: var(--secondary); margin-bottom: 6px; }
.tt-val { color: var(--science); font-family: monospace; }
.tt-divider { border: none; border-top: 1px solid #73591f33; margin: 8px 0; }
.tt-unlocks-label { font-size: 11px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.06em; margin-bottom: 6px; }
.tt-unlock-item { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--primary); margin-bottom: 3px; }
/* ── FILTER BAR ── */
.filter-bar {
position: fixed;
top: 108px; right: 16px;
display: flex;
flex-direction: column;
gap: 4px;
z-index: 50;
}
.filter-chip {
padding: 5px 10px;
border-radius: 3px;
border: 1px solid var(--border);
background: var(--btn);
font-size: 11px;
color: var(--muted);
cursor: pointer;
text-align: center;
}
.filter-chip.on { border-color: var(--gold-b); color: var(--gold); background: #2a1a06; }
</style>
</head>
<body>
<!-- ── HEADER ── -->
<div class="header">
<div class="header-title">Technology Web</div>
<div class="sci-rate">⚗ +22 / turn</div>
<div class="current-research">
Researching: <span class="research-name">Steel Working</span>
<span class="research-turns">· 4 turns</span>
</div>
<div class="close-btn"></div>
</div>
<!-- ── PILLAR LABELS ── -->
<div class="pillar-bar">
<div class="pillar-label active">Military</div>
<div class="pillar-label">Economy</div>
<div class="pillar-label">Industry</div>
<div class="pillar-label">Agriculture</div>
<div class="pillar-label">Governance</div>
<div class="pillar-label">Culture</div>
<div class="pillar-label">Exploration</div>
<div class="pillar-label">Engineering</div>
<div class="pillar-label">Medicine</div>
</div>
<!-- ── FILTER ── -->
<div class="filter-bar">
<div class="filter-chip on">All</div>
<div class="filter-chip">Military</div>
<div class="filter-chip">Economy</div>
<div class="filter-chip">Industry</div>
</div>
<!-- ── TREE ── -->
<div class="tree-scroll">
<div class="tree-canvas" style="height: 820px;">
<!-- Era bands -->
<div class="era-band" style="top:60px"><span class="era-label">Stone Age</span></div>
<div class="era-band" style="top:240px"><span class="era-label">Bronze Age</span></div>
<div class="era-band" style="top:430px"><span class="era-label">Iron Age</span></div>
<div class="era-band" style="top:620px"><span class="era-label">Steel Age</span></div>
<!-- SVG connection lines -->
<svg class="connections-svg">
<!-- Stone → Bronze connections -->
<line x1="195" y1="130" x2="300" y2="185" stroke="#d9a02055" stroke-width="1.5"/>
<line x1="195" y1="130" x2="300" y2="290" stroke="#d9a02033" stroke-width="1"/>
<line x1="195" y1="130" x2="300" y2="390" stroke="#d9a02022" stroke-width="1"/>
<line x1="195" y1="185" x2="300" y2="185" stroke="#d9a02066" stroke-width="1.5"/>
<line x1="195" y1="185" x2="300" y2="290" stroke="#d9a02033" stroke-width="1"/>
<line x1="195" y1="240" x2="300" y2="290" stroke="#d9a02055" stroke-width="1.5"/>
<line x1="195" y1="240" x2="300" y2="390" stroke="#d9a02033" stroke-width="1"/>
<!-- Bronze → Iron connections -->
<line x1="435" y1="185" x2="550" y2="285" stroke="#d9a02055" stroke-width="1.5"/>
<line x1="435" y1="185" x2="550" y2="385" stroke="#66bfff66" stroke-width="1.5" stroke-dasharray="4,3"/>
<line x1="435" y1="290" x2="550" y2="285" stroke="#d9a02044" stroke-width="1.5"/>
<line x1="435" y1="290" x2="550" y2="485" stroke="#d9a02033" stroke-width="1"/>
<line x1="435" y1="390" x2="550" y2="385" stroke="#d9a02055" stroke-width="1.5"/>
<line x1="435" y1="390" x2="550" y2="485" stroke="#d9a02033" stroke-width="1"/>
<!-- Iron → Steel connections -->
<line x1="685" y1="285" x2="800" y2="355" stroke="#66bfff55" stroke-width="1.5" stroke-dasharray="4,3"/>
<line x1="685" y1="285" x2="800" y2="460" stroke="#d9a02033" stroke-width="1"/>
<line x1="685" y1="385" x2="800" y2="355" stroke="#d9a02044" stroke-width="1.5"/>
<line x1="685" y1="385" x2="800" y2="460" stroke="#d9a02055" stroke-width="1.5"/>
<line x1="685" y1="485" x2="800" y2="460" stroke="#d9a02044" stroke-width="1"/>
<line x1="685" y1="485" x2="800" y2="570" stroke="#d9a02033" stroke-width="1"/>
<!-- Steel → Late -->
<line x1="935" y1="355" x2="1050" y2="430" stroke="#d9a02044" stroke-width="1.5"/>
<line x1="935" y1="460" x2="1050" y2="430" stroke="#d9a02044" stroke-width="1.5"/>
<line x1="935" y1="460" x2="1050" y2="545" stroke="#d9a02033" stroke-width="1"/>
<line x1="935" y1="570" x2="1050" y2="545" stroke="#d9a02033" stroke-width="1"/>
<line x1="935" y1="570" x2="1050" y2="660" stroke="#d9a02022" stroke-width="1"/>
<!-- Late → End -->
<line x1="1185" y1="430" x2="1300" y2="500" stroke="#d9a02033" stroke-width="1"/>
<line x1="1185" y1="545" x2="1300" y2="500" stroke="#d9a02033" stroke-width="1"/>
<line x1="1185" y1="660" x2="1300" y2="660" stroke="#d9a02022" stroke-width="1"/>
<!-- Researched glow lines -->
<line x1="195" y1="130" x2="300" y2="185" stroke="#d9a020" stroke-width="2" opacity="0.5"/>
<line x1="195" y1="185" x2="300" y2="185" stroke="#d9a020" stroke-width="2" opacity="0.5"/>
<line x1="195" y1="240" x2="300" y2="290" stroke="#d9a020" stroke-width="2" opacity="0.4"/>
<line x1="435" y1="185" x2="550" y2="285" stroke="#d9a020" stroke-width="2" opacity="0.35"/>
<!-- In-progress animated dash -->
<line x1="550" y1="285" x2="685" y2="285" stroke="#66bfff" stroke-width="2" stroke-dasharray="6,4" opacity="0.7">
<animate attributeName="stroke-dashoffset" values="0;-20" dur="1s" repeatCount="indefinite"/>
</line>
</svg>
<!-- ══ COLUMN 1: STONE AGE ══ -->
<div class="tech-node researched" style="left:65px;top:95px">
<div class="node-header"><span class="node-icon">🪨</span><span class="node-name">Stone Tools</span></div>
<div class="node-body">
<div class="node-cost">✓ Researched</div>
<div class="node-unlocks">Worker · Quarry</div>
</div>
</div>
<div class="tech-node researched" style="left:65px;top:155px">
<div class="node-header"><span class="node-icon">🔥</span><span class="node-name">Fire Making</span></div>
<div class="node-body">
<div class="node-cost">✓ Researched</div>
<div class="node-unlocks">Forge · Ale Hall</div>
</div>
</div>
<div class="tech-node researched" style="left:65px;top:215px">
<div class="node-header"><span class="node-icon">🌾</span><span class="node-name">Agriculture</span></div>
<div class="node-body">
<div class="node-cost">✓ Researched</div>
<div class="node-unlocks">Farm · Granary</div>
</div>
</div>
<!-- ══ COLUMN 2: BRONZE AGE ══ -->
<div class="tech-node researched" style="left:300px;top:155px">
<div class="node-header"><span class="node-icon">🥉</span><span class="node-name">Bronze Casting</span></div>
<div class="node-body">
<div class="node-cost">✓ Researched</div>
<div class="node-unlocks">Spearman · Shield</div>
</div>
</div>
<div class="tech-node researched" style="left:300px;top:260px">
<div class="node-header"><span class="node-icon"></span><span class="node-name">Mining</span></div>
<div class="node-body">
<div class="node-cost">✓ Researched</div>
<div class="node-unlocks">Mine · Pickaxe</div>
</div>
</div>
<div class="tech-node researched" style="left:300px;top:360px">
<div class="node-header"><span class="node-icon">🐂</span><span class="node-name">Animal Husbandry</span></div>
<div class="node-body">
<div class="node-cost">✓ Researched</div>
<div class="node-unlocks">Pasture · War Boar</div>
</div>
</div>
<!-- ══ COLUMN 3: IRON AGE ══ -->
<div class="tech-node in-progress" style="left:550px;top:255px">
<div class="node-header"><span class="node-icon"></span><span class="node-name">Steel Working</span></div>
<div class="node-body">
<div class="node-cost">⚗ 88 / 120 · 4t</div>
<div class="node-unlocks">Iron Warrior · Forge +1</div>
<div class="node-progress-track"><div class="node-progress-fill" style="width:73%"></div></div>
</div>
</div>
<div class="tech-node available" style="left:550px;top:355px">
<div class="node-header"><span class="node-icon">🏹</span><span class="node-name">Archery</span></div>
<div class="node-body">
<div class="node-cost">⚗ 120</div>
<div class="node-unlocks">Archer · Watchtower</div>
</div>
</div>
<div class="tech-node available" style="left:550px;top:455px">
<div class="node-header"><span class="node-icon">🏛</span><span class="node-name">Masonry</span></div>
<div class="node-body">
<div class="node-cost">⚗ 140</div>
<div class="node-unlocks">Walls · Monument</div>
</div>
</div>
<!-- ══ COLUMN 4: STEEL AGE ══ -->
<div class="tech-node locked" style="left:800px;top:325px">
<div class="node-header"><span class="node-icon">🗡</span><span class="node-name">Swordsmanship</span></div>
<div class="node-body">
<div class="node-cost">⚗ 200</div>
<div class="node-unlocks">Swordsman · Siege Eng.</div>
</div>
</div>
<div class="tech-node locked" style="left:800px;top:430px">
<div class="node-header"><span class="node-icon">🔩</span><span class="node-name">Iron Working</span></div>
<div class="node-body">
<div class="node-cost">⚗ 180</div>
<div class="node-unlocks">Forge upgrade · Armorer</div>
</div>
</div>
<div class="tech-node locked" style="left:800px;top:540px">
<div class="node-header"><span class="node-icon">🌊</span><span class="node-name">Hydraulics</span></div>
<div class="node-body">
<div class="node-cost">⚗ 160</div>
<div class="node-unlocks">Aqueduct upgrade</div>
</div>
</div>
<!-- ══ COLUMN 5: LATE ══ -->
<div class="tech-node locked" style="left:1050px;top:400px">
<div class="node-header"><span class="node-icon"></span><span class="node-name">Tactics</span></div>
<div class="node-body">
<div class="node-cost">⚗ 280</div>
<div class="node-unlocks">Formation bonuses</div>
</div>
</div>
<div class="tech-node locked" style="left:1050px;top:515px">
<div class="node-header"><span class="node-icon">🏗</span><span class="node-name">Engineering</span></div>
<div class="node-body">
<div class="node-cost">⚗ 260</div>
<div class="node-unlocks">Catapult · Roads</div>
</div>
</div>
<div class="tech-node locked" style="left:1050px;top:630px">
<div class="node-header"><span class="node-icon">📜</span><span class="node-name">Writing</span></div>
<div class="node-body">
<div class="node-cost">⚗ 220</div>
<div class="node-unlocks">Library · Diplomat</div>
</div>
</div>
<!-- ══ COLUMN 6: END GAME ══ -->
<div class="tech-node locked" style="left:1300px;top:470px">
<div class="node-header"><span class="node-icon">🏆</span><span class="node-name">Dwarven Mastery</span></div>
<div class="node-body">
<div class="node-cost">⚗ 400</div>
<div class="node-unlocks">Victory · All bonuses</div>
</div>
</div>
<div class="tech-node locked" style="left:1300px;top:630px">
<div class="node-header"><span class="node-icon"></span><span class="node-name">Alchemy</span></div>
<div class="node-body">
<div class="node-cost">⚗ 350</div>
<div class="node-unlocks">Alchemist Guild</div>
</div>
</div>
</div>
</div>
<!-- ── TOOLTIP (hovered node) ── -->
<div class="tooltip">
<div class="tt-header">
<div class="tt-icon"></div>
<div>
<div class="tt-name">Steel Working</div>
<div class="tt-era">Iron Age · Military + Industry</div>
</div>
</div>
<div class="tt-body">
<div class="tt-row"><span>Cost</span><span class="tt-val">120 ⚗</span></div>
<div class="tt-row"><span>Progress</span><span class="tt-val" style="color:#66bfff">88 / 120 · 4 turns</span></div>
<div class="tt-row"><span>Requires</span><span class="tt-val" style="color:#d9a020">Bronze Casting, Mining</span></div>
<hr class="tt-divider">
<div class="tt-unlocks-label">Unlocks</div>
<div class="tt-unlock-item"><span></span> Iron Warrior (melee unit)</div>
<div class="tt-unlock-item"><span>🔥</span> Forge upgrade (+2 ⚒)</div>
<div class="tt-unlock-item"><span>🛡</span> Iron Shield (unit equipment)</div>
<div class="tt-unlock-item"><span></span> Enables: Swordsmanship</div>
</div>
</div>
</body>
</html>