added legeal stuff

This commit is contained in:
Rajpreet0 2026-09-25 18:53:25 +02:00
parent f059cfb81c
commit 02af696d4f
23 changed files with 979 additions and 21 deletions

View file

@ -0,0 +1,444 @@
import type { Metadata } from "next"
export const metadata: Metadata = {
title: "Datenschutzerklärung",
}
const Datenschutz = () => {
return (
<>
<h1>Datenschutzerklärung</h1>
<h2>1. Datenschutz auf einen Blick</h2>
<h3>Allgemeine Hinweise</h3>
<p>
Die folgenden Hinweise geben einen einfachen Überblick darüber, was mit Ihren
personenbezogenen Daten passiert, wenn Sie diese Website besuchen. Personenbezogene
Daten sind alle Daten, mit denen Sie persönlich identifiziert werden können.
Ausführliche Informationen zum Thema Datenschutz entnehmen Sie unserer unter diesem
Text aufgeführten Datenschutzerklärung.
</p>
<h3>Datenerfassung auf dieser Website</h3>
<h4>Wer ist verantwortlich für die Datenerfassung auf dieser Website?</h4>
<p>
Die Datenverarbeitung auf dieser Website erfolgt durch den Websitebetreiber. Dessen
Kontaktdaten können Sie dem Abschnitt „Hinweis zur verantwortlichen Stelle“ in dieser
Datenschutzerklärung entnehmen.
</p>
<h4>Wie erfassen wir Ihre Daten?</h4>
<p>
Ihre Daten werden zum einen dadurch erhoben, dass Sie uns diese mitteilen. Hierbei
kann es sich z. B. um Daten handeln, die Sie in ein Kontaktformular eingeben.
</p>
<p>
Andere Daten werden automatisch oder nach Ihrer Einwilligung beim Besuch der Website
durch unsere IT-Systeme erfasst. Das sind vor allem technische Daten (z. B.
Internetbrowser, Betriebssystem oder Uhrzeit des Seitenaufrufs). Die Erfassung dieser
Daten erfolgt automatisch, sobald Sie diese Website betreten.
</p>
<h4>Wofür nutzen wir Ihre Daten?</h4>
<p>
Ein Teil der Daten wird erhoben, um eine fehlerfreie Bereitstellung der Website zu
gewährleisten. Andere Daten können zur Analyse Ihres Nutzerverhaltens verwendet
werden. Sofern über die Website Verträge geschlossen oder angebahnt werden können,
werden die übermittelten Daten auch für Vertragsangebote, Bestellungen oder sonstige
Auftragsanfragen verarbeitet.
</p>
<h4>Welche Rechte haben Sie bezüglich Ihrer Daten?</h4>
<p>
Sie haben jederzeit das Recht, unentgeltlich Auskunft über Herkunft, Empfänger und
Zweck Ihrer gespeicherten personenbezogenen Daten zu erhalten. Sie haben außerdem ein
Recht, die Berichtigung oder Löschung dieser Daten zu verlangen. Wenn Sie eine
Einwilligung zur Datenverarbeitung erteilt haben, können Sie diese Einwilligung
jederzeit für die Zukunft widerrufen. Außerdem haben Sie das Recht, unter bestimmten
Umständen die Einschränkung der Verarbeitung Ihrer personenbezogenen Daten zu
verlangen. Des Weiteren steht Ihnen ein Beschwerderecht bei der zuständigen
Aufsichtsbehörde zu.
</p>
<p>
Hierzu sowie zu weiteren Fragen zum Thema Datenschutz können Sie sich jederzeit an
uns wenden.
</p>
<h3>Analyse-Tools und Tools von Drittanbietern</h3>
<p>
Beim Besuch dieser Website kann Ihr Surf-Verhalten statistisch ausgewertet werden.
Das geschieht vor allem mit sogenannten Analyseprogrammen.
</p>
<p>
Detaillierte Informationen zu diesen Analyseprogrammen finden Sie in der folgenden
Datenschutzerklärung.
</p>
<h2>2. Hosting</h2>
<p>Wir hosten die Inhalte unserer Website bei folgendem Anbieter:</p>
<h3>Externes Hosting</h3>
<p>
Diese Website wird extern gehostet. Die personenbezogenen Daten, die auf dieser
Website erfasst werden, werden auf den Servern des Hosters / der Hoster gespeichert.
Hierbei kann es sich v. a. um IP-Adressen, Kontaktanfragen, Meta- und
Kommunikationsdaten, Vertragsdaten, Kontaktdaten, Namen, Websitezugriffe und
sonstige Daten, die über eine Website generiert werden, handeln.
</p>
<p>
Das externe Hosting erfolgt zum Zwecke der Vertragserfüllung gegenüber unseren
potenziellen und bestehenden Kunden (Art. 6 Abs. 1 lit. b DSGVO) und im Interesse
einer sicheren, schnellen und effizienten Bereitstellung unseres Online-Angebots
durch einen professionellen Anbieter (Art. 6 Abs. 1 lit. f DSGVO). Sofern eine
entsprechende Einwilligung abgefragt wurde, erfolgt die Verarbeitung ausschließlich
auf Grundlage von Art. 6 Abs. 1 lit. a DSGVO und § 25 Abs. 1 TDDDG, soweit die
Einwilligung die Speicherung von Cookies oder den Zugriff auf Informationen im
Endgerät des Nutzers (z. B. Device-Fingerprinting) im Sinne des TDDDG umfasst. Die
Einwilligung ist jederzeit widerrufbar.
</p>
<p>
Unser(e) Hoster wird bzw. werden Ihre Daten nur insoweit verarbeiten, wie dies zur
Erfüllung seiner Leistungspflichten erforderlich ist und unsere Weisungen in Bezug
auf diese Daten befolgen.
</p>
<p>Wir setzen folgende(n) Hoster ein:</p>
<address>
Vercel Inc.
<br />
440 Barranca Ave #4133
<br />
Covina, CA 91723
<br />
USA
</address>
<h4>Auftragsverarbeitung</h4>
<p>
Wir haben einen Vertrag über Auftragsverarbeitung (AVV) zur Nutzung des oben
genannten Dienstes geschlossen. Hierbei handelt es sich um einen
datenschutzrechtlich vorgeschriebenen Vertrag, der gewährleistet, dass dieser die
personenbezogenen Daten unserer Websitebesucher nur nach unseren Weisungen und unter
Einhaltung der DSGVO verarbeitet.
</p>
<h2>3. Allgemeine Hinweise und Pflichtinformationen</h2>
<h3>Datenschutz</h3>
<p>
Die Betreiber dieser Seiten nehmen den Schutz Ihrer persönlichen Daten sehr ernst.
Wir behandeln Ihre personenbezogenen Daten vertraulich und entsprechend den
gesetzlichen Datenschutzvorschriften sowie dieser Datenschutzerklärung.
</p>
<p>
Wenn Sie diese Website benutzen, werden verschiedene personenbezogene Daten erhoben.
Personenbezogene Daten sind Daten, mit denen Sie persönlich identifiziert werden
können. Die vorliegende Datenschutzerklärung erläutert, welche Daten wir erheben und
wofür wir sie nutzen. Sie erläutert auch, wie und zu welchem Zweck das geschieht.
</p>
<p>
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.
</p>
<h3>Hinweis zur verantwortlichen Stelle</h3>
<p>Die verantwortliche Stelle für die Datenverarbeitung auf dieser Website ist:</p>
<address>
Ben Dalhoff, Rajpreet Singh
<br />
Sandweg 91
<br />
48565 Steinfurt
</address>
<p>
Telefon: +49 176 47601638
<br />
E-Mail: <a href="mailto:info@since3.de">info@since3.de</a>
</p>
<p>
Verantwortliche Stelle ist die natürliche oder juristische Person, die allein oder
gemeinsam mit anderen über die Zwecke und Mittel der Verarbeitung von
personenbezogenen Daten (z. B. Namen, E-Mail-Adressen o. Ä.) entscheidet.
</p>
<h3>Speicherdauer</h3>
<p>
Soweit innerhalb dieser Datenschutzerklärung keine speziellere Speicherdauer genannt
wurde, verbleiben Ihre personenbezogenen Daten bei uns, bis der Zweck für die
Datenverarbeitung entfällt. Wenn Sie ein berechtigtes Löschersuchen geltend machen
oder eine Einwilligung zur Datenverarbeitung widerrufen, werden Ihre Daten gelöscht,
sofern wir keine anderen rechtlich zulässigen Gründe für die Speicherung Ihrer
personenbezogenen Daten haben (z. B. steuer- oder handelsrechtliche
Aufbewahrungsfristen); im letztgenannten Fall erfolgt die Löschung nach Fortfall
dieser Gründe.
</p>
<h3>Allgemeine Hinweise zu den Rechtsgrundlagen der Datenverarbeitung auf dieser Website</h3>
<p>
Sofern Sie in die Datenverarbeitung eingewilligt haben, verarbeiten wir Ihre
personenbezogenen Daten auf Grundlage von Art. 6 Abs. 1 lit. a DSGVO bzw. Art. 9 Abs.
2 lit. a DSGVO, sofern besondere Datenkategorien nach Art. 9 Abs. 1 DSGVO verarbeitet
werden. Im Falle einer ausdrücklichen Einwilligung in die Übertragung
personenbezogener Daten in Drittstaaten erfolgt die Datenverarbeitung außerdem auf
Grundlage von Art. 49 Abs. 1 lit. a DSGVO. Sofern Sie in die Speicherung von Cookies
oder in den Zugriff auf Informationen in Ihr Endgerät (z. B. via
Device-Fingerprinting) eingewilligt haben, erfolgt die Datenverarbeitung zusätzlich
auf Grundlage von § 25 Abs. 1 TDDDG. Die Einwilligung ist jederzeit widerrufbar. Sind
Ihre Daten zur Vertragserfüllung oder zur Durchführung vorvertraglicher Maßnahmen
erforderlich, verarbeiten wir Ihre Daten auf Grundlage des Art. 6 Abs. 1 lit. b
DSGVO. Des Weiteren verarbeiten wir Ihre Daten, sofern diese zur Erfüllung einer
rechtlichen Verpflichtung erforderlich sind, auf Grundlage von Art. 6 Abs. 1 lit. c
DSGVO. Die Datenverarbeitung kann ferner auf Grundlage unseres berechtigten
Interesses nach Art. 6 Abs. 1 lit. f DSGVO erfolgen. Über die jeweils im Einzelfall
einschlägigen Rechtsgrundlagen wird in den folgenden Absätzen dieser
Datenschutzerklärung informiert.
</p>
<h3>Empfänger von personenbezogenen Daten</h3>
<p>
Im Rahmen unserer Geschäftstätigkeit arbeiten wir mit verschiedenen externen Stellen
zusammen. Dabei ist teilweise auch eine Übermittlung von personenbezogenen Daten an
diese externen Stellen erforderlich. Wir geben personenbezogene Daten nur dann an
externe Stellen weiter, wenn dies im Rahmen einer Vertragserfüllung erforderlich ist,
wenn wir gesetzlich hierzu verpflichtet sind (z. B. Weitergabe von Daten an
Steuerbehörden), wenn wir ein berechtigtes Interesse nach Art. 6 Abs. 1 lit. f DSGVO
an der Weitergabe haben oder wenn eine sonstige Rechtsgrundlage die Datenweitergabe
erlaubt. Beim Einsatz von Auftragsverarbeitern geben wir personenbezogene Daten
unserer Kunden nur auf Grundlage eines gültigen Vertrags über Auftragsverarbeitung
weiter. Im Falle einer gemeinsamen Verarbeitung wird ein Vertrag über gemeinsame
Verarbeitung geschlossen.
</p>
<h3>Widerruf Ihrer Einwilligung zur Datenverarbeitung</h3>
<p>
Viele Datenverarbeitungsvorgänge sind nur mit Ihrer ausdrücklichen Einwilligung
möglich. Sie können eine bereits erteilte Einwilligung jederzeit widerrufen. Die
Rechtmäßigkeit der bis zum Widerruf erfolgten Datenverarbeitung bleibt vom Widerruf
unberührt.
</p>
<h3>
Widerspruchsrecht gegen die Datenerhebung in besonderen Fällen sowie gegen
Direktwerbung (Art. 21 DSGVO)
</h3>
<p className="legal-caps">
WENN DIE DATENVERARBEITUNG AUF GRUNDLAGE VON ART. 6 ABS. 1 LIT. E ODER F DSGVO
ERFOLGT, HABEN SIE JEDERZEIT DAS RECHT, AUS GRÜNDEN, DIE SICH AUS IHRER BESONDEREN
SITUATION ERGEBEN, GEGEN DIE VERARBEITUNG IHRER PERSONENBEZOGENEN DATEN WIDERSPRUCH
EINZULEGEN; DIES GILT AUCH FÜR EIN AUF DIESE BESTIMMUNGEN GESTÜTZTES PROFILING. DIE
JEWEILIGE RECHTSGRUNDLAGE, AUF DENEN EINE VERARBEITUNG BERUHT, ENTNEHMEN SIE DIESER
DATENSCHUTZERKLÄRUNG. WENN SIE WIDERSPRUCH EINLEGEN, WERDEN WIR IHRE BETROFFENEN
PERSONENBEZOGENEN DATEN NICHT MEHR VERARBEITEN, ES SEI DENN, WIR KÖNNEN ZWINGENDE
SCHUTZWÜRDIGE GRÜNDE FÜR DIE VERARBEITUNG NACHWEISEN, DIE IHRE INTERESSEN, RECHTE
UND FREIHEITEN ÜBERWIEGEN ODER DIE VERARBEITUNG DIENT DER GELTENDMACHUNG, AUSÜBUNG
ODER VERTEIDIGUNG VON RECHTSANSPRÜCHEN (WIDERSPRUCH NACH ART. 21 ABS. 1 DSGVO).
</p>
<p className="legal-caps">
WERDEN IHRE PERSONENBEZOGENEN DATEN VERARBEITET, UM DIREKTWERBUNG ZU BETREIBEN, SO
HABEN SIE DAS RECHT, JEDERZEIT WIDERSPRUCH GEGEN DIE VERARBEITUNG SIE BETREFFENDER
PERSONENBEZOGENER DATEN ZUM ZWECKE DERARTIGER WERBUNG EINZULEGEN; DIES GILT AUCH FÜR
DAS PROFILING, SOWEIT ES MIT SOLCHER DIREKTWERBUNG IN VERBINDUNG STEHT. WENN SIE
WIDERSPRECHEN, WERDEN IHRE PERSONENBEZOGENEN DATEN ANSCHLIESSEND NICHT MEHR ZUM
ZWECKE DER DIREKTWERBUNG VERWENDET (WIDERSPRUCH NACH ART. 21 ABS. 2 DSGVO).
</p>
<h3>Beschwerderecht bei der zuständigen Aufsichtsbehörde</h3>
<p>
Im Falle von Verstößen gegen die DSGVO steht den Betroffenen ein Beschwerderecht bei
einer Aufsichtsbehörde, insbesondere in dem Mitgliedstaat ihres gewöhnlichen
Aufenthalts, ihres Arbeitsplatzes oder des Orts des mutmaßlichen Verstoßes zu. Das
Beschwerderecht besteht unbeschadet anderweitiger verwaltungsrechtlicher oder
gerichtlicher Rechtsbehelfe.
</p>
<h3>Recht auf Datenübertragbarkeit</h3>
<p>
Sie haben das Recht, Daten, die wir auf Grundlage Ihrer Einwilligung oder in
Erfüllung eines Vertrags automatisiert verarbeiten, an sich oder an einen Dritten in
einem gängigen, maschinenlesbaren Format aushändigen zu lassen. Sofern Sie die
direkte Übertragung der Daten an einen anderen Verantwortlichen verlangen, erfolgt
dies nur, soweit es technisch machbar ist.
</p>
<h3>Auskunft, Berichtigung und Löschung</h3>
<p>
Sie haben im Rahmen der geltenden gesetzlichen Bestimmungen jederzeit das Recht auf
unentgeltliche Auskunft über Ihre gespeicherten personenbezogenen Daten, deren
Herkunft und Empfänger und den Zweck der Datenverarbeitung und ggf. ein Recht auf
Berichtigung oder Löschung dieser Daten. Hierzu sowie zu weiteren Fragen zum Thema
personenbezogene Daten können Sie sich jederzeit an uns wenden.
</p>
<h3>Recht auf Einschränkung der Verarbeitung</h3>
<p>
Sie haben das Recht, die Einschränkung der Verarbeitung Ihrer personenbezogenen
Daten zu verlangen. Hierzu können Sie sich jederzeit an uns wenden. Das Recht auf
Einschränkung der Verarbeitung besteht in folgenden Fällen:
</p>
<ul>
<li>
Wenn Sie die Richtigkeit Ihrer bei uns gespeicherten personenbezogenen Daten
bestreiten, benötigen wir in der Regel Zeit, um dies zu überprüfen. Für die Dauer
der Prüfung haben Sie das Recht, die Einschränkung der Verarbeitung Ihrer
personenbezogenen Daten zu verlangen.
</li>
<li>
Wenn die Verarbeitung Ihrer personenbezogenen Daten unrechtmäßig
geschah/geschieht, können Sie statt der Löschung die Einschränkung der
Datenverarbeitung verlangen.
</li>
<li>
Wenn wir Ihre personenbezogenen Daten nicht mehr benötigen, Sie sie jedoch zur
Ausübung, Verteidigung oder Geltendmachung von Rechtsansprüchen benötigen, haben
Sie das Recht, statt der Löschung die Einschränkung der Verarbeitung Ihrer
personenbezogenen Daten zu verlangen.
</li>
<li>
Wenn Sie einen Widerspruch nach Art. 21 Abs. 1 DSGVO eingelegt haben, muss eine
Abwägung zwischen Ihren und unseren Interessen vorgenommen werden. Solange noch
nicht feststeht, wessen Interessen überwiegen, haben Sie das Recht, die
Einschränkung der Verarbeitung Ihrer personenbezogenen Daten zu verlangen.
</li>
</ul>
<p>
Wenn Sie die Verarbeitung Ihrer personenbezogenen Daten eingeschränkt haben, dürfen
diese Daten – von ihrer Speicherung abgesehen – nur mit Ihrer Einwilligung oder zur
Geltendmachung, Ausübung oder Verteidigung von Rechtsansprüchen oder zum Schutz der
Rechte einer anderen natürlichen oder juristischen Person oder aus Gründen eines
wichtigen öffentlichen Interesses der Europäischen Union oder eines Mitgliedstaats
verarbeitet werden.
</p>
<h3>SSL- bzw. TLS-Verschlüsselung</h3>
<p>
Diese Seite nutzt aus Sicherheitsgründen und zum Schutz der Übertragung
vertraulicher Inhalte, wie zum Beispiel Bestellungen oder Anfragen, die Sie an uns
als Seitenbetreiber senden, eine SSL- bzw. TLS-Verschlüsselung. Eine verschlüsselte
Verbindung erkennen Sie daran, dass die Adresszeile des Browsers von „http://“ auf
„https://“ wechselt und an dem Schloss-Symbol in Ihrer Browserzeile.
</p>
<p>
Wenn die SSL- bzw. TLS-Verschlüsselung aktiviert ist, können die Daten, die Sie an
uns übermitteln, nicht von Dritten mitgelesen werden.
</p>
<h2>4. Datenerfassung auf dieser Website</h2>
<h3>Cookies</h3>
<p>
Unsere Internetseiten verwenden so genannte „Cookies“. Cookies sind kleine
Datenpakete und richten auf Ihrem Endgerät keinen Schaden an. Sie werden entweder
vorübergehend für die Dauer einer Sitzung (Session-Cookies) oder dauerhaft
(permanente Cookies) auf Ihrem Endgerät gespeichert. Session-Cookies werden nach
Ende Ihres Besuchs automatisch gelöscht. Permanente Cookies bleiben auf Ihrem
Endgerät gespeichert, bis Sie diese selbst löschen oder eine automatische Löschung
durch Ihren Webbrowser erfolgt.
</p>
<p>
Cookies können von uns (First-Party-Cookies) oder von Drittunternehmen stammen (sog.
Third-Party-Cookies). Third-Party-Cookies ermöglichen die Einbindung bestimmter
Dienstleistungen von Drittunternehmen innerhalb von Webseiten (z. B. Cookies zur
Abwicklung von Zahlungsdienstleistungen).
</p>
<p>
Cookies haben verschiedene Funktionen. Zahlreiche Cookies sind technisch notwendig,
da bestimmte Webseitenfunktionen ohne diese nicht funktionieren würden (z. B. die
Warenkorbfunktion oder die Anzeige von Videos). Andere Cookies können zur Auswertung
des Nutzerverhaltens oder zu Werbezwecken verwendet werden.
</p>
<p>
Cookies, die zur Durchführung des elektronischen Kommunikationsvorgangs, zur
Bereitstellung bestimmter, von Ihnen erwünschter Funktionen (z. B. für die
Warenkorbfunktion) oder zur Optimierung der Website (z. B. Cookies zur Messung des
Webpublikums) erforderlich sind (notwendige Cookies), werden auf Grundlage von Art. 6
Abs. 1 lit. f DSGVO gespeichert, sofern keine andere Rechtsgrundlage angegeben wird.
Der Websitebetreiber hat ein berechtigtes Interesse an der Speicherung von
notwendigen Cookies zur technisch fehlerfreien und optimierten Bereitstellung seiner
Dienste. Sofern eine Einwilligung zur Speicherung von Cookies und vergleichbaren
Wiedererkennungstechnologien abgefragt wurde, erfolgt die Verarbeitung
ausschließlich auf Grundlage dieser Einwilligung (Art. 6 Abs. 1 lit. a DSGVO und § 25
Abs. 1 TDDDG); die Einwilligung ist jederzeit widerrufbar.
</p>
<p>
Sie können Ihren Browser so einstellen, dass Sie über das Setzen von Cookies
informiert werden und Cookies nur im Einzelfall erlauben, die Annahme von Cookies für
bestimmte Fälle oder generell ausschließen sowie das automatische Löschen der Cookies
beim Schließen des Browsers aktivieren. Bei der Deaktivierung von Cookies kann die
Funktionalität dieser Website eingeschränkt sein.
</p>
<p>
Sofern weitere Cookies und Dienste auf dieser Website eingesetzt werden, können Sie
dies dieser Datenschutzerklärung entnehmen.
</p>
<h3>Vercel Analytics</h3>
<p>
Wir nutzen auf unserer Website die Analysedienste Vercel Analytics der Vercel Inc. (440 Barranca Ave #4133, Covina, CA 91723, USA).
Diese Dienste dienen der Messung der Performance unserer Website (z. B. Ladezeiten) sowie der statistischen Auswertung
der Nutzung unseres Online-Angebots. Dabei werden technische Informationen (z. B. aufgerufene Seite, Browsertyp, Ladezeiten)
an Server von Vercel übermittelt.
</p>
<p>
Die Einbindung und Verarbeitung erfolgt ausschließlich auf Grundlage Ihrer ausdrücklichen Einwilligung gemäß
Art. 6 Abs. 1 lit. a DSGVO sowie § 25 Abs. 1 TDDDG. Die Einwilligung wird über unseren Cookie-Banner abgefragt
und ist jederzeit mit Wirkung für die Zukunft über die Cookie-Einstellungen auf unserer Website widerrufbar.
</p>
<h3>Kontaktformular</h3>
<p>
Wenn Sie uns per Kontaktformular Anfragen zukommen lassen, werden Ihre Angaben aus
dem Anfrageformular inklusive der von Ihnen dort angegebenen Kontaktdaten zwecks
Bearbeitung der Anfrage und für den Fall von Anschlussfragen bei uns gespeichert.
Diese Daten geben wir nicht ohne Ihre Einwilligung weiter.
</p>
<p>
Die Verarbeitung dieser Daten erfolgt auf Grundlage von Art. 6 Abs. 1 lit. b DSGVO,
sofern Ihre Anfrage mit der Erfüllung eines Vertrags zusammenhängt oder zur
Durchführung vorvertraglicher Maßnahmen erforderlich ist. In allen übrigen Fällen
beruht die Verarbeitung auf unserem berechtigten Interesse an der effektiven
Bearbeitung der an uns gerichteten Anfragen (Art. 6 Abs. 1 lit. f DSGVO) oder auf
Ihrer Einwilligung (Art. 6 Abs. 1 lit. a DSGVO) sofern diese abgefragt wurde; die
Einwilligung ist jederzeit widerrufbar.
</p>
<p>
Die von Ihnen im Kontaktformular eingegebenen Daten verbleiben bei uns, bis Sie uns
zur Löschung auffordern, Ihre Einwilligung zur Speicherung widerrufen oder der Zweck
für die Datenspeicherung entfällt (z. B. nach abgeschlossener Bearbeitung Ihrer
Anfrage). Zwingende gesetzliche Bestimmungen – insbesondere Aufbewahrungsfristen –
bleiben unberührt.
</p>
<h3>Anfrage per E-Mail, Telefon oder Telefax</h3>
<p>
Wenn Sie uns per E-Mail, Telefon oder Telefax kontaktieren, wird Ihre Anfrage
inklusive aller daraus hervorgehenden personenbezogenen Daten (Name, Anfrage) zum
Zwecke der Bearbeitung Ihres Anliegens bei uns gespeichert und verarbeitet. Diese
Daten geben wir nicht ohne Ihre Einwilligung weiter.
</p>
<p>
Die Verarbeitung dieser Daten erfolgt auf Grundlage von Art. 6 Abs. 1 lit. b DSGVO,
sofern Ihre Anfrage mit der Erfüllung eines Vertrags zusammenhängt oder zur
Durchführung vorvertraglicher Maßnahmen erforderlich ist. In allen übrigen Fällen
beruht die Verarbeitung auf unserem berechtigten Interesse an der effektiven
Bearbeitung der an uns gerichteten Anfragen (Art. 6 Abs. 1 lit. f DSGVO) oder auf
Ihrer Einwilligung (Art. 6 Abs. 1 lit. a DSGVO) sofern diese abgefragt wurde; die
Einwilligung ist jederzeit widerrufbar.
</p>
<p>
Die von Ihnen an uns per Kontaktanfragen übersandten Daten verbleiben bei uns, bis
Sie uns zur Löschung auffordern, Ihre Einwilligung zur Speicherung widerrufen oder
der Zweck für die Datenspeicherung entfällt (z. B. nach abgeschlossener Bearbeitung
Ihres Anliegens). Zwingende gesetzliche Bestimmungen – insbesondere gesetzliche
Aufbewahrungsfristen – bleiben unberührt.
</p>
<p className="legal-source">
Quelle: <a href="https://www.e-recht24.de">https://www.e-recht24.de</a>
</p>
</>
)
}
export default Datenschutz

View file

@ -0,0 +1,46 @@
import type { Metadata } from "next"
export const metadata: Metadata = {
title: "Impressum",
}
const Impressum = () => {
return (
<>
<h1>Impressum</h1>
<address>
Since3 GbR
<br />
Sandweg 91
<br />
48565 Steinfurt
</address>
<h3>Vertreten durch:</h3>
<p>Ben Dalhoff, Rajpreet Singh</p>
<h2>Kontakt</h2>
<p>
Telefon: <a href="tel:+4917647601638">+49 176 47601638</a>
<br />
E-Mail: <a href="mailto:info@since3.de">info@since3.de</a>
</p>
<h2>Redaktionell verantwortlich</h2>
<p>Ben Dalhoff, Rajpreet Singh</p>
<h2>Verbraucherstreitbeilegung/Universalschlichtungsstelle</h2>
<p>
Wir sind nicht bereit oder verpflichtet, an Streitbeilegungsverfahren vor einer
Verbraucherschlichtungsstelle teilzunehmen.
</p>
<p className="legal-source">
Quelle: <a href="https://www.e-recht24.de">https://www.e-recht24.de</a>
</p>
</>
)
}
export default Impressum

22
app/(legal)/layout.tsx Normal file
View file

@ -0,0 +1,22 @@
import Link from "next/link";
import { ArrowLeft } from "lucide-react";
// Shared frame for Impressum and Datenschutz: light page, one readable column
export default function LegalLayout({ children }: { children: React.ReactNode }) {
return (
<section data-theme="light" className="min-h-svh pt-32 pb-section md:pt-40">
<div className="container-site">
<div className="mx-auto max-w-176">
<Link
href="/"
className="inline-flex items-center gap-2 font-mono text-label text-fg-muted transition-colors hover:text-fg"
>
<ArrowLeft className="size-4" aria-hidden />
Zur Startseite
</Link>
<article className="legal-prose mt-10">{children}</article>
</div>
</div>
</section>
);
}

View file

@ -49,6 +49,18 @@
--ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1);
--ease-in-out-quart: cubic-bezier(0.76, 0, 0.24, 1);
/*
* Single stacking scale for every fixed/overlay layer on the page.
* Highest wins, so the custom cursor stays above all real UI, and the
* cookie banner (a third-party widget) is pinned below it explicitly —
* see the vanilla-cookieconsent override further down.
*/
--z-header: 80;
--z-mobile-menu: 85;
--z-cookie-banner: 90;
--z-cursor: 95;
--z-preloader: 100;
}
@theme inline {
@ -244,6 +256,148 @@ html.lenis body {
paint-order: stroke fill;
}
/* ── Cookie Consent Banner ─────────────────────────────── */
:root.cc--elegant-black {
color-scheme: dark;
--cc-bg: #000;
--cc-primary-color: rgb(239, 244, 246);
--cc-secondary-color: #b1bdc3;
--cc-btn-primary-bg: #ffffff;
--cc-btn-primary-color: #000;
--cc-btn-primary-hover-bg: #ccd4d8;
--cc-btn-primary-hover-color: #000;
--cc-btn-secondary-bg: rgba(255, 255, 255, 0.039);
--cc-btn-secondary-color: var(--cc-primary-color);
--cc-btn-secondary-border-color: #252729;
--cc-btn-secondary-hover-bg: #252729;
--cc-btn-secondary-hover-color: #fff;
--cc-btn-secondary-hover-border-color: #252729;
--cc-cookie-category-block-bg: #101111;
--cc-cookie-category-block-border: #1d1e1f;
--cc-cookie-category-block-hover-bg: #151516;
--cc-cookie-category-block-hover-border: #1d1e1f;
--cc-cookie-category-expanded-block-hover-bg: #1d1e1f;
--cc-cookie-category-expanded-block-bg: #101111;
--cc-toggle-readonly-bg: #2f3132;
--cc-overlay-bg: rgba(0, 0, 0, 0.9)!important;
--cc-toggle-on-knob-bg: var(--cc-bg);
--cc-toggle-readonly-knob-bg: var( --cc-cookie-category-block-bg);
--cc-separator-border-color: #252729;
--cc-footer-border-color: #212529;
--cc-footer-bg: #000;
}
.cc--elegant-black #cc-main .cm,
.cc--elegant-black #cc-main .pm {
border: 1px solid var(--cc-separator-border-color);
}
/* ── Cookie consent (vanilla-cookieconsent) ───────────────────────────── */
/*
* The library defaults --cc-z-index to 2147483647 (max signed 32-bit int),
* which sits above literally everything, including the custom cursor.
* Pin it into our own stacking scale instead.
*
* Its stylesheet is imported by <CookieBanner> as a separate CSS module, so
* load order relative to this file isn't guaranteed. Setting the variable on
* #cc-main itself (the library's own root selector) beats a plain :root
* declaration on specificity regardless of which file loads last.
*/
#cc-main {
--cc-z-index: var(--z-cookie-banner);
}
/* ── Legal pages (Impressum, Datenschutz) ─────────────────────────────── */
/* Plain, readable long-form text. No effects, just hierarchy and rhythm. */
@layer components {
.legal-prose {
hyphens: auto;
overflow-wrap: break-word;
}
.legal-prose h1 {
font-size: clamp(2rem, 8vw, 4.5rem);
font-variation-settings: "wght" 800, "wdth" 75;
line-height: 0.9;
letter-spacing: -0.01em;
text-transform: uppercase;
}
.legal-prose h2 {
margin-top: 3.5rem;
padding-top: 2rem;
border-top: 1px solid var(--line);
font-size: var(--text-title);
font-variation-settings: "wght" 600, "wdth" 90;
line-height: 1.15;
letter-spacing: -0.02em;
text-wrap: balance;
}
.legal-prose h1 + h2,
.legal-prose h1 + * {
margin-top: 2.5rem;
}
.legal-prose h3 {
margin-top: 2.5rem;
font-size: 1.1875rem;
font-weight: 600;
line-height: 1.3;
text-wrap: balance;
}
.legal-prose h4 {
margin-top: 1.75rem;
font-weight: 600;
line-height: 1.4;
}
.legal-prose :is(h2, h3) + :is(h3, h4) {
margin-top: 1.25rem;
}
.legal-prose :is(p, ul, address) {
margin-top: 0.875rem;
line-height: 1.7;
color: color-mix(in oklch, var(--fg) 78%, var(--bg));
}
.legal-prose address {
font-style: normal;
}
.legal-prose ul {
padding-left: 1.25rem;
list-style: disc;
}
.legal-prose li + li {
margin-top: 0.5rem;
}
.legal-prose a {
color: var(--fg);
text-decoration: underline;
text-underline-offset: 3px;
}
.legal-prose a:hover {
text-decoration-thickness: 2px;
}
/* The legally required all-caps paragraph (Art. 21 DSGVO), slightly calmer */
.legal-prose .legal-caps {
font-size: 0.9375rem;
letter-spacing: 0.01em;
}
.legal-prose .legal-source {
margin-top: 4rem;
font-family: var(--font-mono);
font-size: var(--text-label);
color: var(--fg-muted);
}
}
/* ── Grain over everything ────────────────────────────────────────────── */
body::after {

View file

@ -12,6 +12,7 @@ import { SoundEffects } from "@/modules/shared/ui/components/sound-effects";
import { mono, sans } from "./fonts";
import "./globals.css";
import CookieBanner from "@/modules/shared/ui/components/cookie-consent";
export const metadata: Metadata = {
metadataBase: new URL(site.url),
@ -48,7 +49,7 @@ export default function RootLayout({ children }: LayoutProps<"/">) {
<div id="top" />
<a
href="#inhalt"
className="sr-only z-100 rounded-full bg-white px-5 py-3 text-black focus:not-sr-only focus:fixed focus:top-4 focus:left-4"
className="sr-only z-[var(--z-preloader)] rounded-full bg-white px-5 py-3 text-black focus:not-sr-only focus:fixed focus:top-4 focus:left-4"
>
Zum Inhalt springen
</a>
@ -62,6 +63,7 @@ export default function RootLayout({ children }: LayoutProps<"/">) {
<main id="inhalt" tabIndex={-1} className="outline-none">
{children}
</main>
<CookieBanner/>
<SiteFooter />
</body>
</html>

54
app/not-found.tsx Normal file
View file

@ -0,0 +1,54 @@
import type { Metadata } from "next";
import Link from "next/link";
import { ArrowRight } from "lucide-react";
import { RequestedPath } from "@/modules/shared/ui/components/requested-path";
import { Magnetic } from "@/modules/shared/ui/components/magnetic";
export const metadata: Metadata = {
title: "Seite nicht gefunden",
};
// Renders inside the root layout, so header, footer and the shared theme
// still apply — this is the same dark, oversized-type language as the hero.
export default function NotFound() {
return (
<section
aria-labelledby="not-found-title"
data-theme="dark"
className="flex min-h-svh flex-col justify-center py-32"
>
<div className="container-site flex flex-col items-start">
<p className="font-mono text-label text-fg-muted">(Fehler 404)</p>
<h1
id="not-found-title"
aria-label="Seite nicht gefunden"
className="mt-6 text-mega leading-none type-poster text-outline"
>
404
</h1>
<p className="type-body mt-6 max-w-[46ch] text-lead text-fg-muted">
Diese Seite gibt es nicht, oder sie ist umgezogen. Der Link war
vielleicht veraltet oder es hat sich jemand vertippt.
</p>
<RequestedPath />
<Magnetic strength={0.3} className="mt-10">
<Link
href="/"
className="group inline-flex h-14 items-center gap-2 rounded-full bg-white px-7 font-medium text-black transition-[scale] duration-500 ease-out-expo hover:scale-105"
>
Zur Startseite
<ArrowRight
aria-hidden
className="size-4 transition-transform duration-500 ease-out-expo group-hover:translate-x-1"
/>
</Link>
</Magnetic>
</div>
</section>
);
}

14
app/robots.ts Normal file
View file

@ -0,0 +1,14 @@
import type { MetadataRoute } from "next";
import { site } from "@/modules/shared/config/site";
// The whole site is public marketing content, so crawlers get full access.
export default function robots(): MetadataRoute.Robots {
return {
rules: {
userAgent: "*",
allow: "/",
},
sitemap: `${site.url}/sitemap.xml`,
};
}

30
app/sitemap.ts Normal file
View file

@ -0,0 +1,30 @@
import type { MetadataRoute } from "next";
import { site } from "@/modules/shared/config/site";
// One entry per actual route. The in-page anchors (/#projekte etc.) are
// sections of "/", not separate pages, so they don't get their own entry.
export default function sitemap(): MetadataRoute.Sitemap {
const lastModified = new Date();
return [
{
url: site.url,
lastModified,
changeFrequency: "weekly",
priority: 1,
},
{
url: `${site.url}/impressum`,
lastModified,
changeFrequency: "yearly",
priority: 0.3,
},
{
url: `${site.url}/datenschutz`,
lastModified,
changeFrequency: "yearly",
priority: 0.3,
},
];
}

View file

@ -33,7 +33,8 @@ export function setEnabled(enabled: boolean) {
type Engine = { ctx: AudioContext; master: GainNode; noise: AudioBuffer }
let engine: Engine | null = null
// Created lazily on first use, which is always inside a user gesture
// Created lazily on first use. Hover is not a user activation, so `play`
// checks activation before calling this — see there.
function getEngine(): Engine {
if (!engine) {
const ctx = new AudioContext()
@ -156,6 +157,16 @@ const VOICES: Record<SoundVoice, (engine: Engine, now: number) => void> = {
export function play(voice: SoundVoice, { force = false } = {}) {
if (typeof window === "undefined") return
if (!force && !isEnabled()) return
// Before the first user activation, a new AudioContext stays "suspended"
// and resume() is a no-op. currentTime is then frozen at 0, so every
// sound scheduled while hovering (not an activation) would queue up at
// t=0 and all fire at once, as one loud burst, once a click resumes it.
const activated = navigator.userActivation?.hasBeenActive ?? true
if (!engine && !activated) return
if (engine && engine.ctx.state !== "running" && !activated) return
const current = getEngine()
if (current.ctx.state !== "running") return
VOICES[voice](current, current.ctx.currentTime)
}

View file

@ -141,6 +141,7 @@ ${el.value}` : text
{...fieldProps("privacy")}
type="checkbox"
required
defaultChecked={state.values?.privacy}
className="mt-0.5 size-5 shrink-0 accent-current"
/>
<label htmlFor={fieldId("privacy")} className="text-sm text-fg-muted">

View file

@ -9,7 +9,13 @@ export const contactSchema = z.object({
email: z
.string()
.trim()
.pipe(z.email("Bitte gib eine gültige E-Mail-Adresse an.")),
// Zod's default email pattern rejects valid Unicode addresses (e.g. müller@example.de)
.pipe(
z.email({
pattern: z.regexes.unicodeEmail,
error: "Bitte gib eine gültige E-Mail-Adresse an.",
})
),
company: z.string().trim().max(120, "Maximal 120 Zeichen.").optional(),
message: z
.string()
@ -28,8 +34,12 @@ export type ContactFormState = {
status: "idle" | "success" | "error"
message?: string
fieldErrors?: Partial<Record<ContactField, string[]>>
// Echoed back so the form keeps its values after a failed submit
values?: Partial<Record<ContactField, string>>
// Echoed back so the form keeps its values after a failed submit.
// `privacy` is separate from ContactField's string values: the checkbox
// needs a boolean, not the raw "on" the form field submits.
values?: Partial<Record<Exclude<ContactField, "privacy">, string>> & {
privacy?: boolean
}
}
export const initialContactState: ContactFormState = { status: "idle" }

View file

@ -36,6 +36,7 @@ export async function submitContact(
email: raw.email,
company: raw.company,
message: raw.message,
privacy: raw.privacy === "on",
},
}
}

View file

@ -15,7 +15,14 @@ export function ContrastTool() {
const [bg, setBg] = useState("#ffffff")
const [lines, setLines] = useState<OutputLine[] | null>(null)
const preview = parseHex(fg) && parseHex(bg) ? { color: fg, background: bg } : undefined
// parseHex accepts values without "#" (e.g. "1a1a1a"), but CSS doesn't —
// build the preview from the parsed RGB channels instead of the raw input
const fgRgb = parseHex(fg)
const bgRgb = parseHex(bg)
const preview =
fgRgb && bgRgb
? { color: `rgb(${fgRgb.join(" ")})`, background: `rgb(${bgRgb.join(" ")})` }
: undefined
const onSubmit = (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault()

View file

@ -11,13 +11,15 @@ export const site = {
city: "Steinfurt",
} as const
// Absolute ("/#...") so the links also work from the legal pages.
// Lenis still scrolls smoothly when they point to the current page.
export const mainNav = [
{ label: "Projekte", href: "#projekte" },
{ label: "Leistungen", href: "#leistungen" },
{ label: "Tools", href: "#tools" },
{ label: "Prozess", href: "#prozess" },
{ label: "Preise", href: "#preise" },
{ label: "Über uns", href: "#ueber-uns" },
{ label: "Projekte", href: "/#projekte" },
{ label: "Leistungen", href: "/#leistungen" },
{ label: "Tools", href: "/#tools" },
{ label: "Prozess", href: "/#prozess" },
{ label: "Preise", href: "/#preise" },
{ label: "Über uns", href: "/#ueber-uns" },
] as const
// Regional terms for local SEO.
@ -36,5 +38,4 @@ export const regions = [
export const legalNav = [
{ label: "Impressum", href: "/impressum" },
{ label: "Datenschutz", href: "/datenschutz" },
{ label: "Barrierefreiheit", href: "/barrierefreiheit" },
] as const

View file

@ -0,0 +1,60 @@
"use client";
import { Analytics } from "@vercel/analytics/next";
import * as CookieConsent from 'vanilla-cookieconsent';
import 'vanilla-cookieconsent/dist/cookieconsent.css';
import { useEffect, useState } from "react";
export default function CookieBanner() {
const [analyticsAccepted, setAnalyticsAccepted] = useState(false);
useEffect(() => {
document.documentElement.classList.add('cc--elegant-black');
CookieConsent.run({
guiOptions: {
consentModal: { layout: 'box', position: 'bottom right' },
preferencesModal: {layout: 'box'},
},
categories: {
analytics: {}
},
language: {
default: 'de',
translations: {
de: {
consentModal: {
title: 'Wir nutzen Cookies',
description:
'Diese Webseite nutzt optionale Cookies für Statistik und Marketing. Mehr dazu in unserer <a href="/datenschutz" target="_blank" rel="noopener">Datenschutzerklärung</a>.',
acceptAllBtn: 'Alle akzeptieren',
showPreferencesBtn: 'Einstellungen verwalten',
},
preferencesModal: {
title: 'Cookie-Einstellungen',
acceptAllBtn: 'Alle akzeptieren',
savePreferencesBtn: 'Auswahl speichern',
sections: [
{ title: "Statistik", linkedCategory: 'analytics' }
],
},
},
},
},
onConsent: ({ cookie }) => {
setAnalyticsAccepted(cookie.categories.includes('analytics'));
},
onChange: ({ cookie }) => {
setAnalyticsAccepted(cookie.categories.includes('analytics'))
}
})
}, []);
if (!analyticsAccepted) return null;
return (
<>
<Analytics/>
</>
)
}

View file

@ -0,0 +1,16 @@
"use client";
import * as CookieConsent from "vanilla-cookieconsent";
export default function CookiePrefencesButton({ className = ""}: { className?: string}) {
return (
<button
type="button"
onClick={() => CookieConsent.showPreferences()}
className={`${className} bg-transparent border-0 p-0 cursor-pointer text-left `}
>
Cookie-Einstellungen
</button>
)
}

View file

@ -92,7 +92,7 @@ export function CustomCursor() {
ref={ref}
aria-hidden="true"
className={cn(
"pointer-events-none fixed top-0 left-0 z-95 will-change-transform",
"pointer-events-none fixed top-0 left-0 z-[var(--z-cursor)] will-change-transform",
mode !== "label" && "mix-blend-difference"
)}
>

View file

@ -74,7 +74,7 @@ export function Preloader() {
<div
ref={rootRef}
aria-hidden="true"
className="preloader fixed inset-0 z-100 flex-col justify-between bg-black p-gutter text-white"
className="preloader fixed inset-0 z-[var(--z-preloader)] flex-col justify-between bg-black p-gutter text-white"
>
<div className="flex items-start justify-between font-mono text-label text-ink-400">
<span>Digitalagentur</span>

View file

@ -0,0 +1,21 @@
"use client"
import { usePathname } from "next/navigation"
/** Echoes the URL that didn't resolve, terminal-log style. */
export function RequestedPath() {
const pathname = usePathname()
return (
<p className="mt-8 max-w-[60ch] rounded-2xl border border-white/15 bg-white/5 px-6 py-4 text-left font-mono text-label text-white">
<span className="text-ink-400">$ curl </span>
{pathname}
<br />
<span className="text-signal-error">404 Not Found</span>
<span
aria-hidden="true"
className="ml-1 inline-block h-4 w-2 translate-y-0.5 animate-pulse bg-white"
/>
</p>
)
}

View file

@ -6,6 +6,7 @@ import { legalNav, mainNav, regions, site } from "@/modules/shared/config/site"
import { LiveClock } from "./live-clock"
import { Magnetic } from "./magnetic"
import CookiePrefencesButton from "./cookie-prefrence-button"
export function SiteFooter() {
const year = new Date().getFullYear()
@ -72,6 +73,9 @@ export function SiteFooter() {
</Link>
</li>
))}
<li>
<CookiePrefencesButton className="hover:text-fg hover:underline text-label"/>
</li>
</ul>
</nav>
</div>

View file

@ -19,6 +19,7 @@ export function SiteHeader() {
const [hidden, setHidden] = useState(false)
const [menuOpen, setMenuOpen] = useState(false)
const firstLinkRef = useRef<HTMLAnchorElement>(null)
const toggleRef = useRef<HTMLButtonElement>(null)
useEffect(() => {
let lastY = window.scrollY
@ -36,7 +37,11 @@ export function SiteHeader() {
if (!menuOpen) return
firstLinkRef.current?.focus()
const onKey = (event: KeyboardEvent) => {
if (event.key === "Escape") setMenuOpen(false)
// Focus would otherwise fall through to <body> once #mobile-menu goes inert
if (event.key === "Escape") {
setMenuOpen(false)
toggleRef.current?.focus()
}
}
document.documentElement.style.overflow = "hidden"
window.addEventListener("keydown", onKey)
@ -52,13 +57,14 @@ export function SiteHeader() {
<>
<header
data-hidden={hidden && !menuOpen}
className="site-header fixed inset-x-0 top-0 z-85"
className="site-header fixed inset-x-0 top-0 z-[var(--z-header)]"
>
<nav
aria-label="Hauptnavigation"
className="container-site grid h-20 grid-cols-[1fr_auto] items-center gap-6 md:h-24 lg:grid-cols-[1fr_auto_1fr]"
>
<a href="#top" aria-label="since3 – nach oben" className="w-fit">
{/* eslint-disable-next-line @next/next/no-html-link-for-pages -- Plain anchor on purpose: Lenis smooth-scrolls same-page hash links, next/link would scroll as well */}
<a href="/#top" aria-label="since3 – zur Startseite" className="w-fit">
<Image
src="/pictures/since3-logo-weiss.svg"
alt=""
@ -82,13 +88,15 @@ export function SiteHeader() {
<div className="flex items-center justify-end gap-2 md:gap-4">
<LiveClock className="hidden font-mono text-label tabular-nums opacity-70 xl:block" />
<SoundToggle />
{/* eslint-disable-next-line @next/next/no-html-link-for-pages -- Plain anchor on purpose: Lenis smooth-scrolls same-page hash links, next/link would scroll as well */}
<a
href="#kontakt"
href="/#kontakt"
className="hidden h-10 items-center rounded-full border border-white px-5 text-sm font-medium transition-colors duration-300 hover:bg-white hover:text-black sm:inline-flex"
>
Projekt starten
</a>
<button
ref={toggleRef}
type="button"
data-sound="off"
onClick={() => {
@ -125,13 +133,13 @@ export function SiteHeader() {
data-theme="dark"
inert={!menuOpen}
className={cn(
"fixed inset-0 z-80 flex flex-col justify-end pb-10 transition-[clip-path] duration-700 ease-in-out-quart lg:hidden",
"fixed inset-0 z-[var(--z-mobile-menu)] flex flex-col justify-end pb-10 transition-[clip-path] duration-700 ease-in-out-quart lg:hidden",
menuOpen ? "[clip-path:inset(0_0_0_0)]" : "[clip-path:inset(0_0_100%_0)]"
)}
>
<nav aria-label="Mobile Navigation" className="container-site">
<ul className="flex flex-col">
{[...mainNav, { label: "Kontakt", href: "#kontakt" }].map((item, index) => (
{[...mainNav, { label: "Kontakt", href: "/#kontakt" }].map((item, index) => (
<li key={item.href} className="overflow-clip border-b border-line">
<a
ref={index === 0 ? firstLinkRef : undefined}

50
package-lock.json generated
View file

@ -9,6 +9,7 @@
"version": "0.1.0",
"dependencies": {
"@base-ui/react": "^1.8.0",
"@vercel/analytics": "^2.0.1",
"class-variance-authority": "^0.7.1",
"cn": "^0.4.0",
"lenis": "^1.3.26",
@ -19,6 +20,7 @@
"react-dom": "19.2.8",
"shadcn": "^4.21.0",
"tw-animate-css": "^1.4.0",
"vanilla-cookieconsent": "^3.1.0",
"zod": "^4.6.5"
},
"devDependencies": {
@ -2945,6 +2947,48 @@
"win32"
]
},
"node_modules/@vercel/analytics": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@vercel/analytics/-/analytics-2.0.1.tgz",
"integrity": "sha512-MTQG6V9qQrt1tsDeF+2Uoo5aPjqbVPys1xvnIftXSJYG2SrwXRHnqEvVoYID7BTruDz4lCd2Z7rM1BdkUehk2g==",
"license": "MIT",
"peerDependencies": {
"@remix-run/react": "^2",
"@sveltejs/kit": "^1 || ^2",
"next": ">= 13",
"nuxt": ">= 3",
"react": "^18 || ^19 || ^19.0.0-rc",
"svelte": ">= 4",
"vue": "^3",
"vue-router": "^4"
},
"peerDependenciesMeta": {
"@remix-run/react": {
"optional": true
},
"@sveltejs/kit": {
"optional": true
},
"next": {
"optional": true
},
"nuxt": {
"optional": true
},
"react": {
"optional": true
},
"svelte": {
"optional": true
},
"vue": {
"optional": true
},
"vue-router": {
"optional": true
}
}
},
"node_modules/accepts": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz",
@ -9586,6 +9630,12 @@
"node": "^20.17.0 || >=22.9.0"
}
},
"node_modules/vanilla-cookieconsent": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/vanilla-cookieconsent/-/vanilla-cookieconsent-3.1.0.tgz",
"integrity": "sha512-/McNRtm/3IXzb9dhqMIcbquoU45SzbN2VB+To4jxEPqMmp7uVniP6BhGLjU8MC7ZCDsNQVOp27fhQTM/ruIXAA==",
"license": "MIT"
},
"node_modules/vary": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",

View file

@ -10,6 +10,7 @@
},
"dependencies": {
"@base-ui/react": "^1.8.0",
"@vercel/analytics": "^2.0.1",
"class-variance-authority": "^0.7.1",
"cn": "^0.4.0",
"lenis": "^1.3.26",
@ -20,6 +21,7 @@
"react-dom": "19.2.8",
"shadcn": "^4.21.0",
"tw-animate-css": "^1.4.0",
"vanilla-cookieconsent": "^3.1.0",
"zod": "^4.6.5"
},
"devDependencies": {