Define CSS variables and styles for a grid layout
by der_robert
HTML
<div class="tree-wrap" id="treeWrap">
<div class="edges"><svg id="edgesSvg"></svg></div>
<div class="grid" id="grid"></div>
</div>
<div class="tooltip" id="tooltip" role="dialog" aria-live="polite"></div>
CSS
:root{
--bg:#0e1420;
--card:#131b2b;
--card2:#0f1625;
--ink:#eaf2ff;
--muted:#9fb4d9;
--accent:#27d3a2;
--warn:#ffb347;
--danger:#ff6b6b;
--grid-gap:14px;
--radius:16px;
}
*{box-sizing:border-box}
body{
margin:0; background:linear-gradient(180deg,#08111c 0%, #0b1523 100%);
color:var(--ink); font:500 16px/1.45 system-ui, Segoe UI, Roboto, sans-serif;
}
h1{margin:16px 16px 8px; font-size:20px; color:var(--ink); font-weight:700}
.toolbar{
display:flex; gap:10px; align-items:center; padding:0 16px 12px; color:var(--muted); flex-wrap:wrap;
}
.toolbar small{opacity:.9}
.tree-wrap{
position:relative; padding:8px; isolation:isolate;
}
/* SVG layer for edges */
.edges{
position:sticky; inset:0 0 auto 0; height:0; pointer-events:none; z-index:0;
}
svg#edgesSvg{position:absolute; left:0; top:0; width:100%; height:100%; overflow:visible}
/* Grid */
.grid{
position:relative; z-index:1;
display:grid; grid-template-columns: repeat(auto-fit, minmax(220px,1fr));
gap:var(--grid-gap); padding:8px 16px 24px;
}
.card{
background:linear-gradient(180deg,var(--card) 0%, var(--card2) 100%);
border:1px solid rgba(255,255,255,.06);
border-radius:var(--radius);
padding:12px 12px 10px;
box-shadow:0 4px 18px rgba(0,0,0,.25);
position:relative; transition:transform .1s ease, box-shadow .1s ease;
cursor:pointer;
}
.card:focus-within,.card:hover{transform:translateY(-1px); box-shadow:0 8px 22px rgba(0,0,0,.32)}
.card .title{
display:flex; align-items:center; justify-content:space-between; gap:8px; margin-bottom:6px;
}
.title .name{font-weight:700}
.badge{
font-size:12px; padding:2px 8px; border-radius:999px; background:#0b2133; color:var(--muted); border:1px solid rgba(255,255,255,.06)
}
.reqs{
display:flex; flex-wrap:wrap; gap:6px; margin-top:6px; color:var(--muted);...
JavaScript
/** ---------------------------------------
* Datenmodell (Beispiel)
* id: eindeutiger Schlüssel
* name: Anzeige
* maxLevel: Obergrenze
* requirements: Liste von { id: 'andereId', level: Mindestlevel }
* --------------------------------------*/
const buildings = [
{ id:'holzfäller', name:'Holzfällerhütte', maxLevel:10, requirements:[] },
{ id:'steinbruch', name:'Steinbruch', maxLevel:10, requirements:[] },
{ id:'sägewerk', name:'Sägewerk', maxLevel:10, requirements:[{id:'holzfäller', level:2}] },
{ id:'steinmetz', name:'Steinmetz', maxLevel:10, requirements:[{id:'steinbruch', level:2}] },
{ id:'lager', name:'Lagerhaus', maxLevel:15, requirements:[{id:'holzfäller', level:3},{id:'steinbruch', level:3}] },
{ id:'werft', name:'Werft', maxLevel:10, requirements:[{id:'sägewerk', level:3},{id:'lager', level:2}] },
{ id:'schmiede', name:'Schmiede', maxLevel:10, requirements:[{id:'steinmetz', level:3},{id:'lager', level:3}] },
{ id:'stadtzentrum', name:'Stadtzentrum', maxLevel:20, requirements:[{id:'lager', level:5},{id:'schmiede', level:2}] },
];
/** Aktuelle Level (simuliert). In deiner App: hier echte Spielerstände einfüllen */
const levels = Object.fromEntries(buildings.map(b => [b.id, 0]));
/** Helper: DOM */
const $ = (sel, ctx=document) => ctx.querySelector(sel);
const $$ = (sel, ctx=document) => Array.from(ctx.querySelectorAll(sel));
/** Grid aufbauen */
const grid = $('#grid');
function renderCards(){
grid.innerHTML = '';
for(const b of buildings){
const card = document.createElement('article');
card.className = 'card';
card.tabIndex = 0;
card.dataset.bid = b.id;
card.innerHTML = `
<div class="title">
<div class="name">${b.name}</div>
<span class="badge">Max Lvl ${b.maxLevel}</span>
</div>
<div class="reqs">
${b.requirements.length
? b.requirements.map(r => {
const ok = (levels[r.id] ?? 0) >=...