Move Projekt-KIQ-HP bahn/ -> dhive/ (dhive project); add steering files

This commit is contained in:
2026-06-30 21:15:59 +02:00
parent d9291f53e4
commit b0e452708a
124 changed files with 74 additions and 0 deletions
+50
View File
@@ -0,0 +1,50 @@
import React from 'react';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import Navigation from './components/Navigation';
import Footer from './components/Footer';
import Home from './pages/Home';
import Impressum from './pages/Impressum';
import Datenschutz from './pages/Datenschutz';
import AccessRequest from './pages/AccessRequest';
import RestrictedArea from './pages/RestrictedArea';
import AdminDashboard from './pages/AdminDashboard';
import Login from './pages/Login';
import ProtectedRoute from './components/ProtectedRoute';
import UseCases from './pages/UseCases';
import BottomDock from './components/BottomDock';
import BackgroundPattern from './components/BackgroundPattern';
import ScrollToTop from './components/ScrollToTop';
function App() {
return (
<Router>
<ScrollToTop />
<div className="app-root">
<BackgroundPattern />
<Navigation />
<Routes>
<Route path="/" element={<Home />} />
<Route path="/impressum" element={<Impressum />} />
<Route path="/datenschutz" element={<Datenschutz />} />
<Route path="/request-access" element={<AccessRequest />} />
<Route path="/login" element={<Login />} />
<Route path="/restricted" element={
<ProtectedRoute allowedRoles={['admin', 'investor']}>
<RestrictedArea />
</ProtectedRoute>
} />
<Route path="/admin" element={
<ProtectedRoute allowedRoles={['admin']}>
<AdminDashboard />
</ProtectedRoute>
} />
<Route path="/usecases" element={<UseCases />} />
</Routes>
<Footer />
<BottomDock />
</div>
</Router>
);
}
export default App;
Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

