diff --git a/CNAME b/CNAME
new file mode 100644
index 0000000..315edf2
--- /dev/null
+++ b/CNAME
@@ -0,0 +1 @@
+ch3nyang.top
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..faa0013
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2024 Ch3nyang
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..81f3630
--- /dev/null
+++ b/README.md
@@ -0,0 +1,3 @@
+# portfolio
+
+This is a portfolio of myself.
diff --git a/assets/noun-ball.svg b/assets/noun-ball.svg
new file mode 100644
index 0000000..7c78d6a
--- /dev/null
+++ b/assets/noun-ball.svg
@@ -0,0 +1 @@
+Created by Malu Gunther from the Noun Project
\ No newline at end of file
diff --git a/assets/noun-circle.svg b/assets/noun-circle.svg
new file mode 100644
index 0000000..93a454f
--- /dev/null
+++ b/assets/noun-circle.svg
@@ -0,0 +1 @@
+Created by Malu Gunther from the Noun Project
\ No newline at end of file
diff --git a/assets/noun-lines.svg b/assets/noun-lines.svg
new file mode 100644
index 0000000..2aa55a9
--- /dev/null
+++ b/assets/noun-lines.svg
@@ -0,0 +1 @@
+Created by Malu Gunther from the Noun Project
\ No newline at end of file
diff --git a/assets/noun-mess.svg b/assets/noun-mess.svg
new file mode 100644
index 0000000..f8b56ea
--- /dev/null
+++ b/assets/noun-mess.svg
@@ -0,0 +1 @@
+Created by Malu Gunther from the Noun Project
\ No newline at end of file
diff --git a/assets/noun-waves.svg b/assets/noun-waves.svg
new file mode 100644
index 0000000..c3b8d47
--- /dev/null
+++ b/assets/noun-waves.svg
@@ -0,0 +1 @@
+Created by Malu Gunther from the Noun Project
\ No newline at end of file
diff --git a/icons/asterisk.svg b/icons/asterisk.svg
new file mode 100644
index 0000000..87d7f73
--- /dev/null
+++ b/icons/asterisk.svg
@@ -0,0 +1,18 @@
+
+
+
diff --git a/icons/bubbles.svg b/icons/bubbles.svg
new file mode 100644
index 0000000..86b7dc1
--- /dev/null
+++ b/icons/bubbles.svg
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/icons/email.svg b/icons/email.svg
new file mode 100644
index 0000000..0e06893
--- /dev/null
+++ b/icons/email.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/icons/github.svg b/icons/github.svg
new file mode 100644
index 0000000..f376c3e
--- /dev/null
+++ b/icons/github.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/icons/hurricane.svg b/icons/hurricane.svg
new file mode 100644
index 0000000..9b87b3c
--- /dev/null
+++ b/icons/hurricane.svg
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/icons/smile.svg b/icons/smile.svg
new file mode 100644
index 0000000..24ebacf
--- /dev/null
+++ b/icons/smile.svg
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/icons/twitter.svg b/icons/twitter.svg
new file mode 100644
index 0000000..8887700
--- /dev/null
+++ b/icons/twitter.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/img/apple-touch-icon.png b/img/apple-touch-icon.png
new file mode 100644
index 0000000..e637828
Binary files /dev/null and b/img/apple-touch-icon.png differ
diff --git a/img/favicon.svg b/img/favicon.svg
new file mode 100644
index 0000000..8ce83ba
--- /dev/null
+++ b/img/favicon.svg
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/img/ogimage.png b/img/ogimage.png
new file mode 100644
index 0000000..18d786e
Binary files /dev/null and b/img/ogimage.png differ
diff --git a/img/twittercard.png b/img/twittercard.png
new file mode 100644
index 0000000..5457fa0
Binary files /dev/null and b/img/twittercard.png differ
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..f2e2695
--- /dev/null
+++ b/index.html
@@ -0,0 +1,102 @@
+
+
+
+
+
+
+
+ Homepage of Ch3nyang
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
yang
+
+
+
+
+
+
+
+
+
+
+
+
Hi there!
+
I'm Ch3nyang, a fullstack developer hailing from Southeast University, China, currently pursuing a Master's degree in Cybersecurity. I have a passion for programming, enjoy writing, and love to share.
+
Hope you enjoy yourself here!
+
+
+
+
skill
+
+ link
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/js/link.js b/js/link.js
new file mode 100644
index 0000000..7b098d9
--- /dev/null
+++ b/js/link.js
@@ -0,0 +1,27 @@
+var blog = document.querySelector('.cluster1 .link-title');
+var originalContent1 = blog.textContent;
+var originalFontSize1 = blog.style.fontSize;
+blog.addEventListener('mouseover', function() {
+ blog.textContent = 'blog.ch3nyang.top';
+ blog.style.fontSize = '1.5em';
+ blog.style.textDecoration = 'underline';
+});
+blog.addEventListener('mouseout', function() {
+ blog.textContent = originalContent1;
+ blog.style.fontSize = originalFontSize1;
+ blog.style.textDecoration = 'none';
+});
+
+var mind = document.querySelector('.cluster2 .link-title');
+var originalContent2 = mind.textContent;
+var originalFontSize2 = mind.style.fontSize;
+mind.addEventListener('mouseover', function() {
+ mind.textContent = 'mind.ch3nyang.top';
+ mind.style.fontSize = '1.5em';
+ mind.style.textDecoration = 'underline';
+});
+mind.addEventListener('mouseout', function() {
+ mind.textContent = originalContent2;
+ mind.style.fontSize = originalFontSize2;
+ mind.style.textDecoration = 'none';
+});
\ No newline at end of file
diff --git a/js/skill.js b/js/skill.js
new file mode 100644
index 0000000..183e5cf
--- /dev/null
+++ b/js/skill.js
@@ -0,0 +1,51 @@
+const skills = [
+ {
+ category: 'Frontend',
+ items: ['html5', 'css3', 'javascript', 'jquery', 'react', 'vuejs', 'sass', 'tailwindcss', 'typescript', 'webpack', 'vitejs'
+ ]
+ },
+ {
+ category: 'Backend',
+ items: ['c', 'cplusplus', 'python', 'rust', 'go', 'mysql', 'sqlite', 'cmake', 'elasticsearch', 'flask', 'pytorch'
+ ]
+ },
+ {
+ category: 'Fullstack',
+ items: ['nodejs', 'qt', 'electron', 'tauri', 'cloudflareworkers', 'jekyll'
+ ]
+ },
+ {
+ category: 'Tools',
+ items: ['linux', 'windows8', 'powershell', 'git', 'github', 'githubactions', 'vim', 'vscode', 'docker', 'cloudflare', 'jupyter', 'postman'
+ ]
+ }
+]
+
+const paint_white = ['rust', 'flask', 'github']
+
+const skill = document.querySelector('.skill')
+
+skills.forEach(({ category, items }, index) => {
+ const title = document.createElement('div')
+ title.classList.add('skill-title')
+ title.textContent = category
+ skill.appendChild(title)
+
+ const ul = document.createElement('ul')
+ items.forEach(item => {
+ const li = document.createElement('li')
+ const img = document.createElement('img')
+ img.src = `https://cdn.jsdelivr.net/gh/devicons/devicon@latest/icons/${item}/${item}-original.svg`
+ img.alt = item
+ if (paint_white.includes(item)) {
+ img.classList.add('white-img')
+ }
+ li.appendChild(img)
+ ul.appendChild(li)
+ })
+ skill.appendChild(ul)
+
+ if (index !== skills.length - 1) {
+ skill.appendChild(document.createElement('hr'))
+ }
+})
\ No newline at end of file
diff --git a/styles/footer.css b/styles/footer.css
new file mode 100644
index 0000000..ff8883d
--- /dev/null
+++ b/styles/footer.css
@@ -0,0 +1,56 @@
+.footer {
+ margin-top: 4rem;
+ background-color: var(--secondary-color);
+ color: var(--black-color);
+ padding: 4rem 0 2rem 0;
+ text-align: center;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ gap: 2rem;
+}
+
+.job {
+ font-size: 2rem;
+ font-weight: 900;
+ font-family: var(--primary-font);
+ text-transform: uppercase;
+ margin: 0 1rem;
+}
+
+.footer ul {
+ display: flex;
+ justify-content: center;
+ gap: 2rem;
+ list-style-type: none;
+ padding: 0;
+ margin: 0;
+}
+
+.footer ul li {
+ font-size: 1.5rem;
+ transition: transform 0.25s ease-in-out;
+}
+
+.footer ul li:hover {
+ transform: translateY(-0.25rem);
+}
+
+.footer ul li a {
+ text-decoration: none;
+ color: var(--black-color);
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+}
+
+.footer ul li a img {
+ height: 4rem;
+ width: 4rem;
+}
+
+.footer-text {
+ margin-top: 2rem;
+}
\ No newline at end of file
diff --git a/styles/home.css b/styles/home.css
new file mode 100644
index 0000000..a2bf35f
--- /dev/null
+++ b/styles/home.css
@@ -0,0 +1,169 @@
+.home {
+ width: 96vw;
+ height: 96vh;
+ display: flex;
+ margin: 1rem auto calc(96vh - 8rem) auto;
+ font-family: var(--primary-font);
+}
+
+.left {
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: flex-start;
+}
+
+.right {
+ height: 100%;
+ width: 100%;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+}
+
+.left-square {
+ width: 100%;
+ height: 100%;
+ padding-right: 0.5rem;
+}
+
+.square-content {
+ width: calc(100% - 0.5rem);
+ height: calc(100% - 0.5rem);
+ border: 2rem solid var(--primary-color);
+ box-sizing: border-box;
+ background-color: var(--white-color);
+}
+
+.subtitle {
+ text-transform: capitalize;
+ letter-spacing: 0.25rem;
+ font-size: 2rem;
+ color: var(--primary-color);
+}
+
+.left-title {
+ text-transform: uppercase;
+ font-size: 8rem;
+ font-weight: 900;
+ color: var(--primary-color);
+ line-height: 8rem;
+ transition: text-shadow 0.25s ease-in-out;
+}
+
+.left-title:hover {
+ text-shadow: 0 0 0.25rem var(--blue-shadow-color);
+}
+
+.right-square {
+ width: 100%;
+ height: 100%;
+ background-color: var(--primary-color);
+ border: 0.25rem solid var(--primary-color);
+ box-sizing: border-box;
+ position: relative;
+}
+
+.right-title {
+ text-transform: uppercase;
+ font-size: 8rem;
+ font-weight: 900;
+ color: var(--white-color);
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ line-height: 1;
+ transform: translateY(0.25rem);
+ transition: text-shadow 0.25s ease-in-out;
+}
+
+.right-title:hover {
+ text-shadow: 0 0 0.25rem var(--white-color);
+}
+
+.star {
+ position: absolute;
+ right: 2rem;
+ top: 2rem;
+}
+
+.star img {
+ width: 16rem;
+ height: 16rem;
+ filter: invert(1) grayscale(1) hue-rotate(0deg);
+}
+
+@keyframes home-scroll {
+ 0% {
+ transform: translateY(0);
+ height: 96vh;
+ }
+
+ 100% {
+ transform: translateY(calc(96vh - 18.75rem));
+ height: 18.75rem;
+ }
+}
+
+.home {
+ animation: home-scroll linear forwards;
+ animation-timeline: scroll();
+ animation-range: 0 calc(96vh - 18.75rem);
+}
+
+@keyframes star-hover {
+ 0% {
+ transform: rotate(0deg);
+ }
+
+ 100% {
+ transform: rotate(360deg);
+ }
+}
+
+.star img:hover {
+ animation: star-hover 1s linear infinite;
+}
+
+@keyframes star-scroll {
+ 0% {
+ transform: rotate(0deg);
+ }
+
+ 100% {
+ transform: rotate(360deg);
+ width: 14.25rem;
+ height: 14.25rem;
+ }
+}
+
+.star img {
+ animation: star-scroll linear forwards;
+ animation-timeline: scroll();
+ animation-range: 0 calc(96vh - 18.75rem);
+}
+
+@media screen and (max-width: 768px) {
+ .left-square,
+ .star {
+ display: none;
+ }
+
+ .home {
+ flex-direction: column;
+ }
+
+ .left {
+ justify-content: end;
+ }
+
+ .right {
+ height: auto;
+ }
+
+ .right-title {
+ position: static;
+ }
+}
\ No newline at end of file
diff --git a/styles/index.css b/styles/index.css
new file mode 100644
index 0000000..5c469c7
--- /dev/null
+++ b/styles/index.css
@@ -0,0 +1,115 @@
+@import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@400..900&family=Lora:ital,wght@0,400..700;1,400..700&display=swap');
+
+@import url('./home.css');
+@import url('./info.css');
+@import url('./skill.css');
+@import url('./link.css');
+@import url('./footer.css');
+
+:root {
+ --primary-color: hsl(225, 100%, 50%);
+ --secondary-color: hsl(200, 100%, 90%);
+ --black-color: hsl(0, 0%, 0%);
+ --white-color: hsl(0, 0%, 100%);
+ --black-shadow-primary-color: hsla(0, 0%, 0%, 0.4);
+ --black-shadow-secondary-color: hsla(0, 0%, 0%, 0.2);
+ --blue-shadow-color: hsl(225, 100%, 70%);
+ --primary-font: "Orbitron", sans-serif;
+ --secondary-font: "Lora", serif;
+
+ font-size: 16px;
+ font-family: var(--secondary-font);
+}
+
+@media screen and (max-width: 1024px) {
+ :root {
+ font-size: 12px;
+ }
+}
+
+@media screen and (max-width: 768px) {
+ :root {
+ font-size: 12px;
+ }
+}
+
+@media screen and (max-width: 425px) {
+ :root {
+ font-size: 10px;
+ }
+}
+
+@media screen and (min-width: 2560px) {
+ :root {
+ font-size: 20px;
+ }
+}
+
+body {
+ margin: 0;
+ background-color: var(--white-color);
+}
+
+h2 {
+ position: relative;
+ width: -moz-fit-content;
+ width: fit-content;
+ font-size: 2rem;
+ font-weight: 900;
+ line-height: 2.5rem;
+ letter-spacing: 0.5rem;
+ font-family: var(--primary-font);
+ text-transform: uppercase;
+ margin: 4rem auto 1rem auto;
+}
+
+h2::before,
+h2::after {
+ content: "";
+ display: block;
+ height: 2rem;
+ width: 2rem;
+ background-color: var(--primary-color);
+ transition: background-color 0.25s ease-in-out;
+}
+
+h2::before {
+ position: absolute;
+ top: 0.25rem;
+ left: -3rem;
+}
+
+h2::after {
+ position: absolute;
+ top: 0.25rem;
+ right: -2.5rem;
+}
+
+h2:hover::before,
+h2:hover::after {
+ background-color: var(--black-color);
+}
+
+@keyframes body-color {
+ 0% {
+ background-color: var(--white-color);
+ }
+
+ 50% {
+ background-color: var(--secondary-color);
+ }
+
+ 750% {
+ background-color: var(--secondary-color);
+ }
+
+ 100% {
+ background-color: var(--white-color);
+ }
+}
+
+body {
+ animation: body-color linear forwards;
+ animation-timeline: scroll();
+ animation-range: 50vh 250vh;
+}
\ No newline at end of file
diff --git a/styles/info.css b/styles/info.css
new file mode 100644
index 0000000..4fc14fc
--- /dev/null
+++ b/styles/info.css
@@ -0,0 +1,112 @@
+.info {
+ width: 96vw;
+ height: 48vh;
+ display: flex;
+ align-items: center;
+ justify-content: end;
+ margin: 0 auto 0 auto;
+}
+
+.smile img {
+ width: 16rem;
+ height: 16rem;
+}
+
+.info-content {
+ margin-left: 8rem;
+ width: 45rem;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: flex-start;
+ gap: 1rem;
+}
+
+.info-title {
+ text-transform: uppercase;
+ font-size: 4rem;
+ font-weight: 900;
+ font-family: var(--primary-font);
+}
+
+.info-text {
+ letter-spacing: 0.05rem;
+ font-size: 1.5rem;
+ line-height: 2.25rem;
+ -webkit-hyphens: auto;
+ hyphens: auto;
+}
+
+.info-text u {
+ transition: color 0.25s ease-out;
+}
+
+.info-text u:hover {
+ background-color: var(--primary-color);
+ text-decoration: none;
+ color: var(--white-color);
+}
+
+@keyframes smile-scroll {
+ 0% {
+ transform: translateX(-100vw) rotate(-60deg) scale(0.5);
+ }
+
+ 80% {
+ transform: translateX(0) rotate(0deg) scale(1);
+ }
+
+ 90% {
+ transform: translateX(5vw) rotate(30deg) scale(1.05);
+ }
+
+ 100% {
+ transform: translateX(0) rotate(0deg) scale(1);
+ }
+}
+
+.smile img {
+ view-timeline: scroll() block;
+ animation-timeline: view();
+ animation-name: smile-scroll;
+ animation-range: entry 0% contain 50%;
+ animation-fill-mode: forwards;
+}
+
+@keyframes info-title-scroll {
+ 0% {
+ color: var(--black-color);
+ }
+
+ 100% {
+ color: var(--primary-color);
+ }
+}
+
+.info-title {
+ view-timeline: scroll() block;
+ animation-timeline: view();
+ animation-name: info-title-scroll;
+ animation-range: entry 100% contain 75%;
+ animation-fill-mode: forwards;
+}
+
+@media screen and (max-width: 768px) {
+ .smile {
+ display: none;
+ }
+
+ .info {
+ justify-content: center;
+ }
+
+ .info-content {
+ margin-left: 0;
+ }
+}
+
+@media screen and (min-width: 1440px) {
+ .info {
+ justify-content: center;
+ }
+}
\ No newline at end of file
diff --git a/styles/link.css b/styles/link.css
new file mode 100644
index 0000000..6441601
--- /dev/null
+++ b/styles/link.css
@@ -0,0 +1,81 @@
+.link {
+ display: flex;
+ justify-content: center;
+ align-items: stretch;
+ gap: 1rem;
+ margin: 3rem 2rem 0 2rem;
+}
+
+.link-cluster {
+ text-decoration: none;
+ color: var(--primary-color);
+ display: grid;
+ grid-template-columns: auto auto;
+ grid-template-rows: auto 1fr;
+ gap: 1rem 2rem;
+ border: 0.25rem solid var(--primary-color);
+ max-width: 31.25rem;
+ padding: 2rem;
+ transition: transform 0.25s ease-in-out;
+}
+
+.link-cluster:hover {
+ transform: translateY(-0.25rem);
+}
+
+.link .cluster1 {
+ background-color: var(--primary-color);
+ color: var(--white-color);
+}
+
+.link-cluster .img {
+ grid-row: 1 / 3;
+ height: 100%;
+}
+
+.link-cluster .img:hover img {
+ transform: translateY(8rem) rotate(30deg);
+}
+
+.link-cluster .img img {
+ height: 8rem;
+ width: 8rem;
+ transition: transform 0.25s ease-in-out;
+}
+
+.cluster1 .img img {
+ filter: invert(1);
+}
+
+.link-cluster .link-title {
+ font-size: 3rem;
+ font-weight: 900;
+ font-family: var(--primary-font);
+ line-height: 4rem;
+ text-transform: uppercase;
+}
+
+.link-cluster .link-text {
+ font-size: 1.5rem;
+ line-height: 2.25rem;
+ letter-spacing: 0.05rem;
+ -webkit-hyphens: auto;
+ hyphens: auto;
+}
+
+@media screen and (max-width: 768px) {
+ .link {
+ flex-direction: column;
+ align-items: center;
+ }
+}
+
+@media screen and (max-width: 425px) {
+ .img {
+ display: none;
+ }
+
+ .link-cluster {
+ grid-template-columns: auto;
+ }
+}
\ No newline at end of file
diff --git a/styles/skill.css b/styles/skill.css
new file mode 100644
index 0000000..1f03f83
--- /dev/null
+++ b/styles/skill.css
@@ -0,0 +1,120 @@
+.white-img {
+ filter: invert(1);
+}
+
+.skill {
+ width: 100%;
+ background-color: var(--black-color);
+ color: var(--white-color);
+ display: grid;
+ grid-template-columns: auto auto;
+ justify-content: center;
+ align-items: start;
+ gap: 3rem;
+ padding: 8rem 0;
+ box-shadow: 0 -1rem 1rem var(--black-shadow-secondary-color), 0 -0.25rem 0.25rem var(--black-shadow-primary-color);
+}
+
+.skill h2 {
+ grid-column: 1 / 3;
+}
+
+.skill h2:hover::before,
+.skill h2:hover::after {
+ background-color: var(--white-color);
+}
+
+.skill-title {
+ text-transform: uppercase;
+ text-align: end;
+ font-size: 3rem;
+ font-weight: 100;
+ font-family: var(--primary-font);
+ height: 100%;
+}
+
+.skill ul {
+ list-style-type: none;
+ display: grid;
+ grid-template-columns: repeat(6, 4rem);
+ gap: 1rem;
+ margin: 0;
+ padding: 0;
+}
+
+
+.skill li {
+ display: grid;
+}
+
+.skill li img {
+ width: 4rem;
+ height: 4rem;
+ transition: transform 0.25s ease-in-out;
+}
+
+.skill li img:hover {
+ transform: scale(0.9) rotate(10deg);
+}
+
+.skill hr {
+ grid-column: 1 / 3;
+ width: 100%;
+ border: 0.0625rem solid var(--primary-color);
+}
+
+@keyframes skill-scroll {
+ from {
+ transform: translateY(50vh);
+ }
+
+ to {
+ transform: translateY(0);
+ }
+}
+
+.skill {
+ transform: translateY(50vh);
+ view-timeline: scroll() block;
+ animation-timeline: view();
+ animation-name: skill-scroll;
+ animation-range: entry 40% entry 90%;
+ animation-fill-mode: forwards;
+}
+
+@keyframes skill-element-scroll {
+ from {
+ opacity: 0;
+ }
+
+ to {
+ opacity: 1;
+ }
+}
+
+.skill-title,
+.skill ul,
+.skill hr {
+ opacity: 0;
+ view-timeline: scroll() block;
+ animation-timeline: view();
+ animation-name: skill-element-scroll;
+ animation-range: entry 50% contain 50%;
+ animation-fill-mode: forwards;
+}
+
+@media screen and (max-width: 768px) {
+ .skill {
+ grid-template-columns: auto;
+ align-items: center;
+ }
+
+ .skill h2,
+ .skill hr {
+ grid-column: 1 / 2;
+ }
+
+ .skill-title {
+ text-align: center;
+ }
+}
\ No newline at end of file