Update site visuals and assets

This commit is contained in:
Raffael Sheikh committed 2026-05-24 04:21:24 +02:00
1 parent 41a5958184
commit 39faad9624
27 files changed
+2087 -610

No files matched your search

Binary file not shown.

Before

Width:  |  Height:  |  Size: 262 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 292 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 565 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 432 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 613 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

+38 -9
View File
@@ -8,7 +8,8 @@
<meta name="robots" content="noindex" />
<link rel="canonical" href="https://tool-ctrl.de/datenschutz" />
<link rel="icon" type="image/png" href="/assets/favicon.png" />
<link rel="stylesheet" href="/styles.css?v=20260525" />
<link rel="preload" href="/assets/fonts/space-grotesk-latin.woff2" as="font" type="font/woff2" crossorigin />
<link rel="stylesheet" href="/styles.css?v=20260562" />
</head>
<body>
@@ -17,7 +18,27 @@
<a class="brand" href="/" aria-label="ToolCTRL Startseite">
<img src="/assets/logo-black.svg" alt="ToolCTRL" class="brand-logo" />
</a>
<a class="legal-back" href="/">Zurück zur Startseite</a>
<nav class="nav" aria-label="Hauptnavigation">
<a href="/#leistungen">Leistungen</a>
<a href="/#branchen">Branchen</a>
<a href="/#vorgehen">Vorgehen</a>
<a href="/#arbeit">Organisation</a>
<a href="/techday">TechDay</a>
<a href="/gamejam">GameJam</a>
<a class="btn btn-solid btn-sm" href="/#kontakt">Ablauf prüfen</a>
</nav>
<button class="nav-toggle" aria-label="Menü" aria-expanded="false">
<span></span><span></span>
</button>
</div>
<div class="mobile-nav" hidden>
<a href="/#leistungen">Leistungen</a>
<a href="/#branchen">Branchen</a>
<a href="/#vorgehen">Vorgehen</a>
<a href="/#arbeit">Organisation</a>
<a href="/techday">TechDay</a>
<a href="/gamejam">GameJam</a>
<a class="btn btn-solid" href="/#kontakt">Ablauf prüfen</a>
</div>
</header>
@@ -154,16 +175,24 @@
</p>
</main>
<footer class="legal-footer">
<div class="wrap legal-footer-inner">
<span>© 2026 ToolCTRL</span>
<span>
<a href="/">Startseite</a> ·
<a href="/impressum">Impressum</a> ·
<footer class="site-footer">
<div class="wrap footer-bar">
<div class="footer-brand">
<img src="/assets/logo-white.svg" alt="ToolCTRL" class="footer-logo" />
<p>© <span id="year">2026</span> ToolCTRL · Bruchsal</p>
</div>
<div class="footer-links">
<a href="mailto:info@tool-ctrl.de">info@tool-ctrl.de</a>
<i></i>
<a href="https://www.linkedin.com/company/toolctrl/" target="_blank" rel="noopener">LinkedIn</a>
<i></i>
<a href="/impressum">Impressum</a>
·
<a href="/datenschutz">Datenschutz</a>
</span>
</div>
</div>
</footer>
<script src="/script.js?v=20260554"></script>
</body>
</html>
+140 -14
View File
@@ -12,10 +12,11 @@
<meta property="og:title" content="AI GameJam — Human in the Loop">
<meta property="og:description" content="Zwei Stunden, KI, ein spielbares Ergebnis: die AI GameJam beim TechDay Bruchsal 2026.">
<meta property="og:url" content="https://tool-ctrl.de/gamejam">
<meta property="og:image" content="https://tool-ctrl.de/assets/logo-a.png">
<meta property="og:image" content="https://tool-ctrl.de/assets/logo-a.webp">
<meta name="twitter:card" content="summary_large_image">
<meta name="theme-color" content="#0c0c0e">
<link rel="icon" type="image/png" href="/assets/favicon.png">
<link rel="preload" href="/assets/fonts/space-grotesk-latin.woff2" as="font" type="font/woff2" crossorigin>
<style>
@font-face {
font-family: "Space Grotesk";
@@ -319,31 +320,140 @@
.dropzone .big { font-size: 15px; font-weight: 600; margin-bottom: 4px; }
.dropzone .sm { color: var(--muted); font-size: 13px; font-family: 'Space Mono', monospace; }
.btn {
background: var(--ac); color: #ffffff; border: none;
position: relative; isolation: isolate; overflow: visible;
background: linear-gradient(180deg, #3c3c3f 0%, #161617 60%, #070708 100%);
color: #ffffff; border: 2px solid #0c0c0e; border-radius: 7px;
padding: 13px 30px; font-size: 14px; font-weight: 700; cursor: pointer;
font-family: inherit; text-transform: uppercase; letter-spacing: 1px;
transition: opacity .15s ease, transform .12s ease;
box-shadow: 0 7px 0 #000000, 0 11px 0 #343437, 0 17px 18px -10px rgba(0,0,0,.48),
inset 0 2px 0 rgba(255,255,255,.22);
transition: box-shadow .12s ease, transform .12s ease, background .15s ease;
}
.btn:hover { opacity: 0.82; transform: translateY(-1px); }
.btn:active { transform: scale(.96); }
.btn:disabled { background: var(--line2); color: var(--muted); cursor: not-allowed; }
.btn::after {
content: ""; position: absolute; left: 5px; right: -6px; bottom: -8px;
height: 8px; z-index: -1; border: 2px solid #0c0c0e; border-top: 0;
border-radius: 0 0 7px 7px; background: #0c0c0e;
transition: height .12s ease, bottom .12s ease;
}
.btn:hover { transform: translateY(-2px); box-shadow: 0 9px 0 #000000, 0 13px 0 #343437, 0 19px 20px -10px rgba(0,0,0,.5),
inset 0 2px 0 rgba(255,255,255,.22); }
.btn:active { transform: translateY(5px) scale(.985); box-shadow: 0 2px 0 #000000, 0 4px 0 #343437, 0 9px 14px -9px rgba(0,0,0,.45); }
.btn:active::after { bottom: -3px; height: 3px; }
.btn:disabled { background: var(--line2); color: var(--muted); cursor: not-allowed; box-shadow: none; }
.btn:disabled::after { display: none; }
.status {
font-family: 'Space Mono', monospace; font-size: 13px; margin-top: 16px; min-height: 20px;
}
.status.ok { color: var(--ac); }
.status.err { color: #c0392b; }
.status.err { color: #0c0c0e; font-weight: 700; }
/* ===== GALLERY ===== */
.btn-ghost {
background: var(--panel); border: 1px solid var(--line2); color: var(--text);
position: relative; isolation: isolate; overflow: visible;
background: linear-gradient(180deg, #ffffff 0%, #f1f1f2 62%, #dfdfe1 100%);
border: 2px solid var(--text); border-radius: 6px; color: var(--text);
padding: 10px 16px; font-size: 12px; font-weight: 600; cursor: pointer;
font-family: 'Space Mono', monospace; text-transform: uppercase; letter-spacing: 1px;
display: inline-flex; align-items: center; gap: 8px;
transition: border-color .15s ease, transform .12s ease;
box-shadow: 0 5px 0 #000000, 0 8px 0 #bbbbbf, 0 13px 16px -10px rgba(0,0,0,.36);
transition: box-shadow .12s ease, transform .12s ease;
}
.btn-ghost:hover { border-color: var(--ac); transform: translateY(-1px); }
.btn-ghost::after {
content: ""; position: absolute; left: 4px; right: -5px; bottom: -7px;
height: 7px; z-index: -1; border: 2px solid var(--text); border-top: 0;
border-radius: 0 0 6px 6px; background: #d9d9dc;
transition: height .12s ease, bottom .12s ease;
}
.btn-ghost:hover { transform: translateY(-2px); box-shadow: 0 7px 0 #000000, 0 10px 0 #bbbbbf, 0 15px 18px -10px rgba(0,0,0,.38); }
.btn-ghost:active { transform: translateY(4px) scale(.985); box-shadow: 0 1px 0 #000000, 0 3px 0 #bbbbbf, 0 7px 12px -9px rgba(0,0,0,.34); }
.btn-ghost:active::after { bottom: -3px; height: 3px; }
.btn-ghost svg.ic { width: 13px; height: 13px; }
.btn,
.btn-ghost {
max-width: 100%;
min-height: 40px;
line-height: 1.1;
white-space: normal;
text-align: center;
justify-content: center;
}
.btn::after,
.btn-ghost::after { display: none; }
.btn {
display: inline-flex; align-items: center;
box-shadow: 0 5px 0 #000000, 0 8px 12px -8px rgba(0,0,0,.48),
inset 0 2px 0 rgba(255,255,255,.22);
}
.btn:hover {
transform: translateY(-1px);
box-shadow: 0 6px 0 #000000, 0 10px 14px -9px rgba(0,0,0,.5),
inset 0 2px 0 rgba(255,255,255,.22);
}
.btn:active {
transform: translateY(3px) scale(.96);
box-shadow: 0 2px 0 #000000, 0 7px 10px -9px rgba(0,0,0,.45);
}
.btn-ghost {
box-shadow: 0 5px 0 #000000, 0 8px 12px -8px rgba(0,0,0,.32);
}
.btn-ghost:hover {
transform: translateY(-1px);
box-shadow: 0 6px 0 #000000, 0 10px 14px -9px rgba(0,0,0,.34);
}
.btn-ghost:active {
transform: translateY(3px) scale(.96);
box-shadow: 0 2px 0 #000000, 0 7px 10px -9px rgba(0,0,0,.3);
}
.btn,
.btn-ghost {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 8px;
max-width: 100%;
min-height: 40px;
padding: 11px 20px;
border: 2px solid var(--text);
border-radius: 6px;
line-height: 1.1;
white-space: normal;
text-align: center;
overflow-wrap: anywhere;
transform: translateY(0);
box-shadow: 0 4px 0 #000000, 0 10px 16px -12px rgba(0,0,0,.42);
}
.btn::before,
.btn::after,
.btn-ghost::before,
.btn-ghost::after {
display: none;
}
.btn:hover,
.btn-ghost:hover {
transform: translateY(-1px);
box-shadow: 0 5px 0 #000000, 0 12px 18px -12px rgba(0,0,0,.44);
}
.btn:active,
.btn-ghost:active {
transform: translateY(2px) scale(.98);
box-shadow: 0 1px 0 #000000, 0 6px 10px -10px rgba(0,0,0,.4);
}
.btn {
border-color: #ffffff;
box-shadow: 0 4px 0 #9f9f9f, 0 10px 16px -12px rgba(255,255,255,.38),
inset 0 2px 0 rgba(255,255,255,.24);
}
.btn:hover {
box-shadow: 0 5px 0 #bcbcbc, 0 12px 18px -12px rgba(255,255,255,.42),
inset 0 2px 0 rgba(255,255,255,.24);
}
.btn:active {
box-shadow: 0 1px 0 #bcbcbc, 0 6px 10px -10px rgba(255,255,255,.34);
}
.games { display: grid; grid-template-columns: repeat(2, 1fr); gap: 20px; margin-top: 6px; }
.game { background: var(--panel); border: 1px solid var(--line); }
.game .frame { width: 100%; aspect-ratio: 16/10; border: none; background: var(--panel2); display: block; }
@@ -375,6 +485,13 @@
font-family: 'Space Mono', monospace; color: var(--muted); font-size: 12px;
letter-spacing: 0.5px;
}
footer .links {
display: flex; flex-wrap: wrap; justify-content: center; gap: 8px 14px;
font-family: 'Space Mono', monospace; font-size: 12px; letter-spacing: .5px;
color: var(--muted);
}
footer .links a { color: var(--muted); text-decoration: none; }
footer .links a:hover { color: var(--text); }
@keyframes heroRise {
from { opacity: 0; transform: translateY(6px); }
@@ -416,12 +533,12 @@
<div class="topbar">
<div class="inner">
<div class="left">
<a href="/" aria-label="Zur ToolCTRL-Startseite"><img class="tc" src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyBpZD0iTGF5ZXJfMSIgZGF0YS1uYW1lPSJMYXllciAxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgNzEzLjMyIDY3OC42MSI+CiAgPGRlZnM+CiAgICA8c3R5bGU+CiAgICAgIC5jbHMtMSB7CiAgICAgICAgZmlsbDogdXJsKCNsaW5lYXItZ3JhZGllbnQtNSk7CiAgICAgIH0KCiAgICAgIC5jbHMtMiB7CiAgICAgICAgZmlsbDogdXJsKCNsaW5lYXItZ3JhZGllbnQtNik7CiAgICAgIH0KCiAgICAgIC5jbHMtMyB7CiAgICAgICAgZmlsbDogdXJsKCNsaW5lYXItZ3JhZGllbnQtNCk7CiAgICAgIH0KCiAgICAgIC5jbHMtNCB7CiAgICAgICAgZmlsbDogdXJsKCNsaW5lYXItZ3JhZGllbnQtMyk7CiAgICAgIH0KCiAgICAgIC5jbHMtNSB7CiAgICAgICAgZmlsbDogdXJsKCNsaW5lYXItZ3JhZGllbnQtMik7CiAgICAgIH0KCiAgICAgIC5jbHMtNiB7CiAgICAgICAgZmlsbDogdXJsKCNsaW5lYXItZ3JhZGllbnQpOwogICAgICB9CiAgICA8L3N0eWxlPgogICAgPGxpbmVhckdyYWRpZW50IGlkPSJsaW5lYXItZ3JhZGllbnQiIHgxPSI2NTguOTYiIHkxPSIzMS45NiIgeDI9IjI5Ny43IiB5Mj0iNDU4LjYiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj4KICAgICAgPHN0b3Agb2Zmc2V0PSIwIiBzdG9wLWNvbG9yPSIjMDAwIi8+CiAgICAgIDxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iIzMzMyIvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudCBpZD0ibGluZWFyLWdyYWRpZW50LTIiIHgxPSIxNjg0LjMiIHkxPSIxMTQyLjc1IiB4Mj0iMjIwNi4wOSIgeTI9IjE1NTMuNTEiIGdyYWRpZW50VHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTE4MzMuNzQgLTExMDguOTYpIHJvdGF0ZSg1LjA2KSBza2V3WCgxNC4yNSkiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj4KICAgICAgPHN0b3Agb2Zmc2V0PSIwIiBzdG9wLWNvbG9yPSIjYjJiMmIyIi8+CiAgICAgIDxzdG9wIG9mZnNldD0iLjc4IiBzdG9wLWNvbG9yPSIjZmZmIi8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50IGlkPSJsaW5lYXItZ3JhZGllbnQtMyIgeDE9IjE3MTkuMTMiIHkxPSIxMDk4LjUxIiB4Mj0iMjI0MC45MSIgeTI9IjE1MDkuMjgiIHhsaW5rOmhyZWY9IiNsaW5lYXItZ3JhZGllbnQtMiIvPgogICAgPGxpbmVhckdyYWRpZW50IGlkPSJsaW5lYXItZ3JhZGllbnQtNCIgeDE9IjE3NjQuODIiIHkxPSIxMDQwLjQ3IiB4Mj0iMjI4Ni42IiB5Mj0iMTQ1MS4yNCIgeGxpbms6aHJlZj0iI2xpbmVhci1ncmFkaWVudC0yIi8+CiAgICA8bGluZWFyR3JhZGllbnQgaWQ9ImxpbmVhci1ncmFkaWVudC01IiB4MT0iMTgwNi4yNyIgeTE9Ijk4Ny44MiIgeDI9IjIzMjguMDUiIHkyPSIxMzk4LjU5IiB4bGluazpocmVmPSIjbGluZWFyLWdyYWRpZW50LTIiLz4KICAgIDxsaW5lYXJHcmFkaWVudCBpZD0ibGluZWFyLWdyYWRpZW50LTYiIHgxPSIzNDUuMDMiIHkxPSItMTAuMTUiIHgyPSIxMDE0LjU1IiB5Mj0iNTE2LjkxIiBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDEsMCwwLDEsMCwwKSIgeGxpbms6aHJlZj0iI2xpbmVhci1ncmFkaWVudC0yIi8+CiAgPC9kZWZzPgogIDxnPgogICAgPHBhdGggZD0iTTY4OC43LDU3Mi4wOWwtMTYwLDk4Ljk1Yy05LjE0LDUuNzMtMTkuOTksOC4zNS0zMC43Nyw3LjM3bC0zODAuNjgtMzQuMzZjLTIyLjQ4LTIuMDEtNDAuNzYtMTkuMDEtNDQuMzUtNDEuMzFMLjY0LDE1OS4zMWMtMy4xNy0xOS41Niw1LjYtMzkuMTIsMjIuMy00OS43MkwxODkuNDYsOC4wOGMtMTMuOTUsOS43NSwyMy43NywzMS41NSwyNi44OCw0OS45NWw5MS4zLDM2MS4xM2M2LjIxLDM2LjY4LDM2LjM3LDY0LjU4LDczLjQyLDY3LjkzbDI3OC42NCw0Mi45YzguNjUuNzksMjEuODcsNDUuNjgsMjguOTQsNDIuMDNsLjA2LjA2WiIvPgogICAgPHBhdGggY2xhc3M9ImNscy02IiBkPSJNNjg4LjY0LDU3Mi4wM2MtNy4wNywzLjY2LTE1LjIzLDUuMzYtMjMuODgsNC41N2wtMzQ5LTMxLjVjLTM3LjA0LTMuMzUtNjcuMjEtMzEuMjYtNzMuNDItNjcuOTNMMTcwLjM5LDUzLjM1Yy0zLjExLTE4LjQsNS4xMi0zNS41MiwxOS4wNy00NS4yN2wxLjk1LTEuMTZjNy45OC01LjA2LDE3LjYxLTcuNjIsMjcuOTEtNi43NmwzNTguNTYsMzAuMzRjMjkuNDksMi41LDUzLjU2LDI0LjYyLDU4LjYxLDUzLjhsNzYuMTYsNDQwLjM5YzMuNTMsMjAuMjktNy4xOSwzOC45OS0yNC4wMSw0Ny4zNFoiLz4KICA8L2c+CiAgPGc+CiAgICA8Zz4KICAgICAgPHBhdGggY2xhc3M9ImNscy01IiBkPSJNMzAwLjIyLDM0My45M2wtMTUuMDEsNC4yNiwxNS43Myw5Ni4wNWM0LjIzLDI1LjgzLDIxLjg4LDQyLjU5LDQ3LjIxLDQ0LjgzbDIwLjQyLDEuODEtMi40OC0xNS4xNC0yMC40Mi0xLjgxYy0xNS44MS0xLjQtMjYuMDQtMTEuNDQtMjguNzktMjguMjhsLTguMjQtNTAuMzQsNDQuOTMsMy45Ny0yLjQ1LTE0Ljk0LTQ0LjkzLTMuOTctNS45Ny0zNi40M1oiLz4KICAgICAgPHBhdGggY2xhc3M9ImNscy00IiBkPSJNNDIxLjk2LDM4Ny45N2MtMzEuODgtMi44Mi01MS4yNiwxOC4xLTQ2LjA4LDQ5LjczLDUuMTgsMzEuNjQsMzIuMDgsNTYuNjUsNjMuOTcsNTkuNDcsMzEuODgsMi44Miw1MS4yNi0xOC4xLDQ2LjA4LTQ5LjczLTUuMTgtMzEuNjQtMzIuMDgtNTYuNjUtNjMuOTctNTkuNDdaTTQzNy4zNiw0ODIuMDNjLTIyLjktMi4wMy00MS41NC0xOS42Ny00NS4zNS00Mi45LTMuOC0yMy4yMyw5LjUzLTM4LjA0LDMyLjQzLTM2LjAyLDIyLjksMi4wMyw0MS41NCwxOS42Niw0NS4zNSw0Mi45LDMuOCwyMy4yMy05LjUzLDM4LjA0LTMyLjQyLDM2LjAyWiIvPgogICAgICA8cGF0aCBjbGFzcz0iY2xzLTMiIGQ9Ik01NDEuMzcsMzk4LjUzYy0zMS44OC0yLjgyLTUxLjI2LDE4LjEtNDYuMDgsNDkuNzMsNS4xOCwzMS42NCwzMi4wOCw1Ni42NSw2My45Nyw1OS40NywzMS44OCwyLjgyLDUxLjI2LTE4LjEsNDYuMDgtNDkuNzMtNS4xOC0zMS42NC0zMi4wOC01Ni42NS02My45Ny01OS40N1pNNTU2Ljc3LDQ5Mi41OWMtMjIuOS0yLjAzLTQxLjU0LTE5LjY3LTQ1LjM1LTQyLjktMy44LTIzLjIzLDkuNTMtMzguMDQsMzIuNDMtMzYuMDIsMjIuOSwyLjAzLDQxLjU0LDE5LjY2LDQ1LjM1LDQyLjksMy44LDIzLjIzLTkuNTMsMzguMDQtMzIuNDIsMzYuMDJaIi8+CiAgICAgIDxwb2x5Z29uIGNsYXNzPSJjbHMtMSIgcG9pbnRzPSI2MDcuNjcgMzY4LjQxIDYzMS4xIDUxMS40NiA2NDcuMDQgNTEyLjg3IDYyMi42OCAzNjQuMTUgNjA3LjY3IDM2OC40MSIvPgogICAgPC9nPgogICAgPHBhdGggY2xhc3M9ImNscy0yIiBkPSJNNTgyLjM5LDE2NC4wN2wxOC4zLDEuNjItNTYuMjktNzUuMTJjLTMuMTUtNC4yLTcuOTMtNi44Ni0xMy4xNi03LjMzaDBjLTcuNjEtLjY3LTE0Ljg2LDMuNDEtMTguMjIsMTAuMjdsLTMwLjMsNjEuNzUsMTkuMiwxLjcsMjcuNTctNTYuMmMuOTktMi4wMSwzLjc1LTIuMjcsNS4xLS40OGw0Ny44MSw2My43OVoiLz4KICA8L2c+Cjwvc3ZnPg==" alt="ToolCTRL"></a>
<a href="/" aria-label="Zur ToolCTRL-Startseite"><img class="tc" src="/assets/logo-black.svg" alt="ToolCTRL"></a>
<a class="back" href="/"><svg class="ic" viewBox="0 0 24 24"><path d="M19 12H5M12 19l-7-7 7-7"/></svg> Startseite</a>
</div>
<div class="right">
<span class="ev">TechDay Bruchsal · 27.05.2026</span>
<img class="mit" src="data:image/png;base64,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 truncated
<img class="mit" src="/assets/mitup-logo.webp" alt="mITup Bruchsal">
</div>
</div>
</div>
@@ -582,10 +699,19 @@
<footer>
<div class="inner">
<div class="logos">
<img class="tc" src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyBpZD0iTGF5ZXJfMSIgZGF0YS1uYW1lPSJMYXllciAxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgNzEzLjMyIDY3OC42MSI+CiAgPGRlZnM+CiAgICA8c3R5bGU+CiAgICAgIC5jbHMtMSB7CiAgICAgICAgZmlsbDogdXJsKCNsaW5lYXItZ3JhZGllbnQtNSk7CiAgICAgIH0KCiAgICAgIC5jbHMtMiB7CiAgICAgICAgZmlsbDogdXJsKCNsaW5lYXItZ3JhZGllbnQtNik7CiAgICAgIH0KCiAgICAgIC5jbHMtMyB7CiAgICAgICAgZmlsbDogdXJsKCNsaW5lYXItZ3JhZGllbnQtNCk7CiAgICAgIH0KCiAgICAgIC5jbHMtNCB7CiAgICAgICAgZmlsbDogdXJsKCNsaW5lYXItZ3JhZGllbnQtMyk7CiAgICAgIH0KCiAgICAgIC5jbHMtNSB7CiAgICAgICAgZmlsbDogdXJsKCNsaW5lYXItZ3JhZGllbnQtMik7CiAgICAgIH0KCiAgICAgIC5jbHMtNiB7CiAgICAgICAgZmlsbDogdXJsKCNsaW5lYXItZ3JhZGllbnQpOwogICAgICB9CiAgICA8L3N0eWxlPgogICAgPGxpbmVhckdyYWRpZW50IGlkPSJsaW5lYXItZ3JhZGllbnQiIHgxPSI2NTguOTYiIHkxPSIzMS45NiIgeDI9IjI5Ny43IiB5Mj0iNDU4LjYiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj4KICAgICAgPHN0b3Agb2Zmc2V0PSIwIiBzdG9wLWNvbG9yPSIjMDAwIi8+CiAgICAgIDxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iIzMzMyIvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudCBpZD0ibGluZWFyLWdyYWRpZW50LTIiIHgxPSIxNjg0LjMiIHkxPSIxMTQyLjc1IiB4Mj0iMjIwNi4wOSIgeTI9IjE1NTMuNTEiIGdyYWRpZW50VHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTE4MzMuNzQgLTExMDguOTYpIHJvdGF0ZSg1LjA2KSBza2V3WCgxNC4yNSkiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj4KICAgICAgPHN0b3Agb2Zmc2V0PSIwIiBzdG9wLWNvbG9yPSIjYjJiMmIyIi8+CiAgICAgIDxzdG9wIG9mZnNldD0iLjc4IiBzdG9wLWNvbG9yPSIjZmZmIi8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50IGlkPSJsaW5lYXItZ3JhZGllbnQtMyIgeDE9IjE3MTkuMTMiIHkxPSIxMDk4LjUxIiB4Mj0iMjI0MC45MSIgeTI9IjE1MDkuMjgiIHhsaW5rOmhyZWY9IiNsaW5lYXItZ3JhZGllbnQtMiIvPgogICAgPGxpbmVhckdyYWRpZW50IGlkPSJsaW5lYXItZ3JhZGllbnQtNCIgeDE9IjE3NjQuODIiIHkxPSIxMDQwLjQ3IiB4Mj0iMjI4Ni42IiB5Mj0iMTQ1MS4yNCIgeGxpbms6aHJlZj0iI2xpbmVhci1ncmFkaWVudC0yIi8+CiAgICA8bGluZWFyR3JhZGllbnQgaWQ9ImxpbmVhci1ncmFkaWVudC01IiB4MT0iMTgwNi4yNyIgeTE9Ijk4Ny44MiIgeDI9IjIzMjguMDUiIHkyPSIxMzk4LjU5IiB4bGluazpocmVmPSIjbGluZWFyLWdyYWRpZW50LTIiLz4KICAgIDxsaW5lYXJHcmFkaWVudCBpZD0ibGluZWFyLWdyYWRpZW50LTYiIHgxPSIzNDUuMDMiIHkxPSItMTAuMTUiIHgyPSIxMDE0LjU1IiB5Mj0iNTE2LjkxIiBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDEsMCwwLDEsMCwwKSIgeGxpbms6aHJlZj0iI2xpbmVhci1ncmFkaWVudC0yIi8+CiAgPC9kZWZzPgogIDxnPgogICAgPHBhdGggZD0iTTY4OC43LDU3Mi4wOWwtMTYwLDk4Ljk1Yy05LjE0LDUuNzMtMTkuOTksOC4zNS0zMC43Nyw3LjM3bC0zODAuNjgtMzQuMzZjLTIyLjQ4LTIuMDEtNDAuNzYtMTkuMDEtNDQuMzUtNDEuMzFMLjY0LDE1OS4zMWMtMy4xNy0xOS41Niw1LjYtMzkuMTIsMjIuMy00OS43MkwxODkuNDYsOC4wOGMtMTMuOTUsOS43NSwyMy43NywzMS41NSwyNi44OCw0OS45NWw5MS4zLDM2MS4xM2M2LjIxLDM2LjY4LDM2LjM3LDY0LjU4LDczLjQyLDY3LjkzbDI3OC42NCw0Mi45YzguNjUuNzksMjEuODcsNDUuNjgsMjguOTQsNDIuMDNsLjA2LjA2WiIvPgogICAgPHBhdGggY2xhc3M9ImNscy02IiBkPSJNNjg4LjY0LDU3Mi4wM2MtNy4wNywzLjY2LTE1LjIzLDUuMzYtMjMuODgsNC41N2wtMzQ5LTMxLjVjLTM3LjA0LTMuMzUtNjcuMjEtMzEuMjYtNzMuNDItNjcuOTNMMTcwLjM5LDUzLjM1Yy0zLjExLTE4LjQsNS4xMi0zNS41MiwxOS4wNy00NS4yN2wxLjk1LTEuMTZjNy45OC01LjA2LDE3LjYxLTcuNjIsMjcuOTEtNi43NmwzNTguNTYsMzAuMzRjMjkuNDksMi41LDUzLjU2LDI0LjYyLDU4LjYxLDUzLjhsNzYuMTYsNDQwLjM5YzMuNTMsMjAuMjktNy4xOSwzOC45OS0yNC4wMSw0Ny4zNFoiLz4KICA8L2c+CiAgPGc+CiAgICA8Zz4KICAgICAgPHBhdGggY2xhc3M9ImNscy01IiBkPSJNMzAwLjIyLDM0My45M2wtMTUuMDEsNC4yNiwxNS43Myw5Ni4wNWM0LjIzLDI1LjgzLDIxLjg4LDQyLjU5LDQ3LjIxLDQ0LjgzbDIwLjQyLDEuODEtMi40OC0xNS4xNC0yMC40Mi0xLjgxYy0xNS44MS0xLjQtMjYuMDQtMTEuNDQtMjguNzktMjguMjhsLTguMjQtNTAuMzQsNDQuOTMsMy45Ny0yLjQ1LTE0Ljk0LTQ0LjkzLTMuOTctNS45Ny0zNi40M1oiLz4KICAgICAgPHBhdGggY2xhc3M9ImNscy00IiBkPSJNNDIxLjk2LDM4Ny45N2MtMzEuODgtMi44Mi01MS4yNiwxOC4xLTQ2LjA4LDQ5LjczLDUuMTgsMzEuNjQsMzIuMDgsNTYuNjUsNjMuOTcsNTkuNDcsMzEuODgsMi44Miw1MS4yNi0xOC4xLDQ2LjA4LTQ5LjczLTUuMTgtMzEuNjQtMzIuMDgtNTYuNjUtNjMuOTctNTkuNDdaTTQzNy4zNiw0ODIuMDNjLTIyLjktMi4wMy00MS41NC0xOS42Ny00NS4zNS00Mi45LTMuOC0yMy4yMyw5LjUzLTM4LjA0LDMyLjQzLTM2LjAyLDIyLjksMi4wMyw0MS41NCwxOS42Niw0NS4zNSw0Mi45LDMuOCwyMy4yMy05LjUzLDM4LjA0LTMyLjQyLDM2LjAyWiIvPgogICAgICA8cGF0aCBjbGFzcz0iY2xzLTMiIGQ9Ik01NDEuMzcsMzk4LjUzYy0zMS44OC0yLjgyLTUxLjI2LDE4LjEtNDYuMDgsNDkuNzMsNS4xOCwzMS42NCwzMi4wOCw1Ni42NSw2My45Nyw1OS40NywzMS44OCwyLjgyLDUxLjI2LTE4LjEsNDYuMDgtNDkuNzMtNS4xOC0zMS42NC0zMi4wOC01Ni42NS02My45Ny01OS40N1pNNTU2Ljc3LDQ5Mi41OWMtMjIuOS0yLjAzLTQxLjU0LTE5LjY3LTQ1LjM1LTQyLjktMy44LTIzLjIzLDkuNTMtMzguMDQsMzIuNDMtMzYuMDIsMjIuOSwyLjAzLDQxLjU0LDE5LjY2LDQ1LjM1LDQyLjksMy44LDIzLjIzLTkuNTMsMzguMDQtMzIuNDIsMzYuMDJaIi8+CiAgICAgIDxwb2x5Z29uIGNsYXNzPSJjbHMtMSIgcG9pbnRzPSI2MDcuNjcgMzY4LjQxIDYzMS4xIDUxMS40NiA2NDcuMDQgNTEyLjg3IDYyMi42OCAzNjQuMTUgNjA3LjY3IDM2OC40MSIvPgogICAgPC9nPgogICAgPHBhdGggY2xhc3M9ImNscy0yIiBkPSJNNTgyLjM5LDE2NC4wN2wxOC4zLDEuNjItNTYuMjktNzUuMTJjLTMuMTUtNC4yLTcuOTMtNi44Ni0xMy4xNi03LjMzaDBjLTcuNjEtLjY3LTE0Ljg2LDMuNDEtMTguMjIsMTAuMjdsLTMwLjMsNjEuNzUsMTkuMiwxLjcsMjcuNTctNTYuMmMuOTktMi4wMSwzLjc1LTIuMjcsNS4xLS40OGw0Ny44MSw2My43OVoiLz4KICA8L2c+Cjwvc3ZnPg==" alt="ToolCTRL">
<img src="data:image/png;base64,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 truncated
<img class="tc" src="/assets/logo-black.svg" alt="ToolCTRL">
<img src="/assets/mitup-logo.webp" alt="mITup Bruchsal">
</div>
<div class="ft">AI GameJam · Human in the Loop · veranstaltet von ToolCTRL beim TechDay Bruchsal 2026</div>
<div class="links">
<a href="mailto:info@tool-ctrl.de">info@tool-ctrl.de</a>
<span>·</span>
<a href="https://www.linkedin.com/company/toolctrl/" target="_blank" rel="noopener">LinkedIn</a>
<span>·</span>
<a href="/impressum">Impressum</a>
<span>·</span>
<a href="/datenschutz">Datenschutz</a>
</div>
</div>
</footer>
+38 -9
View File
@@ -8,7 +8,8 @@
<meta name="robots" content="noindex" />
<link rel="canonical" href="https://tool-ctrl.de/impressum" />
<link rel="icon" type="image/png" href="/assets/favicon.png" />
<link rel="stylesheet" href="/styles.css?v=20260525" />
<link rel="preload" href="/assets/fonts/space-grotesk-latin.woff2" as="font" type="font/woff2" crossorigin />
<link rel="stylesheet" href="/styles.css?v=20260562" />
</head>
<body>
@@ -17,7 +18,27 @@
<a class="brand" href="/" aria-label="ToolCTRL Startseite">
<img src="/assets/logo-black.svg" alt="ToolCTRL" class="brand-logo" />
</a>
<a class="legal-back" href="/">Zurück zur Startseite</a>
<nav class="nav" aria-label="Hauptnavigation">
<a href="/#leistungen">Leistungen</a>
<a href="/#branchen">Branchen</a>
<a href="/#vorgehen">Vorgehen</a>
<a href="/#arbeit">Organisation</a>
<a href="/techday">TechDay</a>
<a href="/gamejam">GameJam</a>
<a class="btn btn-solid btn-sm" href="/#kontakt">Ablauf prüfen</a>
</nav>
<button class="nav-toggle" aria-label="Menü" aria-expanded="false">
<span></span><span></span>
</button>
</div>
<div class="mobile-nav" hidden>
<a href="/#leistungen">Leistungen</a>
<a href="/#branchen">Branchen</a>
<a href="/#vorgehen">Vorgehen</a>
<a href="/#arbeit">Organisation</a>
<a href="/techday">TechDay</a>
<a href="/gamejam">GameJam</a>
<a class="btn btn-solid" href="/#kontakt">Ablauf prüfen</a>
</div>
</header>
@@ -89,16 +110,24 @@
</p>
</main>
<footer class="legal-footer">
<div class="wrap legal-footer-inner">
<span>© 2026 ToolCTRL</span>
<span>
<a href="/">Startseite</a> ·
<a href="/impressum">Impressum</a> ·
<footer class="site-footer">
<div class="wrap footer-bar">
<div class="footer-brand">
<img src="/assets/logo-white.svg" alt="ToolCTRL" class="footer-logo" />
<p>© <span id="year">2026</span> ToolCTRL · Bruchsal</p>
</div>
<div class="footer-links">
<a href="mailto:info@tool-ctrl.de">info@tool-ctrl.de</a>
<i></i>
<a href="https://www.linkedin.com/company/toolctrl/" target="_blank" rel="noopener">LinkedIn</a>
<i></i>
<a href="/impressum">Impressum</a>
·
<a href="/datenschutz">Datenschutz</a>
</span>
</div>
</div>
</footer>
<script src="/script.js?v=20260554"></script>
</body>
</html>
+159 -149
View File
@@ -3,20 +3,21 @@
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>ToolCTRL — Software gegen Excel, WhatsApp-Chaos und Insellösungen</title>
<meta name="description" content="ToolCTRL baut interne Software, Automatisierung und All-in-One-Systeme für Teams, deren Abläufe nicht in Standardtools passen." />
<title>ToolCTRL — EU-first Software für souveräne Betriebe</title>
<meta name="description" content="ToolCTRL baut schnelle, bezahlbare SaaS-Systeme für Mittelständler: EU-first gedacht, DSGVO-konform und ohne unnötige US-Cloud-Pflicht." />
<link rel="canonical" href="https://tool-ctrl.de/" />
<meta property="og:type" content="website" />
<meta property="og:locale" content="de_DE" />
<meta property="og:site_name" content="ToolCTRL" />
<meta property="og:title" content="ToolCTRL — Software gegen Tool-Chaos" />
<meta property="og:description" content="Wir ersetzen Excel, WhatsApp-Chaos und Insellösungen durch Software, die Teams wirklich benutzen." />
<meta property="og:title" content="ToolCTRL — EU-first Software für souveräne Betriebe" />
<meta property="og:description" content="Schnelle SaaS-Systeme für Mittelständler, die keine US-Cloud-Pflicht und keine aufgeblasenen Agenturprojekte wollen." />
<meta property="og:url" content="https://tool-ctrl.de/" />
<meta property="og:image" content="https://tool-ctrl.de/assets/logo-a.png" />
<meta property="og:image" content="https://tool-ctrl.de/assets/logo-a.webp" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="theme-color" content="#0A0A0A" />
<link rel="icon" type="image/png" href="/assets/favicon.png" />
<link rel="stylesheet" href="/styles.css?v=20260525" />
<link rel="preload" href="/assets/fonts/space-grotesk-latin.woff2" as="font" type="font/woff2" crossorigin />
<link rel="stylesheet" href="/styles.css?v=20260562" />
<script type="application/ld+json">
{
"@context": "https://schema.org",
@@ -49,8 +50,8 @@
<a href="#branchen">Branchen</a>
<a href="#vorgehen">Vorgehen</a>
<a href="#arbeit">Organisation</a>
<a href="#events">Events</a>
<a href="/techday">TechDay</a>
<a href="/gamejam">GameJam</a>
<a class="btn btn-solid btn-sm" href="#kontakt">Ablauf prüfen</a>
</nav>
<button class="nav-toggle" aria-label="Menü" aria-expanded="false">
@@ -62,8 +63,8 @@
<a href="#branchen">Branchen</a>
<a href="#vorgehen">Vorgehen</a>
<a href="#arbeit">Organisation</a>
<a href="#events">Events</a>
<a href="/techday">TechDay</a>
<a href="/gamejam">GameJam</a>
<a class="btn btn-solid" href="#kontakt">Ablauf prüfen</a>
</div>
</header>
@@ -74,134 +75,92 @@
<section class="hero">
<div class="wrap hero-grid">
<div class="hero-copy">
<span class="hero-kicker">Interne Software · Automatisierung · Betrieb</span>
<h1 class="hero-title">
Moderne Software für Abläufe, die zu lange in Excel und Chats festhängen.
<span class="no-break">EU-first</span> Software für souveräne Betriebe.
</h1>
<p class="hero-lead">
ToolCTRL baut Software für Teams, deren echte Abläufe zu speziell für
Standardtools sind: klare Oberflächen, automatische Übergaben,
belastbare Daten und ein Betrieb, der nicht nach dem Launch endet.
Keine US-Cloud-Pflicht. Kein Agentur-Bullshit. ToolCTRL baut
individuelle SaaS-Systeme schnell, bezahlbar und passend zu echten
Abläufen.
</p>
<div class="hero-actions">
<a class="btn btn-solid" href="#kontakt">Ablauf prüfen lassen</a>
<a class="btn btn-ghost" href="#leistungen">Leistungen ansehen</a>
</div>
<div class="trust-strip" aria-label="ToolCTRL Vertrauenssignale">
<span>Direkter Ansprechpartner</span>
<span>Keine Baukastenlösung</span>
<span>Made in Bruchsal</span>
<span>Made in Germany</span>
<span>DSGVO-konform</span>
<span>Keine US-Cloud nötig</span>
</div>
</div>
<!-- Automatisierung trifft Kontrolle — generisch, kein reales Produkt -->
<div class="hero-visual" aria-hidden="true">
<div class="hero-visual" aria-label="Interaktive Workflow-Control-Grafik">
<div class="visual-frame">
<div class="visual-label">
<span class="dot"></span> Workflow · ctrl
<div class="visual-label" aria-hidden="true">
<span class="window-dots"><i></i><i></i><i></i></span>
</div>
<div class="control-board" data-control-board>
<svg class="control-lines" viewBox="0 0 540 400" preserveAspectRatio="none" aria-hidden="true">
<path data-line="inbox"></path>
<path data-line="docs"></path>
<path data-line="chat"></path>
<path data-line="crm"></path>
<path data-line="team"></path>
<path data-line="report"></path>
</svg>
<div class="logo-node" data-logo-node>
<img src="/assets/emblem-black.svg" alt="" draggable="false" />
</div>
<button class="flow-node is-input" type="button" data-node="inbox" style="--x: 6%; --y: 18%; --r: -2deg;">Anfrage</button>
<button class="flow-node is-input" type="button" data-node="docs" style="--x: 7%; --y: 56%; --r: 1deg;">Dokumente</button>
<button class="flow-node is-input" type="button" data-node="chat" style="--x: 18%; --y: 78%; --r: -1deg;">Chat</button>
<button class="flow-node is-output" type="button" data-node="crm" style="--x: 72%; --y: 16%; --r: 2deg;">CRM</button>
<button class="flow-node is-output" type="button" data-node="team" style="--x: 76%; --y: 56%; --r: -1deg;">Team</button>
<button class="flow-node is-output" type="button" data-node="report" style="--x: 63%; --y: 78%; --r: 1.5deg;">Report</button>
</div>
<svg class="node-graph" viewBox="0 0 540 400" role="presentation">
<defs>
<pattern id="grid" width="26" height="26" patternUnits="userSpaceOnUse">
<path d="M26 0H0V26" fill="none" stroke="#ECECEC" stroke-width="1" />
</pattern>
<linearGradient id="capface" x1="0" y1="0" x2="0" y2="1">
<stop offset="0" stop-color="#2A2A2A" />
<stop offset="1" stop-color="#101010" />
</linearGradient>
</defs>
<rect width="540" height="400" fill="url(#grid)" />
<!-- Leitungen -->
<g class="flow-lines" fill="none" stroke="#1A1A1A" stroke-width="1.6">
<path d="M116 78 C 165 78, 152 182, 200 182" />
<path d="M116 202 C 158 202, 168 202, 200 202" />
<path d="M116 326 C 165 326, 152 224, 200 224" />
<path d="M340 192 C 388 192, 378 118, 424 118" />
<path d="M340 214 C 388 214, 378 292, 424 292" />
</g>
<circle class="flow-signal" r="3.5">
<animateMotion dur="7.5s" repeatCount="indefinite"
path="M116 202 C 158 202, 168 202, 200 202" />
</circle>
<g class="flow-ports" fill="#1A1A1A">
<circle cx="116" cy="78" r="3" /><circle cx="116" cy="202" r="3" />
<circle cx="116" cy="326" r="3" /><circle cx="424" cy="118" r="3" />
<circle cx="424" cy="292" r="3" />
</g>
<!-- Eingangs-Knoten -->
<g class="gnode">
<rect x="24" y="56" width="92" height="44" />
<text x="70" y="83" text-anchor="middle">Daten</text>
</g>
<g class="gnode">
<rect x="24" y="180" width="92" height="44" />
<text x="70" y="207" text-anchor="middle">Auslöser</text>
</g>
<g class="gnode">
<rect x="24" y="304" width="92" height="44" />
<text x="70" y="331" text-anchor="middle">System</text>
</g>
<!-- Ausgangs-Knoten -->
<g class="gnode">
<rect x="424" y="96" width="92" height="44" />
<text x="470" y="123" text-anchor="middle">Aktion</text>
</g>
<g class="gnode">
<rect x="424" y="270" width="92" height="44" />
<text x="470" y="297" text-anchor="middle">Report</text>
</g>
<!-- ToolCTRL-Emblem in der Mitte -->
<image class="graph-emblem" href="/assets/emblem-black.svg" x="190" y="128"
width="160" height="152" />
<g class="flow-ports flow-ports-center" fill="#000000">
<circle cx="200" cy="182" r="3" /><circle cx="200" cy="202" r="3" />
<circle cx="200" cy="224" r="3" /><circle cx="340" cy="192" r="3" />
<circle cx="340" cy="214" r="3" />
</g>
</svg>
</div>
<div class="visual-meta">
<span>Automatisiert</span>
<span>Kontrolliert</span>
<span>Wartbar</span>
</div>
</div>
</div>
</section>
<!-- ============ SYSTEM PROGRESS ============ -->
<section class="mission-rail" aria-label="Von Tool-Chaos zu Betriebssystem">
<!-- ============ KAMPF / WERTE ============ -->
<section class="section stance-section" id="kampf">
<div class="wrap">
<div class="mission-head">
<span>Live System Progress</span>
<strong>Vom Flickwerk zum steuerbaren Ablauf</strong>
<div class="section-head stance-head">
<span class="eyebrow eyebrow-light">Wofür wir kämpfen</span>
<h2 class="section-title">Keine Konzernleine. Keine Folienfabrik.</h2>
<p class="section-intro">
Wir bauen für Mittelständler, die Kontrolle über Daten, Kosten und
Abläufe zurückholen wollen. EU-first, pragmatisch und allergisch gegen
digitale Showprojekte.
</p>
</div>
<div class="mission-track">
<div class="mission-line"></div>
<div class="mission-step is-done">
<span></span>
<b>Chaos sichtbar</b>
<em>Tabellen, Chats, Rückfragen</em>
</div>
<div class="mission-step is-active">
<span></span>
<b>Ablauf modelliert</b>
<em>Status, Rollen, Daten</em>
</div>
<div class="mission-step">
<span></span>
<b>System gebaut</b>
<em>Oberfläche, Logik, Schnittstellen</em>
</div>
<div class="mission-step">
<span></span>
<b>Betrieb läuft</b>
<em>Wartung, Ausbau, Kontrolle</em>
</div>
<div class="stance-grid">
<article class="stance-card">
<span>01</span>
<h3>Digitale Souveränität</h3>
<p>
Keine automatische US-Cloud, kein blinder Plattformgehorsam. Wenn ein
System sinnvoll europäisch laufen kann, wird es so geplant.
</p>
</article>
<article class="stance-card stance-card-dark">
<span>02</span>
<h3>Agenturapparat aus</h3>
<p>
Keine Workshop-Show, keine Tagessatzmaschine, keine sechsstelligen
Projekte, die nach Monaten immer noch vor allem gut aussehen.
</p>
</article>
<article class="stance-card">
<span>03</span>
<h3>Ablauf vor Ego</h3>
<p>
Wir bauen keine Tools für Pitchdecks. Wir bauen Systeme, die im
Alltag führen, Zuständigkeiten klären und Arbeit sichtbar machen.
</p>
</article>
</div>
</div>
</section>
@@ -240,32 +199,32 @@
</div>
<div class="ui-layout">
<aside class="ui-sidebar">
<span class="ui-nav active">Eingang</span>
<span class="ui-nav">Angebote</span>
<span class="ui-nav">Planung</span>
<span class="ui-nav">Abschluss</span>
<button class="ui-nav active" type="button" data-product-tab="eingang">Eingang</button>
<button class="ui-nav" type="button" data-product-tab="angebote">Angebote</button>
<button class="ui-nav" type="button" data-product-tab="planung">Planung</button>
<button class="ui-nav" type="button" data-product-tab="abschluss">Abschluss</button>
</aside>
<div class="ui-main">
<div class="ui-main-head">
<div>
<span class="ui-kicker">Heute · 14 aktive Vorgänge</span>
<strong>Workflow Control</strong>
<span class="ui-kicker" data-product-kicker>Heute · 14 aktive Vorgänge</span>
<strong data-product-title>Workflow Control</strong>
</div>
<span class="ui-pill">3 Blocker</span>
<span class="ui-pill" data-product-pill>3 Blocker</span>
</div>
<div class="ui-flow">
<div class="ui-flow" data-product-flow>
<span class="done">Anfrage</span>
<span class="active">Prüfung</span>
<span>Angebot</span>
<span>Termin</span>
<span>Rechnung</span>
</div>
<div class="ui-metrics">
<div class="ui-metrics" data-product-metrics>
<div><span>Antwortzeit</span><strong>18 min</strong></div>
<div><span>Auto-Schritte</span><strong>74%</strong></div>
<div><span>Offene Übergaben</span><strong>03</strong></div>
</div>
<div class="ui-table">
<div class="ui-table" data-product-table>
<div class="ui-row is-hot"><span>Kunde wartet auf Rückmeldung</span><b>Jetzt</b></div>
<div class="ui-row"><span>Dokumente aus Postfach übernommen</span><b>Auto</b></div>
<div class="ui-row"><span>Team-Zuständigkeit gesetzt</span><b>11:15</b></div>
@@ -277,8 +236,51 @@
</div>
</section>
<!-- ============ VORSPRUNG ============ -->
<section class="section velocity-section" id="vorsprung">
<div class="wrap velocity-grid">
<div class="velocity-copy">
<span class="eyebrow">Unser Vorsprung</span>
<h2 class="section-title">Schneller SaaS bauen. Ohne Baukasten-Vibe.</h2>
<p class="section-intro">
Wir starten nicht mit leerem Repository und endlosen Abstimmungen. Unsere
eigene technische Grundlage deckt Rollen, Datenmodelle, Workflows,
Dashboards, Schnittstellen und Betrieb ab. Dadurch wird Individualsoftware
schneller, ohne nach Standardtool zu riechen.
</p>
</div>
<div class="velocity-stack" aria-label="Warum ToolCTRL schneller liefert">
<article class="velocity-item">
<span>01</span>
<h3>Eigene SaaS-Basis</h3>
<p>Bewährte Infrastruktur statt leerem Repository. Das spart Zeit,
Kosten und Projektchaos.</p>
</article>
<article class="velocity-item">
<span>02</span>
<h3>Früh in den Betrieb</h3>
<p>Wir bauen schnell eine echte Version, testen sie am Ablauf und
verbessern dort, wo Arbeit wirklich passiert.</p>
</article>
<article class="velocity-item">
<span>03</span>
<h3>Budget ins Produkt</h3>
<p>Weniger Reibung, weniger Meeting-Schleifen, weniger Neuentwicklung.
Das Budget landet im System.</p>
</article>
<article class="velocity-item">
<span>04</span>
<h3>Individuell im Ergebnis</h3>
<p>Die Oberfläche und Logik werden auf Ihren Betrieb zugeschnitten.
Die Geschwindigkeit kommt aus unserer Technik.</p>
</article>
</div>
</div>
</section>
<!-- ============ LEISTUNGEN ============ -->
<section class="section" id="leistungen">
<section class="section services-section" id="leistungen">
<div class="wrap">
<div class="section-head">
<span class="eyebrow">Leistungen</span>
@@ -334,11 +336,11 @@
</section>
<!-- ============ BRANCHEN ============ -->
<section class="section section-alt" id="branchen">
<section class="section industry-section" id="branchen">
<div class="wrap">
<div class="section-head">
<span class="eyebrow">Branchen</span>
<h2 class="section-title">Für Teams, bei denen Standardsoftware nie ganz passt.</h2>
<h2 class="section-title">Nicht die Branche ist speziell. Der Ablauf ist es.</h2>
<p class="section-intro">
ToolCTRL ist interessant, wenn Ihr Ablauf speziell genug ist, dass
Baukastenlösungen ständig Workarounds erzwingen und niemand mehr
@@ -346,31 +348,31 @@
</p>
</div>
<div class="industry-grid">
<article class="industry-card">
<div class="industry-map" aria-label="Typische Abläufe">
<div class="industry-row">
<span>01</span>
<h3>Handwerk &amp; Service</h3>
<p>Von Anfrage bis Einsatzplanung: weniger Telefonketten, klare Zuständigkeiten, mobile Rückmeldungen.</p>
<strong>Handwerk &amp; Service</strong>
<p>Anfrage, Angebot, Termin, mobile Rückmeldung und Abschluss in einem kontrollierten Ablauf.</p>
<small>Anfrage → Angebot → Termin → Abschluss</small>
</article>
<article class="industry-card">
</div>
<div class="industry-row">
<span>02</span>
<h3>Events &amp; Organisation</h3>
<p>Anmeldungen, Teilnehmer, Programm und Kommunikation laufen in einem kontrollierten Ablauf zusammen.</p>
<strong>Events &amp; Organisation</strong>
<p>Anmeldungen, Teilnehmer, Programm und Kommunikation laufen sichtbar zusammen.</p>
<small>Ticket → Check-in → Info → Auswertung</small>
</article>
<article class="industry-card">
</div>
<div class="industry-row">
<span>03</span>
<h3>Vereine &amp; Verbände</h3>
<p>Mitglieder, Rollen, Beiträge und Projekte werden verwaltbar, ohne dass Ehrenamt im Tool-Chaos endet.</p>
<strong>Vereine &amp; Verbände</strong>
<p>Mitglieder, Rollen, Beiträge und Projekte werden verwaltbar, auch wenn vieles nebenbei passiert.</p>
<small>Mitglied → Rolle → Beitrag → Projekt</small>
</article>
<article class="industry-card">
</div>
<div class="industry-row">
<span>04</span>
<h3>Lokale Dienstleister</h3>
<p>Leads, Termine, Angebote und Kundenstatus werden sichtbar, statt in Postfächern zu verschwinden.</p>
<strong>Lokale Dienstleister</strong>
<p>Leads, Termine, Angebote und Kundenstatus verschwinden nicht mehr in Postfächern.</p>
<small>Lead → Beratung → Auftrag → Bindung</small>
</article>
</div>
</div>
</div>
</section>
@@ -468,15 +470,18 @@
<div class="wrap">
<div class="section-head event-head">
<span class="eyebrow">Events</span>
<h2 class="section-title">Feldtest statt Hochglanzbehauptung.</h2>
<h2 class="section-title">Lieber ausprobieren als schönreden.</h2>
<p class="section-intro">
TechDay und GameJam zeigen, wie wir arbeiten: nah an echten
Anwendern, lokal verankert und mit sichtbaren Ergebnissen.
TechDay und GameJam zeigen unsere Arbeit dort, wo echte Leute sie
anfassen: lokal, direkt und mit Ergebnissen, über die man reden kann.
</p>
</div>
<div class="event-grid">
<article class="event-card event-card-media">
<div class="event-poster">
<img src="/assets/techday-event.webp" alt="TechDay Bruchsal 2026 Motiv" width="683" height="384" loading="lazy" decoding="async" />
</div>
<div>
<span class="event-label">27. Mai 2026</span>
<h3>TechDay Bruchsal</h3>
@@ -485,6 +490,11 @@
</div>
</article>
<article class="event-card event-card-code">
<div class="mini-terminal" aria-hidden="true">
<span>AI_GAMEJAM</span>
<strong>Human in the Loop</strong>
<em>2 Stunden / KI / spielbar</em>
</div>
<div>
<span class="event-label">TechDay Format</span>
<h3>AI GameJam</h3>
@@ -584,6 +594,6 @@
</div>
</footer>
<script src="/script.js"></script>
<script src="/script.js?v=20260554"></script>
</body>
</html>
+253 -2
View File
@@ -36,6 +36,50 @@
});
}
/* ---- Console-Easter-Eggs fuer neugierige Inspektoren ---- */
var inspectAscii = [
" _______ _______ _______ ___ _______ _______ _______ ",
"| || || || | | || || |",
"|_ _|| _ || _ || | | ||_ _|| ___|",
" | | | | | || | | || | | | | | | |___ ",
" | | | |_| || |_| || |___ | _| | | | ___|",
" | | | || || || |_ | | | |___ ",
" |___| |_______||_______||_______||_______| |___| |_______|"
].join("\n");
var inspectHints = [
"CTRL-KEY EVENT: Inspect gedrueckt. Bitte keine Produktivsysteme anfassen.",
"Hidden combo: window.toolctrl.press()",
"Status: schwarz/weiss. Farbe wurde zurueck in den Werkzeugkoffer gelegt."
];
var inspectLogged = false;
function logControlConsole(reason) {
if (reason === "devtools" && inspectLogged) return;
if (reason === "devtools") inspectLogged = true;
console.log(
"%c" + inspectAscii,
"font-family: monospace; font-weight: 900; color: #000; background: #fff; padding: 10px; border: 3px solid #000;"
);
console.log("%c" + inspectHints[Math.floor(Math.random() * inspectHints.length)],
"font-family: monospace; color: #fff; background: #000; padding: 6px 8px;");
}
window.toolctrl = window.toolctrl || {};
window.toolctrl.press = function () {
console.log("%c[ CTRL ] *klack* Ablauf uebernommen.", "font-family: monospace; font-weight: 900;");
return "pressed";
};
window.addEventListener("load", function () {
setTimeout(function () { logControlConsole("load"); }, 450);
});
setInterval(function () {
var open = Math.abs(window.outerWidth - window.innerWidth) > 160 ||
Math.abs(window.outerHeight - window.innerHeight) > 160;
document.documentElement.toggleAttribute("data-inspecting", open);
if (open) logControlConsole("devtools");
}, 1200);
/* ---- Dezente Scroll-Reveals ---- */
var reduceMotion = window.matchMedia &&
window.matchMedia("(prefers-reduced-motion: reduce)").matches;
@@ -43,16 +87,20 @@
".hero-copy > *",
".hero-visual",
".trust-strip span",
".mission-head",
".mission-step",
".stance-head > *",
".stance-card",
".product-copy > *",
".product-ui",
".velocity-copy > *",
".velocity-item",
".section-head",
".card",
".industry-card",
".step",
".arbeit-copy > *",
".kanban-wrap",
".event-poster",
".mini-terminal",
".event-card",
".kontakt-copy > *",
".contact-promises li",
@@ -82,6 +130,209 @@
revealEls.forEach(function (el) { observer.observe(el); });
}
/* ---- Hero Workflow Nodes: ziehbare Kontrollpunkte ---- */
var board = document.querySelector("[data-control-board]");
if (board) {
var lineSvg = board.querySelector(".control-lines");
var logoNode = board.querySelector("[data-logo-node]");
var nodes = Array.prototype.slice.call(board.querySelectorAll("[data-node]"));
var draggableItems = nodes.concat(logoNode ? [logoNode] : []);
var activeDrag = null;
var lineFrame = 0;
if (logoNode) {
logoNode.addEventListener("dragstart", function (e) {
e.preventDefault();
});
}
function boardRect() {
return board.getBoundingClientRect();
}
function centerOf(el, b) {
var r = el.getBoundingClientRect();
return {
x: r.left - b.left + r.width / 2,
y: r.top - b.top + r.height / 2
};
}
function clamp(value, min, max) {
return Math.max(min, Math.min(max, value));
}
function updateLines() {
if (!lineSvg || !logoNode) return;
var b = boardRect();
var target = centerOf(logoNode, b);
lineSvg.setAttribute("viewBox", "0 0 " + b.width + " " + b.height);
nodes.forEach(function (node) {
var path = lineSvg.querySelector('[data-line="' + node.dataset.node + '"]');
if (!path) return;
var nodeCenter = centerOf(node, b);
var isOutput = node.classList.contains("is-output");
var start = isOutput ? target : nodeCenter;
var end = isOutput ? nodeCenter : target;
var bend = Math.max(44, Math.abs(end.x - start.x) * 0.38);
var c1x = start.x + (end.x > start.x ? bend : -bend);
var c2x = end.x + (end.x > start.x ? -bend : bend);
var d = "M " + start.x + " " + start.y +
" C " + c1x + " " + start.y +
", " + c2x + " " + end.y +
", " + end.x + " " + end.y;
path.classList.toggle("is-output", isOutput);
path.setAttribute("d", d);
});
lineFrame = 0;
}
function requestLineUpdate() {
if (lineFrame) return;
lineFrame = window.requestAnimationFrame(updateLines);
}
draggableItems.forEach(function (item) {
item.addEventListener("pointerdown", function (e) {
var r = item.getBoundingClientRect();
if (item === logoNode) item.classList.add("is-positioned");
activeDrag = {
node: item,
isLogo: item === logoNode,
offsetX: e.clientX - r.left,
offsetY: e.clientY - r.top
};
item.classList.add("is-dragging");
item.setPointerCapture(e.pointerId);
e.preventDefault();
});
item.addEventListener("pointermove", function (e) {
if (!activeDrag || activeDrag.node !== item) return;
var b = boardRect();
var x = clamp(e.clientX - b.left - activeDrag.offsetX, 8, b.width - item.offsetWidth - 8);
var y = clamp(e.clientY - b.top - activeDrag.offsetY, 8, b.height - item.offsetHeight - 8);
item.style.left = x + "px";
item.style.top = y + "px";
if (activeDrag.isLogo) {
item.classList.add("is-positioned");
} else {
item.style.removeProperty("--x");
item.style.removeProperty("--y");
}
requestLineUpdate();
});
item.addEventListener("pointerup", function (e) {
if (!activeDrag || activeDrag.node !== item) return;
item.classList.remove("is-dragging");
item.releasePointerCapture(e.pointerId);
activeDrag = null;
requestLineUpdate();
});
item.addEventListener("pointercancel", function () {
item.classList.remove("is-dragging");
activeDrag = null;
});
});
window.addEventListener("resize", requestLineUpdate, { passive: true });
updateLines();
setTimeout(requestLineUpdate, 150);
}
/* ---- Produktwirkung: klickbare Workflow-Zustaende ---- */
var productUi = document.querySelector(".product-ui");
if (productUi) {
var productStates = {
eingang: {
kicker: "Heute · 14 aktive Vorgänge",
title: "Workflow Control",
pill: "3 Blocker",
flow: ["Anfrage", "Prüfung", "Angebot", "Termin", "Rechnung"],
active: 1,
done: 0,
metrics: [["Antwortzeit", "18 min"], ["Auto-Schritte", "74%"], ["Offene Übergaben", "03"]],
rows: [["Kunde wartet auf Rückmeldung", "Jetzt", "is-hot"], ["Dokumente aus Postfach übernommen", "Auto", ""], ["Team-Zuständigkeit gesetzt", "11:15", ""], ["Status an Leitung gemeldet", "Erledigt", "is-done"]]
},
angebote: {
kicker: "Vertrieb · 8 Angebote offen",
title: "Angebote steuern",
pill: "2 fällig",
flow: ["Lead", "Kalkulation", "Freigabe", "Versand", "Follow-up"],
active: 2,
done: 1,
metrics: [["Durchlauf", "2,4 h"], ["Vorlagen", "91%"], ["Rückfragen", "05"]],
rows: [["Angebot braucht interne Freigabe", "Heute", "is-hot"], ["PDF aus Kundendaten erstellt", "Auto", ""], ["Nachfass-Termin gesetzt", "Morgen", ""], ["Alte Version archiviert", "Erledigt", "is-done"]]
},
planung: {
kicker: "Team · 21 Einsätze geplant",
title: "Planung sichtbar",
pill: "1 Konflikt",
flow: ["Auftrag", "Ressource", "Slot", "Route", "Update"],
active: 2,
done: 1,
metrics: [["Auslastung", "82%"], ["Auto-Routen", "68%"], ["Konflikte", "01"]],
rows: [["Termin überschneidet sich", "Prüfen", "is-hot"], ["Route für Außendienst gebaut", "Auto", ""], ["Materialliste angehängt", "09:40", ""], ["Kunde informiert", "Erledigt", "is-done"]]
},
abschluss: {
kicker: "Abschluss · 36 Vorgänge fertig",
title: "Betrieb im Blick",
pill: "0 kritisch",
flow: ["Abnahme", "Doku", "Rechnung", "Feedback", "Archiv"],
active: 3,
done: 2,
metrics: [["Abnahmen", "96%"], ["Auto-Doku", "88%"], ["Offen", "00"]],
rows: [["Feedback für nächste Version notiert", "Neu", ""], ["Rechnung vorbereitet", "Auto", ""], ["Abnahme protokolliert", "13:20", "is-done"], ["Projekt sauber archiviert", "Erledigt", "is-done"]]
}
};
var productTabs = Array.prototype.slice.call(productUi.querySelectorAll("[data-product-tab]"));
var productKicker = productUi.querySelector("[data-product-kicker]");
var productTitle = productUi.querySelector("[data-product-title]");
var productPill = productUi.querySelector("[data-product-pill]");
var productFlow = productUi.querySelector("[data-product-flow]");
var productMetrics = productUi.querySelector("[data-product-metrics]");
var productTable = productUi.querySelector("[data-product-table]");
function setProductState(key) {
var state = productStates[key];
if (!state) return;
productUi.classList.add("is-switching");
productTabs.forEach(function (tab) {
tab.classList.toggle("active", tab.dataset.productTab === key);
});
window.setTimeout(function () {
if (productKicker) productKicker.textContent = state.kicker;
if (productTitle) productTitle.textContent = state.title;
if (productPill) productPill.textContent = state.pill;
if (productFlow) {
productFlow.innerHTML = state.flow.map(function (label, index) {
var cls = index === state.active ? "active" : (index <= state.done ? "done" : "");
return '<span class="' + cls + '">' + label + '</span>';
}).join("");
}
if (productMetrics) {
productMetrics.innerHTML = state.metrics.map(function (metric) {
return "<div><span>" + metric[0] + "</span><strong>" + metric[1] + "</strong></div>";
}).join("");
}
if (productTable) {
productTable.innerHTML = state.rows.map(function (row) {
return '<div class="ui-row ' + row[2] + '"><span>' + row[0] + '</span><b>' + row[1] + '</b></div>';
}).join("");
}
productUi.classList.remove("is-switching");
}, 90);
}
productTabs.forEach(function (tab) {
tab.addEventListener("click", function () {
setProductState(tab.dataset.productTab);
});
});
}
/* ---- Lead-Formular ---- */
var form = document.getElementById("lead-form");
var status = document.getElementById("form-status");
+1392 -413
View File
File diff suppressed because it is too large. Load diff
+13 -10
View File
@@ -12,11 +12,12 @@
<meta property="og:title" content="ToolCTRL beim TechDay Bruchsal 2026" />
<meta property="og:description" content="Vortrag, AI GameJam und mITapp beim ersten Bruchsaler TechDay am 27. Mai 2026." />
<meta property="og:url" content="https://tool-ctrl.de/techday" />
<meta property="og:image" content="https://tool-ctrl.de/assets/techday-event.png" />
<meta property="og:image" content="https://tool-ctrl.de/assets/techday-event.webp" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="theme-color" content="#0A0A0A" />
<link rel="icon" type="image/png" href="/assets/favicon.png" />
<link rel="stylesheet" href="/styles.css?v=20260525" />
<link rel="preload" href="/assets/fonts/space-grotesk-latin.woff2" as="font" type="font/woff2" crossorigin />
<link rel="stylesheet" href="/styles.css?v=20260562" />
</head>
<body>
@@ -28,11 +29,12 @@
</a>
<nav class="nav" aria-label="Hauptnavigation">
<a href="/#leistungen">Leistungen</a>
<a href="/#branchen">Branchen</a>
<a href="/#vorgehen">Vorgehen</a>
<a href="/#arbeit">Organisation</a>
<a href="/techday">TechDay</a>
<a href="/gamejam">GameJam</a>
<a class="btn btn-solid btn-sm" href="/#kontakt">Kontakt aufnehmen</a>
<a class="btn btn-solid btn-sm" href="/#kontakt">Ablauf prüfen</a>
</nav>
<button class="nav-toggle" aria-label="Menü" aria-expanded="false">
<span></span><span></span>
@@ -40,11 +42,12 @@
</div>
<div class="mobile-nav" hidden>
<a href="/#leistungen">Leistungen</a>
<a href="/#branchen">Branchen</a>
<a href="/#vorgehen">Vorgehen</a>
<a href="/#arbeit">Organisation</a>
<a href="/techday">TechDay</a>
<a href="/gamejam">GameJam</a>
<a class="btn btn-solid" href="/#kontakt">Kontakt aufnehmen</a>
<a class="btn btn-solid" href="/#kontakt">Ablauf prüfen</a>
</div>
</header>
@@ -87,7 +90,7 @@
mit der mITapp als digitalem Zuhause des Events.
</p>
</div>
<img class="td-feature-img" src="/assets/techday-event.png"
<img class="td-feature-img" src="/assets/techday-event.webp" width="683" height="384" decoding="async" fetchpriority="high"
alt="TechDay Bruchsal 2026: Human in the Loop" />
</div>
</div>
@@ -134,7 +137,7 @@
<aside class="speaker-card">
<div class="sp-label">Speaker</div>
<div class="sp-head">
<img class="sp-photo" src="/assets/speaker-david.jpg" alt="David Bertram" />
<img class="sp-photo" src="/assets/speaker-david.webp" alt="David Bertram" width="320" height="320" loading="lazy" decoding="async" />
<div>
<div class="sp-name">David Bertram</div>
<div class="sp-role">Co-Founder &amp; Head of Product, ToolCTRL</div>
@@ -167,15 +170,15 @@
<div class="mitapp-shots">
<figure class="shot">
<img src="/assets/mitapp-dashboard.png" alt="mITapp Dashboard-Ansicht" />
<img src="/assets/mitapp-dashboard.webp" alt="mITapp Dashboard-Ansicht" width="1100" height="825" loading="lazy" decoding="async" />
<figcaption>Dashboard</figcaption>
</figure>
<figure class="shot">
<img src="/assets/mitapp-roadmap.png" alt="mITapp Event-Roadmap" />
<img src="/assets/mitapp-roadmap.webp" alt="mITapp Event-Roadmap" width="1100" height="825" loading="lazy" decoding="async" />
<figcaption>Event-Roadmap</figcaption>
</figure>
<figure class="shot">
<img src="/assets/mitapp-qr.png" alt="mITapp Networking per QR-Code" />
<img src="/assets/mitapp-qr.webp" alt="mITapp Networking per QR-Code" width="1100" height="825" loading="lazy" decoding="async" />
<figcaption>Networking per QR-Code</figcaption>
</figure>
</div>
@@ -268,6 +271,6 @@
</div>
</footer>
<script src="/script.js"></script>
<script src="/script.js?v=20260554"></script>
</body>
</html>
+54 -4
View File
@@ -16,6 +16,7 @@ const path = require("path");
const crypto = require("crypto");
const os = require("os");
const net = require("net");
const zlib = require("zlib");
const ROOT = __dirname;
const PUBLIC_DIR = path.join(ROOT, "public");
@@ -65,6 +66,7 @@ const MIME = {
".png": "image/png",
".jpg": "image/jpeg",
".jpeg": "image/jpeg",
".webp": "image/webp",
".ico": "image/x-icon",
".json": "application/json; charset=utf-8",
".woff2": "font/woff2"
@@ -77,11 +79,35 @@ const CLEAN_ROUTES = {
"/datenschutz": "/datenschutz.html"
};
const IMMUTABLE_EXTS = new Set([".webp", ".svg", ".woff2", ".png", ".jpg", ".jpeg", ".ico"]);
const COMPRESSIBLE_EXTS = new Set([".html", ".css", ".js", ".svg", ".json", ".txt"]);
function redirect(res, location) {
res.writeHead(308, { Location: location });
res.end();
}
function cacheControlFor(urlPath, ext, cacheKey) {
if (urlPath.startsWith("/gamejam-games/")) return "public, max-age=60";
if (ext === ".html") return "no-cache";
if (ext === ".css" || ext === ".js") {
return cacheKey ? "public, max-age=31536000, immutable" : "no-cache";
}
if (IMMUTABLE_EXTS.has(ext)) return "public, max-age=31536000, immutable";
return "no-cache";
}
function etagFor(stat) {
return 'W/"' + stat.size.toString(16) + "-" + Math.floor(stat.mtimeMs).toString(16) + '"';
}
function preferredEncoding(req) {
const accepted = req.headers["accept-encoding"] || "";
if (/\bbr\b/.test(accepted)) return "br";
if (/\bgzip\b/.test(accepted)) return "gzip";
return null;
}
/* ---------- Lead-Speicher vorbereiten ---------- */
function ensureLeadStore() {
if (!fs.existsSync(LEADS_DIR)) fs.mkdirSync(LEADS_DIR, { recursive: true });
@@ -163,11 +189,35 @@ function serveStatic(req, res) {
return;
}
const ext = path.extname(filePath).toLowerCase();
res.writeHead(200, {
const etag = etagFor(stat);
const headers = {
"Content-Type": MIME[ext] || "application/octet-stream",
"Cache-Control": "no-cache"
});
fs.createReadStream(filePath).pipe(res);
"Cache-Control": cacheControlFor(urlPath, ext, parsedUrl.search),
"ETag": etag,
"Last-Modified": stat.mtime.toUTCString(),
"X-Content-Type-Options": "nosniff"
};
if (COMPRESSIBLE_EXTS.has(ext)) headers["Vary"] = "Accept-Encoding";
if ((req.headers["if-none-match"] || "").includes(etag)) {
res.writeHead(304, headers);
res.end();
return;
}
let stream = fs.createReadStream(filePath);
const encoding = COMPRESSIBLE_EXTS.has(ext) ? preferredEncoding(req) : null;
if (encoding === "br") {
headers["Content-Encoding"] = "br";
stream = stream.pipe(zlib.createBrotliCompress());
} else if (encoding === "gzip") {
headers["Content-Encoding"] = "gzip";
stream = stream.pipe(zlib.createGzip({ level: 6 }));
}
res.writeHead(200, headers);
stream.pipe(res);
});
}