@@ -0,0 +1,60 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Ebene_1" x="0px" y="0px" viewBox="0 0 680.3 286.3" style="enable-background:new 0 0 680.3 286.3;" xml:space="preserve">
<style type="text/css">
.st0{clip-path:url(#SVGID_2_);fill:url(#SVGID_3_);}
.st1{clip-path:url(#SVGID_5_);fill:url(#SVGID_6_);}
.st2{clip-path:url(#SVGID_8_);fill:#575756;}
.st3{fill:#7BB33D;}
</style>
<g>
<defs>
<path id="SVGID_1_" d="M64.4,159.3c-13.3-13.3-13.3-34.9,0-48.2l36.9-36.9l36.8,36.8l0.2,0.2c0.1,0.1,0.1,0.1,0.2,0.2 c12.5,12.7,13,33,1.3,46.3c-0.6,0.7-1.1,1.1-1.6,1.6c-0.5,0.5-1.1,1.1-1.7,1.7l-0.3,0.3l-34.9,35L64.4,159.3z M54.7,101.5 c-18.6,18.6-18.6,48.8,0,67.5l46.6,46.6l44.3-44.3c0.8-0.7,1.6-1.5,2.4-2.2c0.7-0.7,1.4-1.5,2.1-2.3c16.4-18.7,15.8-47-1.9-64.9 c-0.1-0.1-0.1-0.2-0.2-0.2c-0.1-0.1-0.2-0.2-0.3-0.3l-46.3-46.3L54.7,101.5z"></path>
</defs>
<clipPath id="SVGID_2_">
<use xlink:href="#SVGID_1_" style="overflow:visible;"></use>
</clipPath>
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="-0.797" y1="838.1785" x2="0.203" y2="838.1785" gradientTransform="matrix(0 160.5962 160.5962 0 -134507.0469 182.9318)">
<stop offset="0" style="stop-color:#00652D"></stop>
<stop offset="0.2285" style="stop-color:#2D762E"></stop>
<stop offset="0.7433" style="stop-color:#6A9E2A"></stop>
<stop offset="1" style="stop-color:#83B025"></stop>
</linearGradient>
<rect x="36.1" y="54.9" class="st0" width="130.4" height="160.6"></rect>
</g>
<g>
<defs>
<path id="SVGID_4_" d="M82.8,140.9c-3.1-3.1-3.1-8.1,0-11.2l24.1,24.1l-5.6,5.6L82.8,140.9z M105.6,115.4c0.2,0.2,0.3,0.3,0.4,0.5 l14.1,14.1c2.6,2.9,2.6,7.5,0.1,10.5c-0.2,0.2-0.3,0.3-0.4,0.4c0,0,0,0,0,0l-24.2-24.2l-12.8-12.8l0,0l-12.9,12.9l0,0 c-10.1,10.2-10.1,26.7,0,36.9l31.3,31.3l29.5-29.5l0.5-0.5c0.5-0.4,0.9-0.9,1.3-1.3c0.3-0.3,0.7-0.7,1.2-1.2 c1.4-1.6,2.6-3.4,3.6-5.2c4.9-9.4,3.6-21.1-3.6-29.3l-32.4-32.4C96.2,95.2,97.7,107.2,105.6,115.4"></path>
</defs>
<clipPath id="SVGID_5_">
<use xlink:href="#SVGID_4_" style="overflow:visible;"></use>
</clipPath>
<linearGradient id="SVGID_6_" gradientUnits="userSpaceOnUse" x1="-1.2865" y1="835.8968" x2="-0.2865" y2="835.8968" gradientTransform="matrix(0 99.4949 99.4949 0 -83066.4766 213.5198)">
<stop offset="0" style="stop-color:#C6C6C6"></stop>
<stop offset="0.3036" style="stop-color:#ACACAB"></stop>
<stop offset="0.95" style="stop-color:#706F6F"></stop>
<stop offset="1" style="stop-color:#706F6F"></stop>
</linearGradient>
<rect x="59.8" y="85.5" class="st1" width="82.4" height="99.5"></rect>
</g>
<g>
<defs>
<rect id="SVGID_7_" x="24.9" y="35.3" width="545.1" height="218"></rect>
</defs>
<clipPath id="SVGID_8_">
<use xlink:href="#SVGID_7_" style="overflow:visible;"></use>
</clipPath>
<path class="st2" d="M213.3,93.3c-9.6,28.4-18,56.2-25.3,83.2c5.1,0.7,11.4,0.9,16.9,0.9l5.7-20.4h24l5.6,20.4 c6.2,0,12-0.1,18.3-0.9c-7.3-26.7-15.9-55.2-24.8-83.2H213.3z M214.7,141.8l6.2-22.6c0.5-2.1,0.8-4.2,0.9-7.1h1.2 c0.1,2.9,0.5,5,1,7.1l6.2,22.6H214.7z"></path>
<path class="st2" d="M451.1,92.1c-21,0-35.9,12.7-35.9,43.6c0,30.7,14.4,42.6,36,42.6c21,0,35.9-12.7,35.9-43.1 C487.1,104,472.7,92.1,451.1,92.1 M451.2,162.6c-11.3,0-16.3-6.8-16.3-27.4c0-21.4,5-27.4,16.1-27.4c10.8,0,16.3,6.1,16.3,27.4 C467.3,156.2,462.6,162.6,451.2,162.6"></path>
<path class="st2" d="M553.7,152.3c0-25.3-34.5-23.8-34.5-36.3c0-5.5,3-8.6,9.6-8.6c5.8,0,13.8,0.9,19.4,2.4 c1.1-5.1,1.9-10.9,2.1-15.6c-5.8-1.4-13.2-2.1-18.5-2.1c-18.4,0-31.4,8.7-31.4,25.1c0,26.3,34.6,23.2,34.6,36.9 c0,5.6-3,8.8-9.8,8.8c-6.7,0-15.5-1.6-21.6-4.2c-1.4,4.5-2.9,10.1-3.6,15.8c6.8,2.9,15.8,3.9,22.9,3.9 C540.7,178.3,553.7,169.8,553.7,152.3"></path>
<path class="st2" d="M311.6,139.6c8.1-3,15.1-11.1,15.1-22.2c0-17.8-12.8-25-28.2-25c-8.4,0-16.8,0.5-27.7,1.7v82.3c0,0,0,0,0,0 s0,0,0,0h0h0c0,0,0,0,0.1,0c0,0,0.1,0,0.1,0c0,0,0,0,0,0c0.1,0,0.1,0,0.2,0h0c0,0,0.1,0,0.1,0c0.2,0,0.5,0,0.8,0.1c0,0,0,0,0.1,0 c0.1,0,0.2,0,0.2,0c0.1,0,0.1,0,0.2,0c0.1,0,0.1,0,0.2,0c0.1,0,0.2,0,0.4,0c0.1,0,0.1,0,0.2,0c0.1,0,0.2,0,0.3,0c0.1,0,0.1,0,0.2,0 c0.1,0,0.3,0,0.4,0c0.1,0,0.1,0,0.2,0c0.2,0,0.3,0,0.5,0c0,0,0,0,0,0c0.2,0,0.4,0,0.6,0c0,0,0.1,0,0.1,0c0.2,0,0.4,0,0.6,0 c0,0,0,0,0.1,0c0.2,0,0.4,0,0.7,0c0,0,0,0,0,0c0.2,0,0.4,0,0.7,0c0,0,0.1,0,0.1,0c3.6,0.2,7.8,0.4,10.7,0.4V177h0v-31.8h7.6 c3.1,3.6,7.3,10.9,11.6,20l5.5,12.3c6.1,0,13.4-0.4,19.7-1.1l-9.1-19.1C320.4,150.1,316.3,144.1,311.6,139.6 M295.8,131.4h-7.1 v-23.8c2.6-0.2,5.3-0.4,8.6-0.4c7.1,0,10.9,4,10.9,11.5C308.3,127.8,302.9,131.4,295.8,131.4"></path>
<path class="st2" d="M398.1,219.7h4.7v6.2c-0.9,0.3-2.9,0.4-4.3,0.4c-4.8,0-7.5-3.6-7.5-11.8c0-10,3.3-12.3,8.6-12.3 c3.3,0,7.1,0.8,9.5,2c0.6-2.4,1.1-5.3,1.2-7.4c-2.8-1.2-7.5-1.8-11.2-1.8c-9.6,0-16.8,5.7-16.8,19.2c0,12.4,5.7,19.3,16.3,19.3 c4.7,0,9.8-1.2,12.5-2.6v-18.4h-13.3C397.5,215,397.7,217.6,398.1,219.7"></path>
<path class="st2" d="M467.4,195.1c-9.4,0-16.1,5.7-16.1,19.5c0,13.7,6.4,19.1,16.1,19.1c9.4,0,16.1-5.7,16.1-19.3 C483.5,200.4,477.1,195.1,467.4,195.1 M467.4,226.6c-5.1,0-7.3-3.1-7.3-12.3c0-9.6,2.2-12.3,7.2-12.3c4.8,0,7.3,2.7,7.3,12.3 C474.7,223.8,472.6,226.6,467.4,226.6"></path>
<path class="st2" d="M512.1,218.7c0,5.6-1.9,7.3-6.6,7.3c-4.7,0-6.4-1.6-6.4-7.3v-23.1h-8.2v22.7c0,11.7,5.6,15.3,14.5,15.3 c9.5,0,14.5-4.8,14.5-15.3v-22.7h-7.8V218.7z"></path>
<path class="st2" d="M541.6,195.2c-4.4,0-8.5,0.3-12.3,0.8v37.1h8.1v-11.7h3.8c6.7,0,13-3.8,13-13.6 C554.2,199.5,549.2,195.2,541.6,195.2 M540.5,214.6h-3.1v-12.7c1.3-0.1,2.4-0.2,3.7-0.2c3.1,0,5.1,2.3,5.1,6 C546.1,212.2,544.2,214.6,540.5,214.6"></path>
<path class="st2" d="M443.4,224.3c-1.6-3.2-3.4-5.9-5.5-7.9c3.6-1.3,6.8-4.9,6.8-10c0-8-5.7-11.2-12.6-11.2 c-3.8,0-7.5,0.2-12.4,0.8v37l0,0c0,0,0.9,0.1,2.1,0.1c0.2,0,0.4,0,0.7,0h0c0.5,0,1,0.1,1.5,0.1c0,0,0,0,0,0c0.2,0,0.5,0,0.7,0 c0.1,0,0.1,0,0.2,0c0.2,0,0.3,0,0.5,0c0.1,0,0.2,0,0.3,0c0.2,0,0.3,0,0.5,0c0.1,0,0.2,0,0.3,0c0.2,0,0.3,0,0.5,0c0.1,0,0.1,0,0.2,0 c0.2,0,0.4,0,0.6,0v-1.1h0v-13.4h3.4c1.4,1.6,3.3,4.9,5.2,9l2.4,5.5c3,0,6.1-0.2,8.8-0.5L443.4,224.3z M430.8,212.7h-3.2V202 c1.2-0.1,2.4-0.2,3.8-0.2c3.2,0,4.9,1.8,4.9,5.2C436.4,211.1,434,212.7,430.8,212.7"></path>
<path class="st2" d="M389,93.2L374.3,149c-0.6,2.1-1,4.5-1.1,7H372c-0.2-2.5-0.6-4.8-1.2-7l-14.5-55.8l0,0c0,0-12.4,0.1-17.8,0.6 c-0.2,0-0.4,0-0.5,0.1c7,28.1,14.9,55.9,23.9,83.2H382c9.2-27.6,17.5-54.9,24.7-83.2c-0.2,0-0.5-0.1-0.8-0.1 C400.9,93.4,391,93.2,389,93.2"></path>
</g>
<rect x="674.7" y="-16.4" class="st3" width="5.7" height="303.3"></rect>
</svg>

After

Width:  |  Height:  |  Size: 6.4 KiB

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" id="Layer_1" data-name="Layer 1" viewBox="0 0 500 117">
<defs>
<style>.cls-1{fill:#fecc00;}</style>
</defs>
<polygon points="487.75 56.11 382.85 3.39 292.39 3.39 487.72 101.1 487.75 56.16 487.75 56.11"></polygon>
<polygon class="cls-1" points="487.73 3.39 382.85 3.39 487.75 56.11 487.73 3.39"></polygon>
<polygon points="72.44 10.75 12.55 10.75 12.55 96.91 73.03 96.91 73.03 87.02 23.94 87.02 23.94 57.17 69.19 57.17 69.19 47.94 23.94 47.94 23.94 20.62 72.44 20.62 72.44 10.75"></polygon>
<path d="M124.14,52.62c-.45-5.92-1.62-9.17-4.35-12.41-4.17-4.88-11.57-7.61-20.68-7.61C84.47,32.6,75.24,39.68,75.24,51a14.57,14.57,0,0,0,4.55,10.93c2.48,2.28,5.66,3.7,12.36,5.33,1.56.39,6,1.51,8.19,2,12.61,3.06,15.73,5.13,15.73,10.6,0,6.17-6.1,10.27-15.47,10.27C90.33,90.14,85,86,84,77.2H73.87c.52,14,9.83,21.46,26.8,21.46,15.73,0,26.08-7.8,26.08-19.84a14.93,14.93,0,0,0-6-12.28c-3.84-2.92-8.4-4.49-18.27-6.76-1.95-.46-4-.92-5.92-1.44a31.32,31.32,0,0,1-6.18-1.88c-3.26-1.5-4.62-3.51-4.62-6.7,0-5.39,4.75-8.53,12.88-8.53,9.43,0,14.12,3.52,15.21,11.39Z"></path>
<path d="M184.68,41.23c-10.33,0-16.59,6.39-18.27,18.6h36.41c-1-11.7-7.66-18.6-18.14-18.6m.85,57.43c-18.47,0-29.79-12.29-29.79-32.58,0-19.64,12-33.48,29.21-33.48,11.5,0,21,6.17,25.49,16.38,1.93,4.49,3,10.73,3,17.68v1.63H166.34c.39,14.44,7,21.85,19.45,21.85,9,0,13.84-3.83,16.77-13.26H212.7c-3.24,14.5-12.48,21.78-27.17,21.78"></path>
<path d="M277.74,41.23c-10.35,0-16.59,6.39-18.27,18.6h36.41c-1-11.7-7.68-18.6-18.14-18.6m.84,57.43c-18.46,0-29.78-12.29-29.78-32.58,0-19.64,12-33.48,29.2-33.48,11.51,0,21,6.17,25.48,16.38,2,4.49,3,10.73,3,17.68v1.63H259.4c.39,14.44,6.89,21.85,19.44,21.85,9,0,13.86-3.83,16.77-13.26h10.08c-3.18,14.5-12.41,21.78-27.11,21.78"></path>
<path d="M157.69,34.42H145.21V15.81H135V34.42H124.47V42.8H135V74l.07,10.34c.06,10.21,3.71,13.58,14.75,13.58a64.72,64.72,0,0,0,7.87-.51V88.65a21.09,21.09,0,0,1-5.53.71c-5.92,0-6.95-1.37-6.95-9.61V42.8h12.48Z"></path>
<path d="M345.29,32.6c-11.82,0-18.79,4.42-23.47,14.88V34.42h-9.56V96.91h10.28V72.59c0-14,1.3-19.25,6-24A18.36,18.36,0,0,1,342,43.13c.66,0,1.83.07,3.25.19Z"></path>
<path d="M252.58,32.6c-11.84,0-18.8,4.42-23.49,14.88V34.42h-9.55V96.91h10.27V72.59c0-14,1.3-19.25,6-24a18.38,18.38,0,0,1,13.52-5.46c.66,0,1.83.07,3.27.19Z"></path>
<rect x="2.73" y="3.39" width="2.16" height="110.3"></rect>
<rect x="495.11" y="3.32" width="2.16" height="110.29"></rect>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="130" height="60" viewBox="0 0 130 60" fill="none">
<g clip-path="url(#clip0)">
<path d="M84.8641 31.3476V28.2498H92.688V35.2314C91.7944 36.4259 90.6326 37.385 89.2998 38.0286C87.967 38.6721 86.5021 38.9813 85.0277 38.9302C79.6936 38.9302 75.6499 35.1666 75.6499 29.6831C75.6484 28.4397 75.8911 27.2086 76.3638 26.0621C76.8365 24.9155 77.5296 23.8767 78.4024 23.0066C79.2752 22.1365 80.3101 21.4527 81.4463 20.9954C82.5825 20.538 83.7971 20.3164 85.0186 20.3435C86.4307 20.3357 87.8268 20.6487 89.1049 21.2598C90.383 21.8709 91.5109 22.7647 92.4063 23.8759L89.9619 26.1045C89.3787 25.3418 88.6374 24.7193 87.7908 24.2814C86.9443 23.8435 86.0132 23.6008 85.064 23.5708C81.8654 23.5708 79.5301 26.2339 79.5301 29.6369C79.5301 33.2155 81.72 35.6937 85.064 35.6937C86.5502 35.6595 87.9713 35.0666 89.0532 34.0292V31.3476H84.8641Z" fill="#00616D"></path>
<path d="M103.856 23.5709C100.739 23.5709 98.4766 26.234 98.4766 29.637C98.4766 33.0399 100.739 35.6938 103.856 35.6938C106.973 35.6938 109.208 33.0399 109.208 29.637C109.208 26.234 106.955 23.5709 103.856 23.5709ZM103.856 38.8933C102.064 38.8696 100.319 38.3072 98.8402 37.2768C97.3615 36.2464 96.2152 34.7941 95.5455 33.1024C94.8758 31.4108 94.7126 29.5554 95.0765 27.7696C95.4403 25.9839 96.3149 24.3475 97.5904 23.0662C98.8658 21.785 100.485 20.9162 102.244 20.569C104.004 20.2218 105.825 20.4118 107.478 21.1151C109.132 21.8184 110.544 23.0036 111.538 24.5215C112.531 26.0395 113.061 27.8225 113.061 29.6462C113.061 30.8708 112.822 32.0831 112.358 33.2129C111.894 34.3428 111.214 35.3675 110.358 36.2278C109.502 37.0881 108.486 37.7667 107.37 38.2243C106.254 38.6818 105.059 38.9093 103.856 38.8933Z" fill="#00616D"></path>
<path d="M126.755 38.5879L118.686 27.3805V38.5879H115.088V20.6855H118.259L126.401 31.9115V20.6855H129.999V38.5879H126.755Z" fill="#00616D"></path>
<path d="M22.7818 38.5879V30.9128H15.3214V38.5879H11.5867V20.6855H15.3214V27.8151H22.7818V20.6855H26.5166V38.5879H22.7818Z" fill="#00616D"></path>
<path d="M28.7793 38.5977V20.6953H40.4016V23.7838H32.4777V27.8248H40.4016V30.9226H32.4777V35.4999H40.4016V38.5977H28.7793Z" fill="#00616D"></path>
<path d="M53.7684 38.5879L49.8247 32.4478L45.8537 38.5879H41.4556L47.5802 29.4795L41.7009 20.6763H46.2262L49.9246 26.4835L53.6412 20.6763H58.0393L52.16 29.424L58.2938 38.5879H53.7684Z" fill="#00616D"></path>
<path d="M65.4908 32.2722H69.6344L67.6262 26.2615L65.4908 32.2722ZM71.788 38.5879L70.6703 35.259H64.4912L63.3281 38.5879H59.3389L66.4358 20.6855H69.3164L75.8408 38.5879H71.788Z" fill="#00616D"></path>
<path d="M23.4808 54.7984L3.73476 42.3333V16.9315L23.4808 4.46635L31.332 9.4228L34.8759 7.185L23.4808 0L0 14.8139V44.4508L23.4808 59.2647L34.8759 52.0797L31.332 49.8419L23.4808 54.7984Z" fill="#00B8A8"></path>
<path d="M22.7817 42.3425V44.4508L46.2625 59.2462L69.7433 44.4508V42.3425H66.0086L46.2625 54.7983L26.5165 42.3425H22.7817ZM22.7817 16.9314V14.7954L46.2625 0L69.7433 14.7954V16.913H66.0086L46.2625 4.46635L26.5165 16.9314H22.7817Z" fill="#189298"></path>
<path d="M77.522 46.6332H78.149C79.0577 46.6332 79.6938 46.291 79.6938 45.3386C79.7073 45.1586 79.6825 44.9777 79.6212 44.8083C79.5598 44.639 79.4634 44.485 79.3384 44.3569C79.2134 44.2288 79.0627 44.1296 78.8967 44.066C78.7307 44.0025 78.5532 43.976 78.3762 43.9885H77.4675L77.522 46.6332ZM78.4307 42.3425C78.8281 42.32 79.2258 42.3801 79.5995 42.5193C79.9732 42.6585 80.3151 42.8739 80.6042 43.1522C80.8934 43.4304 81.1237 43.7658 81.2811 44.1378C81.4385 44.5097 81.5197 44.9105 81.5197 45.3155C81.5197 45.7204 81.4385 46.1212 81.2811 46.4931C81.1237 46.8651 80.8934 47.2005 80.6042 47.4788C80.3151 47.757 79.9732 47.9724 79.5995 48.1116C79.2258 48.2508 78.8281 48.311 78.4307 48.2884H77.522V51.8855H75.8682V42.3425H78.4307Z" fill="#00616D"></path>
<path d="M89.1624 47.382C89.1624 50.3873 88.1991 52.0055 85.8819 52.0055C83.5648 52.0055 82.647 50.341 82.647 47.382V42.3423H84.3008V47.6409C84.3008 49.4903 84.9187 50.341 85.9092 50.341C86.8997 50.341 87.5085 49.4718 87.5085 47.6409V42.3423H89.1624V47.382Z" fill="#00616D"></path>
<path d="M92.6062 46.4298H93.2514C94.0783 46.4298 94.7053 46.0784 94.7053 45.2462C94.7145 45.0786 94.6889 44.9109 94.63 44.7541C94.5712 44.5972 94.4805 44.4548 94.3638 44.3361C94.2472 44.2174 94.1072 44.1251 93.9531 44.0652C93.799 44.0053 93.6342 43.9792 93.4695 43.9886H92.5608L92.6062 46.4298ZM93.5149 42.3426C93.8993 42.3084 94.2864 42.3575 94.6507 42.4868C95.0149 42.6161 95.3481 42.8227 95.6281 43.0928C95.9081 43.3628 96.1286 43.6903 96.275 44.0536C96.4214 44.4168 96.4903 44.8076 96.4773 45.2C96.5037 45.7777 96.3465 46.3488 96.029 46.8284C95.7115 47.3081 95.2505 47.671 94.7144 47.8631C95.4323 49.0468 96.6409 50.9979 97.1952 51.8856H95.1142L92.8879 48.0851H92.6062V51.8856H90.9524V42.3426H93.5149Z" fill="#00616D"></path>
<path d="M104.501 47.382C104.501 50.3873 103.529 52.0055 101.212 52.0055C98.8946 52.0055 97.9768 50.341 97.9768 47.382V42.3423H99.6306V47.6409C99.6306 49.4903 100.258 50.341 101.239 50.341C102.22 50.341 102.847 49.4718 102.847 47.6409V42.3423H104.501V47.382Z" fill="#00616D"></path>
<path d="M109.108 43.8402C108.977 43.8186 108.843 43.8264 108.716 43.8631C108.588 43.8998 108.47 43.9645 108.369 44.0526C108.269 44.1407 108.189 44.2502 108.134 44.3732C108.08 44.4963 108.052 44.63 108.054 44.7649C108.054 45.5047 108.817 45.6896 109.435 45.9671C110.58 46.4294 111.962 47.0582 111.962 49.0648C111.966 49.4682 111.889 49.8681 111.734 50.2397C111.58 50.6112 111.352 50.9464 111.065 51.2241C110.777 51.5019 110.437 51.7163 110.064 51.8539C109.691 51.9915 109.295 52.0494 108.899 52.0239C108.297 52.0171 107.704 51.8693 107.166 51.5919C106.629 51.3145 106.162 50.9149 105.801 50.4242L106.891 49.1573C107.114 49.5021 107.412 49.79 107.761 49.9985C108.111 50.207 108.504 50.3305 108.908 50.3594C109.073 50.3752 109.24 50.3551 109.397 50.3005C109.554 50.2459 109.698 50.158 109.819 50.0426C109.94 49.9272 110.036 49.787 110.1 49.6312C110.163 49.4754 110.194 49.3076 110.19 49.1388C110.19 48.3251 109.454 48.0107 108.627 47.6593C107.582 47.1969 106.4 46.6513 106.4 44.8204C106.387 44.4656 106.447 44.1118 106.576 43.7818C106.705 43.4518 106.9 43.1527 107.149 42.9038C107.397 42.6549 107.695 42.4616 108.021 42.3362C108.348 42.2109 108.696 42.1562 109.045 42.1757C110.064 42.1729 111.043 42.5782 111.771 43.3039L110.862 44.7002C110.431 44.2098 109.834 43.9028 109.19 43.8402" fill="#00616D"></path>
</g>
<defs>
<clipPath id="clip0">
<rect width="130" height="59.2647" fill="white"></rect>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 546 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 919 KiB

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="35.93" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 228"><path fill="#00D8FF" d="M210.483 73.824a171.49 171.49 0 0 0-8.24-2.597c.465-1.9.893-3.777 1.273-5.621c6.238-30.281 2.16-54.676-11.769-62.708c-13.355-7.7-35.196.329-57.254 19.526a171.23 171.23 0 0 0-6.375 5.848a155.866 155.866 0 0 0-4.241-3.917C100.759 3.829 77.587-4.822 63.673 3.233C50.33 10.957 46.379 33.89 51.995 62.588a170.974 170.974 0 0 0 1.892 8.48c-3.28.932-6.445 1.924-9.474 2.98C17.309 83.498 0 98.307 0 113.668c0 15.865 18.582 31.778 46.812 41.427a145.52 145.52 0 0 0 6.921 2.165a167.467 167.467 0 0 0-2.01 9.138c-5.354 28.2-1.173 50.591 12.134 58.266c13.744 7.926 36.812-.22 59.273-19.855a145.567 145.567 0 0 0 5.342-4.923a168.064 168.064 0 0 0 6.92 6.314c21.758 18.722 43.246 26.282 56.54 18.586c13.731-7.949 18.194-32.003 12.4-61.268a145.016 145.016 0 0 0-1.535-6.842c1.62-.48 3.21-.974 4.76-1.488c29.348-9.723 48.443-25.443 48.443-41.52c0-15.417-17.868-30.326-45.517-39.844Zm-6.365 70.984c-1.4.463-2.836.91-4.3 1.345c-3.24-10.257-7.612-21.163-12.963-32.432c5.106-11 9.31-21.767 12.459-31.957c2.619.758 5.16 1.557 7.61 2.4c23.69 8.156 38.14 20.213 38.14 29.504c0 9.896-15.606 22.743-40.946 31.14Zm-10.514 20.834c2.562 12.94 2.927 24.64 1.23 33.787c-1.524 8.219-4.59 13.698-8.382 15.893c-8.067 4.67-25.32-1.4-43.927-17.412a156.726 156.726 0 0 1-6.437-5.87c7.214-7.889 14.423-17.06 21.459-27.246c12.376-1.098 24.068-2.894 34.671-5.345a134.17 134.17 0 0 1 1.386 6.193ZM87.276 214.515c-7.882 2.783-14.16 2.863-17.955.675c-8.075-4.657-11.432-22.636-6.853-46.752a156.923 156.923 0 0 1 1.869-8.499c10.486 2.32 22.093 3.988 34.498 4.994c7.084 9.967 14.501 19.128 21.976 27.15a134.668 134.668 0 0 1-4.877 4.492c-9.933 8.682-19.886 14.842-28.658 17.94ZM50.35 144.747c-12.483-4.267-22.792-9.812-29.858-15.863c-6.35-5.437-9.555-10.836-9.555-15.216c0-9.322 13.897-21.212 37.076-29.293c2.813-.98 5.757-1.905 8.812-2.773c3.204 10.42 7.406 21.315 12.477 32.332c-5.137 11.18-9.399 22.249-12.634 32.792a134.718 134.718 0 0 1-6.318-1.979Zm12.378-84.26c-4.811-24.587-1.616-43.134 6.425-47.789c8.564-4.958 27.502 2.111 47.463 19.835a144.318 144.318 0 0 1 3.841 3.545c-7.438 7.987-14.787 17.08-21.808 26.988c-12.04 1.116-23.565 2.908-34.161 5.309a160.342 160.342 0 0 1-1.76-7.887Zm110.427 27.268a347.8 347.8 0 0 0-7.785-12.803c8.168 1.033 15.994 2.404 23.343 4.08c-2.206 7.072-4.956 14.465-8.193 22.045a381.151 381.151 0 0 0-7.365-13.322Zm-45.032-43.861c5.044 5.465 10.096 11.566 15.065 18.186a322.04 322.04 0 0 0-30.257-.006c4.974-6.559 10.069-12.652 15.192-18.18ZM82.802 87.83a323.167 323.167 0 0 0-7.227 13.238c-3.184-7.553-5.909-14.98-8.134-22.152c7.304-1.634 15.093-2.97 23.209-3.984a321.524 321.524 0 0 0-7.848 12.897Zm8.081 65.352c-8.385-.936-16.291-2.203-23.593-3.793c2.26-7.3 5.045-14.885 8.298-22.6a321.187 321.187 0 0 0 7.257 13.246c2.594 4.48 5.28 8.868 8.038 13.147Zm37.542 31.03c-5.184-5.592-10.354-11.779-15.403-18.433c4.902.192 9.899.29 14.978.29c5.218 0 10.376-.117 15.453-.343c-4.985 6.774-10.018 12.97-15.028 18.486Zm52.198-57.817c3.422 7.8 6.306 15.345 8.596 22.52c-7.422 1.694-15.436 3.058-23.88 4.071a382.417 382.417 0 0 0 7.859-13.026a347.403 347.403 0 0 0 7.425-13.565Zm-16.898 8.101a358.557 358.557 0 0 1-12.281 19.815a329.4 329.4 0 0 1-23.444.823c-7.967 0-15.716-.248-23.178-.732a310.202 310.202 0 0 1-12.513-19.846h.001a307.41 307.41 0 0 1-10.923-20.627a310.278 310.278 0 0 1 10.89-20.637l-.001.001a307.318 307.318 0 0 1 12.413-19.761c7.613-.576 15.42-.876 23.31-.876H128c7.926 0 15.743.303 23.354.883a329.357 329.357 0 0 1 12.335 19.695a358.489 358.489 0 0 1 11.036 20.54a329.472 329.472 0 0 1-11 20.722Zm22.56-122.124c8.572 4.944 11.906 24.881 6.52 51.026c-.344 1.668-.73 3.367-1.15 5.09c-10.622-2.452-22.155-4.275-34.23-5.408c-7.034-10.017-14.323-19.124-21.64-27.008a160.789 160.789 0 0 1 5.888-5.4c18.9-16.447 36.564-22.941 44.612-18.3ZM128 90.808c12.625 0 22.86 10.235 22.86 22.86s-10.235 22.86-22.86 22.86s-22.86-10.235-22.86-22.86s10.235-22.86 22.86-22.86Z"></path></svg>

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 816 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 708 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 866 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 8.5 KiB

@@ -0,0 +1,66 @@
.bg-pattern-wrapper {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
z-index: -10;
overflow: hidden;
background-color: var(--bg-color);
pointer-events: none;
}
.bg-scroll-container {
display: flex;
width: 4000px; /* 2 seamless blocks of 2000px width */
height: 2000px;
animation: endlessDrift 60s linear infinite;
opacity: 0.15; /* Subtle blend */
}
/*
One seamless block consists of 4 flipped versions of the original 1000px image,
making it a 2000px x 2000px perfectly seamless tile.
*/
.seamless-block {
width: 2000px;
height: 2000px;
display: flex;
flex-wrap: wrap;
flex-shrink: 0;
}
.bg-quadrant {
width: 1000px;
height: 1000px;
background-image: url('/logos/d_-hive-lines_1-1.svg');
background-size: 1000px 1000px;
background-repeat: no-repeat;
}
/* Mirroring to force seamless edge matching */
.top-left {
transform: scale(1, 1);
}
.top-right {
transform: scale(-1, 1);
}
.bottom-left {
transform: scale(1, -1);
}
.bottom-right {
transform: scale(-1, -1);
}
/* Move the entire double-block leftwards by the exact width of ONE block (2000px) */
@keyframes endlessDrift {
0% {
transform: translate(0, 0);
}
100% {
transform: translate(-2000px, -500px); /* Move left 2000px, and up a bit for diagonal drift */
}
}
@@ -0,0 +1,34 @@
import React from 'react';
import './BackgroundPattern.css';
export default function BackgroundPattern() {
return (
<div className="bg-pattern-wrapper">
{/*
To create a perfectly seamless infinite tile from a non-seamless image,
we create a single massive seamless "block" by mirroring the image
in all 4 directions (Top-Left, Top-Right, Bottom-Left, Bottom-Right).
Then we duplicate this massive block to loop it.
*/}
<div className="bg-scroll-container">
{/* Block 1 */}
<div className="seamless-block">
<div className="bg-quadrant top-left"></div>
<div className="bg-quadrant top-right"></div>
<div className="bg-quadrant bottom-left"></div>
<div className="bg-quadrant bottom-right"></div>
</div>
{/* Block 2 (Duplicate for infinite seamless scroll) */}
<div className="seamless-block">
<div className="bg-quadrant top-left"></div>
<div className="bg-quadrant top-right"></div>
<div className="bg-quadrant bottom-left"></div>
<div className="bg-quadrant bottom-right"></div>
</div>
</div>
</div>
);
}
@@ -0,0 +1,125 @@
.dock-container {
position: fixed;
bottom: 30px;
left: 50%;
transform: translateX(-50%);
z-index: 1000;
display: flex;
justify-content: center;
}
.dock {
position: relative;
overflow: hidden;
/* background/border is now handled by pseudo-elements for the light effect */
padding: 8px 12px;
border-radius: 24px; /* Pill shape */
display: flex;
gap: 16px;
align-items: center;
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.5), 0 0 20px rgba(0, 255, 0, 0.05);
transition: all 0.3s ease;
z-index: 1;
}
/* The running light (rotating gradient) */
.dock::before {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 250%; /* Make it large enough to cover the pill shape while rotating */
height: 250%;
background: conic-gradient(transparent, transparent, transparent, rgba(0, 255, 0, 1));
transform: translate(-50%, -50%);
animation: rotateLight 4s linear infinite;
z-index: -2;
}
/* The inner mask that creates the border thickness */
.dock::after {
content: '';
position: absolute;
top: 1px;
left: 1px;
right: 1px;
bottom: 1px;
background: rgba(20, 20, 20, 0.9);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
border-radius: 23px; /* Matches inner curve */
z-index: -1;
}
@keyframes rotateLight {
0% { transform: translate(-50%, -50%) rotate(0deg); }
100% { transform: translate(-50%, -50%) rotate(360deg); }
}
.dock-item-wrapper {
position: relative;
display: flex;
flex-direction: column;
align-items: center;
z-index: 2; /* Keep above the inner mask */
}
.dock-item {
position: relative;
width: 48px;
height: 48px;
display: flex;
justify-content: center;
align-items: center;
border-radius: 16px;
color: var(--text-secondary);
transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
text-decoration: none;
}
.dock-item:hover {
color: var(--text-primary);
background: rgba(255, 255, 255, 0.08);
transform: translateY(-8px) scale(1.15);
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.3);
}
.dock-item.active {
color: var(--accent-color);
background: rgba(0, 255, 0, 0.1);
}
.dock-item.active::after {
content: '';
position: absolute;
bottom: -4px;
width: 4px;
height: 4px;
border-radius: 50%;
background-color: var(--accent-color);
box-shadow: 0 0 10px var(--accent-color);
}
/* Tooltip */
.dock-tooltip {
position: absolute;
top: -45px;
background: rgba(10, 10, 10, 0.9);
color: #fff;
padding: 6px 12px;
border-radius: 8px;
font-size: 0.8rem;
font-weight: 500;
white-space: nowrap;
opacity: 0;
pointer-events: none;
transform: translateY(10px);
transition: all 0.3s ease;
border: 1px solid rgba(255, 255, 255, 0.1);
}
.dock-item:hover ~ .dock-tooltip,
.dock-item-wrapper:hover .dock-tooltip {
opacity: 1;
transform: translateY(0);
}
@@ -0,0 +1,49 @@
import React from 'react';
import { Link, useLocation } from 'react-router-dom';
import { Home, Lightbulb, FileText, Settings, Lock } from 'lucide-react';
import { useAuth } from '../contexts/AuthContext';
import './BottomDock.css';
export default function BottomDock() {
const location = useLocation();
const { session, role } = useAuth();
const publicItems = [
{ label: 'Home', path: '/', icon: <Home size={22} /> },
{ label: 'Use Cases', path: '/usecases', icon: <Lightbulb size={22} /> },
{ label: 'Zugang anfragen', path: '/request-access', icon: <FileText size={22} /> },
];
// Both investor and admin can see the locked area
const investorItems = session
? [{ label: 'Investor Area', path: '/restricted', icon: <Lock size={22} /> }]
: [];
// Only admin sees the admin panel
const adminItems = role === 'admin'
? [{ label: 'Admin', path: '/admin', icon: <Settings size={22} /> }]
: [];
const navItems = [...publicItems, ...investorItems, ...adminItems];
return (
<div className="dock-container">
<nav className="dock">
{navItems.map((item, index) => {
const isActive = location.pathname === item.path;
return (
<div className="dock-item-wrapper" key={index}>
<span className="dock-tooltip">{item.label}</span>
<Link
to={item.path}
className={`dock-item ${isActive ? 'active' : ''}`}
>
{item.icon}
</Link>
</div>
);
})}
</nav>
</div>
);
}
@@ -0,0 +1,68 @@
import React from 'react';
import './Marquee.css';
// Import logos via Vite asset pipeline for robustness
import arvosLogo from '../assets/logos/arvos.svg';
import estererLogo from '../assets/logos/esterer.svg';
import mtoLogo from '../assets/logos/Logo-MTO.png';
import beierLogo from '../assets/logos/Paul-Beier-GmbH-Logo-white.png';
import sikaLogo from '../assets/logos/sika-logo.png';
import hexagonLogo from '../assets/logos/hexagon-purus-logo-4aa648.svg';
export default function Customers() {
const customerLogos = [
{ src: arvosLogo, link: 'https://www.arvos-group.com/', styleType: 'white-bg' },
{ src: estererLogo, link: 'https://www.esterer.de/', styleType: 'white-bg' },
{ src: mtoLogo, link: 'https://www.mto-kassel.de/', styleType: 'original' },
{ src: beierLogo, link: 'https://www.paul-beier.de/', styleType: 'original' },
{ src: sikaLogo, link: 'https://www.sika.com/', styleType: 'original' },
{ src: hexagonLogo, link: 'https://www.hexagonpurus.com/', styleType: 'original' },
];
// Triple the array for smooth infinite scrolling
const marqueeItems = [...customerLogos, ...customerLogos, ...customerLogos];
return (
<section id="kunden" className="marquee-section">
<div className="section-header">
<h2 className="section-title" style={{fontSize: '2rem', marginBottom: '40px'}}>Unsere <span className="text-gradient">Kunden</span></h2>
</div>
<div className="marquee-fade-left"></div>
<div className="marquee-fade-right"></div>
<div className="marquee-container">
<div className="marquee-content">
{marqueeItems.map((item, index) => {
const isWhiteBg = item.styleType === 'white-bg';
const isMonochrome = item.styleType === 'monochrome';
return (
<a
href={item.link}
target="_blank"
rel="noopener noreferrer"
className={`marquee-item logo-item ${isWhiteBg ? 'logo-white-bg' : ''}`}
key={index}
>
<img
src={item.src}
alt="Kundenlogo"
style={{
height: '40px',
width: 'auto',
display: 'block',
filter: isMonochrome ? 'brightness(0) invert(1)' : 'none',
transition: 'transform 0.3s ease'
}}
onMouseOver={(e) => e.currentTarget.style.transform = 'scale(1.1)'}
onMouseOut={(e) => e.currentTarget.style.transform = 'scale(1)'}
/>
</a>
);
})}
</div>
</div>
</section>
);
}
@@ -0,0 +1,70 @@
.footer-section {
padding: 80px 0 40px 0;
background-color: var(--bg-color);
}
.cta-container {
margin-bottom: 80px;
}
.cta-content {
text-align: center;
padding: 80px 40px;
background: linear-gradient(145deg, rgba(25, 25, 25, 0.8), rgba(10, 10, 10, 0.9));
border: 1px solid rgba(16, 185, 129, 0.2);
box-shadow: 0 20px 50px rgba(0, 0, 0, 0.5), inset 0 0 0 1px rgba(255, 255, 255, 0.05);
}
.cta-content h2 {
font-size: 2.5rem;
margin-bottom: 20px;
color: #fff;
}
.cta-content p {
color: var(--text-secondary);
font-size: 1.2rem;
max-width: 600px;
margin: 0 auto 40px auto;
}
.footer-bottom {
display: flex;
justify-content: space-between;
align-items: center;
border-top: 1px solid rgba(255, 255, 255, 0.05);
padding-top: 40px;
}
.footer-logo {
font-size: 1.5rem;
font-weight: 800;
letter-spacing: -1px;
}
.footer-links {
display: flex;
gap: 24px;
}
.footer-links a {
color: var(--text-secondary);
font-weight: 400;
}
.footer-links a:hover {
color: #fff;
}
.footer-copyright {
color: var(--text-secondary);
font-size: 0.9rem;
}
@media (max-width: 768px) {
.footer-bottom {
flex-direction: column;
gap: 20px;
text-align: center;
}
}
@@ -0,0 +1,30 @@
import React from 'react';
import { Link } from 'react-router-dom';
import './Footer.css';
export default function Footer() {
return (
<footer id="kontakt" className="footer-section">
<div className="cta-container app-container">
<div className="cta-content glass-panel">
<h2>Ihr habt ein spannendes Projekt?</h2>
<p>Lasst uns gemeinsam herausfinden, wie wir eure Prozesse intelligenter machen können.</p>
<a href="mailto:KIQ@d-hive.de" className="primary-button">Jetzt Kontakt aufnehmen</a>
</div>
</div>
<div className="footer-bottom app-container">
<div className="footer-logo">
<img src="/logos/d-Hive_logo_transparent_crop.png" alt="d-HIVE" style={{ height: '50px', objectFit: 'contain' }} />
</div>
<div className="footer-links">
<Link to="/impressum">Impressum</Link>
<Link to="/datenschutz">Datenschutz</Link>
</div>
<div className="footer-copyright">
&copy; {new Date().getFullYear()} dHIVE. Alle Rechte vorbehalten.
</div>
</div>
</footer>
);
}
@@ -0,0 +1,32 @@
import React from 'react';
export default function Gefoerdert() {
return (
<section className="app-container" style={{ padding: '60px 20px', textAlign: 'center', borderTop: '1px solid rgba(255, 255, 255, 0.05)' }}>
<h3 style={{ fontSize: '1.2rem', color: 'var(--text-secondary)', marginBottom: '30px', fontWeight: '600', letterSpacing: '1px', textTransform: 'uppercase' }}>Gefördert durch</h3>
<div style={{ display: 'flex', justifyContent: 'center' }}>
<a
href="https://digitales.hessen.de/foerderprogramme/distral"
target="_blank"
rel="noopener noreferrer"
style={{
display: 'inline-block',
background: '#ffffff',
padding: '15px 30px',
borderRadius: '16px',
transition: 'transform 0.3s ease',
textDecoration: 'none'
}}
onMouseOver={(e) => e.currentTarget.style.transform = 'scale(1.05)'}
onMouseOut={(e) => e.currentTarget.style.transform = 'scale(1)'}
>
<img
src="/logos/download-logo-distral-data.png"
alt="Gefördert durch distral"
style={{ maxHeight: '90px', maxWidth: '300px', objectFit: 'contain', display: 'block' }}
/>
</a>
</div>
</section>
);
}
@@ -0,0 +1,56 @@
.hero {
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
position: relative;
overflow: hidden;
text-align: center;
padding-top: 80px;
}
.hero-content {
position: relative;
z-index: 10;
max-width: 900px;
animation: fadeUp 1s cubic-bezier(0.16, 1, 0.3, 1) forwards;
}
.hero h1 {
font-size: clamp(2.5rem, 6vw, 4.5rem);
line-height: 1.1;
margin-bottom: 24px;
}
.text-gradient {
background: var(--accent-gradient);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
display: inline-block;
}
.hero-subtext {
font-size: clamp(1.1rem, 2vw, 1.3rem);
color: var(--text-secondary);
max-width: 700px;
margin: 0 auto 40px auto;
line-height: 1.6;
}
.background-mesh {
position: absolute;
top: -20%;
left: 50%;
transform: translateX(-50%);
width: 1000px;
height: 600px;
background: radial-gradient(circle, rgba(16, 185, 129, 0.15) 0%, rgba(10, 10, 10, 0) 70%);
z-index: 1;
pointer-events: none;
}
@keyframes fadeUp {
0% { opacity: 0; transform: translateY(30px); }
100% { opacity: 1; transform: translateY(0); }
}
@@ -0,0 +1,24 @@
import React from 'react';
import './Hero.css';
export default function Hero() {
return (
<section className="hero">
<div className="hero-glow background-mesh"></div>
<div className="app-container hero-content">
<h1>
Das souveräne KI-Betriebssystem <br />
<span className="text-gradient">für den deutschen Mittelstand</span>
</h1>
<p className="hero-subtext">
Modernste KI-Anwendungen, souverän komplett aus Deutschland.
Völlig unabhängig von amerikanischen Hyperscalern oder chinesischem Big-Tech.
Höchste Performance trifft auf digitale Souveränität.
</p>
<div className="hero-actions">
<a href="/request-access" className="primary-button">Access Request</a>
</div>
</div>
</section>
);
}
@@ -0,0 +1,78 @@
.marquee-section {
position: relative;
width: 100%;
padding: 80px 0;
background-color: var(--bg-color); /* pure black */
overflow: hidden;
border-top: 1px solid rgba(255, 255, 255, 0.03);
border-bottom: 1px solid rgba(255, 255, 255, 0.03);
}
.marquee-fade-left, .marquee-fade-right {
position: absolute;
top: 0;
width: 15%;
height: 100%;
z-index: 2;
pointer-events: none;
}
.marquee-fade-left {
left: 0;
background: linear-gradient(to right, var(--bg-color), transparent);
}
.marquee-fade-right {
right: 0;
background: linear-gradient(to left, var(--bg-color), transparent);
}
.marquee-container {
width: 100%;
overflow: hidden;
}
.marquee-content {
display: flex;
width: fit-content;
animation: scroll 30s linear infinite;
align-items: center;
}
.marquee-item {
margin: 0 40px;
white-space: nowrap;
transition: transform 0.4s ease;
}
.logo-item img {
max-height: 60px;
max-width: 200px;
object-fit: contain;
transition: all 0.4s ease;
opacity: 0.8; /* Base opacity for all */
}
.logo-white-bg {
background: #ffffff;
padding: 10px 18px;
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 4px 12px rgba(0,0,0,0.2);
}
.logo-white-bg img {
opacity: 1 !important;
filter: none !important;
}
.marquee-item:hover img {
opacity: 1;
}
@keyframes scroll {
0% { transform: translateX(0); }
100% { transform: translateX(-33.33%); }
}
@@ -0,0 +1,28 @@
import React from 'react';
export default function Memberships() {
const membershipLogos = [
{ src: 'DE_KI-Verband-Logo_weiss-scaled.png', link: 'https://ki-verband.de/' },
{ src: 'GKS_Logo.jpg', link: 'https://gemeinsamklimaschuetzen.de/' },
{ src: 'science-park-kassel-logo.png', link: 'https://www.sciencepark-kassel.de/' }
];
return (
<section id="netzwerk" className="app-container" style={{ padding: '60px 20px', textAlign: 'center' }}>
<h2 style={{ fontSize: '2rem', marginBottom: '40px' }}>Mitgliedschaften & <span className="text-gradient">Partnerschaften</span></h2>
<div style={{ display: 'flex', justifyContent: 'center', gap: '60px', flexWrap: 'wrap', alignItems: 'center' }}>
{membershipLogos.map((item, index) => (
<a key={index} href={item.link} target="_blank" rel="noopener noreferrer" style={{ display: 'block' }}>
<img
src={`/logos/${item.src}`}
alt="Mitgliedschaft / Partner"
style={{ maxHeight: '80px', maxWidth: '200px', objectFit: 'contain', transition: 'transform 0.3s ease' }}
onMouseOver={(e) => e.currentTarget.style.transform = 'scale(1.1)'}
onMouseOut={(e) => e.currentTarget.style.transform = 'scale(1)'}
/>
</a>
))}
</div>
</section>
);
}
@@ -0,0 +1,116 @@
.navigation {
position: fixed;
top: 0;
left: 0;
width: 100%;
z-index: 1000;
transition: all 0.3s ease;
padding: 20px 0;
}
.navigation.scrolled {
padding: 15px 0;
border-bottom: 1px solid var(--glass-border);
border-radius: 0;
backdrop-filter: blur(12px);
background: rgba(10, 10, 10, 0.8);
}
.nav-container {
display: flex;
justify-content: space-between;
align-items: center;
}
.logo-image {
height: 70px;
width: auto;
object-fit: contain;
}
/* Hamburger Menu */
.hamburger {
display: flex;
flex-direction: column;
gap: 6px;
background: transparent;
border: none;
cursor: pointer;
z-index: 1001; /* Above overlay */
padding: 10px;
}
.hamburger span {
display: block;
width: 30px;
height: 2px;
background-color: var(--text-primary);
transition: all 0.3s ease;
}
.hamburger.active span:nth-child(1) {
transform: translateY(8px) rotate(45deg);
}
.hamburger.active span:nth-child(2) {
opacity: 0;
}
.hamburger.active span:nth-child(3) {
transform: translateY(-8px) rotate(-45deg);
}
/* Overlay Navigation */
.nav-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100vh;
background: rgba(10, 10, 10, 0.95);
backdrop-filter: blur(15px);
-webkit-backdrop-filter: blur(15px);
z-index: 999; /* Below header */
display: flex;
justify-content: center;
align-items: center;
opacity: 0;
visibility: hidden;
transition: all 0.4s cubic-bezier(0.16, 1, 0.3, 1);
}
.nav-overlay.open {
opacity: 1;
visibility: visible;
}
.overlay-content {
display: flex;
flex-direction: column;
align-items: center;
gap: 40px;
}
.overlay-link {
font-size: 3rem;
font-weight: 800;
color: var(--text-primary);
text-decoration: none;
opacity: 0;
transform: translateY(20px);
transition: all 0.3s ease;
}
.nav-overlay.open .overlay-link {
opacity: 1;
transform: translateY(0);
}
.nav-overlay.open .overlay-link:nth-child(1) { transition-delay: 0.1s; }
.nav-overlay.open .overlay-link:nth-child(2) { transition-delay: 0.2s; }
.nav-overlay.open .overlay-link:nth-child(3) { transition-delay: 0.3s; }
.nav-overlay.open .overlay-link:nth-child(4) { transition-delay: 0.4s; }
.overlay-link:hover {
color: var(--accent-color);
}
@@ -0,0 +1,57 @@
import React, { useEffect, useState } from 'react';
import { Link, useLocation } from 'react-router-dom';
import './Navigation.css';
export default function Navigation() {
const [scrolled, setScrolled] = useState(false);
const [isOverlayOpen, setIsOverlayOpen] = useState(false);
const location = useLocation();
useEffect(() => {
const handleScroll = () => {
setScrolled(window.scrollY > 50);
};
window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll);
}, []);
// Close overlay on route change — use a layout effect to avoid setState-in-body lint
const prevPathRef = React.useRef(location.pathname);
React.useLayoutEffect(() => {
if (prevPathRef.current !== location.pathname) {
prevPathRef.current = location.pathname;
setIsOverlayOpen(false);
}
}, [location.pathname]);
return (
<>
<nav className={`navigation ${scrolled ? 'scrolled glass-panel' : ''}`}>
<div className="nav-container app-container">
<Link to="/" className="logo">
<img src="/logos/logo-dHIVE-2x.webp" alt="d-HIVE Logo" className="logo-image" />
</Link>
<button
className={`hamburger ${isOverlayOpen ? 'active' : ''}`}
onClick={() => setIsOverlayOpen(!isOverlayOpen)}
aria-label="Toggle menu"
>
<span></span>
<span></span>
<span></span>
</button>
</div>
</nav>
{/* Overlay Menu */}
<div className={`nav-overlay ${isOverlayOpen ? 'open' : ''}`}>
<div className="overlay-content">
<Link to="/" className="overlay-link" onClick={() => setIsOverlayOpen(false)}>Home</Link>
<Link to="/usecases" className="overlay-link" onClick={() => setIsOverlayOpen(false)}>Use Cases</Link>
<Link to="/request-access" className="overlay-link" onClick={() => setIsOverlayOpen(false)}>Request Access</Link>
</div>
</div>
</>
);
}
@@ -0,0 +1,61 @@
.platform-usp {
padding: 100px 0;
position: relative;
overflow: hidden;
}
.usp-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 30px;
margin-top: 60px;
}
.usp-card {
padding: 40px;
border-radius: 24px;
display: flex;
flex-direction: column;
transition: transform 0.3s ease, box-shadow 0.3s ease, border-color 0.3s ease;
background-size: cover;
background-position: center;
min-height: 380px;
border: 1px solid rgba(255, 255, 255, 0.1);
justify-content: flex-end; /* Align content to bottom for a modern look */
}
.usp-card:hover {
transform: translateY(-8px);
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.5);
border-color: var(--accent-color);
}
.usp-card h3 {
font-size: 1.6rem;
margin-bottom: 20px;
color: #fff;
text-shadow: 0 2px 4px rgba(0,0,0,0.5);
}
.usp-card ul {
list-style: none;
padding: 0;
margin: 0;
}
.usp-card li {
color: #efefef; /* Slightly brighter for readability against dark overlay */
line-height: 1.6;
margin-bottom: 12px;
padding-left: 24px;
position: relative;
font-size: 0.95rem;
text-shadow: 0 1px 2px rgba(0,0,0,0.5);
}
.usp-card li::before {
content: '→';
position: absolute;
left: 0;
color: var(--accent-color);
}
@@ -0,0 +1,72 @@
import React from 'react';
import './PlatformUSP.css';
// Import background images
import devBg from '../assets/usp/developer.png';
import bizBg from '../assets/usp/business.png';
import sovBg from '../assets/usp/sovereignty.png';
const features = [
{
title: 'Für Entwickler: Speed & Participation',
points: [
'Maximale Liefergeschwindigkeit durch fertige Infrastruktur.',
'Direkte Beteiligung am Erfolg jedes Use-Cases (Shared Benefit).',
'Die besten Entwickler Deutschlands bündeln ihre Kraft.'
],
bgImage: devBg
},
{
title: 'Für Unternehmen: Time-to-Value',
points: [
'Use-Cases sofort sehen und für sich nutzbar machen.',
'Kein IT-Overhead, kein Setup-Stress.',
'Direkter Zugang zu High-End KI-Expertise.'
],
bgImage: bizBg
},
{
title: '100% Souveränität',
points: [
'Komplett Made in Germany.',
'Keine Abhängigkeit von US-Hyperscalern.',
'Kein chinesisches Big-Tech.',
'Sicherer Hafen für sensibelste Unternehmensdaten.'
],
bgImage: sovBg
}
];
export default function PlatformUSP() {
return (
<section className="platform-usp">
<div className="app-container">
<div className="section-header">
<h2 className="section-title">Die <span className="text-gradient">Plattform-Vision</span></h2>
<p className="section-subtitle">
Wo die besten Entwickler für die besten Unternehmen bauen und alle direkt profitieren.
</p>
</div>
<div className="usp-grid">
{features.map((f, i) => (
<div
key={i}
className="usp-card glass-panel"
style={{
backgroundImage: `linear-gradient(rgba(0, 0, 0, 0.75), rgba(0, 0, 0, 0.85)), url(${f.bgImage})`
}}
>
<h3>{f.title}</h3>
<ul>
{f.points.map((p, j) => (
<li key={j}>{p}</li>
))}
</ul>
</div>
))}
</div>
</div>
</section>
);
}
@@ -0,0 +1,28 @@
import React from 'react';
import { Navigate, useLocation } from 'react-router-dom';
import { useAuth } from '../contexts/AuthContext';
/**
* ProtectedRoute: checks session via AuthContext.
* allowedRoles: array of roles that can access this route.
* If no session, redirects to /login.
* If role set but not allowed, redirects to /.
*/
export default function ProtectedRoute({ children, allowedRoles }) {
const { session, role, loading } = useAuth();
const location = useLocation();
if (loading) {
return <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', height: '100vh', color: '#00FF00', fontFamily: 'monospace' }}>Authentifizierung läuft...</div>;
}
if (!session) {
return <Navigate to="/login" state={{ from: location }} replace />;
}
if (allowedRoles && !allowedRoles.includes(role)) {
return <Navigate to="/" replace />;
}
return children;
}
@@ -0,0 +1,16 @@
import { useEffect } from 'react';
import { useLocation } from 'react-router-dom';
/**
* ScrollToTop component ensures that the page scroll position
* is reset to (0, 0) whenever the route changes.
*/
export default function ScrollToTop() {
const { pathname } = useLocation();
useEffect(() => {
window.scrollTo(0, 0);
}, [pathname]);
return null;
}
@@ -0,0 +1,93 @@
.services-section {
padding: 120px 20px;
}
.section-header {
text-align: center;
max-width: 700px;
margin: 0 auto 60px auto;
}
.section-title {
font-size: 3rem;
margin-bottom: 20px;
}
.section-subtitle {
color: var(--text-secondary);
font-size: 1.1rem;
line-height: 1.6;
}
.bento-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 24px;
max-width: 1000px;
margin: 0 auto;
}
.bento-item {
position: relative;
border-radius: 24px;
padding: 40px;
display: flex;
flex-direction: column;
justify-content: flex-end;
min-height: 300px;
overflow: hidden;
transition: transform 0.4s cubic-bezier(0.16, 1, 0.3, 1);
border: 1px solid rgba(255, 255, 255, 0.05);
}
.bento-item.span-2 {
grid-column: span 2;
}
.bento-content {
position: relative;
z-index: 2;
}
.bento-title {
font-size: 1.5rem;
margin-bottom: 12px;
color: #fff;
}
.bento-text {
color: var(--text-secondary);
line-height: 1.6;
font-size: 1rem;
margin: 0;
}
.bento-glow {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: radial-gradient(circle at 100% 100%, rgba(16, 185, 129, 0.1), transparent 50%);
opacity: 0;
transition: opacity 0.4s ease;
z-index: 1;
}
.bento-item:hover {
transform: translateY(-8px);
border-color: rgba(16, 185, 129, 0.3);
}
.bento-item:hover .bento-glow {
opacity: 1;
}
@media (max-width: 768px) {
.bento-grid {
grid-template-columns: 1fr;
}
.bento-item.span-2 {
grid-column: span 1;
}
}
@@ -0,0 +1,61 @@
import React from 'react';
import './Services.css';
export default function Services() {
const services = [
{
title: 'Datenschutz & Souveränität',
desc: 'Wir garantieren 100% DSGVO- und AI-Act konforme KI-Lösungen ohne Lock-in durch US-Hyperscaler wie OpenAI oder Google.',
bg: '/images/automation_bg.png', // Temporary placeholder visuals
span: 'span-2'
},
{
title: 'Plug and Play KI',
desc: 'Kein Ressourcenmangel mehr. Out-of-the-box Infrastruktur für smarte Anwendungsfälle.',
bg: '/images/ai_bg.png',
span: ''
},
{
title: 'Netzwerk & Forschung',
desc: 'Partnerschaft zwischen Unternehmen und Universität Kassel für modernste Begleitung.',
bg: '/images/workshops_bg.png',
span: ''
},
{
title: 'Vorausschauende Wartung & Automatisierung',
desc: 'Nutzen Sie Custom GPTs für B2B: Von Predictive Maintenance bis komplexe Dokumentenverarbeitung out-of-the-box.',
bg: '/images/transformation_bg.png',
span: 'span-2'
}
];
return (
<section id="leistungen" className="services-section app-container">
<div className="section-header">
<h2 className="section-title">Unsere <span className="text-gradient">Lösung</span></h2>
<p className="section-subtitle">Project KIQ liefert die gesamte KI-Infrastruktur out-of-the-box. Radikaler Fokus auf den Use Case.</p>
</div>
<div className="bento-grid">
{services.map((service, index) => (
<div
key={index}
className={`bento-item glass-panel ${service.span}`}
style={{
backgroundImage: `linear-gradient(to bottom, rgba(10, 10, 10, 0.4), rgba(10, 10, 10, 0.95)), url(${service.bg})`,
backgroundSize: 'cover',
backgroundPosition: 'center',
backgroundRepeat: 'no-repeat'
}}
>
<div className="bento-content">
<h3 className="bento-title">{service.title}</h3>
<p className="bento-text">{service.desc}</p>
</div>
<div className="bento-glow"></div>
</div>
))}
</div>
</section>
);
}
@@ -0,0 +1,59 @@
.cube-section {
display: flex;
justify-content: center;
align-items: center;
padding: 100px 20px 150px 20px;
perspective: 1200px;
}
.cube-container {
width: 300px;
height: 300px;
position: relative;
transform-style: preserve-3d;
animation: spinCube 16s infinite cubic-bezier(0.25, 0.1, 0.25, 1);
}
.cube-face {
position: absolute;
width: 300px;
height: 300px;
background: rgba(15, 15, 15, 0.95); /* solid background prevents seeing through nicely */
border: 1px solid rgba(0, 255, 0, 0.2);
backdrop-filter: blur(10px);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
box-shadow: 0 0 40px rgba(0, 255, 0, 0.1) inset, 0 10px 40px rgba(0, 0, 0, 0.5);
backface-visibility: hidden; /* Hide faces turned away to prevent jumbled mess if translucent */
}
/* 3D Geometry */
.face-1 { transform: rotateY(0deg) translateZ(150px); }
.face-2 { transform: rotateY(90deg) translateZ(150px); }
.face-3 { transform: rotateY(180deg) translateZ(150px); }
.face-4 { transform: rotateY(-90deg) translateZ(150px); }
@keyframes spinCube {
0%, 15% { transform: rotateY(0deg); }
25%, 40% { transform: rotateY(-90deg); }
50%, 65% { transform: rotateY(-180deg); }
75%, 90% { transform: rotateY(-270deg); }
100% { transform: rotateY(-360deg); }
}
.stat-value {
font-size: 4rem;
font-weight: 800;
margin-bottom: 10px;
color: #fff;
filter: drop-shadow(0 0 15px rgba(0, 255, 0, 0.5));
}
.stat-label {
font-size: 1.5rem;
color: var(--text-secondary);
text-transform: uppercase;
letter-spacing: 2px;
}
@@ -0,0 +1,24 @@
import React from 'react';
import './Stats.css';
export default function Stats() {
const stats = [
{ value: '6', label: 'Pilotkunden', faceClass: 'face-1' },
{ value: '100%', label: 'DSGVO & AI-Act', faceClass: 'face-2' },
{ value: '6', label: 'Use Cases live', faceClass: 'face-3' },
{ value: 'EU', label: 'Hosting', faceClass: 'face-4' },
];
return (
<section className="cube-section app-container">
<div className="cube-container">
{stats.map((stat, i) => (
<div className={`cube-face ${stat.faceClass}`} key={i}>
<div className="stat-value text-gradient">{stat.value}</div>
<div className="stat-label">{stat.label}</div>
</div>
))}
</div>
</section>
);
}
@@ -0,0 +1,49 @@
import React from 'react';
export default function Team() {
return (
<section className="app-container" style={{ padding: '40px 20px 100px 20px' }}>
<div className="glass-panel" style={{ padding: '60px', borderRadius: '24px', border: '1px solid rgba(0, 255, 0, 0.1)' }}>
<h2 style={{ fontSize: '2rem', marginBottom: '20px', color: '#fff' }}>Das sind wir</h2>
<p style={{ color: 'var(--text-secondary)', lineHeight: '1.8', marginBottom: '30px', fontSize: '1.05rem', maxWidth: '800px' }}>
Unser Team setzt sich zusammen aus Problemlösern mit wissenschaftlichen Hintergründen in den Bereichen der Regelungs- und Elektrotechnik, Mechatronik, Maschinenbau, Informatik und Physik. Und wir alle haben uns in irgendeiner Form dem Generieren von Wissen durch das Erheben und Verarbeiten von Daten verschrieben.
<br/><br/>
Stellvertretend für unser Team stellen wir hier unsere Gründer vor: André unser KI, Leadership und Sensorik-Experte und Alex unser Mess-, Regelungs und Automatisierungs-Experte. Die beiden begleiten unsere Kunden und unsere internen und externen Mitarbeitenden durch die Projekte.
</p>
{/* Founders Grid */}
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(340px, 1fr))', gap: '40px', marginTop: '60px' }}>
{/* André */}
<div style={{ background: 'rgba(255,255,255,0.02)', padding: '40px', borderRadius: '20px', border: '1px solid rgba(255,255,255,0.05)' }}>
<h3 style={{ fontSize: '1.8rem', color: '#fff', marginBottom: '5px' }}>Dr. André Knie</h3>
<p style={{ color: 'var(--accent-color)', fontWeight: '600', marginBottom: '25px', fontSize: '1.1rem' }}>Mensch-Maschine-Moderator</p>
<div style={{ fontStyle: 'italic', color: '#ccc', borderLeft: '3px solid var(--accent-color)', paddingLeft: '15px', marginBottom: '20px', lineHeight: '1.7' }}>
Die Angst vor Technologie und Veränderung lähmt viele Organisationen und Menschen. Ich helfe dabei, diese Ängste zu überwinden, und gestalte Technologie sowie Change-Prozesse so, dass sie echten Mehrwert schaffen und Begeisterung auslösen."
</div>
<p style={{ color: 'var(--text-secondary)', lineHeight: '1.7', marginBottom: '15px' }}>
Als promovierter Physiker betrachte ich Systeme und Zusammenhänge aus einer einzigartigen Perspektive.
</p>
</div>
{/* Alex */}
<div style={{ background: 'rgba(255,255,255,0.02)', padding: '40px', borderRadius: '20px', border: '1px solid rgba(255,255,255,0.05)' }}>
<h3 style={{ fontSize: '1.8rem', color: '#fff', marginBottom: '5px' }}>Dr.-Ing. Alexander Schrodt</h3>
<p style={{ color: 'var(--accent-color)', fontWeight: '600', marginBottom: '25px', fontSize: '1.1rem' }}>Automatisierungs-Analyse-Architekt</p>
<div style={{ fontStyle: 'italic', color: '#ccc', borderLeft: '3px solid var(--accent-color)', paddingLeft: '15px', marginBottom: '20px', lineHeight: '1.7' }}>
„Ich führe die KI-Diskussion über Buzzwords hinaus: Für mich ist KI keine universelle Antwort, sondern ein hochspezialisiertes Werkzeug, um in technischen Systemen echten, messbaren Mehrwert zu schaffen."
</div>
<p style={{ color: 'var(--text-secondary)', lineHeight: '1.7', marginBottom: '15px' }}>
Mein Fundament als promovierter Regelungstechniker ist die Systemtheorie. Ich verstehe, wie technische Prozesse im Kern funktionieren, wie sie stabil designt und sicher betrieben werden.
</p>
</div>
</div>
</div>
</section>
);
}
@@ -0,0 +1,62 @@
.uct-section {
padding: 100px 20px;
}
.uct-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
gap: 20px;
margin-top: 48px;
}
.uct-card {
padding: 28px;
border-radius: 18px;
display: flex;
flex-direction: column;
gap: 12px;
transition: border-color 0.25s, transform 0.25s;
}
.uct-card:hover {
border-color: rgba(0, 255, 0, 0.25);
transform: translateY(-3px);
}
.uct-icon {
font-size: 1.8rem;
line-height: 1;
}
.uct-title {
font-size: 1.15rem;
color: #fff;
margin: 0;
}
.uct-summary {
color: var(--text-secondary);
font-size: 0.88rem;
line-height: 1.6;
margin: 0;
flex: 1;
}
.uct-status {
display: inline-block;
align-self: flex-start;
background: rgba(0,255,0,0.08);
border: 1px solid rgba(0,255,0,0.2);
color: var(--accent-color);
font-size: 0.73rem;
font-weight: 700;
padding: 3px 10px;
border-radius: 50px;
letter-spacing: 0.06em;
}
.uct-cta {
display: flex;
justify-content: center;
margin-top: 48px;
}
@@ -0,0 +1,34 @@
import React from 'react';
import { Link } from 'react-router-dom';
import { USE_CASES } from '../data/useCases';
import './UseCasesTeaser.css';
export default function UseCasesTeaser() {
return (
<section className="uct-section app-container">
<div className="section-header">
<h2 className="section-title">Bewiesene <span className="text-gradient">Use Cases</span></h2>
<p className="section-subtitle">
Fünf KI-Agenten, bereits im Einsatz bei Praxispartnern aus der Region Kassel.
</p>
</div>
<div className="uct-grid">
{USE_CASES.map((uc) => (
<div key={uc.id} className="uct-card glass-panel">
<div className="uct-icon">{uc.icon}</div>
<h3 className="uct-title">{uc.title}</h3>
<p className="uct-summary">{uc.summary}</p>
<span className="uct-status"> Live</span>
</div>
))}
</div>
<div className="uct-cta">
<Link to="/usecases" className="primary-button">
Alle Use Cases ansehen
</Link>
</div>
</section>
);
}
@@ -0,0 +1,73 @@
import React, { createContext, useContext, useEffect, useState } from 'react';
const API_BASE = import.meta.env.VITE_API_URL || '';
const AuthContext = createContext({});
export const useAuth = () => useContext(AuthContext);
export const AuthProvider = ({ children }) => {
const [user, setUser] = useState(null);
const [session, setSession] = useState(null);
const [role, setRole] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
// Check if we have an active session
fetch(`${API_BASE}/api/me`, { credentials: 'include' })
.then(res => res.json())
.then(data => {
if (data.user) {
setUser(data.user);
setSession(true);
setRole(data.user.role);
} else {
setUser(null);
setSession(null);
setRole(null);
}
})
.catch(() => {
setUser(null);
setSession(null);
setRole(null);
})
.finally(() => setLoading(false));
}, []);
const login = async (username, password) => {
const res = await fetch(`${API_BASE}/api/login`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
credentials: 'include',
body: JSON.stringify({ username, password }),
});
if (!res.ok) {
const err = await res.json();
throw new Error(err.error || 'Login fehlgeschlagen');
}
const data = await res.json();
setUser(data.user);
setSession(true);
setRole(data.user.role);
return data.user;
};
const logout = async () => {
await fetch(`${API_BASE}/api/logout`, {
method: 'POST',
credentials: 'include',
});
setUser(null);
setSession(null);
setRole(null);
};
const val = { session, user, role, loading, login, logout };
return (
<AuthContext.Provider value={val}>
{children}
</AuthContext.Provider>
);
};
+62
View File
@@ -0,0 +1,62 @@
export const USE_CASES = [
{
id: 'teileerkennung',
icon: '🔍',
title: 'Teileerkennung',
tagline: 'Automatische Bauteil-Identifikation per Foto',
summary: 'Ein Algorithmus identifiziert Bauteile auf einem Foto und ermittelt automatisch Teilenummer und Lagerplatz.',
detail: 'Mitarbeitende können per Smartphone-Foto ein unbekanntes Bauteil sofort identifizieren. Das KI-System gleicht das Bild mit der Teiledatenbank ab und gibt Teilenummer, Lagerplatz und verfügbare Menge zurück. Suchzeiten in der Produktion werden auf Sekunden reduziert.',
outcome: 'Drastische Reduktion von Suchzeiten, weniger Fehlbestellungen, schnellere Instandhaltung.',
status: 'Live',
},
{
id: 'pruefprotokolle',
icon: '📋',
title: 'Prüfprotokolle',
tagline: 'Automatische QS-Dokumentation aus Aufträgen',
summary: 'Das System erzeugt aus Auftrag und Zeichnungen automatisch vollständige Prüfprotokolle für die Qualitätssicherung.',
detail: 'Aus eingehenden Aufträgen und technischen Zeichnungen generiert der KI-Agent automatisch strukturierte Prüfprotokolle, die alle relevanten Qualitätskriterien abbilden. Die manuelle Erstellung entfällt nahezu vollständig.',
outcome: 'Zeitersparnis von mehreren Stunden pro Auftrag, konsistente Qualitätsdokumentation, weniger Fehler.',
status: 'Live',
},
{
id: 'marktanalyse',
icon: '📈',
title: 'Marktanalyse',
tagline: 'Kontinuierliches Wettbewerbs-Monitoring',
summary: 'Ein KI-Agent überwacht Wettbewerber, erkennt neue Produkte und Entwicklungen und erstellt automatisiert Wettbewerbsanalysen.',
detail: 'Der Agent durchsucht kontinuierlich öffentliche Quellen (Websites, Pressemitteilungen, Messeauftritte) und aggregiert relevante Wettbewerberinformationen zu strukturierten Berichten. Trenderkennungen werden automatisch aufbereitet.',
outcome: 'Statt Wochen dauert eine vollständige Wettbewerbsanalyse nur Minuten. Strategische Reaktionen werden frühzeitig möglich.',
status: 'Live',
},
{
id: 'angebotsunterstuetzung',
icon: '📝',
title: 'Angebotsunterstützung',
tagline: 'Angebote in Minuten statt Tagen',
summary: 'Ein KI-Agent erstellt unter Berücksichtigung rechtlicher und fachlicher Vorgaben innerhalb weniger Minuten umfangreiche Angebote.',
detail: 'Auf Basis von Lastenheften, Preislisten und internen Vorgaben erstellt der Agent vollständige, rechtlich konforme Angebote. Individuelle Anpassungen bleiben dem Vertrieb überlassen, der Routineaufwand entfällt.',
outcome: 'Angebotserstellung von Tagen auf Minuten verkürzt. Höhere Angebotskapazität ohne Personalaufbau.',
status: 'Live',
},
{
id: 'berichtserzeugung',
icon: '📊',
title: 'Berichtserzeugung',
tagline: 'Monatliche Reports auf Knopfdruck',
summary: 'Monatliche Berichterstattung an die Muttergesellschaft wird weitgehend automatisiert und reduziert den Aufwand von einer Woche auf wenige Minuten.',
detail: 'Der KI-Agent sammelt alle relevanten Kennzahlen aus den internen Systemen, verdichtet sie und formatiert sie entsprechend den Vorgaben der Muttergesellschaft. Das Ergebnis ist ein fertiger, versandbereiter Bericht.',
outcome: 'Zeitaufwand von ca. 1 Woche auf unter 30 Minuten reduziert. Mitarbeitende werden für wertschöpfende Aufgaben freigesetzt.',
status: 'Live',
},
{
id: 'rag-chatbot',
icon: '🤖',
title: 'Individueller RAG-Chatbot',
tagline: 'Sicherer Know-how-Chat für Ihr Unternehmen',
summary: 'Interagieren Sie direkt mit Ihren Unternehmensdokumenten, ohne Daten mit US- oder China-Hyperscalern teilen zu müssen.',
detail: 'Die KI nutzt modernste RAG- (Retrieval-Augmented Generation) oder Graph-Technologien, um auf Basis Ihrer internen Dokumente Fragen präzise zu beantworten. Das Wissen bleibt zu 100% in Deutschland und ist DSGVO-konform gesichert.',
outcome: 'Sofortiger Zugriff auf Expertenwissen, höchste Datensouveränität, kein Risiko durch Cloud-Anbieter.',
status: 'Neu',
},
];
+137
View File
@@ -0,0 +1,137 @@
@import url('https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;600;800&display=swap');
:root {
--bg-color: #0a0a0a;
--text-primary: #f0f0f0;
--text-secondary: #999999;
--accent-color: #00FF00; /* Neon Green */
--accent-color-rgb: 0, 255, 0;
--accent-gradient: linear-gradient(135deg, #00FF00, #00b300);
--glass-bg: rgba(25, 25, 25, 0.6);
--glass-border: rgba(255, 255, 255, 0.08);
}
* {
box-sizing: border-box;
}
body {
margin: 0;
padding: 0;
background-color: var(--bg-color);
color: var(--text-primary);
font-family: 'Outfit', sans-serif;
overflow-x: hidden;
}
h1, h2, h3, h4, h5, h6 {
font-weight: 800;
letter-spacing: -0.02em;
margin: 0;
}
a {
text-decoration: none;
color: inherit;
transition: color 0.3s ease;
}
a:hover {
color: var(--accent-color);
}
.primary-button {
display: inline-block;
background: var(--accent-gradient);
color: #000; /* Dark text for neon green */
padding: 14px 28px;
border-radius: 50px;
font-weight: 800;
font-size: 1.1rem;
box-shadow: 0 4px 15px rgba(0, 255, 0, 0.3);
transition: transform 0.3s ease, box-shadow 0.3s ease;
border: none;
cursor: pointer;
}
.primary-button:hover {
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(0, 255, 0, 0.5);
color: #000;
}
/* Layout Helpers */
.app-container {
max-width: 1200px;
margin: 0 auto;
padding: 0 24px;
}
.logout-btn {
background: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 255, 255, 0.1);
color: var(--text-secondary);
padding: 6px 16px;
border-radius: 50px;
font-size: 0.82rem;
cursor: pointer;
transition: all 0.3s ease;
}
.logout-btn:hover {
background: rgba(255, 60, 60, 0.1);
color: #ff6b6b;
border-color: rgba(255, 60, 60, 0.2);
}
.admin-header-row, .res-header-row {
display: flex;
justify-content: center;
align-items: center;
gap: 20px;
margin-bottom: 24px;
}
.glass-panel {
background: var(--glass-bg);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
border: 1px solid var(--glass-border);
border-radius: 16px;
}
/* Visual Effects */
.text-gradient {
background: var(--accent-gradient);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.background-mesh {
position: absolute;
width: 100%;
height: 100%;
background: radial-gradient(circle at 50% 50%, rgba(0, 255, 0, 0.05) 0%, transparent 50%),
radial-gradient(circle at 0% 0%, rgba(0, 255, 0, 0.03) 0%, transparent 40%),
radial-gradient(circle at 100% 100%, rgba(0, 255, 0, 0.03) 0%, transparent 40%);
pointer-events: none;
z-index: -1;
}
.section-header {
text-align: center;
margin-bottom: 60px;
}
.section-title {
font-size: clamp(2rem, 5vw, 3rem);
margin-bottom: 16px;
}
.section-subtitle {
color: var(--text-secondary);
max-width: 600px;
margin: 0 auto;
line-height: 1.6;
}
+13
View File
@@ -0,0 +1,13 @@
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import './index.css'
import App from './App.jsx'
import { AuthProvider } from './contexts/AuthContext.jsx'
createRoot(document.getElementById('root')).render(
<StrictMode>
<AuthProvider>
<App />
</AuthProvider>
</StrictMode>,
)
+118
View File
@@ -0,0 +1,118 @@
import React from 'react';
import '../components/Hero.css';
export default function About() {
return (
<main>
{/* Hero Section */}
<section className="hero" style={{ minHeight: '50vh', paddingBottom: '40px' }}>
<div className="hero-glow background-mesh"></div>
<div className="app-container hero-content">
<h1 style={{ fontSize: 'clamp(2.5rem, 6vw, 4.5rem)' }}>
<span className="text-gradient">Über uns</span>
</h1>
<p className="hero-subtext" style={{ maxWidth: '800px', marginBottom: '20px', fontSize: '1.2rem' }}>
Unsere Werte sind Nachhaltigkeit und Fortschritt. Das haben wir auch in unser Motto aufgenommen: <strong style={{color: '#fff'}}>wir hassen Verschwendung und lieben Wandel.</strong>
</p>
<p style={{ color: 'var(--text-secondary)', maxWidth: '800px', margin: '0 auto', lineHeight: '1.8', fontSize: '1.1rem' }}>
Gemeinsam mit euch machen wir eure Produkte smarter. Das heißt konkret: Wir erarbeiten mit euch ein Konzept, um euer Produkt mit der passenden Sensorik, Datenerfassung und zugehöriger Software auszustatten, damit euer Produkt bestimmte Fragestellungen in Zukunft selbstständig beantworten kann.
<br/><br/>
Die anschließende Automatisierung oder die Betreuung bei der Integration in die Herstellung von Produktserien gehört dabei dazu.
</p>
</div>
</section>
{/* Stats Section */}
<section className="app-container" style={{ padding: '20px 20px 60px 20px', textAlign: 'center' }}>
<h2 style={{ fontSize: '1.5rem', marginBottom: '30px', color: '#fff' }}>Zahlen, Daten, Fakten</h2>
<div style={{ display: 'flex', justifyContent: 'center', gap: '40px', flexWrap: 'wrap' }}>
<div className="glass-panel" style={{ padding: '30px 50px', borderRadius: '16px', minWidth: '200px' }}>
<h3 style={{ fontSize: '3rem', color: 'var(--accent-color)', marginBottom: '5px' }}>2021</h3>
<p style={{ color: 'var(--text-secondary)', fontWeight: '500' }}>Gründung</p>
</div>
<div className="glass-panel" style={{ padding: '30px 50px', borderRadius: '16px', minWidth: '200px' }}>
<h3 style={{ fontSize: '3rem', color: 'var(--accent-color)', marginBottom: '5px' }}>50+</h3>
<p style={{ color: 'var(--text-secondary)', fontWeight: '500' }}>Projekte erfolgreich umgesetzt</p>
</div>
</div>
</section>
{/* Team Intro */}
<section className="app-container" style={{ padding: '40px 20px 100px 20px' }}>
<div className="glass-panel" style={{ padding: '60px', borderRadius: '24px', border: '1px solid rgba(0, 255, 0, 0.1)' }}>
<h2 style={{ fontSize: '2rem', marginBottom: '20px', color: '#fff' }}>Das sind wir</h2>
<p style={{ color: 'var(--text-secondary)', lineHeight: '1.8', marginBottom: '30px', fontSize: '1.05rem', maxWidth: '800px' }}>
Unser Team setzt sich zusammen aus Problemlösern mit wissenschaftlichen Hintergründen in den Bereichen der Regelungs- und Elektrotechnik, Mechatronik, Maschinenbau, Informatik und Physik. Und wir alle haben uns in irgendeiner Form dem Generieren von Wissen durch das Erheben und Verarbeiten von Daten verschrieben.
<br/><br/>
Stellvertretend für unser Team stellen wir hier unsere Gründer vor: André unser KI, Leadership und Sensorik-Experte und Alex unser Mess-, Regelungs und Automatisierungs-Experte. Die beiden begleiten unsere Kunden und unsere internen und externen Mitarbeitenden durch die Projekte.
</p>
{/* Founders Grid */}
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(340px, 1fr))', gap: '40px', marginTop: '60px' }}>
{/* André */}
<div style={{ background: 'rgba(255,255,255,0.02)', padding: '40px', borderRadius: '20px', border: '1px solid rgba(255,255,255,0.05)' }}>
<h3 style={{ fontSize: '1.8rem', color: '#fff', marginBottom: '5px' }}>Dr. André Knie</h3>
<p style={{ color: 'var(--accent-color)', fontWeight: '600', marginBottom: '25px', fontSize: '1.1rem' }}>Mensch-Maschine-Moderator</p>
<div style={{ fontStyle: 'italic', color: '#ccc', borderLeft: '3px solid var(--accent-color)', paddingLeft: '15px', marginBottom: '20px', lineHeight: '1.7' }}>
Die Angst vor Technologie und Veränderung lähmt viele Organisationen und Menschen. Ich helfe dabei, diese Ängste zu überwinden, und gestalte Technologie sowie Change-Prozesse so, dass sie echten Mehrwert schaffen und Begeisterung auslösen."
</div>
<p style={{ color: 'var(--text-secondary)', lineHeight: '1.7', marginBottom: '15px' }}>
Als promovierter Physiker betrachte ich Systeme und Zusammenhänge aus einer einzigartigen Perspektive. Meine wissenschaftliche Herangehensweise ermöglicht es mir, komplexe Herausforderungen analytisch zu durchdringen und visionäre Lösungen zu entwickeln, die technisch fundiert und praxisnah sind.
</p>
<p style={{ color: 'var(--text-secondary)', lineHeight: '1.7', marginBottom: '15px' }}>
Doch Technik allein reicht nicht aus. Ich verbinde diese Visionen mit Menschlichkeit und einer Kultur, die Veränderung als Chance begreift. Ein Beispiel für meine gelebten Werte ist mein Verzicht auf Gehalt, um im Jobsharing die Möglichkeit zu haben, Führung auf Augenhöhe zu übernehmen und das Team weiterzuentwickeln. Diese menschenzentrierte Haltung ist das Herzstück meiner Arbeit.
</p>
<div style={{ background: 'rgba(0,255,0,0.03)', padding: '15px 20px', borderRadius: '12px', marginBottom: '20px' }}>
<p style={{ color: '#fff', marginBottom: '10px', fontWeight: '500' }}>Meine Expertise konzentriert sich auf drei Kernthemen:</p>
<ol style={{ color: 'var(--text-secondary)', marginLeft: '20px', lineHeight: '1.6' }}>
<li>Innovation und Technologie</li>
<li>Mensch & Kultur</li>
<li>Verantwortung</li>
</ol>
<p style={{ color: 'var(--text-secondary)', marginTop: '10px', fontSize: '0.95rem' }}>Diese Säulen bilden das Fundament meiner Beratung, Workshops und Vorträge.</p>
</div>
<p style={{ color: 'var(--text-secondary)', lineHeight: '1.7', fontSize: '0.95rem' }}>
In Projekten sind KI, Sensorik, Konzeption, Produktentwicklung, Projektplanung, Design Thinking, New Work und Projektdurchführung Andrés Hauptarbeitsbereiche. Er stellt gerne unbequeme Warum-Fragen und hat stets den Kunden unserer Kunden im Blick. Wenn das Ziel klar ist, wird an Konzept und Umsetzung gearbeitet. Meistens ist André aber dabei das Ziel gemeinsam mit dem Kunden zu schärfen und das Problem zu analysieren.
</p>
</div>
{/* Alex */}
<div style={{ background: 'rgba(255,255,255,0.02)', padding: '40px', borderRadius: '20px', border: '1px solid rgba(255,255,255,0.05)' }}>
<h3 style={{ fontSize: '1.8rem', color: '#fff', marginBottom: '5px' }}>Dr.-Ing. Alexander Schrodt</h3>
<p style={{ color: 'var(--accent-color)', fontWeight: '600', marginBottom: '25px', fontSize: '1.1rem' }}>Automatisierungs-Analyse-Architekt</p>
<div style={{ fontStyle: 'italic', color: '#ccc', borderLeft: '3px solid var(--accent-color)', paddingLeft: '15px', marginBottom: '20px', lineHeight: '1.7' }}>
„Ich führe die KI-Diskussion über Buzzwords hinaus: Für mich ist KI keine universelle Antwort, sondern ein hochspezialisiertes Werkzeug, um in technischen Systemen echten, messbaren Mehrwert zu schaffen."
</div>
<p style={{ color: 'var(--text-secondary)', lineHeight: '1.7', marginBottom: '15px' }}>
Mein Fundament als promovierter Regelungstechniker ist die Systemtheorie. Ich verstehe, wie technische Prozesse im Kern funktionieren, wie sie stabil designt und sicher betrieben werden. Diese systemische Sicht erlaubt es mir, nicht nur KI-Modelle zu trainieren, sondern sie so in die Automatisierung zu integrieren, dass sie robust, effizient und vorhersagbar arbeiten.
</p>
<p style={{ color: 'var(--text-secondary)', lineHeight: '1.7', marginBottom: '20px' }}>
Ich suche nicht nach dem neuesten Algorithmus, sondern nach der optimalen und einfachsten Lösung, die das Problem des Kunden nachhaltig löst.
</p>
<p style={{ color: 'var(--text-secondary)', lineHeight: '1.7', marginBottom: '20px' }}>
Im Maschinenbau und in der Produktion führt dieser Ansatz zu messbaren Erfolgen: Wir senken den Ausschuss, minimieren Ausfallzeiten und vereinfachen die Wartung. Wir nutzen KI nicht um ihrer selbst willen, sondern um die Effizienz zu steigern und eine präzise, datenbasierte Einsicht in die gesamten Abläufe zu gewinnen.
</p>
<div style={{ fontStyle: 'italic', color: '#ccc', borderLeft: '3px solid var(--accent-color)', paddingLeft: '15px', marginBottom: '20px', lineHeight: '1.7' }}>
Meine Leidenschaft ist es, komplexe Systeme zu entschlüsseln und sie robuster und leistungsfähiger zu machen. Ich befähige unsere Kunden und Teams, Daten nicht nur zu sammeln, sondern sie für stabile, effiziente Prozesse zu nutzen und Wissen in einen klaren Wettbewerbsvorteil zu verwandeln.
</div>
<p style={{ color: 'var(--text-secondary)', lineHeight: '1.7', fontSize: '0.95rem' }}>
In Projekten liegen Alex Schwerpunkte in der Systemtheorie, der regelungsorientierten Datenanalyse (KI und klassisch) und der Konzeption smarter Automatisierungslösungen. Er ist der Architekt, der sicherstellt, dass die von dHive entwickelten Lösungen nicht nur intelligent, sondern auch industrietauglich sind.
</p>
</div>
</div>
</div>
</section>
</main>
);
}
@@ -0,0 +1,207 @@
.ar-page {
min-height: 100vh;
padding-bottom: 100px;
}
.ar-hero {
position: relative;
padding: 160px 20px 80px;
text-align: center;
overflow: hidden;
}
.ar-hero-content {
position: relative;
z-index: 10;
max-width: 700px;
margin: 0 auto;
}
.ar-hero h1 {
font-size: clamp(2.5rem, 5vw, 3.5rem);
line-height: 1.1;
margin-bottom: 20px;
}
.ar-label-tag {
display: inline-block;
background: rgba(0, 255, 0, 0.1);
border: 1px solid rgba(0, 255, 0, 0.3);
color: var(--accent-color);
font-size: 0.85rem;
font-weight: 600;
letter-spacing: 0.12em;
text-transform: uppercase;
padding: 6px 16px;
border-radius: 50px;
margin-bottom: 24px;
}
.ar-subtitle {
color: var(--text-secondary);
font-size: 1.1rem;
line-height: 1.7;
margin-bottom: 24px;
}
.ar-login-alt {
font-size: 0.95rem;
color: var(--text-secondary);
}
.ar-login-link {
color: var(--accent-color);
font-weight: 600;
text-decoration: underline;
margin-left: 4px;
}
/* Form */
.ar-container {
max-width: 820px !important;
}
.ar-form {
padding: 48px;
border-radius: 24px;
}
.ar-form-header {
margin-bottom: 36px;
}
.ar-form-header h2 {
font-size: 1.6rem;
color: #fff;
margin-bottom: 8px;
}
.ar-form-header p {
color: var(--text-secondary);
font-size: 0.9rem;
}
.ar-grid-2 {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20px;
margin-bottom: 20px;
}
@media (max-width: 600px) {
.ar-grid-2 { grid-template-columns: 1fr; }
.ar-form { padding: 28px 20px; }
}
.ar-field {
display: flex;
flex-direction: column;
gap: 8px;
}
.ar-label {
font-size: 0.88rem;
font-weight: 600;
color: var(--text-secondary);
letter-spacing: 0.04em;
}
.ar-required {
color: var(--accent-color);
margin-left: 2px;
}
.ar-input {
background: rgba(255, 255, 255, 0.04);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 10px;
color: var(--text-primary);
font-family: 'Outfit', sans-serif;
font-size: 1rem;
padding: 13px 16px;
transition: border-color 0.25s, box-shadow 0.25s;
width: 100%;
outline: none;
box-sizing: border-box;
}
.ar-input option {
background: #1a1a1a;
}
.ar-input:focus {
border-color: rgba(0, 255, 0, 0.5);
box-shadow: 0 0 0 3px rgba(0, 255, 0, 0.08);
}
.ar-textarea {
resize: vertical;
min-height: 130px;
margin-bottom: 20px;
}
.ar-disclaimer {
display: flex;
align-items: center;
gap: 10px;
font-size: 0.85rem;
color: var(--text-secondary);
background: rgba(255,255,255,0.02);
border: 1px solid rgba(255,255,255,0.06);
border-radius: 10px;
padding: 14px 16px;
margin: 24px 0;
}
.ar-disclaimer svg {
flex-shrink: 0;
color: var(--accent-color);
}
.ar-submit-btn {
width: 100%;
font-size: 1.05rem;
padding: 16px;
border-radius: 12px;
}
/* Success */
.ar-success {
max-width: 500px;
margin: 200px auto 0;
padding: 60px 48px;
text-align: center;
border-radius: 24px;
}
.ar-success-icon {
width: 72px;
height: 72px;
border-radius: 50%;
background: rgba(0, 255, 0, 0.12);
border: 2px solid rgba(0, 255, 0, 0.4);
color: var(--accent-color);
font-size: 2rem;
display: flex;
align-items: center;
justify-content: center;
margin: 0 auto 24px;
}
.ar-success h2 {
font-size: 1.8rem;
color: #fff;
margin-bottom: 16px;
}
.ar-success p {
color: var(--text-secondary);
line-height: 1.7;
margin-bottom: 12px;
}
.ar-redirect {
font-size: 0.85rem;
color: rgba(153,153,153,0.6) !important;
margin-top: 24px !important;
}
@@ -0,0 +1,133 @@
import React, { useState } from 'react';
import { useNavigate, Link } from 'react-router-dom';
import './AccessRequest.css';
const API_BASE = import.meta.env.VITE_API_URL || '';
const FIELD = ({ id, label, type = 'text', required = true, value, onChange, as: As = 'input', children, rows }) => (
<div className="ar-field">
<label className="ar-label" htmlFor={id}>{label}{required && <span className="ar-required">*</span>}</label>
{As === 'select' ? (
<select id={id} className="ar-input" value={value} onChange={onChange} required={required}>
{children}
</select>
) : As === 'textarea' ? (
<textarea id={id} className="ar-input ar-textarea" value={value} onChange={onChange} required={required} rows={rows || 4} />
) : (
<input id={id} type={type} className="ar-input" value={value} onChange={onChange} required={required} />
)}
</div>
);
export default function AccessRequest() {
const [formData, setFormData] = useState({
name: '', company: '', role: '', email: '', phone: '', reason: '', purpose: ''
});
const [submitted, setSubmitted] = useState(false);
const [submitting, setSubmitting] = useState(false);
const [error, setError] = useState('');
const navigate = useNavigate();
const set = (key) => (e) => setFormData(prev => ({ ...prev, [key]: e.target.value }));
const handleSubmit = async (e) => {
e.preventDefault();
setSubmitting(true);
setError('');
try {
if (!formData.name || !formData.email || !formData.company) {
throw new Error('Pflichtfelder fehlen.');
}
const res = await fetch(`${API_BASE}/api/access-requests`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ user_data: formData }),
});
if (res.ok) {
setSubmitted(true);
setTimeout(() => navigate('/'), 4000);
} else {
setError('Übermittlung fehlgeschlagen. Bitte versuchen Sie es erneut.');
}
} catch (err) {
console.error(err);
setError('Fehler bei der Übermittlung. Bitte prüfen Sie Ihre Eingaben.');
} finally {
setSubmitting(false);
}
};
if (submitted) {
return (
<div className="ar-page">
<div className="ar-success glass-panel">
<div className="ar-success-icon"></div>
<h2>Anfrage eingegangen</h2>
<p>Vielen Dank, <strong>{formData.name}</strong>. Wir prüfen Ihre Anfrage und melden uns in Kürze bei <strong>{formData.email}</strong>.</p>
<p className="ar-redirect">Sie werden automatisch weitergeleitet</p>
</div>
</div>
);
}
return (
<div className="ar-page">
{/* Hero */}
<div className="ar-hero">
<div className="hero-glow background-mesh" />
<div className="ar-hero-content">
<p className="ar-label-tag">Geschützter Bereich</p>
<h1>Zugang <span className="text-gradient">anfragen</span></h1>
<p className="ar-subtitle">Bitte geben Sie Ihre beruflichen Daten an. Unser Team prüft Ihre Anfrage und schaltet Ihnen den Zugang zu vertraulichen Investorenunterlagen frei.</p>
<div className="ar-login-alt">
Bereits registriert? <Link to="/login" className="ar-login-link">Hier einloggen</Link>
</div>
</div>
</div>
{/* Form */}
<div className="ar-container app-container">
<form className="ar-form glass-panel" onSubmit={handleSubmit} noValidate>
<div className="ar-form-header">
<h2>Ihre Daten</h2>
<p>Alle mit <span className="ar-required">*</span> markierten Felder sind Pflichtfelder.</p>
</div>
<div className="ar-grid-2">
<FIELD id="ar-name" label="Vollständiger Name" value={formData.name} onChange={set('name')} />
<FIELD id="ar-company" label="Unternehmen / Organisation" value={formData.company} onChange={set('company')} />
<FIELD id="ar-role" label="Rolle / Position" value={formData.role} onChange={set('role')} />
<FIELD id="ar-email" label="Geschäftliche E-Mail" type="email" value={formData.email} onChange={set('email')} />
<FIELD id="ar-phone" label="Telefonnummer" type="tel" value={formData.phone} onChange={set('phone')} />
<FIELD id="ar-purpose" label="Gesprächsziel" as="select" value={formData.purpose} onChange={set('purpose')}>
<option value="">Bitte wählen</option>
<option value="funding">Finanzierungsgespräch (MBG / Förderung)</option>
<option value="partnership">Unternehmenspartnerschaft</option>
<option value="evaluation">Allgemeine Evaluierung</option>
<option value="other">Sonstiges</option>
</FIELD>
</div>
<FIELD id="ar-reason" label="Motivation & Interesse" as="textarea" rows={5} value={formData.reason} onChange={set('reason')}>
</FIELD>
{error && (
<div className="login-error" style={{ marginBottom: '16px' }}>{error}</div>
)}
<div className="ar-disclaimer">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>
Ihre Daten werden vertraulich behandelt und ausschließlich zur Prüfung Ihrer Zugriffsanfrage verwendet.
</div>
<button type="submit" className="primary-button ar-submit-btn" disabled={submitting}>
{submitting ? 'Wird gesendet…' : 'Zugang anfragen →'}
</button>
</form>
</div>
</div>
);
}
@@ -0,0 +1,283 @@
.ad-page {
min-height: 100vh;
padding-bottom: 120px;
}
/* Hero */
.ad-hero {
position: relative;
padding: 160px 20px 80px;
text-align: center;
overflow: hidden;
}
.ad-hero-content {
position: relative;
z-index: 10;
max-width: 700px;
margin: 0 auto;
}
.ad-tag {
display: inline-block;
background: rgba(255, 165, 0, 0.1);
border: 1px solid rgba(255, 165, 0, 0.3);
color: #ffb347;
font-size: 0.82rem;
font-weight: 600;
letter-spacing: 0.1em;
text-transform: uppercase;
padding: 6px 16px;
border-radius: 50px;
margin-bottom: 24px;
}
.ad-hero h1 {
font-size: clamp(2.5rem, 5vw, 3.5rem);
line-height: 1.1;
margin-bottom: 16px;
}
.ad-subtitle {
color: var(--text-secondary);
font-size: 1.05rem;
line-height: 1.7;
}
/* Container */
.ad-container {
display: flex;
flex-direction: column;
gap: 24px;
max-width: 1100px !important;
}
/* Metrics */
.ad-metrics {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 16px;
}
@media (max-width: 700px) {
.ad-metrics { grid-template-columns: repeat(2, 1fr); }
}
.ad-metric {
display: flex;
flex-direction: column;
align-items: center;
padding: 24px 16px;
border-radius: 16px;
text-align: center;
gap: 6px;
}
.ad-metric-highlight {
border-color: rgba(255, 165, 0, 0.3) !important;
background: rgba(255, 165, 0, 0.05) !important;
}
.ad-metric-icon { font-size: 1.4rem; }
.ad-metric-val {
font-size: 2.2rem;
font-weight: 800;
color: #fff;
}
.ad-metric-label {
font-size: 0.8rem;
color: var(--text-secondary);
text-transform: uppercase;
letter-spacing: 0.06em;
}
/* Table section */
.ad-section {
border-radius: 20px;
overflow: hidden;
}
.ad-section-head {
display: flex;
align-items: center;
justify-content: space-between;
padding: 28px 32px;
border-bottom: 1px solid rgba(255,255,255,0.06);
}
.ad-section-head h2 {
font-size: 1.3rem;
color: #fff;
}
.ad-count {
font-size: 0.82rem;
color: var(--text-secondary);
background: rgba(255,255,255,0.04);
padding: 4px 12px;
border-radius: 50px;
border: 1px solid rgba(255,255,255,0.08);
}
.ad-table-wrap {
overflow-x: auto;
}
.ad-table {
width: 100%;
border-collapse: collapse;
font-size: 0.9rem;
}
.ad-table th {
text-align: left;
padding: 14px 20px;
font-size: 0.78rem;
font-weight: 600;
color: var(--text-secondary);
text-transform: uppercase;
letter-spacing: 0.07em;
border-bottom: 1px solid rgba(255,255,255,0.06);
}
.ad-row {
cursor: pointer;
transition: background 0.2s;
}
.ad-row:hover, .ad-row-active {
background: rgba(255,255,255,0.03);
}
.ad-row td {
padding: 16px 20px;
border-bottom: 1px solid rgba(255,255,255,0.04);
vertical-align: middle;
color: var(--text-primary);
}
.ad-row td strong {
display: block;
margin-bottom: 3px;
}
.ad-sub {
color: var(--text-secondary);
font-size: 0.82rem;
}
.ad-muted { color: var(--text-secondary); }
.ad-done { display: block; text-align: center; }
/* Badges */
.ad-badge {
display: inline-block;
font-size: 0.75rem;
font-weight: 700;
padding: 4px 12px;
border-radius: 50px;
letter-spacing: 0.04em;
}
.ad-badge-pending { background: rgba(255,165,0,0.15); color: #ffb347; border: 1px solid rgba(255,165,0,0.3); }
.ad-badge-approved { background: rgba(0,255,0,0.1); color: var(--accent-color); border: 1px solid rgba(0,255,0,0.25); }
.ad-badge-rejected { background: rgba(255,60,60,0.1); color: #ff6b6b; border: 1px solid rgba(255,60,60,0.2); }
/* Action buttons */
.ad-actions {
display: flex;
gap: 8px;
}
.ad-btn {
font-family: 'Outfit', sans-serif;
font-size: 0.8rem;
font-weight: 700;
padding: 6px 14px;
border-radius: 8px;
border: none;
cursor: pointer;
transition: opacity 0.2s;
}
.ad-btn:hover { opacity: 0.8; }
.ad-btn-approve { background: rgba(0,255,0,0.2); color: var(--accent-color); border: 1px solid rgba(0,255,0,0.3); }
.ad-btn-reject { background: rgba(255,60,60,0.15); color: #ff6b6b; border: 1px solid rgba(255,60,60,0.25); }
/* Detail row */
.ad-detail-row td {
background: rgba(0,255,0,0.02);
border-bottom: 1px solid rgba(255,255,255,0.04);
}
.ad-detail {
padding: 16px 20px;
color: var(--text-secondary);
font-size: 0.9rem;
line-height: 1.6;
}
.ad-detail a { color: var(--accent-color); }
.ad-detail-reason {
margin: 8px 0 0;
font-style: italic;
}
/* Info grid */
.ad-info-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 16px;
}
@media (max-width: 700px) {
.ad-info-grid { grid-template-columns: 1fr; }
}
.ad-info {
border-radius: 16px;
padding: 28px;
}
.ad-info h3 {
font-size: 1.05rem;
color: #fff;
margin-bottom: 20px;
}
.ad-info-list {
list-style: none;
padding: 0;
margin: 0;
display: flex;
flex-direction: column;
gap: 12px;
}
.ad-info-list li {
display: flex;
justify-content: space-between;
font-size: 0.88rem;
color: var(--text-secondary);
padding-bottom: 12px;
border-bottom: 1px solid rgba(255,255,255,0.05);
}
.ad-info-list li:last-child { border-bottom: none; padding-bottom: 0; }
.ad-info-list strong {
color: #fff;
font-weight: 600;
}
/* Note */
.ad-mockup-note {
text-align: center;
font-size: 0.82rem;
color: rgba(153,153,153,0.5);
margin-top: 8px;
}
@@ -0,0 +1,206 @@
import React, { useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import { useAuth } from '../contexts/AuthContext';
import './AdminDashboard.css';
const API_BASE = import.meta.env.VITE_API_URL || '';
const STATUS_LABELS = {
pending: { label: 'Ausstehend', cls: 'ad-badge-pending' },
approved: { label: 'Genehmigt', cls: 'ad-badge-approved' },
rejected: { label: 'Abgelehnt', cls: 'ad-badge-rejected' },
};
export default function AdminDashboard() {
const navigate = useNavigate();
const { logout } = useAuth();
const [requests, setRequests] = useState([]);
const [activeRow, setActiveRow] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetchRequests();
}, []);
const fetchRequests = async () => {
try {
const res = await fetch(`${API_BASE}/api/access-requests`, {
credentials: 'include',
});
if (!res.ok) throw new Error('Fetch failed');
const data = await res.json();
const formatted = data.map(row => ({
id: row.id,
status: row.status,
date: new Date(row.created_at).toLocaleDateString('de-DE'),
name: row.user_data?.name || 'Unbekannt',
company: row.user_data?.company || 'Unbekannt',
role: row.user_data?.role || '',
email: row.user_data?.email || '',
purpose: row.user_data?.purpose || '',
reason: row.user_data?.reason || ''
}));
setRequests(formatted);
} catch (err) {
console.error('Error fetching requests:', err);
} finally {
setLoading(false);
}
};
const updateStatus = async (id, newStatus) => {
try {
const res = await fetch(`${API_BASE}/api/access-requests/${id}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
credentials: 'include',
body: JSON.stringify({ status: newStatus }),
});
if (!res.ok) throw new Error('Update failed');
setRequests(rs => rs.map(r => r.id === id ? { ...r, status: newStatus } : r));
} catch (err) {
console.error('Error updating status:', err);
alert('Status-Update fehlgeschlagen.');
}
};
const approve = (id) => updateStatus(id, 'approved');
const reject = (id) => updateStatus(id, 'rejected');
const metrics = {
total: requests.length,
pending: requests.filter(r => r.status === 'pending').length,
approved: requests.filter(r => r.status === 'approved').length,
rejected: requests.filter(r => r.status === 'rejected').length,
};
const handleLogout = async () => {
await logout();
navigate('/');
};
return (
<div className="ad-page">
<div className="ad-hero">
<div className="hero-glow background-mesh" />
<div className="ad-hero-content">
<div className="admin-header-row">
<p className="ad-tag">Control Center</p>
<button onClick={handleLogout} className="logout-btn">Abmelden</button>
</div>
<h1>Admin <span className="text-gradient">Dashboard</span></h1>
<p className="ad-subtitle">Verwaltung von Zugriffsanfragen und Systemmetriken.</p>
</div>
</div>
<div className="ad-container app-container">
{/* Metrics */}
<div className="ad-metrics">
{[
{ label: 'Gesamt Anfragen', val: metrics.total, icon: '📋' },
{ label: 'Ausstehend', val: metrics.pending, icon: '⏳', highlight: true },
{ label: 'Genehmigt', val: metrics.approved, icon: '✅' },
{ label: 'Abgelehnt', val: metrics.rejected, icon: '❌' },
].map(({ label, val, icon, highlight }) => (
<div key={label} className={`ad-metric glass-panel ${highlight && val > 0 ? 'ad-metric-highlight' : ''}`}>
<span className="ad-metric-icon">{icon}</span>
<span className="ad-metric-val">{val}</span>
<span className="ad-metric-label">{label}</span>
</div>
))}
</div>
{/* Request Table */}
<section className="ad-section glass-panel">
<div className="ad-section-head">
<h2>Zugriffsanfragen</h2>
<span className="ad-count">{requests.length} Einträge</span>
</div>
<div className="ad-table-wrap">
<table className="ad-table">
<thead>
<tr>
<th>Name & Organisation</th>
<th>Rolle</th>
<th>Gesprächsziel</th>
<th>Datum</th>
<th>Status</th>
<th>Aktionen</th>
</tr>
</thead>
<tbody>
{requests.map(r => {
const { label, cls } = STATUS_LABELS[r.status];
return (
<React.Fragment key={r.id}>
<tr
className={`ad-row ${activeRow === r.id ? 'ad-row-active' : ''}`}
onClick={() => setActiveRow(activeRow === r.id ? null : r.id)}
>
<td>
<strong>{r.name}</strong>
<span className="ad-sub">{r.company}</span>
</td>
<td className="ad-muted">{r.role}</td>
<td className="ad-muted">{r.purpose}</td>
<td className="ad-muted">{r.date}</td>
<td><span className={`ad-badge ${cls}`}>{label}</span></td>
<td>
{r.status === 'pending' && (
<div className="ad-actions" onClick={e => e.stopPropagation()}>
<button className="ad-btn ad-btn-approve" onClick={() => approve(r.id)}>Genehmigen</button>
<button className="ad-btn ad-btn-reject" onClick={() => reject(r.id)}>Ablehnen</button>
</div>
)}
{r.status !== 'pending' && (
<span className="ad-muted ad-done"></span>
)}
</td>
</tr>
{activeRow === r.id && (
<tr className="ad-detail-row">
<td colSpan={6}>
<div className="ad-detail">
<strong>E-Mail:</strong> <a href={`mailto:${r.email}`}>{r.email}</a>
<br /><br />
<strong>Kommentar / Motivation:</strong>
<p className="ad-detail-reason">{r.reason}</p>
</div>
</td>
</tr>
)}
</React.Fragment>
);
})}
</tbody>
</table>
</div>
</section>
{/* System info */}
<section className="ad-info-grid">
<div className="ad-info glass-panel">
<h3>Systemstatus</h3>
<ul className="ad-info-list">
<li><span>Genehmigte Nutzer</span><strong>{metrics.approved}</strong></li>
<li><span>Ausstehende Anfragen</span><strong>{metrics.pending}</strong></li>
</ul>
</div>
<div className="ad-info glass-panel">
<h3>Hinweise</h3>
<ul className="ad-info-list">
<li><span> E-Mail-Benachrichtigung</span><strong>Aktiv</strong></li>
<li><span>📄 Pitch Deck</span><strong>Versand per E-Mail</strong></li>
</ul>
</div>
</section>
{loading && <p style={{textAlign: 'center', marginTop: '2rem'}}>Lade Anfragen...</p>}
</div>
</div>
);
}
@@ -0,0 +1,165 @@
import React from 'react';
import '../components/Hero.css';
export default function Datenschutz() {
return (
<main>
<section className="app-container" style={{ paddingTop: '150px', paddingBottom: '100px', maxWidth: '900px', margin: '0 auto' }}>
<h1 style={{ fontSize: '3rem', marginBottom: '40px' }}><span className="text-gradient">Datenschutzerklärung</span></h1>
<div className="legal-text-container" style={{ color: 'var(--text-secondary)', lineHeight: '1.8', fontSize: '1.05rem' }}>
<h2 style={{ color: '#fff', fontSize: '1.8rem', marginBottom: '30px', marginTop: '50px' }}>I. Allgemeine Informationen zum Datenschutz & Betroffenenrechte</h2>
<h3 style={{ color: 'var(--accent-color)', fontSize: '1.3rem', marginBottom: '15px' }}>§1 Allgemeine Informationen</h3>
<p style={{ marginBottom: '20px' }}>
Datenschutz ist ein wichtiges Thema. Im Folgenden informieren wir über die Erhebung und Verarbeitung von personenbezogenen Daten. Personenbezogene Daten sind alle Daten, die auf Sie persönlich beziehbar sind.
</p>
<p style={{ marginBottom: '20px' }}>
<strong>Verantwortlicher gem. Art. 4 Abs. 7 DSGVO</strong><br/>
Data Hive Cassel GmbH<br/>
Universitätsplatz 12<br/>
34127 Kassel
</p>
<p style={{ marginBottom: '20px' }}>
<strong>Datenschutzbeauftragter</strong><br/>
Den persönlich bestellten Datenschutzbeauftragten unserer Firma erreichen Sie unter folgender Adresse:<br/>
Herr Dr.-Ing. Alexander Schrodt<br/>
Data Hive Cassel GmbH<br/>
Universitätsplatz 12<br/>
34127 Kassel<br/>
E-Mail: schrodt@d-hive.de
</p>
<p style={{ marginBottom: '30px' }}>Sollten Sie Fragen zur Verarbeitung, der Sicherheit oder ein Auskunftsverlangen haben, können Sie sich direkt vertrauensvoll an diesen wenden.</p>
<h3 style={{ color: 'var(--accent-color)', fontSize: '1.3rem', marginBottom: '15px' }}>§2 Allgemeine Übersicht der Daten und Verarbeitungsvorgänge</h3>
<p style={{ marginBottom: '20px' }}>Wir wollen Ihnen die geforderte Übersichtlichkeit gem. Art. 12 DSGVO bieten. Daher folgende Übersicht der Verarbeitungen:</p>
<p style={{ marginBottom: '10px' }}><strong>Arten der verarbeiteten Daten:</strong></p>
<ul style={{ paddingLeft: '20px', marginBottom: '20px' }}>
<li style={{ marginBottom: '8px' }}>Nutzungsdaten Kommunikationsdaten (Beim Abruf einer Internetseite, IP Adresse, Geräteinformation, Zugriffszeit und Zugriffszeitpunkt usw.)</li>
<li style={{ marginBottom: '8px' }}>Kontaktdaten bei Anmeldung oder Eingabe der Daten</li>
<li style={{ marginBottom: '8px' }}>Bestandsdaten (Name, Firma, Adresse)</li>
<li style={{ marginBottom: '8px' }}>Kommunikationsdaten (ggf. Meta-Daten über Anrufe, E-Mails)</li>
<li style={{ marginBottom: '8px' }}>Inhaltsdaten (insbesondere bei der Zusendung von Mails)</li>
</ul>
<p style={{ marginBottom: '20px' }}>Ausserdem (intern) noch folgende zusätzliche Daten für unsere Kunden, Interessenten, Lieferanten und Geschäftspartnern für die Erbringung von Leistungen im Bereich Angebots- und Vertragswesen, Service und Marketing, der Direktwerbung und der Kundenpflege:</p>
<ul style={{ paddingLeft: '20px', marginBottom: '20px' }}>
<li style={{ marginBottom: '8px' }}>Vertragsdaten</li>
<li style={{ marginBottom: '8px' }}>Bestandsdaten der Kunden (CRM)</li>
<li style={{ marginBottom: '8px' }}>Lieferantendaten</li>
<li style={{ marginBottom: '8px' }}>Zahlungsdaten</li>
<li style={{ marginBottom: '8px' }}>Auftragsdaten und Rechnungsdaten</li>
</ul>
<p style={{ marginBottom: '10px' }}><strong>Betroffene Personen (Kategorien):</strong></p>
<ul style={{ paddingLeft: '20px', marginBottom: '20px' }}>
<li style={{ marginBottom: '8px' }}>Nutzer dieser Internetseite (auch Besucher genannt)</li>
<li style={{ marginBottom: '8px' }}>Kunden</li>
<li style={{ marginBottom: '8px' }}>Lieferanten</li>
</ul>
<p style={{ marginBottom: '10px' }}><strong>Zwecke:</strong></p>
<ul style={{ paddingLeft: '20px', marginBottom: '30px' }}>
<li style={{ marginBottom: '8px' }}>Betreiben der Website und Zur Verfügung stellen der Information</li>
<li style={{ marginBottom: '8px' }}>Die Sicherstellung des Betriebs der Internetseite und unserer Systeme (z. B. Firewall)</li>
<li style={{ marginBottom: '8px' }}>Kommunikation mit unseren Kunden</li>
<li style={{ marginBottom: '8px' }}>Beantwortung von Anfragen</li>
<li style={{ marginBottom: '8px' }}>Optimierung und Analyse der Website</li>
<li style={{ marginBottom: '8px' }}>Zur Verfügung stellen von Informationen für unsere (potentiellen) Kunden</li>
</ul>
<h3 style={{ color: 'var(--accent-color)', fontSize: '1.3rem', marginBottom: '15px' }}>§3 Ihre Rechte</h3>
<p style={{ marginBottom: '15px' }}>Sie haben gegenüber uns folgende Rechte hinsichtlich der Sie betreffenden personenbezogenen Daten:</p>
<ul style={{ paddingLeft: '20px', marginBottom: '20px' }}>
<li style={{ marginBottom: '8px' }}>Recht auf Auskunft, Berichtigung oder Löschung, Einschränkung der Verarbeitung, Widerspruch gegen die Verarbeitung, Datenübertragbarkeit, Beschwerde bei der Datenschutz-Aufsichtsbehörde.</li>
</ul>
<p style={{ marginBottom: '15px' }}><strong>Ausführliche Rechte:</strong></p>
<ul style={{ paddingLeft: '20px', marginBottom: '20px' }}>
<li style={{ marginBottom: '8px' }}>gemäß Art. 15 DSGVO Auskunft über Ihre von uns verarbeiteten personenbezogenen Daten zu verlangen.</li>
<li style={{ marginBottom: '8px' }}>gemäß Art. 16 DSGVO unverzüglich die Berichtigung unrichtiger oder Vervollständigung Ihrer Daten zu verlangen.</li>
<li style={{ marginBottom: '8px' }}>gemäß Art. 17 DSGVO die Löschung Ihrer Daten zu verlangen.</li>
<li style={{ marginBottom: '8px' }}>gemäß Art. 18 DSGVO die Einschränkung der Verarbeitung zu verlangen.</li>
<li style={{ marginBottom: '8px' }}>gemäß Art. 20 DSGVO Ihre Daten in strukturiertem Format zu erhalten (Datenübertragbarkeit).</li>
<li style={{ marginBottom: '8px' }}>gemäß Art. 7 Abs. 3 DSGVO Ihre einmal erteilte Einwilligung jederzeit zu widerrufen.</li>
<li style={{ marginBottom: '8px' }}>gemäß Art. 77 DSGVO sich bei einer Aufsichtsbehörde zu beschweren.</li>
</ul>
<p style={{ marginBottom: '15px' }}><strong>Ausnahmen (Kein Recht auf Löschung):</strong></p>
<ul style={{ paddingLeft: '20px', marginBottom: '30px' }}>
<li style={{ marginBottom: '8px' }}>Zur Ausübung des Rechts auf freie Meinungsäußerung und Information.</li>
<li style={{ marginBottom: '8px' }}>Zur Erfüllung rechtlicher Verpflichtungen.</li>
<li style={{ marginBottom: '8px' }}>Aus Gründen des öffentlichen Interesses (Gesundheit, Archiv, Forschung).</li>
<li style={{ marginBottom: '8px' }}>Zur Geltendmachung, Ausübung oder Verteidigung von Rechtsansprüchen.</li>
</ul>
<h3 style={{ color: 'var(--accent-color)', fontSize: '1.3rem', marginBottom: '15px' }}>§4 Rechtsgrundlagen allgemein</h3>
<p style={{ marginBottom: '30px' }}>
Bei der Verarbeitung zur Erfüllung eines Vertrags dient Art. 6 Abs. 1 lit. b DSGVO als Rechtsgrundlage. Zur Wahrung eines berechtigten Interesses dient Art. 6 Abs. 1 lit. f DSGVO. Zur Erfüllung rechtlicher Verpflichtungen dient Art. 6 Abs. 1 lit. c DSGVO. Bei lebenswichtigen Interessen dient Art. 6 Abs. 1 lit. d DSGVO. Bei Einwilligung dient Art. 6 Abs. 1 lit. a DSGVO.
</p>
<h2 style={{ color: '#fff', fontSize: '1.8rem', marginBottom: '30px', marginTop: '50px' }}>II. Website</h2>
<h3 style={{ color: 'var(--accent-color)', fontSize: '1.3rem', marginBottom: '15px' }}>§5 Bestimmungen für Nutzer der Website</h3>
<p style={{ marginBottom: '15px' }}><strong>Allgemeine Daten und Logfiles</strong></p>
<p style={{ marginBottom: '20px' }}>
Bei informatorischer Nutzung erheben wir personenlose Daten, die Ihr Browser übermittelt (berechtigtes Interesse, Art. 6 Abs. 1 lit. f DSGVO). Die Speicherung in Logfiles erfolgt für Sicherheit und Optimierung für maximal 7 Tage, danach werden IP-Adressen verfremdet/gelöscht.
</p>
<p style={{ marginBottom: '15px' }}><strong>Cookies</strong></p>
<p style={{ marginBottom: '30px' }}>
Wir verwenden technisch notwendige Cookies (Art. 6 Abs. 1 lit. f DSGVO), die meist nach Browser-Schließung gelöscht werden, sowie Analyse-/Marketing-Cookies (Art. 6 Abs. 1 lit. a DSGVO). Sie können Cookies jederzeit im Browser löschen.
</p>
<h3 style={{ color: 'var(--accent-color)', fontSize: '1.3rem', marginBottom: '15px' }}>§6 Dienste von Drittanbietern</h3>
<p style={{ marginBottom: '20px' }}>Wir nutzen Dienste, um unser Angebot nutzerfreundlicher zu gestalten (Art. 6 Abs. 1 lit. f DSGVO oder Art. 6 Abs. 1 lit. a DSGVO bei Einwilligung).</p>
<p style={{ marginBottom: '15px' }}><strong>Google-Dienste</strong></p>
<p style={{ marginBottom: '20px' }}>
Wir verwenden Google Analytics (_anonymizeIp aktiviert), Google Ads (Remarketing, Conversion-Tracking) und Google Tag Manager nach Einwilligung (Art. 6 Abs. 1 lit. a DSGVO). Datenübermittlung in die USA basiert auf Art. 49 Abs. 1 lit. a DSGVO. Widerspruch möglich via Browser-Plug-In oder Cookie-Opt-Out.
</p>
<p style={{ marginBottom: '15px' }}><strong>Weitere Dienste</strong></p>
<ul style={{ paddingLeft: '20px', marginBottom: '30px' }}>
<li style={{ marginBottom: '8px' }}><strong>YouTube & Vimeo:</strong> Eingebunden im erweiterten Datenschutz-Modus.</li>
<li style={{ marginBottom: '8px' }}><strong>LinkedIn Analytics / Ads:</strong> Conversion-Tracking und Retargeting.</li>
<li style={{ marginBottom: '8px' }}><strong>Calendly:</strong> Zur Terminbuchung.</li>
<li style={{ marginBottom: '8px' }}><strong>Social Media:</strong> Links zu den Portalen (keine Pflicht).</li>
<li style={{ marginBottom: '8px' }}><strong>Facebook-Pixel / Custom Audiences:</strong> Für Marketing.</li>
<li style={{ marginBottom: '8px' }}><strong>Hotjar:</strong> Zur Nutzungsverhaltensanalyse.</li>
<li style={{ marginBottom: '8px' }}><strong>Nudgify:</strong> Marketing-Hinweise.</li>
<li style={{ marginBottom: '8px' }}><strong>Webflow (CDN):</strong> Erhöhte Ausfallsicherheit (Art. 6 Abs. 1 lit. f DSGVO).</li>
<li style={{ marginBottom: '8px' }}><strong>Matomo:</strong> Eigenes Open-Source Analytics-Tool. IP anonymisiert.</li>
</ul>
<h3 style={{ color: 'var(--accent-color)', fontSize: '1.3rem', marginBottom: '15px' }}>§7 Formulare und E-Mail Kontakt</h3>
<p style={{ marginBottom: '30px' }}>
Ihre im Formular oder per Mail gesendeten Daten (Name, E-Mail, Telefon, etc.) werden nur zur Beantwortung gespeichert (Art. 6 Abs. 1 lit. f DSGVO) und anschließend gelöscht.
</p>
<h2 style={{ color: '#fff', fontSize: '1.8rem', marginBottom: '30px', marginTop: '50px' }}>III. Newsletterabonnenten</h2>
<h3 style={{ color: 'var(--accent-color)', fontSize: '1.3rem', marginBottom: '15px' }}>§8 Bestimmungen für den Newsletter</h3>
<p style={{ marginBottom: '30px' }}>
Versand nur nach ausdrücklicher Einwilligung (Art. 6 Abs. 1 lit. a DSGVO). Nutzung von Web-Beacons zur Reichweitenmessung (Art. 6 Abs. 1 lit. f DSGVO). Widerruf ist per Abmeldelink jederzeit möglich.
</p>
<h2 style={{ color: '#fff', fontSize: '1.8rem', marginBottom: '30px', marginTop: '50px' }}>IV. Bewerbungen</h2>
<h3 style={{ color: 'var(--accent-color)', fontSize: '1.3rem', marginBottom: '15px' }}>§9 Bestimmungen für Bewerber</h3>
<p style={{ marginBottom: '30px' }}>
Verarbeitung (Stammdaten, Lebenslauf, Zeugnisse) zur Durchführung des Bewerbungsverfahrens (Art. 6 Abs. 1 lit. b DSGVO, § 26 BDSG). Bei Absage erfolgt eine Löschung nach 6 Monaten, es sei denn, es liegt eine Einwilligung für den Talentpool vor.
</p>
<h2 style={{ color: '#fff', fontSize: '1.8rem', marginBottom: '30px', marginTop: '50px' }}>V. Stand der Datenschutzerklärung</h2>
<p style={{ marginBottom: '30px' }}>
Die Datenschutzerklärung wird gelegentlich angepasst. Stand: Juli 2023.
</p>
</div>
</section>
</main>
);
}
+24
View File
@@ -0,0 +1,24 @@
import React from 'react';
import Hero from '../components/Hero';
import Stats from '../components/Stats';
import Services from '../components/Services';
import Customers from '../components/Customers';
import Memberships from '../components/Memberships';
import Team from '../components/Team';
import UseCasesTeaser from '../components/UseCasesTeaser';
import PlatformUSP from '../components/PlatformUSP';
export default function Home() {
return (
<main>
<Hero />
<Stats />
<PlatformUSP />
<Services />
<UseCasesTeaser />
<Team />
<Customers />
<Memberships />
</main>
);
}
@@ -0,0 +1,77 @@
import React from 'react';
import '../components/Hero.css';
export default function Impressum() {
return (
<main>
<section className="app-container" style={{ paddingTop: '150px', paddingBottom: '100px', maxWidth: '900px', margin: '0 auto' }}>
<h1 style={{ fontSize: '3rem', marginBottom: '40px' }}><span className="text-gradient">Impressum</span></h1>
<div className="legal-text-container" style={{ color: 'var(--text-secondary)', lineHeight: '1.8', fontSize: '1.05rem' }}>
<h2 style={{ color: '#fff', fontSize: '1.5rem', marginBottom: '15px', marginTop: '40px' }}>Angaben gemäß § 5 TMG</h2>
<p style={{ marginBottom: '20px' }}>
Data Hive Cassel GmbH<br/>
Universitätsplatz 12<br/>
34127 Kassel
</p>
<p style={{ marginBottom: '20px' }}>
<strong>Vertreten durch die Geschäftsführer:</strong><br/>
Dr.-Ing. Alexander Schrodt, Dr. André Knie
</p>
<p style={{ marginBottom: '20px' }}>
<strong>Kontakt:</strong><br/>
Telefon: +49 561 82793737<br/>
E-Mail: kontakt@d-hive.de
</p>
<p style={{ marginBottom: '40px' }}>
<strong>Registereintrag:</strong><br/>
USt-IdNr.: DE347634609<br/>
Registergericht der GmbH: Amtsgericht Kassel<br/>
Registernummer der GmbH: HRB 18835
</p>
<h2 style={{ color: '#fff', fontSize: '1.8rem', marginBottom: '20px', marginTop: '50px' }}>Haftungsausschluss</h2>
<h3 style={{ color: 'var(--accent-color)', fontSize: '1.2rem', marginBottom: '10px', marginTop: '30px' }}>Haftung für Inhalte</h3>
<p style={{ marginBottom: '20px' }}>
Die Inhalte unserer Seiten wurden mit größter Sorgfalt erstellt. Für die Richtigkeit, Vollständigkeit und Aktualität der Inhalte können wir jedoch keine Gewähr übernehmen. Als Diensteanbieter sind wir gemäß § 7 Abs.1 TMG für eigene Inhalte auf diesen Seiten nach den allgemeinen Gesetzen verantwortlich. Nach §§ 8 bis 10 TMG sind wir als Diensteanbieter jedoch nicht verpflichtet, übermittelte oder gespeicherte fremde Informationen zu überwachen oder nach Umständen zu forschen, die auf eine rechtswidrige Tätigkeit hinweisen. Verpflichtungen zur Entfernung oder Sperrung der Nutzung von Informationen nach den allgemeinen Gesetzen bleiben hiervon unberührt. Eine diesbezügliche Haftung ist jedoch erst ab dem Zeitpunkt der Kenntnis einer konkreten Rechtsverletzung möglich. Bei Bekanntwerden von entsprechenden Rechtsverletzungen werden wir diese Inhalte umgehend entfernen.
</p>
<h3 style={{ color: 'var(--accent-color)', fontSize: '1.2rem', marginBottom: '10px', marginTop: '30px' }}>Haftung für Links</h3>
<p style={{ marginBottom: '20px' }}>
Unser Angebot enthält Links zu externen Webseiten Dritter, auf deren Inhalte wir keinen Einfluss haben. Deshalb können wir für diese fremden Inhalte auch keine Gewähr übernehmen. Für die Inhalte der verlinkten Seiten ist stets der jeweilige Anbieter oder Betreiber der Seiten verantwortlich. Die verlinkten Seiten wurden zum Zeitpunkt der Verlinkung auf mögliche Rechtsverstöße überprüft. Rechtswidrige Inhalte waren zum Zeitpunkt der Verlinkung nicht erkennbar. Eine permanente inhaltliche Kontrolle der verlinkten Seiten ist jedoch ohne konkrete Anhaltspunkte einer Rechtsverletzung nicht zumutbar. Bei Bekanntwerden von Rechtsverletzungen werden wir derartige Links umgehend entfernen.
</p>
<h3 style={{ color: 'var(--accent-color)', fontSize: '1.2rem', marginBottom: '10px', marginTop: '30px' }}>Urheberrecht</h3>
<p style={{ marginBottom: '20px' }}>
Die durch die Seitenbetreiber erstellten Inhalte und Werke auf diesen Seiten unterliegen dem deutschen Urheberrecht. Die Vervielfältigung, Bearbeitung, Verbreitung und jede Art der Verwertung außerhalb der Grenzen des Urheberrechtes bedürfen der schriftlichen Zustimmung des jeweiligen Autors bzw. Erstellers. Downloads und Kopien dieser Seite sind nur für den privaten, nicht kommerziellen Gebrauch gestattet. Soweit die Inhalte auf dieser Seite nicht vom Betreiber erstellt wurden, werden die Urheberrechte Dritter beachtet. Insbesondere werden Inhalte Dritter als solche gekennzeichnet. Sollten Sie trotzdem auf eine Urheberrechtsverletzung aufmerksam werden, bitten wir um einen entsprechenden Hinweis. Bei Bekanntwerden von Rechtsverletzungen werden wir derartige Inhalte umgehend entfernen.
</p>
<h3 style={{ color: 'var(--accent-color)', fontSize: '1.2rem', marginBottom: '10px', marginTop: '30px' }}>Datenschutz</h3>
<p style={{ marginBottom: '20px' }}>
Die Nutzung unserer Webseite ist in der Regel ohne Angabe personenbezogener Daten möglich. Soweit auf unseren Seiten personenbezogene Daten (beispielsweise Name, Anschrift oder eMail-Adressen) erhoben werden, erfolgt dies, soweit möglich, stets auf freiwilliger Basis. Diese Daten werden ohne Ihre ausdrückliche Zustimmung nicht an Dritte weitergegeben.
<br/><br/>
Wir weisen darauf hin, dass die Datenübertragung im Internet (z.B. bei der Kommunikation per E-Mail) Sicherheitslücken aufweisen kann. Ein lückenloser Schutz der Daten vor dem Zugriff durch Dritte ist nicht möglich.
<br/><br/>
Der Nutzung von im Rahmen der Impressumspflicht veröffentlichten Kontaktdaten durch Dritte zur Übersendung von nicht ausdrücklich angeforderter Werbung und Informationsmaterialien wird hiermit ausdrücklich widersprochen. Die Betreiber der Seiten behalten sich ausdrücklich rechtliche Schritte im Falle der unverlangten Zusendung von Werbeinformationen, etwa durch Spam-Mails, vor.
</p>
<h2 style={{ color: '#fff', fontSize: '1.8rem', marginBottom: '20px', marginTop: '50px' }}>Drittanbieter</h2>
<h3 style={{ color: 'var(--text-primary)', fontSize: '1.2rem', marginBottom: '10px', marginTop: '30px' }}>Google Analytics</h3>
<p style={{ marginBottom: '20px' }}>
Diese Website benutzt Google Analytics, einen Webanalysedienst der Google Inc. ("Google"). Google Analytics verwendet sog. "Cookies", Textdateien, die auf Ihrem Computer gespeichert werden und die eine Analyse der Benutzung der Website durch Sie ermöglicht. Die durch den Cookie erzeugten Informationen über Ihre Benutzung dieser Website (einschließlich Ihrer IP-Adresse) wird an einen Server von Google in den USA übertragen und dort gespeichert. Google wird diese Informationen benutzen, um Ihre Nutzung der Website auszuwerten, um Reports über die Websiteaktivitäten für die Websitebetreiber zusammenzustellen und um weitere mit der Websitenutzung und der Internetnutzung verbundene Dienstleistungen zu erbringen. Auch wird Google diese Informationen gegebenenfalls an Dritte übertragen, sofern dies gesetzlich vorgeschrieben oder soweit Dritte diese Daten im Auftrag von Google verarbeiten. Google wird in keinem Fall Ihre IP-Adresse mit anderen Daten der Google in Verbindung bringen. Sie können die Installation der Cookies durch eine entsprechende Einstellung Ihrer Browser Software verhindern; wir weisen Sie jedoch darauf hin, dass Sie in diesem Fall gegebenenfalls nicht sämtliche Funktionen dieser Website voll umfänglich nutzen können. Durch die Nutzung dieser Website erklären Sie sich mit der Bearbeitung der über Sie erhobenen Daten durch Google in der zuvor beschriebenen Art und Weise und zu dem zuvor benannten Zweck einverstanden.
</p>
<h3 style={{ color: 'var(--text-primary)', fontSize: '1.2rem', marginBottom: '10px', marginTop: '30px' }}>Google AdSense</h3>
<p style={{ marginBottom: '20px' }}>
Diese Website benutzt Google Adsense, einen Webanzeigendienst der Google Inc., USA ("Google"). Google Adsense verwendet sog. "Cookies" (Textdateien), die auf Ihrem Computer gespeichert werden und die eine Analyse der Benutzung der Website durch Sie ermöglicht. Google Adsense verwendet auch sog. "Web Beacons" (kleine unsichtbare Grafiken) zur Sammlung von Informationen. Durch die Verwendung des Web Beacons können einfache Aktionen wie der Besucherverkehr auf der Webseite aufgezeichnet und gesammelt werden. Die durch den Cookie und/oder Web Beacon erzeugten Informationen über Ihre Benutzung dieser Website (einschließlich Ihrer IP-Adresse) werden an einen Server von Google in den USA übertragen und dort gespeichert. Google wird diese Informationen benutzen, um Ihre Nutzung der Website im Hinblick auf die Anzeigen auszuwerten, um Reports über die Websiteaktivitäten und Anzeigen für die Websitebetreiber zusammenzustellen und um weitere mit der Websitenutzung und der Internetnutzung verbundene Dienstleistungen zu erbringen. Auch wird Google diese Informationen gegebenenfalls an Dritte übertragen, sofern dies gesetzlich vorgeschrieben oder soweit Dritte diese Daten im Auftrag von Google verarbeiten. Google wird in keinem Fall Ihre IP-Adresse mit anderen Daten der Google in Verbindung bringen. Das Speichern von Cookies auf Ihrer Festplatte und die Anzeige von Web Beacons können Sie verhindern, indem Sie in Ihren Browser-Einstellungen "keine Cookies akzeptieren" wählen (Im MS Internet-Explorer unter "Extras &gt; Internetoptionen &gt; Datenschutz &gt; Einstellung"; im Firefox unter "Extras &gt; Einstellungen &gt; Datenschutz &gt; Cookies"); wir weisen Sie jedoch darauf hin, dass Sie in diesem Fall gegebenenfalls nicht sämtliche Funktionen dieser Website voll umfänglich nutzen können. Durch die Nutzung dieser Website erklären Sie sich mit der Bearbeitung der über Sie erhobenen Daten durch Google in der zuvor beschriebenen Art und Weise und zu dem zuvor benannten Zweck einverstanden.
</p>
</div>
</section>
</main>
);
}
+112
View File
@@ -0,0 +1,112 @@
.login-page {
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
position: relative;
overflow: hidden;
padding: 40px 20px;
}
.login-hero-bg {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: -1;
opacity: 0.4;
}
.login-container {
max-width: 480px !important;
width: 100%;
}
.login-form {
padding: 60px 40px;
border-radius: 32px;
}
.login-header {
text-align: center;
margin-bottom: 40px;
}
.login-tag {
display: inline-block;
padding: 6px 14px;
background: rgba(var(--accent-color-rgb), 0.1);
color: var(--accent-color);
border-radius: 100px;
font-size: 0.8rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 1px;
margin-bottom: 16px;
}
.login-header h1 {
font-size: 2.5rem;
margin-bottom: 12px;
}
.login-header p {
color: var(--text-secondary);
}
.login-error {
padding: 12px 16px;
background: rgba(255, 0, 0, 0.1);
border: 1px solid rgba(255, 0, 0, 0.2);
color: #ff6b6b;
border-radius: 12px;
font-size: 0.9rem;
margin-bottom: 30px;
text-align: center;
}
.login-field {
margin-bottom: 24px;
}
.login-field label {
display: block;
font-size: 0.9rem;
font-weight: 500;
margin-bottom: 10px;
color: var(--text-secondary);
}
.login-input {
width: 100%;
background: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 255, 255, 0.1);
padding: 14px 18px;
border-radius: 14px;
color: #fff;
font-size: 1rem;
transition: all 0.3s ease;
}
.login-input:focus {
outline: none;
border-color: var(--accent-color);
background: rgba(var(--accent-color-rgb), 0.05);
box-shadow: 0 0 20px rgba(var(--accent-color-rgb), 0.1);
}
.login-btn {
width: 100%;
padding: 18px;
margin-top: 20px;
font-size: 1.1rem;
}
.login-footer {
text-align: center;
margin-top: 30px;
font-size: 0.85rem;
color: var(--text-secondary);
line-height: 1.6;
}
+83
View File
@@ -0,0 +1,83 @@
import React, { useState } from 'react';
import { useNavigate, useLocation } from 'react-router-dom';
import { useAuth } from '../contexts/AuthContext';
import './Login.css';
export default function Login() {
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const [error, setError] = useState('');
const [loading, setLoading] = useState(false);
const { login } = useAuth();
const navigate = useNavigate();
const location = useLocation();
const from = location.state?.from?.pathname || '/restricted';
const handleLogin = async (e) => {
e.preventDefault();
setLoading(true);
setError('');
try {
await login(username, password);
navigate(from, { replace: true });
} catch (err) {
setError('Ungültige Anmeldedaten. Bitte prüfen Sie Benutzername und Passwort.');
setLoading(false);
}
};
return (
<div className="login-page">
<div className="login-hero-bg background-mesh" />
<div className="login-container app-container">
<form className="login-form glass-panel" onSubmit={handleLogin}>
<div className="login-header">
<div className="login-tag">Interner Bereich</div>
<h1>System <span className="text-gradient">Login</span></h1>
<p>Bitte authentifizieren Sie sich, um fortzufahren.</p>
</div>
{error && <div className="login-error">{error}</div>}
<div className="login-field">
<label htmlFor="username">Benutzername</label>
<input
id="username"
type="text"
className="login-input"
value={username}
onChange={(e) => setUsername(e.target.value)}
autoComplete="username"
required
/>
</div>
<div className="login-field">
<label htmlFor="password">Passwort</label>
<input
id="password"
type="password"
className="login-input"
value={password}
onChange={(e) => setPassword(e.target.value)}
autoComplete="current-password"
required
/>
</div>
<button type="submit" className="primary-button login-btn" disabled={loading}>
{loading ? 'Lade...' : 'Anmelden →'}
</button>
<p className="login-footer">
Probleme beim Login? Kontaktieren Sie den Systemadministrator.
</p>
</form>
</div>
</div>
);
}
@@ -0,0 +1,326 @@
.ra-page {
min-height: 100vh;
padding-bottom: 120px;
}
/* Hero */
.ra-hero {
position: relative;
padding: 160px 20px 80px;
text-align: center;
overflow: hidden;
}
.ra-hero-content {
position: relative;
z-index: 10;
max-width: 800px;
margin: 0 auto;
}
.ra-badge {
display: inline-block;
background: rgba(0, 255, 0, 0.08);
border: 1px solid rgba(0, 255, 0, 0.25);
color: var(--accent-color);
font-size: 0.82rem;
font-weight: 600;
letter-spacing: 0.1em;
text-transform: uppercase;
padding: 7px 18px;
border-radius: 50px;
margin-bottom: 28px;
}
.ra-hero h1 {
font-size: clamp(2.5rem, 5vw, 4rem);
line-height: 1.1;
margin-bottom: 16px;
}
.ra-hero-sub {
color: var(--text-secondary);
font-size: 1.1rem;
line-height: 1.7;
}
/* Container */
.ra-container {
display: flex;
flex-direction: column;
gap: 28px;
max-width: 940px !important;
}
/* Sections */
.ra-section {
border-radius: 20px;
overflow: hidden;
}
.ra-section-header {
display: flex;
align-items: flex-start;
gap: 20px;
padding: 32px 40px 24px;
border-bottom: 1px solid rgba(255,255,255,0.06);
}
.ra-icon {
font-size: 1.8rem;
line-height: 1;
flex-shrink: 0;
}
.ra-section-title {
font-size: 1.5rem;
color: #fff;
margin-bottom: 6px;
}
.ra-section-badge {
display: inline-block;
background: rgba(0, 255, 0, 0.07);
border: 1px solid rgba(0, 255, 0, 0.2);
color: var(--accent-color);
font-size: 0.78rem;
font-weight: 600;
padding: 4px 12px;
border-radius: 50px;
letter-spacing: 0.06em;
}
.ra-section-body {
padding: 32px 40px;
}
/* Budget allocation */
.ra-alloc {
display: flex;
flex-direction: column;
gap: 24px;
}
.ra-alloc-row {
display: flex;
flex-direction: column;
gap: 8px;
}
.ra-alloc-meta {
display: flex;
justify-content: space-between;
align-items: center;
}
.ra-alloc-label {
font-weight: 600;
color: #fff;
font-size: 0.95rem;
}
.ra-alloc-amount {
font-weight: 800;
color: var(--accent-color);
font-size: 1rem;
}
.ra-progress-track {
height: 6px;
background: rgba(255,255,255,0.06);
border-radius: 99px;
overflow: hidden;
}
.ra-progress-bar {
height: 100%;
background: var(--accent-gradient);
border-radius: 99px;
transition: width 0.8s ease;
}
.ra-alloc-desc {
color: var(--text-secondary);
font-size: 0.88rem;
margin: 0;
}
/* Text blocks */
.ra-text-block p {
color: var(--text-secondary);
line-height: 1.8;
margin-bottom: 16px;
}
.ra-highlight {
color: var(--accent-color);
font-weight: 700;
}
.ra-list {
color: var(--text-secondary);
line-height: 1.9;
padding-left: 20px;
margin: 12px 0 24px;
}
.ra-list li::marker {
color: var(--accent-color);
}
/* Phase grid */
.ra-phase-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: 16px;
margin-top: 24px;
}
.ra-phase {
background: rgba(0,255,0,0.03);
border: 1px solid rgba(0,255,0,0.1);
border-radius: 14px;
padding: 20px;
}
.ra-phase-num {
display: inline-block;
font-size: 0.75rem;
font-weight: 700;
letter-spacing: 0.1em;
color: var(--accent-color);
text-transform: uppercase;
margin-bottom: 8px;
}
.ra-phase strong {
display: block;
color: #fff;
font-size: 1rem;
margin-bottom: 8px;
}
.ra-phase p {
color: var(--text-secondary);
font-size: 0.88rem;
line-height: 1.6;
margin: 0;
}
/* Business Model */
.ra-bm-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: 20px;
}
.ra-bm-card {
padding: 24px;
border-radius: 14px !important;
}
.ra-bm-title {
font-size: 1.05rem;
color: #fff;
margin-bottom: 4px;
}
.ra-bm-sub {
font-size: 0.82rem;
color: var(--accent-color);
font-weight: 600;
margin-bottom: 12px;
}
.ra-bm-desc {
font-size: 0.9rem;
color: var(--text-secondary);
line-height: 1.6;
margin: 0;
}
/* Traction */
.ra-traction-stats {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 20px;
margin-bottom: 28px;
}
@media (max-width: 700px) {
.ra-traction-stats { grid-template-columns: repeat(2, 1fr); }
.ra-section-header { flex-direction: column; padding: 24px; }
.ra-section-body { padding: 24px; }
}
.ra-tstat {
background: rgba(255,255,255,0.02);
border: 1px solid rgba(255,255,255,0.06);
border-radius: 14px;
padding: 20px;
text-align: center;
}
.ra-tstat-val {
display: block;
font-size: 2rem;
font-weight: 800;
margin-bottom: 6px;
}
.ra-tstat-label {
font-size: 0.82rem;
color: var(--text-secondary);
text-transform: uppercase;
letter-spacing: 0.06em;
}
.ra-traction-note {
background: rgba(0,255,0,0.04);
border-left: 3px solid var(--accent-color);
padding: 14px 18px;
border-radius: 0 10px 10px 0;
color: var(--text-secondary);
font-size: 0.9rem;
line-height: 1.7;
margin: 0;
}
/* Values */
.ra-values-list li {
margin-bottom: 4px;
}
/* Download */
.ra-download {
display: flex;
align-items: center;
justify-content: space-between;
gap: 24px;
padding: 36px 40px;
border-radius: 20px;
flex-wrap: wrap;
}
.ra-download-text h3 {
font-size: 1.3rem;
color: #fff;
margin-bottom: 6px;
}
.ra-download-text p {
color: var(--text-secondary);
font-size: 0.9rem;
margin: 0;
}
/* Meeting CTA */
.ra-meeting {
text-align: center;
margin-top: 12px;
}
.ra-meeting p {
color: var(--text-secondary);
margin-bottom: 16px;
}
@@ -0,0 +1,191 @@
import React from 'react';
import { Link, useNavigate } from 'react-router-dom';
import { useAuth } from '../contexts/AuthContext';
import './RestrictedArea.css';
const SECTIONS = [
{
id: 'investition',
icon: '€',
title: 'Kapitalbedarf: Tranche 1',
badge: '150.000 € Stille Beteiligung · Zielrendite 10%',
content: (
<div className="ra-alloc">
{[
{ label: 'Runway & Liquiditätspuffer', amount: '70.000 €', pct: 47, desc: 'Absicherung der Skalierungsphase.' },
{ label: 'Go-to-Market', amount: '50.000 €', pct: 33, desc: 'Sales, Messen, Multiplikatoren.' },
{ label: 'Legal & Zertifizierungen', amount: '30.000 €', pct: 20, desc: 'ISO 27001 / DSGVO-Compliance.' },
].map(({ label, amount, pct, desc }) => (
<div key={label} className="ra-alloc-row">
<div className="ra-alloc-meta">
<span className="ra-alloc-label">{label}</span>
<span className="ra-alloc-amount">{amount}</span>
</div>
<div className="ra-progress-track">
<div className="ra-progress-bar" style={{ width: `${pct}%` }} />
</div>
<p className="ra-alloc-desc">{desc}</p>
</div>
))}
</div>
),
},
{
id: 'markt',
icon: '📈',
title: 'Marktchance & Positionierung',
badge: 'Europäischer Mittelstand',
content: (
<div className="ra-text-block">
<p>Europas Mittelstand steht einem fundamentalen Dilemma gegenüber: Die KI-Revolution läuft, doch die sichere, compliant-fähige Infrastruktur fehlt. US-Hyperscaler (OpenAI, Google) scheiden aus regulatorischen und sicherheitstechnischen Gründen aus.</p>
<p>Project KIQ besetzt genau diese Lücke. Als <strong className="ra-highlight">souveränes KI-Betriebssystem</strong> für den europäischen Mittelstand liefert es:</p>
<ul className="ra-list">
<li>100% DSGVO & AI-Act Konformität von Anfang an</li>
<li>Kein Vendor-Lock-in durch US-Hyperscaler</li>
<li>Plug-and-Play Deployment ohne eigenes IT-Team</li>
<li>Wissenschaftliche Begleitung durch Universität Kassel</li>
</ul>
<div className="ra-phase-grid">
<div className="ra-phase">
<span className="ra-phase-num">Phase 1</span>
<strong>Pretotyping & MVP</strong>
<p>35 Pilotpartner, je bis zu 6 TEUR Förderung. Schnelle Entwicklung eines minimal testbaren Produkts.</p>
</div>
<div className="ra-phase">
<span className="ra-phase-num">Phase 2</span>
<strong>Produktionsumgebung</strong>
<p>Skalierbare KI-Infrastruktur, Landesförderung, laufende Kostenbeteiligung. Perspektivisch eigene Hardware.</p>
</div>
<div className="ra-phase">
<span className="ra-phase-num">Phase 3</span>
<strong>200 Kunden in 24 Monaten</strong>
<p>Aufbau dediziertes B2B-Sales-Team, Expansion über öffentliche Träger & Wirtschaftsförderung als Multiplikatoren.</p>
</div>
</div>
</div>
),
},
{
id: 'geschaeftsmodell',
icon: '💡',
title: 'Geschäftsmodell & Revenue',
badge: 'Dreistufig · Skalierbar',
content: (
<div className="ra-bm-grid">
{[
{ title: 'Setup-Fee', sub: 'Einmalig ~2.500 €', desc: 'Deckt Onboarding & Schnittstellen-Anbindung. Deckt sofort Vertriebsaufwände.' },
{ title: 'Token-Marge (MRR)', sub: 'Monatlich, nutzungsbasiert', desc: '2050% Marge auf Server/Token-Kosten. Hochgradig skalierbar ohne Einstiegshürde.' },
{ title: 'Developer 80/20', sub: 'Plattform-Abgabe', desc: 'Externe Entwickler behalten 80% Gewinn. 20% finanzieren Plattform-Betrieb dauerhaft.' },
].map(({ title, sub, desc }) => (
<div key={title} className="ra-bm-card glass-panel">
<h4 className="ra-bm-title">{title}</h4>
<p className="ra-bm-sub">{sub}</p>
<p className="ra-bm-desc">{desc}</p>
</div>
))}
</div>
),
},
{
id: 'traction',
icon: '🚀',
title: 'Traction & Proof of Concept',
badge: 'Bereits profitabel im Testbetrieb',
content: (
<div className="ra-traction">
<div className="ra-traction-stats">
{[
{ val: '6', label: 'Zahlende Pilotkunden' },
{ val: '60k€', label: 'Initialumsatz geflossen' },
{ val: '12+', label: 'Aktive Use Cases' },
{ val: 'M15', label: 'Break-Even Prognose' },
].map(({ val, label }) => (
<div key={label} className="ra-tstat">
<span className="ra-tstat-val text-gradient">{val}</span>
<span className="ra-tstat-label">{label}</span>
</div>
))}
</div>
<p className="ra-traction-note">Identifizierte Use Cases aus dem laufenden Betrieb: Teileerkennung, Prüfprotokolle, Marktanalyse, Angebotsunterstützung, Berichtserzeugung, Wissensmanagement.</p>
</div>
),
},
{
id: 'strategie',
icon: '🏛',
title: 'Governance & Fundamentale Werte',
badge: 'Verfassung v0.2',
content: (
<div className="ra-text-block">
<p>Project KIQ wird als modernes, krisenfestes Unternehmen für Top-Talente gebaut. Kernprinzipien aus der bindenden Verfassung:</p>
<ul className="ra-list ra-values-list">
{[
'Souveränität: Datensouveränität der Kunden ist das höchste Gut.',
'Null-Veto-Politik: Psychologische Sicherheit bei Kunden- & Teamaufnahme.',
'Solidarisches Entlohnungsmodell: Existenzsicherndes Basisgehalt plus Gewinnbeteiligung.',
'Pragmatismus: „Robust > fancy" Keep it simple & stupid.',
'Transparenz: Offene Gehaltspolitik & Open-Source-Kodex intern.',
].map(v => <li key={v}>{v}</li>)}
</ul>
<p>Zielstruktur: <strong className="ra-highlight">GmbH & Co. KG</strong> operatives Geschäft sauber von Investitionskapital getrennt. Investoren als Stille Teilhaber ohne Einfluss auf Verfassungsprinzipien.</p>
</div>
),
},
];
export default function RestrictedArea() {
const navigate = useNavigate();
const { logout } = useAuth();
const handleLogout = async () => {
await logout();
navigate('/');
};
return (
<div className="ra-page">
<div className="ra-hero">
<div className="hero-glow background-mesh" />
<div className="ra-hero-content">
<div className="res-header-row">
<span className="ra-badge">🔒 Geschützter Bereich</span>
<button onClick={handleLogout} className="logout-btn">Abmelden</button>
</div>
<h1>Investor <span className="text-gradient">Relations</span></h1>
<p className="ra-hero-sub">Confidential Business Case, Marktchance & Investment-Unterlagen für Project KIQ.</p>
</div>
</div>
{/* Content */}
<div className="ra-container app-container">
{SECTIONS.map(({ id, icon, title, badge, content }) => (
<section key={id} className="ra-section glass-panel">
<div className="ra-section-header">
<div className="ra-icon">{icon}</div>
<div>
<h2 className="ra-section-title">{title}</h2>
<span className="ra-section-badge">{badge}</span>
</div>
</div>
<div className="ra-section-body">{content}</div>
</section>
))}
{/* Document notice (replaces PDF download) */}
<div className="ra-download glass-panel">
<div className="ra-download-text">
<h3>Pitch Deck & Unterlagen</h3>
<p>Das vollständige Pitch Deck mit allen Finanz-Projektionen und technischen Details wird Ihnen nach Genehmigung per E-Mail bereitgestellt.</p>
</div>
<span className="ra-doc-notice">📧 Dokumente werden per E-Mail bereitgestellt</span>
</div>
{/* CTA to request meeting */}
<div className="ra-meeting">
<p>Bereit für das nächste Gespräch?</p>
<Link to="/request-access" className="primary-button">Gespräch anfragen </Link>
</div>
</div>
</div>
);
}
+207
View File
@@ -0,0 +1,207 @@
.uc-page {
min-height: 100vh;
padding-bottom: 120px;
}
/* Hero */
.uc-hero {
position: relative;
padding: 160px 20px 80px;
text-align: center;
overflow: hidden;
}
.uc-hero-content {
position: relative;
z-index: 10;
max-width: 780px;
margin: 0 auto;
}
.uc-label-tag {
display: inline-block;
background: rgba(0, 255, 0, 0.1);
border: 1px solid rgba(0, 255, 0, 0.3);
color: var(--accent-color);
font-size: 0.82rem;
font-weight: 600;
letter-spacing: 0.12em;
text-transform: uppercase;
padding: 6px 16px;
border-radius: 50px;
margin-bottom: 24px;
}
.uc-hero h1 {
font-size: clamp(2.5rem, 5vw, 4rem);
line-height: 1.1;
margin-bottom: 20px;
}
.uc-subtitle {
color: var(--text-secondary);
font-size: 1.1rem;
line-height: 1.7;
}
/* Context banner */
.uc-context {
padding: 24px 32px;
border-radius: 16px;
margin-bottom: 12px;
}
.uc-context p {
color: var(--text-secondary);
line-height: 1.7;
font-size: 0.95rem;
margin: 0;
}
/* Container */
.uc-container {
display: flex;
flex-direction: column;
gap: 20px;
margin-top: 20px;
max-width: 940px !important;
}
/* Cards */
.uc-card {
border-radius: 20px;
overflow: hidden;
transition: border-color 0.25s;
}
.uc-card:hover {
border-color: rgba(0, 255, 0, 0.2);
}
.uc-card-header {
display: flex;
align-items: flex-start;
justify-content: space-between;
padding: 32px 40px 24px;
border-bottom: 1px solid rgba(255,255,255,0.06);
}
.uc-card-meta {
display: flex;
align-items: flex-start;
gap: 20px;
}
.uc-icon {
font-size: 2rem;
flex-shrink: 0;
line-height: 1;
}
.uc-status {
display: inline-block;
background: rgba(0,255,0,0.1);
border: 1px solid rgba(0,255,0,0.25);
color: var(--accent-color);
font-size: 0.73rem;
font-weight: 700;
padding: 3px 10px;
border-radius: 50px;
letter-spacing: 0.06em;
margin-bottom: 8px;
}
.uc-title {
font-size: 1.5rem;
color: #fff;
margin-bottom: 4px;
}
.uc-tagline {
color: var(--text-secondary);
font-size: 0.95rem;
margin: 0;
}
.uc-number {
font-size: 3.5rem;
font-weight: 800;
color: rgba(0,255,0,0.08);
line-height: 1;
flex-shrink: 0;
user-select: none;
}
/* Card body */
.uc-card-body {
padding: 28px 40px;
display: grid;
grid-template-columns: 1fr 1fr;
gap: 32px;
}
@media (max-width: 680px) {
.uc-card-body { grid-template-columns: 1fr; }
.uc-card-header { flex-direction: column; gap: 12px; padding: 24px; }
.uc-card-body { padding: 24px; gap: 20px; }
.uc-number { font-size: 2.5rem; }
}
.uc-detail-block h3,
.uc-outcome-block h3 {
font-size: 0.78rem;
font-weight: 700;
letter-spacing: 0.1em;
text-transform: uppercase;
color: var(--text-secondary);
margin-bottom: 10px;
}
.uc-detail-block p,
.uc-outcome-block p {
color: var(--text-secondary);
font-size: 0.92rem;
line-height: 1.7;
margin: 0;
}
.uc-outcome-block {
background: rgba(0,255,0,0.03);
border: 1px solid rgba(0,255,0,0.08);
border-radius: 12px;
padding: 20px;
}
.uc-outcome-block h3 {
color: var(--accent-color);
}
.uc-outcome-block p {
color: #ccc;
}
/* CTA */
.uc-cta {
margin-top: 60px;
max-width: 940px !important;
}
.uc-cta-inner {
padding: 56px 48px;
border-radius: 24px;
text-align: center;
}
.uc-cta-inner h2 {
font-size: clamp(1.4rem, 3vw, 2rem);
color: #fff;
margin-bottom: 16px;
}
.uc-cta-inner p {
color: var(--text-secondary);
font-size: 1rem;
line-height: 1.7;
max-width: 560px;
margin: 0 auto 32px;
}
@@ -0,0 +1,71 @@
import React from 'react';
import { Link } from 'react-router-dom';
import { USE_CASES } from '../data/useCases';
import './UseCases.css';
export default function UseCases() {
return (
<div className="uc-page">
{/* Hero */}
<div className="uc-hero">
<div className="hero-glow background-mesh" />
<div className="uc-hero-content">
<span className="uc-label-tag">Projektergebnisse</span>
<h1>Bewiesene <span className="text-gradient">Use Cases</span></h1>
<p className="uc-subtitle">
Im Rahmen des Projekts KI für KMU" (Transformationsnetzwerk Region Kassel) wurden gemeinsam mit Praxispartnern fünf KI-Agenten erfolgreich entwickelt und eingesetzt. Hier sind die Ergebnisse.
</p>
</div>
</div>
{/* Context Banner */}
<div className="app-container">
<div className="uc-context glass-panel">
<p>
<strong style={{ color: '#fff' }}>Ausgangslage:</strong> Viele Unternehmen wollen KI einsetzen, scheitern aber an fehlenden Leitplanken, Sicherheitsbedenken und unkoordinierten Eigenversuchen mit US-basierten SaaS-Lösungen.
Project KIQ liefert die Infrastruktur für <strong style={{ color: '#fff' }}>kontrollierte, sichere und regelkonforme</strong> KI — und diese fünf Use Cases belegen, dass es funktioniert.
</p>
</div>
</div>
{/* Use Cases */}
<div className="uc-container app-container">
{USE_CASES.map((uc, i) => (
<article key={uc.id} className="uc-card glass-panel">
<div className="uc-card-header">
<div className="uc-card-meta">
<span className="uc-icon">{uc.icon}</span>
<div>
<span className="uc-status">✓ {uc.status}</span>
<h2 className="uc-title">{uc.title}</h2>
<p className="uc-tagline">{uc.tagline}</p>
</div>
</div>
<span className="uc-number">0{i + 1}</span>
</div>
<div className="uc-card-body">
<div className="uc-detail-block">
<h3>Wie es funktioniert</h3>
<p>{uc.detail}</p>
</div>
<div className="uc-outcome-block">
<h3>Ergebnis</h3>
<p>{uc.outcome}</p>
</div>
</div>
</article>
))}
</div>
{/* CTA */}
<div className="uc-cta app-container">
<div className="uc-cta-inner glass-panel">
<h2>Bereit, einen Use Case in Ihrem Unternehmen umzusetzen?</h2>
<p>Wir zeigen Ihnen, welcher Use Case zu Ihrem Unternehmen passt — in einem ersten, unverbindlichen Gespräch.</p>
<Link to="/request-access" className="primary-button">Gespräch anfragen </Link>
</div>
</div>
</div>
);
}