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) >=...