+
+
+
LUCAS
CIZERON
-
+
+
+
+
+
LUCAS
+ CIZERON
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PROJECTS PROJECTS PROJECTS PROJECTS PROJECTS PROJECTS PROJECTS PROJECTS PROJECTS PROJECTS
+ PROJECTS PROJECTS PROJECTS PROJECTS PROJECTS PROJECTS
+
+
+ PROJECTS PROJECTS PROJECTS PROJECTS PROJECTS PROJECTS PROJECTS PROJECTS PROJECTS PROJECTS
+ PROJECTS PROJECTS PROJECTS PROJECTS PROJECTS PROJECTS
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ EXPERIENCES EXPERIENCES EXPERIENCES EXPERIENCES EXPERIENCES EXPERIENCES EXPERIENCES EXPERIENCES
+ EXPERIENCES EXPERIENCES
+ EXPERIENCES EXPERIENCES EXPERIENCES EXPERIENCES EXPERIENCES EXPERIENCES
+
+
+ EXPERIENCES EXPERIENCES EXPERIENCES EXPERIENCES EXPERIENCES EXPERIENCES EXPERIENCES EXPERIENCES
+ EXPERIENCES EXPERIENCES
+ EXPERIENCES EXPERIENCES EXPERIENCES EXPERIENCES EXPERIENCES EXPERIENCES
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/js/javascript_i18n.js b/src/js/javascript_i18n.js
index 6b34479..dd7a44d 100644
--- a/src/js/javascript_i18n.js
+++ b/src/js/javascript_i18n.js
@@ -1,34 +1,115 @@
function switchLanguage(lang) {
- console.log('Switching to language:', lang);
- document.documentElement.lang = lang;
- const elements = document.querySelectorAll('[data-i18n]');
- elements.forEach(element => {
- element.textContent = translations[lang][element.getAttribute('data-i18n')];
- });
-}
-const translations = {
- en: {
- welcome: "Welcome to my portfolio",
- about: "About Me",
- contact: "Contact",
- languageSwitch: "FR",
- epitaStudent: "Epita student",
- },
- fr: {
- welcome: "Bienvenue sur mon portfolio",
- about: "À propos de moi",
- contact: "Contact",
- languageSwitch: "EN",
- epitaStudent: "Etudiant à epita",
- }
-};
+ const translations = {
+ en: {
+ welcome: "Welcome to my portfolio",
+ contact: "Contact",
+ languageSwitch: "FR",
+ epitaStudent: "Epita student",
+ about_me_title_1: "About Me",
+ about_me_1: "Currently a 4th-year student at EPITA, specializing in the SIGL major (Système d’Information et Génie Logiciel). Passionate about technology and problem-solving, I am acquiring the tools to transform innovative ideas into reliable and scalable IT solutions.",
+ about_me_title_2: "What Is SIGL?",
+ about_me_2: "SIGL is a major at EPITA that
prepares to assist businesses in transitioning to a new, scalable IT framework aligned with business needs. The topics covered include leadership and management, cloud and architecture, mobility and applications, as well as digitalization and transformation.",
+ about_me_title_3: "Why This Portfolio?",
+ about_me_3: "I spend my time working on various personal projects, hence this portfolio. I have always had a keen interest in designing and developing websites since I started studying computer science, and this portfolio reflects my journey in honing that skill.",
+ status: "Status:",
+ status_done: "Done",
+ status_wip: "In progress",
+ _42sh: "42SH is a shell project that I made during my third year at EPITA. It is a reproduction of a UNIX shell that can execute commands, manage environment variables, and handle signals all while conforming to the POSIX standard.",
+ gymrat: "Development of a fitness mobile application in Flutter and Dart, it allows to keep track of fitness objectives and performances. Chatgpt 4.0 queries also allow the detection of macros by taking a picture of the dish for macros monitoring. The backend part is integrated in SQL and hosted with Firebase. I plan to deploy it on App and Play store once finished.",
+ ping: "Reproduction of the front-end & back-end of an IDE including client constraints to emulate client collaboration. Supports multiple languages auto-completion and syntax highlighting as well as all maven & git functionnalities. Deployed using electron.",
+ ocr: "Optical character recognition software capable of detecting a sudoku grid as well as the numbers it contains to automatically solve it. The project was programmed from scratch in C without using any library.",
+ tiger: "Implementation of a C++ compiler for the Tiger language, using tools such as Bison and Flex.",
+ portfolio: "This portfolio was created using HTML, CSS, and JavaScript. It is hosted on GitHub Pages and the source code is available on my GitHub repository. It has been redone many times as my skills improved, until its latest iteration that you see now.",
+ bpce: "6-month internship at BPCE-IT's FabLab, an innovation team responsible for studying the feasibility of innovative projects, developing them, and deploying them. The work is done following the Agile methodology and DevOps culture. During these 6 months, I was able to participate in the development and deployment of 4 internal projects.",
+ csumb: "I had the opportunity to study abroad at the California State University - Monterey Bay. It was during this semester that I started web development. Besides the academic aspect, I was able to discover the American culture and travel throughout the country.",
+ footer_text: "Sincerely,",
+ footer_text_2: "Lucas."
+ },
+ fr: {
+ welcome: "Bienvenue sur mon portfolio",
+ contact: "Contact",
+ languageSwitch: "EN",
+ epitaStudent: "Etudiant à epita",
+ about_me_title_1: "Présentation",
+ about_me_1: "Actuellement étudiant en 4ème année à l'EPITA, me spécialisant dans la majeure SIGL (Système d’Information et Génie Logiciel). Passionné par la technologie et la résolution de problèmes, je construis une carrière à l'intersection des Systèmes d'Information et du Génie Logiciel. Grâce à ce programme, j'acquiers les outils pour transformer des idées innovantes en solutions informatiques fiables et évolutives.",
+ about_me_title_2: "Qu'est-ce que SIGL?",
+ about_me_2: "SIGL est une majeure à l'EPITA qui \"
prépare à aider les entreprises à passer à un nouveau cadre informatique évolutif aligné sur les besoins de l'entreprise. Les sujets abordés incluent le leadership et la gestion, le cloud et l'architecture, la mobilité et les applications, ainsi que la numérisation et la transformation\".",
+ about_me_title_3: "Pourquoi ce portfolio?",
+ about_me_3: "Lorsque je ne suis pas en train d'étudier à l'EPITA, je consacre mon temps à travailler sur divers projets personnels, d'où ce portfolio. J'ai toujours eu un certain intérêt pour la conception et le développement de sites web depuis que j'ai commencé à programmer, ce portfolio reflète mon parcours concernant cette compétence.",
+ status: "Statut:",
+ status_done: "Terminé",
+ status_wip: "En cours",
+ _42sh: "42SH est un projet de shell que j'ai réalisé lors de ma troisième année à l'EPITA. C'est une reproduction d'un shell UNIX qui peut exécuter des commandes, gérer des variables d'environnement et gérer des signaux tout en respectant la norme POSIX.",
+ gymrat: "Développement d'une application mobile de fitness en Flutter et Dart, elle permet de suivre les objectifs et performances de fitness. Les requêtes Chatgpt 4.0 permettent également la détection des macros en prenant une photo du plat pour le suivi des macros. La partie backend est intégrée en SQL et hébergée avec Firebase. Je prévois de le déployer sur App et Play store une fois terminé.",
+ ping: "Reproduction du front-end & back-end d'un IDE incluant des contraintes pour émuler la collaboration client. Permet la complétion automatique en plusieurs langages et la coloration syntaxique ainsi que les fonctionnalités maven & git. Déployé avec electron.",
+ ocr: "Logiciel de reconnaissance optique de caractères capable de détecter une grille de sudoku ainsi que les chiffres qu'elle contient pour la résoudre automatiquement. Codé à partir de zéro en C sans utiliser de librairies.",
+ tiger: "Implémentation d'un compilateur C++ pour le langage Tiger, en utilisant des outils tels que Bison et Flex.",
+ portfolio: "Ce portfolio a été créé en utilisant HTML, CSS, et JavaScript. Il est hébergé sur GitHub Pages et le code source est disponible sur mon dépôt. Il a été refait de nombreuses fois au fur et à mesure que mes compétences s'amélioraient, jusqu'à sa dernière itération que vous voyez maintenant.",
+ bpce: "Stage de 6 mois au sein du FabLab de BPCE-IT, une équipe d'innovation chargée d'étudier la faisabilité de projets innovants, de les développer puis de les déployer. Le travail s'effectue en suivant la méthodologie Agile et la culture DevOps. Durant ces 6 mois, j'ai pu participer au dévelopement et déploiement de 4 projets internes.",
+ csumb:"J'ai eu la chance d'effectuer un semestre à l'international au sein de la California State University - Monterey Bay. C'est lors de ce semestre que j'ai commencé le développement web. Hormis l'aspect académique, j'ai surtout pu découvrir la culture américaine et voyager à travers le pays.",
+ geneva: "GENÈVE",
+ geneva_description: "J'ai développé durant 3 mois un jeu vidéo à but éducatif pour le compte d'un cabinet orthophonique genevois. Le dévelopement s'est fait en C# et se basait sur Unity pour le rendu. Le jeu permettait aux enfants de travailler leur orthographe en explorant un environnement 2D.",
+ footer_text: "Cordialement,",
+ footer_text_2: "Lucas."
+ }
+ };
+
+ // -------- Variables and constants --------
+ const fadeInElements = document.querySelectorAll('.fade-in');
+
+ // --------Screen update wave animation--------
+ const wave1 = document.createElement('div');
+ wave1.classList.add('wave', 'wave1');
+ const wave2 = document.createElement('div');
+ wave2.classList.add('wave', 'wave2');
+ const wave3 = document.createElement('div');
+ wave3.classList.add('wave', 'wave3');
+
+ document.body.appendChild(wave1);
+ document.body.appendChild(wave2);
+ document.body.appendChild(wave3);
+
+ setTimeout(() => {
+ wave1.remove();
+ wave2.remove();
+ wave3.remove();
+ }, 1000);
+
+ // --------Language switch while waves play--------
+ setTimeout(() => {
+ document.documentElement.lang = lang;
+ const elements = document.querySelectorAll('[data-i18n]');
+ elements.forEach(element => {
+ element.innerHTML = translations[lang][element.getAttribute('data-i18n')];
+ });
+ // --------Fade in animation--------
+ fadeInElements.forEach(element => {
+ element.classList.add('fade-in-up');
+ });
+ }, 200);
+
+ // --------Fade-in element stays visible after animation is done--------
+ setTimeout(() => {
+ fadeInElements.forEach(element => {
+ element.style.opacity = 1;
+ });
+ }, 1200);
+
+}
+// --------Main function--------
document.addEventListener('DOMContentLoaded', () => {
- switchLanguage('fr'); // Default language
+ switchLanguage('fr');
let currentLanguage = 'FR';
const languageSwitch = document.getElementById('language-switch');
languageSwitch.addEventListener('click', () => {
+ const fadeInElements = document.querySelectorAll('.fade-in');
+ setTimeout(() => {
+ fadeInElements.forEach(element => {
+ element.style.opacity = 1;
+ });
+ }, 1200);
if (currentLanguage === 'FR') {
currentLanguage = 'EN';
switchLanguage('en');
diff --git a/src/js/javascript_main.js b/src/js/javascript_main.js
index c84eea3..9ad3023 100644
--- a/src/js/javascript_main.js
+++ b/src/js/javascript_main.js
@@ -1,4 +1,5 @@
document.addEventListener('DOMContentLoaded', () => {
+
// Create the blob element
const blob = document.createElement('div');
blob.classList.add('blob');
@@ -6,7 +7,7 @@ document.addEventListener('DOMContentLoaded', () => {
let mouseX = 0, mouseY = 0;
let blobX = 0, blobY = 0;
- const speed = 0.78; // Adjust the speed for latency effect
+ const speed = 0.78;
let isHovering = false;
// Update the mouse position on mouse move
@@ -32,7 +33,7 @@ document.addEventListener('DOMContentLoaded', () => {
animateBlob();
- // Handle size transition on hover over clickable elements
+ // Handle size transition of blob on hover over clickable elements
const clickableElements = document.querySelectorAll('a, button, .clickable');
clickableElements.forEach(element => {
element.addEventListener('mouseenter', () => {
@@ -47,9 +48,49 @@ document.addEventListener('DOMContentLoaded', () => {
});
element.addEventListener('mouseleave', () => {
isHovering = false;
- blob.style.width = '30px'; // Revert to initial small size
- blob.style.height = '30px'; // Revert to initial small size
+ blob.style.width = '30px';
+ blob.style.height = '30px';
blob.classList.remove('transition');
});
});
+
+ // Scroll fade-in functionality
+ const scrollFadeInElements = document.querySelectorAll('.scroll-fade-in');
+
+ const observer = new IntersectionObserver((entries, observer) => {
+ entries.forEach(entry => {
+ if (entry.isIntersecting) {
+ entry.target.classList.add('visible');
+ observer.unobserve(entry.target);
+ }
+ });
+ }, { threshold: 0.1 });
+
+ scrollFadeInElements.forEach(element => {
+ observer.observe(element);
+ });
+
+ // NAVBAR change on scroll
+ const containerFluid = document.querySelector('.container-fluid');
+ window.addEventListener('scroll', () => {
+ if (window.scrollY > 500) {
+ containerFluid.classList.add('scrolled');
+ } else {
+ containerFluid.classList.remove('scrolled');
+ }
+ });
+});
+
+document.addEventListener("scroll", function () {
+ var pageTop = window.scrollY;
+ var pageBottom = pageTop + window.innerHeight;
+ var tags = document.querySelectorAll(".scroll-fade-in");
+
+ tags.forEach(function (tag) {
+ if (tag.getBoundingClientRect().top + pageTop < pageBottom) {
+ tag.classList.add("visible");
+ } else {
+ tag.classList.remove("visible");
+ }
+ });
});
diff --git a/src/js/javascript_mouse_effect.js b/src/js/javascript_mouse_effect.js
index 29af296..406d82e 100644
--- a/src/js/javascript_mouse_effect.js
+++ b/src/js/javascript_mouse_effect.js
@@ -43,8 +43,8 @@ document.addEventListener('DOMContentLoaded', () => {
});
element.addEventListener('mouseleave', () => {
isHovering = false;
- blob.style.width = '30px'; // Revert to initial small size
- blob.style.height = '30px'; // Revert to initial small size
+ blob.style.width = '30px';
+ blob.style.height = '30px';
blob.classList.remove('transition');
});
});
diff --git a/src/js/javascript_smooth_scroll.js b/src/js/javascript_smooth_scroll.js
new file mode 100644
index 0000000..cffb646
--- /dev/null
+++ b/src/js/javascript_smooth_scroll.js
@@ -0,0 +1,42 @@
+const lenis = new Lenis({
+ duration: 1.2,
+ easing: (t) => Math.min(1, 1.001 - Math.pow(2, -10 * t))
+});
+
+function raf(time) {
+ lenis.raf(time);
+ ScrollTrigger.update();
+ requestAnimationFrame(raf);
+}
+
+requestAnimationFrame(raf);
+
+const section_1 = document.getElementById("vertical");
+const col_left = document.querySelector(".col_left");
+const timeln = gsap.timeline({ paused: true });
+
+timeln.fromTo(col_left, {y: 0}, {y: '40vh', duration: 1, ease: 'none'}, 0);
+
+const scroll_1 = ScrollTrigger.create({
+ animation: timeln,
+ trigger: section_1,
+ start: 'top top',
+ end: 'bottom center',
+ scrub: 1
+});
+
+const section_2 = document.getElementById("horizontal");
+const horizontalstop = document.getElementById("horizontalstop");
+let box_items = gsap.utils.toArray(".horizontal__item");
+
+gsap.to(box_items, {
+xPercent: -100 * (box_items.length - 1),
+ease: "sine.out",
+scrollTrigger: {
+ trigger: horizontalstop,
+ pin: true,
+ scrub: 3,
+ snap: 1 / (box_items.length - 1),
+ end: "+=" + section_2.offsetWidth
+}
+});
\ No newline at end of file
diff --git a/src/js/javascript_text_effect.js b/src/js/javascript_text_effect.js
index 38c55da..2c2ca2f 100644
--- a/src/js/javascript_text_effect.js
+++ b/src/js/javascript_text_effect.js
@@ -9,7 +9,7 @@ document.addEventListener('DOMContentLoaded', () => {
letters.forEach((letter) => {
const span = document.createElement('span');
span.textContent = letter;
- span.style.transition = 'color 0.5s ease'; // Add transition for smooth color change
+ span.style.transition = 'color 0.5s ease';
element.appendChild(span);
});
@@ -22,7 +22,7 @@ document.addEventListener('DOMContentLoaded', () => {
span.style.color = color;
// Schedule the next color change
- const randomDelay = Math.random() * (1000 - 200) + 200; // Random delay between 0.2s and 1s
+ const randomDelay = Math.random() * (1000 - 200) + 200;
setTimeout(() => changeColor(span), randomDelay);
}
diff --git a/src/style/style_main.css b/src/style/style_main.css
index fee9902..a5ba036 100644
--- a/src/style/style_main.css
+++ b/src/style/style_main.css
@@ -1,6 +1,7 @@
-@import url('https://fonts.googleapis.com/css2?family=Dancing+Script:wght@400..700&family=Mrs+Saint+Delafield&family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap');
/* Fonts */
+@import url('https://fonts.googleapis.com/css2?family=Dancing+Script:wght@400..700&family=Mrs+Saint+Delafield&family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap');
+
@font-face {
font-family: 'Humane';
src: url('../../public/fonts/Humane-Bold.otf') format('opentype');
@@ -19,22 +20,19 @@
font-weight: lighter;
}
-@font-face {
- font-family: 'Maisy';
- src: url('../../public/fonts/CSMaisy-Regular.otf') format('opentype');
- font-weight: bold;
-}
-@font-face {
- font-family: 'Caleb';
- src: url('../../public/fonts/CSCalebMono-Regular.otf') format('opentype');
- font-weight: bold;
+
+/* Main content */
+
+html {
+ scroll-behavior: initial;
+ overflow: hidden;
}
-html, body {
- height: 100%;
- margin: 0;
- padding: 0;
+html,
+body {
+ width: 100%;
+ min-height: 100%;
}
body {
@@ -45,7 +43,7 @@ body {
cursor: cell;
font-size: 2em;
color: #d8d6ce;
- letter-spacing: 0.05em;
+ letter-spacing: 0.05em;
overflow-x: hidden;
}
@@ -61,9 +59,10 @@ body::before {
z-index: -1;
}
+
/* Navbar */
-.navbar{
+.navbar {
display: flex;
padding: 0px;
background-color: #00000000;
@@ -71,19 +70,43 @@ body::before {
justify-content: center;
}
+.container-fluid {
+ text-align: center;
+ margin-top: 2vh;
+ padding: 10px;
+ background-color: transparent;
+ border-radius: 20px;
+ backdrop-filter: blur(0);
+ transition: background-color 0.5s ease, backdrop-filter 0.5s ease, width 0.5s ease;
+}
+
+.container-fluid.scrolled {
+ width: 40%;
+ background-color: #5b5b5b53;
+ backdrop-filter: blur(10px);
+}
+
.navbar-brand {
+ margin: 10px 0 0 10px;
font-family: 'Humane', sans-serif;
font-size: 1.7em;
+ text-align: center;
font-weight: bolder;
+ line-height: 5px;
color: #d8d6ce;
- transform: scaleY(0.9);
+ transform: scaleY(0.8);
}
.navbar-brand:hover {
color: #d8d6ce;
}
-/* Titles and paragraphs */
+
+/* Titles and text */
+
+.titleContainer {
+ margin-bottom: 80vh;
+}
/* Main title */
@@ -95,7 +118,7 @@ body::before {
text-align: center;
letter-spacing: 0.02em;
line-height: 30vw;
- transform: scaleY(0.8);
+ transform: scaleY(0.8);
}
.mainTitleWhite {
@@ -124,9 +147,26 @@ body::before {
}
+/* About me section */
+.about_me_title {
+ font-family: 'Poppins', sans-serif;
+ font-size: 2vw;
+ font-weight: bolder;
+ color: #d8d6ce;
+ text-align: center;
+ margin-bottom: 20px;
+}
+.about_me_text {
+ font-family: 'Poppins', sans-serif;
+ font-size: 1.3vw;
+ font-weight: normal;
+ color: #d8d6ce;
+ text-align: center;
+ margin-bottom: 20px;
+}
-/* Roll Animation */
+/* Roll Animation */
.roll-hover {
width: 50px;
height: 50px;
@@ -142,7 +182,7 @@ body::before {
left: 0;
transform: translateY(-50%);
transition: top 0.3s;
- pointer-events: auto;
+ pointer-events: auto;
}
.roll-hover-element-two {
@@ -152,7 +192,7 @@ body::before {
left: 0;
transform: translateY(-50%);
transition: top 0.3s;
- pointer-events: none;
+ pointer-events: none;
}
.roll-hover:hover .roll-hover-element-one {
@@ -162,27 +202,311 @@ body::before {
.roll-hover:hover .roll-hover-element-two {
top: 50%;
- pointer-events: auto;
+ pointer-events: auto;
}
+
+/* Mouse Blob Animation */
+
.blob {
position: fixed;
- width: 30px; /* Initial small size */
- height: 30px; /* Initial small size */
+ width: 30px;
+ height: 30px;
background-color: #d8d6ce;
border-radius: 50%;
pointer-events: none;
mix-blend-mode: difference;
transform: translate(-50%, -50%);
z-index: 9999;
- transition: width 0.3s ease, height 0.3s ease, transform 0.3s ease, left 0.1s ease, top 0.1s ease; /* Transition for size and position change */
+ transition: width 0.3s ease, height 0.3s ease, transform 0.3s ease, left 0.1s ease, top 0.1s ease;
}
.blob.transition {
- transition: width 0.3s ease, height 0.3s ease, transform 0.3s ease, left 0.3s ease, top 0.3s ease; /* Transition for size and position change */
+ transition: width 0.3s ease, height 0.3s ease, transform 0.3s ease, left 0.3s ease, top 0.3s ease;
}
.blob.large {
- width: 100px; /* Larger size on hover */
- height: 100px; /* Larger size on hover */
+ width: 100px;
+ height: 100px;
+}
+
+
+/* Waves Animation */
+
+@keyframes wave {
+ 0% {
+ opacity: 1;
+ transform: translateY(100%);
+ }
+
+ 40% {
+ transform: translateY(0);
+ }
+
+ 60% {
+ transform: translateY(0);
+ }
+
+ 100% {
+ opacity: 1;
+ transform: translateY(-100%);
+ }
}
+
+.wave {
+ position: fixed;
+ width: 100%;
+ height: 100%;
+ bottom: 0;
+ left: 0;
+ pointer-events: none;
+ opacity: 0;
+ z-index: 10000;
+ animation: wave .7s ease-in-out;
+}
+
+.wave1 {
+ background-color: #ffe76f;
+ animation-delay: 0s;
+}
+
+.wave2 {
+ background-color: #fc5f5f;
+ animation-delay: 0.05s;
+}
+
+.wave3 {
+ background-color: #4f4fa0;
+ animation-delay: 0.1s;
+}
+
+
+/* Fade-in animation */
+
+@keyframes fadeInUp {
+ 0% {
+ opacity: 0;
+ transform: translateY(20px);
+ }
+
+ 50% {
+ opacity: 0;
+ transform: translateY(20px);
+ }
+
+ 100% {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
+
+.fade-in {
+ opacity: 0;
+}
+
+
+.fade-in-up {
+ animation: fadeInUp 1.2s ease-in-out;
+}
+
+.scroll-fade-in {
+ opacity: 0;
+ transition: all .7s;
+ transform: translate(0, 150px);
+ will-change: opacity, transform;
+}
+
+.scroll-fade-in.visible {
+ opacity: 1;
+ transform: translate(0, 0);
+}
+
+
+/* Horizontal Scrolling Line */
+
+@keyframes scroll {
+ 0% {
+ transform: translateX(0);
+ }
+
+ 100% {
+ transform: translateX(-50%);
+ }
+}
+
+.scrolling-text {
+ font-family: 'Humane', sans-serif;
+ white-space: nowrap;
+ overflow: hidden;
+ position: relative;
+ margin-top: 10vh;
+ width: 100%;
+ color: #d8d6ce;
+ font-size: 6em;
+ font-weight: bold;
+ will-change: transform;
+}
+
+.scrolling-text span {
+ display: inline-block;
+ padding-right: 100%;
+ animation: scroll 100s linear infinite;
+}
+
+.scrolling-text .text-group {
+ display: inline-block;
+}
+
+/* TEST */
+
+
+.lenis_container {
+ width: 100%;
+}
+
+section {
+ padding: 50px 0;
+}
+
+.col {
+ width: 50%;
+}
+
+#vertical {
+ height: 100vh;
+ width: 100vw;
+}
+
+.vertical__content {
+ display: flex;
+ justify-content: center;
+ align-items: flex-start;
+ width: 100%;
+}
+
+.vertical__content .col_left {
+ height: 100%;
+}
+
+.vertical__content .col.col_right {
+ width: 40%;
+ padding: 20px;
+ margin-right: 2vw;
+ background-color: #1e1e1e47;
+ backdrop-filter: blur(2px);
+ border-radius: 20px;
+}
+
+
+
+.vertical__item:not(:last-child) {
+ margin-bottom: 90px;
+}
+
+
+/* Card elements */
+
+.cardTitle {
+ font-family: 'Humane', sans-serif;
+ font-size: 2em;
+ font-weight: bolder;
+ color: #d8d6ce;
+ text-align: center;
+ margin-bottom: 20px;
+}
+
+.cardDescription {
+ font-family: 'Poppins', sans-serif;
+ font-size: 0.5em;
+ font-weight: normal;
+ color: #d8d6ce;
+ text-align: center;
+ margin-bottom: 20px;
+}
+
+.cardLanguage {
+ font-family: 'Humane', sans-serif;
+ font-size: 1.5em;
+ font-weight: bolder;
+ color: #d8d6ce;
+ text-align: center;
+ margin-bottom: 20px;
+}
+
+.background_diagram {
+ position: absolute;
+ width: 80vw;
+ height: auto;
+ z-index: -1;
+ will-change: transform, opacity;
+}
+
+.background_diagram_1 {
+ right: 0;
+ top: 0;
+ z-index: -1;
+}
+
+.background_diagram_2 {
+ width: 70vw;
+ left: 0;
+ top: 200vh;
+}
+
+.background_diagram_3 {
+ width: 50vw;
+ right: 0;
+ top: 400vh;
+}
+
+
+.background_diagram_4 {
+ width: 40vw;
+ left: 0;
+ top: 430vh;
+}
+
+.background_diagram_5 {
+ width: 60vw;
+ right: 0;
+ top: 500vh;
+}
+
+.footer {
+ padding-top: 20vh;
+ padding-bottom: 5vh;
+ display: flex;
+ flex-direction: column;
+ text-align: center;
+ align-items: center;
+ justify-content: center;
+ width: 100%;
+}
+
+.footer_socials_container {
+ display: flex;
+ flex-direction: row;
+ justify-content: center;
+ align-items: center;
+ will-change: transform, opacity;
+}
+
+.footer_text_container {
+ margin-left: 20%;
+ display: flex;
+ flex-direction: row;
+}
+
+.footer_text {
+ font-family: 'Mrs Saint Delafield', sans-serif;
+ color: #866aff;
+ font-size: 8vw;
+ font-weight: bolder;
+ text-align: center;
+ z-index: 10;
+ transform: translate(-50%, -50%) rotate(-10deg);
+}
+
+.placeholder {
+ margin-top: 200vh;
+}
\ No newline at end of file
diff --git a/src/style/style_project_cards.css b/src/style/style_project_cards.css
new file mode 100644
index 0000000..fd36f40
--- /dev/null
+++ b/src/style/style_project_cards.css
@@ -0,0 +1,229 @@
+main {
+ display: grid;
+ grid-template-columns: 1fr repeat(12, minmax(auto, 60px)) 1fr;
+ grid-gap: 40px;
+ padding: 60px 0;
+}
+
+.cards {
+ grid-column: 2 / span 12;
+ display: grid;
+ grid-template-columns: repeat(12, minmax(auto, 60px));
+ gap: 40px;
+}
+
+
+.card_stack {
+ grid-column-end: span 4;
+ display: flex;
+ flex-direction: column;
+ transition: all 0.3s ease 0s;
+}
+
+.card_stack::before {
+ content: "";
+ position: absolute;
+ top: 20px;
+ left: 20px;
+ width: 100%;
+ height: 100%;
+ background-size: cover;
+ border-radius: 20px;
+ z-index: -1;
+}
+
+.card_stack1::before {
+ background-image: url("../../public/media/card_thermals/thermal_1_compressed.jpg");
+}
+
+.card_stack4::before {
+ background-image: url("../../public/media/card_thermals/thermal_4_compressed.jpg");
+}
+
+.card_stack6::before {
+ background-image: url("../../public/media/card_thermals/thermal_6_compressed.jpg");
+}
+
+.card_stack9::before {
+ background-image: url("../../public/media/card_thermals/thermal_9_compressed.jpg");
+}
+
+.card_stack10::before {
+ background-image: url("../../public/media/card_thermals/thermal_10_compressed.jpg");
+}
+
+.card_stack8::before {
+ background-image: url("../../public/media/card_thermals/thermal_8_compressed.jpg");
+}
+
+.card {
+ display: flex;
+ height: 100%;
+ border-radius: 20px;
+ overflow: hidden;
+ flex-direction: column;
+ background-color: #1d1d1d8f;
+ backdrop-filter: blur(5px);
+ transition: all 0.3s ease 0s;
+}
+
+.card:hover {
+ transform: translateY(-7px);
+}
+
+.card__image-container {
+ width: 100%;
+ padding-top: 56.25%;
+ overflow: hidden;
+ position: relative;
+ }
+
+ .card__image-container img {
+ width: 100%;
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ }
+
+.card_content {
+ padding: 20px;
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+ align-items: space-between;
+}
+
+.card_title {
+ font-family: "Humane", sans-serif;
+ line-height: 0.8em;
+ transform: scaleY(0.7);
+ font-weight: 900;
+ width: max-content;
+ font-size: 3em;
+ font-weight: 400;
+ color: #ecf0f1;
+}
+
+.card_description {
+ font-family: "Poppins", sans-serif;
+ font-size: 0.5em;
+ margin: 0;
+ font-weight: 400;
+ color: #ecf0f1;
+}
+
+.card_info {
+ display: flex;
+ margin-top: 20px;
+ align-items: center;
+ justify-content: space-between;
+}
+
+
+/* Card status */
+
+/* Status Text */
+
+.card_status {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 10px;
+ text-align: center;
+ flex-direction: row;
+ padding: 5px 20px;
+ background-color: #25252573;
+ border-radius: 15px;
+}
+
+.card_status_text {
+ font-family: "Poppins", sans-serif;
+ font-size: 0.35em;
+ font-weight: 400;
+ margin: 0;
+ color: #ecf0f1;
+}
+
+.card_status_text_done {
+ color: #039700;
+ text-shadow: 0 0 10px #039700;
+}
+
+.card_status_text_in_progress {
+ color: #fe7f30;
+ text-shadow: 0 0 10px #fe7f30;
+}
+
+
+/* Status Dot */
+
+.dot {
+ height: 10px;
+ width: 10px;
+ border-radius: 50%;
+ display: inline-block;
+}
+
+.dot_done {
+ background-color: #039700;
+ box-shadow: 0 0 10px #039700;
+}
+
+.dot_in_progress {
+ background-color: #fe7f30;
+ box-shadow: 0 0 10px #fe7f30;
+}
+
+
+/* Language Text */
+
+.card_language {
+ text-align: center;
+ padding: 5px 7px;
+ background-color: #25252573;
+ border-radius: 15px;
+ font-family: "Poppins", sans-serif;
+ font-size: 0.4em;
+ font-weight: 800;
+ margin: 0;
+ color: #866aff;
+}
+
+
+/* Grid media queries */
+
+@media only screen and (max-width: 1000px) {
+ .card_stack {
+ grid-column-end: span 6;
+ }
+}
+
+@media only screen and (max-width: 700px) {
+ main {
+ grid-gap: 20px;
+ }
+
+ .card_stack {
+ grid-column-end: span 12;
+ }
+}
+
+@media only screen and (max-width: 500px) {
+ main {
+ grid-template-columns: 10px repeat(6, 1fr) 10px;
+ grid-gap: 10px;
+ }
+
+ .cards {
+ grid-column: 2 / span 6;
+ grid-template-columns: repeat(6, 1fr);
+ grid-gap: 20px;
+ }
+
+ .card_stack {
+ grid-column-end: span 6;
+ margin: 20px;
+ }
+}
\ No newline at end of file