initial commit

This commit is contained in:
2026-04-14 16:20:22 +03:00
commit 724f16b589
39 changed files with 1179 additions and 0 deletions
+3
View File
@@ -0,0 +1,3 @@
.idea/
.vscode/
.codex
+23
View File
@@ -0,0 +1,23 @@
[
{
"key": "git",
"name": "Git",
"label": "git.scuroneko.dev",
"url": "https://git.scuroneko.dev/ScuroNeko",
"tone": "red"
},
{
"key": "gh",
"name": "GitHub",
"label": "github.com/ScuroNeko",
"url": "https://github.com/ScuroNeko",
"tone": "purple"
},
{
"key": "tg",
"name": "Telegram",
"label": "@scuroneko",
"url": "https://t.me/scuroneko",
"tone": "blue"
}
]
+21
View File
@@ -0,0 +1,21 @@
[
{
"description": "A personal page for projects, stack notes, and developer work.",
"key": "web",
"name": "ScuroNeko.dev",
"stack": ["html", "css", "js"],
"status": "active",
"tone": "purple"
},
{
"description": "A personal page for projects, stack notes, and developer work.",
"key": "lib",
"links": {
"sources": "https://git.scuroneko.dev/ScuroNeko/Laniakea"
},
"name": "Laniakea",
"stack": ["go", "tg"],
"status": "active",
"tone": "purple"
}
]
+69
View File
@@ -0,0 +1,69 @@
[
{
"key": "go",
"name": "Go",
"tone": "blue",
"years": 7
},
{
"key": "py",
"name": "Python",
"tone": "gold",
"years": 8
},
{
"key": "ts",
"name": "TypeScript",
"tone": "purple",
"years": 5
},
{
"key": "re",
"name": "React",
"tags": ["lib", "js"],
"tone": "blue",
"years": 7
},
{
"key": "mdb",
"name": "MongoDB",
"tags": ["db"],
"tone": "red",
"years": 2
},
{
"key": "psql",
"name": "PostgreSQL",
"tags": ["db"],
"tone": "blue",
"years": 7
},
{
"key": "tg",
"name": "Telegram API",
"tags": ["api"],
"tone": "blue",
"years": 2
},
{
"hide": true,
"key": "html",
"name": "HTML",
"tone": "red",
"years": 7
},
{
"hide": true,
"key": "css",
"name": "CSS",
"tone": "cyan",
"years": 7
},
{
"hide": true,
"key": "js",
"name": "JavaScript",
"tone": "cyan",
"years": 7
}
]
+13
View File
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>403 Forbidden...</title>
<link rel="stylesheet" href="./errors.css" />
</head>
<body>
<img src="./img/403.png" alt="" />
</body>
</html>
+13
View File
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>404 Not found...</title>
<link rel="stylesheet" href="./errors.css" />
</head>
<body>
<img src="./img/404.png" alt="" />
</body>
</html>
+13
View File
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>500 Internal Server Error...</title>
<link rel="stylesheet" href="./errors.css" />
</head>
<body>
<img src="../img/500.png" alt="" />
</body>
</html>
+13
View File
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>502 Bad gateway...</title>
<link rel="stylesheet" href="./errors.css" />
</head>
<body>
<img src="../img/502.png" alt="" />
</body>
</html>
+13
View File
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>503 Service unavailable...</title>
<link rel="stylesheet" href="./errors.css" />
</head>
<body>
<img src="../img/503.png" alt="" />
</body>
</html>
+13
View File
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>504 Gateway timeout...</title>
<link rel="stylesheet" href="./errors.css" />
</head>
<body>
<img src="../img/504.png" alt="" />
</body>
</html>
+24
View File
@@ -0,0 +1,24 @@
@keyframes fade {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
html,
body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
}
body {
background-color: #1f1f28;
display: flex;
}
img {
animation: fade 500ms ease-in-out;
margin: auto;
width: 100%;
}
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

+1
View File
@@ -0,0 +1 @@
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>CSS</title><path d="M0 0v20.16A3.84 3.84 0 0 0 3.84 24h16.32A3.84 3.84 0 0 0 24 20.16V3.84A3.84 3.84 0 0 0 20.16 0Zm14.256 13.08c1.56 0 2.28 1.08 2.304 2.64h-1.608c.024-.288-.048-.6-.144-.84-.096-.192-.288-.264-.552-.264-.456 0-.696.264-.696.84-.024.576.288.888.768 1.08.72.288 1.608.744 1.92 1.296q.432.648.432 1.656c0 1.608-.912 2.592-2.496 2.592-1.656 0-2.4-1.032-2.424-2.688h1.68c0 .792.264 1.176.792 1.176.264 0 .456-.072.552-.24.192-.312.24-1.176-.048-1.512-.312-.408-.912-.6-1.32-.816q-.828-.396-1.224-.936c-.24-.36-.36-.888-.36-1.536 0-1.44.936-2.472 2.424-2.448m5.4 0c1.584 0 2.304 1.08 2.328 2.64h-1.608c0-.288-.048-.6-.168-.84-.096-.192-.264-.264-.528-.264-.48 0-.72.264-.72.84s.288.888.792 1.08c.696.288 1.608.744 1.92 1.296.264.432.408.984.408 1.656.024 1.608-.888 2.592-2.472 2.592-1.68 0-2.424-1.056-2.448-2.688h1.68c0 .744.264 1.176.792 1.176.264 0 .456-.072.552-.24.216-.312.264-1.176-.048-1.512-.288-.408-.888-.6-1.32-.816-.552-.264-.96-.576-1.2-.936s-.36-.888-.36-1.536c-.024-1.44.912-2.472 2.4-2.448m-11.031.018c.711-.006 1.419.198 1.839.63.432.432.672 1.128.648 1.992H9.336c.024-.456-.096-.792-.432-.96-.312-.144-.768-.048-.888.24-.12.264-.192.576-.168.864v3.504c0 .744.264 1.128.768 1.128a.65.65 0 0 0 .552-.264c.168-.24.192-.552.168-.84h1.776c.096 1.632-.984 2.712-2.568 2.688-1.536 0-2.496-.864-2.472-2.472v-4.032c0-.816.24-1.44.696-1.848.432-.408 1.146-.624 1.857-.63"/></svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

+1
View File
@@ -0,0 +1 @@
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>GitHub</title><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg>

After

Width:  |  Height:  |  Size: 822 B

+1
View File
@@ -0,0 +1 @@
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Gitea</title><path d="M4.209 4.603c-.247 0-.525.02-.84.088-.333.07-1.28.283-2.054 1.027C-.403 7.25.035 9.685.089 10.052c.065.446.263 1.687 1.21 2.768 1.749 2.141 5.513 2.092 5.513 2.092s.462 1.103 1.168 2.119c.955 1.263 1.936 2.248 2.89 2.367 2.406 0 7.212-.004 7.212-.004s.458.004 1.08-.394c.535-.324 1.013-.893 1.013-.893s.492-.527 1.18-1.73c.21-.37.385-.729.538-1.068 0 0 2.107-4.471 2.107-8.823-.042-1.318-.367-1.55-.443-1.627-.156-.156-.366-.153-.366-.153s-4.475.252-6.792.306c-.508.011-1.012.023-1.512.027v4.474l-.634-.301c0-1.39-.004-4.17-.004-4.17-1.107.016-3.405-.084-3.405-.084s-5.399-.27-5.987-.324c-.187-.011-.401-.032-.648-.032zm.354 1.832h.111s.271 2.269.6 3.597C5.549 11.147 6.22 13 6.22 13s-.996-.119-1.641-.348c-.99-.324-1.409-.714-1.409-.714s-.73-.511-1.096-1.52C1.444 8.73 2.021 7.7 2.021 7.7s.32-.859 1.47-1.145c.395-.106.863-.12 1.072-.12zm8.33 2.554c.26.003.509.127.509.127l.868.422-.529 1.075a.686.686 0 0 0-.614.359.685.685 0 0 0 .072.756l-.939 1.924a.69.69 0 0 0-.66.527.687.687 0 0 0 .347.763.686.686 0 0 0 .867-.206.688.688 0 0 0-.069-.882l.916-1.874a.667.667 0 0 0 .237-.02.657.657 0 0 0 .271-.137 8.826 8.826 0 0 1 1.016.512.761.761 0 0 1 .286.282c.073.21-.073.569-.073.569-.087.29-.702 1.55-.702 1.55a.692.692 0 0 0-.676.477.681.681 0 1 0 1.157-.252c.073-.141.141-.282.214-.431.19-.397.515-1.16.515-1.16.035-.066.218-.394.103-.814-.095-.435-.48-.638-.48-.638-.467-.301-1.116-.58-1.116-.58s0-.156-.042-.27a.688.688 0 0 0-.148-.241l.516-1.062 2.89 1.401s.48.218.583.619c.073.282-.019.534-.069.657-.24.587-2.1 4.317-2.1 4.317s-.232.554-.748.588a1.065 1.065 0 0 1-.393-.045l-.202-.08-4.31-2.1s-.417-.218-.49-.596c-.083-.31.104-.691.104-.691l2.073-4.272s.183-.37.466-.497a.855.855 0 0 1 .35-.077z"/></svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

+1
View File
@@ -0,0 +1 @@
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Go</title><path d="M1.811 10.231c-.047 0-.058-.023-.035-.059l.246-.315c.023-.035.081-.058.128-.058h4.172c.046 0 .058.035.035.07l-.199.303c-.023.036-.082.07-.117.07zM.047 11.306c-.047 0-.059-.023-.035-.058l.245-.316c.023-.035.082-.058.129-.058h5.328c.047 0 .07.035.058.07l-.093.28c-.012.047-.058.07-.105.07zm2.828 1.075c-.047 0-.059-.035-.035-.07l.163-.292c.023-.035.07-.07.117-.07h2.337c.047 0 .07.035.07.082l-.023.28c0 .047-.047.082-.082.082zm12.129-2.36c-.736.187-1.239.327-1.963.514-.176.046-.187.058-.34-.117-.174-.199-.303-.327-.548-.444-.737-.362-1.45-.257-2.115.175-.795.514-1.204 1.274-1.192 2.22.011.935.654 1.706 1.577 1.835.795.105 1.46-.175 1.987-.77.105-.13.198-.27.315-.434H10.47c-.245 0-.304-.152-.222-.35.152-.362.432-.97.596-1.274a.315.315 0 01.292-.187h4.253c-.023.316-.023.631-.07.947a4.983 4.983 0 01-.958 2.29c-.841 1.11-1.94 1.8-3.33 1.986-1.145.152-2.209-.07-3.143-.77-.865-.655-1.356-1.52-1.484-2.595-.152-1.274.222-2.419.993-3.424.83-1.086 1.928-1.776 3.272-2.02 1.098-.2 2.15-.07 3.096.571.62.41 1.063.97 1.356 1.648.07.105.023.164-.117.2m3.868 6.461c-1.064-.024-2.034-.328-2.852-1.029a3.665 3.665 0 01-1.262-2.255c-.21-1.32.152-2.489.947-3.529.853-1.122 1.881-1.706 3.272-1.95 1.192-.21 2.314-.095 3.33.595.923.63 1.496 1.484 1.648 2.605.198 1.578-.257 2.863-1.344 3.962-.771.783-1.718 1.273-2.805 1.495-.315.06-.63.07-.934.106zm2.78-4.72c-.011-.153-.011-.27-.034-.387-.21-1.157-1.274-1.81-2.384-1.554-1.087.245-1.788.935-2.045 2.033-.21.912.234 1.835 1.075 2.21.643.28 1.285.244 1.905-.07.923-.48 1.425-1.228 1.484-2.233z"/></svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

+1
View File
@@ -0,0 +1 @@
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>HTML5</title><path d="M1.5 0h21l-1.91 21.563L11.977 24l-8.564-2.438L1.5 0zm7.031 9.75l-.232-2.718 10.059.003.23-2.622L5.412 4.41l.698 8.01h9.126l-.326 3.426-2.91.804-2.955-.81-.188-2.11H6.248l.33 4.171L12 19.351l5.379-1.443.744-8.157H8.531z"/></svg>

After

Width:  |  Height:  |  Size: 327 B

+1
View File
@@ -0,0 +1 @@
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>JavaScript</title><path d="M0 0h24v24H0V0zm22.034 18.276c-.175-1.095-.888-2.015-3.003-2.873-.736-.345-1.554-.585-1.797-1.14-.091-.33-.105-.51-.046-.705.15-.646.915-.84 1.515-.66.39.12.75.42.976.9 1.034-.676 1.034-.676 1.755-1.125-.27-.42-.404-.601-.586-.78-.63-.705-1.469-1.065-2.834-1.034l-.705.089c-.676.165-1.32.525-1.71 1.005-1.14 1.291-.811 3.541.569 4.471 1.365 1.02 3.361 1.244 3.616 2.205.24 1.17-.87 1.545-1.966 1.41-.811-.18-1.26-.586-1.755-1.336l-1.83 1.051c.21.48.45.689.81 1.109 1.74 1.756 6.09 1.666 6.871-1.004.029-.09.24-.705.074-1.65l.046.067zm-8.983-7.245h-2.248c0 1.938-.009 3.864-.009 5.805 0 1.232.063 2.363-.138 2.711-.33.689-1.18.601-1.566.48-.396-.196-.597-.466-.83-.855-.063-.105-.11-.196-.127-.196l-1.825 1.125c.305.63.75 1.172 1.324 1.517.855.51 2.004.675 3.207.405.783-.226 1.458-.691 1.811-1.411.51-.93.402-2.07.397-3.346.012-2.054 0-4.109 0-6.179l.004-.056z"/></svg>

After

Width:  |  Height:  |  Size: 974 B

+1
View File
@@ -0,0 +1 @@
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>MongoDB</title><path d="M17.193 9.555c-1.264-5.58-4.252-7.414-4.573-8.115-.28-.394-.53-.954-.735-1.44-.036.495-.055.685-.523 1.184-.723.566-4.438 3.682-4.74 10.02-.282 5.912 4.27 9.435 4.888 9.884l.07.05A73.49 73.49 0 0111.91 24h.481c.114-1.032.284-2.056.51-3.07.417-.296.604-.463.85-.693a11.342 11.342 0 003.639-8.464c.01-.814-.103-1.662-.197-2.218zm-5.336 8.195s0-8.291.275-8.29c.213 0 .49 10.695.49 10.695-.381-.045-.765-1.76-.765-2.405z"/></svg>

After

Width:  |  Height:  |  Size: 527 B

+1
View File
File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.1 KiB

+1
View File
@@ -0,0 +1 @@
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Python</title><path d="M14.25.18l.9.2.73.26.59.3.45.32.34.34.25.34.16.33.1.3.04.26.02.2-.01.13V8.5l-.05.63-.13.55-.21.46-.26.38-.3.31-.33.25-.35.19-.35.14-.33.1-.3.07-.26.04-.21.02H8.77l-.69.05-.59.14-.5.22-.41.27-.33.32-.27.35-.2.36-.15.37-.1.35-.07.32-.04.27-.02.21v3.06H3.17l-.21-.03-.28-.07-.32-.12-.35-.18-.36-.26-.36-.36-.35-.46-.32-.59-.28-.73-.21-.88-.14-1.05-.05-1.23.06-1.22.16-1.04.24-.87.32-.71.36-.57.4-.44.42-.33.42-.24.4-.16.36-.1.32-.05.24-.01h.16l.06.01h8.16v-.83H6.18l-.01-2.75-.02-.37.05-.34.11-.31.17-.28.25-.26.31-.23.38-.2.44-.18.51-.15.58-.12.64-.1.71-.06.77-.04.84-.02 1.27.05zm-6.3 1.98l-.23.33-.08.41.08.41.23.34.33.22.41.09.41-.09.33-.22.23-.34.08-.41-.08-.41-.23-.33-.33-.22-.41-.09-.41.09zm13.09 3.95l.28.06.32.12.35.18.36.27.36.35.35.47.32.59.28.73.21.88.14 1.04.05 1.23-.06 1.23-.16 1.04-.24.86-.32.71-.36.57-.4.45-.42.33-.42.24-.4.16-.36.09-.32.05-.24.02-.16-.01h-8.22v.82h5.84l.01 2.76.02.36-.05.34-.11.31-.17.29-.25.25-.31.24-.38.2-.44.17-.51.15-.58.13-.64.09-.71.07-.77.04-.84.01-1.27-.04-1.07-.14-.9-.2-.73-.25-.59-.3-.45-.33-.34-.34-.25-.34-.16-.33-.1-.3-.04-.25-.02-.2.01-.13v-5.34l.05-.64.13-.54.21-.46.26-.38.3-.32.33-.24.35-.2.35-.14.33-.1.3-.06.26-.04.21-.02.13-.01h5.84l.69-.05.59-.14.5-.21.41-.28.33-.32.27-.35.2-.36.15-.36.1-.35.07-.32.04-.28.02-.21V6.07h2.09l.14.01zm-6.47 14.25l-.23.33-.08.41.08.41.23.33.33.23.41.08.41-.08.33-.23.23-.33.08-.41-.08-.41-.23-.33-.33-.23-.41-.08-.41.08z"/></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

+1
View File
@@ -0,0 +1 @@
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>React</title><path d="M14.23 12.004a2.236 2.236 0 0 1-2.235 2.236 2.236 2.236 0 0 1-2.236-2.236 2.236 2.236 0 0 1 2.235-2.236 2.236 2.236 0 0 1 2.236 2.236zm2.648-10.69c-1.346 0-3.107.96-4.888 2.622-1.78-1.653-3.542-2.602-4.887-2.602-.41 0-.783.093-1.106.278-1.375.793-1.683 3.264-.973 6.365C1.98 8.917 0 10.42 0 12.004c0 1.59 1.99 3.097 5.043 4.03-.704 3.113-.39 5.588.988 6.38.32.187.69.275 1.102.275 1.345 0 3.107-.96 4.888-2.624 1.78 1.654 3.542 2.603 4.887 2.603.41 0 .783-.09 1.106-.275 1.374-.792 1.683-3.263.973-6.365C22.02 15.096 24 13.59 24 12.004c0-1.59-1.99-3.097-5.043-4.032.704-3.11.39-5.587-.988-6.38-.318-.184-.688-.277-1.092-.278zm-.005 1.09v.006c.225 0 .406.044.558.127.666.382.955 1.835.73 3.704-.054.46-.142.945-.25 1.44-.96-.236-2.006-.417-3.107-.534-.66-.905-1.345-1.727-2.035-2.447 1.592-1.48 3.087-2.292 4.105-2.295zm-9.77.02c1.012 0 2.514.808 4.11 2.28-.686.72-1.37 1.537-2.02 2.442-1.107.117-2.154.298-3.113.538-.112-.49-.195-.964-.254-1.42-.23-1.868.054-3.32.714-3.707.19-.09.4-.127.563-.132zm4.882 3.05c.455.468.91.992 1.36 1.564-.44-.02-.89-.034-1.345-.034-.46 0-.915.01-1.36.034.44-.572.895-1.096 1.345-1.565zM12 8.1c.74 0 1.477.034 2.202.093.406.582.802 1.203 1.183 1.86.372.64.71 1.29 1.018 1.946-.308.655-.646 1.31-1.013 1.95-.38.66-.773 1.288-1.18 1.87-.728.063-1.466.098-2.21.098-.74 0-1.477-.035-2.202-.093-.406-.582-.802-1.204-1.183-1.86-.372-.64-.71-1.29-1.018-1.946.303-.657.646-1.313 1.013-1.954.38-.66.773-1.286 1.18-1.868.728-.064 1.466-.098 2.21-.098zm-3.635.254c-.24.377-.48.763-.704 1.16-.225.39-.435.782-.635 1.174-.265-.656-.49-1.31-.676-1.947.64-.15 1.315-.283 2.015-.386zm7.26 0c.695.103 1.365.23 2.006.387-.18.632-.405 1.282-.66 1.933-.2-.39-.41-.783-.64-1.174-.225-.392-.465-.774-.705-1.146zm3.063.675c.484.15.944.317 1.375.498 1.732.74 2.852 1.708 2.852 2.476-.005.768-1.125 1.74-2.857 2.475-.42.18-.88.342-1.355.493-.28-.958-.646-1.956-1.1-2.98.45-1.017.81-2.01 1.085-2.964zm-13.395.004c.278.96.645 1.957 1.1 2.98-.45 1.017-.812 2.01-1.086 2.964-.484-.15-.944-.318-1.37-.5-1.732-.737-2.852-1.706-2.852-2.474 0-.768 1.12-1.742 2.852-2.476.42-.18.88-.342 1.356-.494zm11.678 4.28c.265.657.49 1.312.676 1.948-.64.157-1.316.29-2.016.39.24-.375.48-.762.705-1.158.225-.39.435-.788.636-1.18zm-9.945.02c.2.392.41.783.64 1.175.23.39.465.772.705 1.143-.695-.102-1.365-.23-2.006-.386.18-.63.406-1.282.66-1.933zM17.92 16.32c.112.493.2.968.254 1.423.23 1.868-.054 3.32-.714 3.708-.147.09-.338.128-.563.128-1.012 0-2.514-.807-4.11-2.28.686-.72 1.37-1.536 2.02-2.44 1.107-.118 2.154-.3 3.113-.54zm-11.83.01c.96.234 2.006.415 3.107.532.66.905 1.345 1.727 2.035 2.446-1.595 1.483-3.092 2.295-4.11 2.295-.22-.005-.406-.05-.553-.132-.666-.38-.955-1.834-.73-3.703.054-.46.142-.944.25-1.438zm4.56.64c.44.02.89.034 1.345.034.46 0 .915-.01 1.36-.034-.44.572-.895 1.095-1.345 1.565-.455-.47-.91-.993-1.36-1.565z"/></svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

+1
View File
@@ -0,0 +1 @@
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Telegram</title><path d="M11.944 0A12 12 0 0 0 0 12a12 12 0 0 0 12 12 12 12 0 0 0 12-12A12 12 0 0 0 12 0a12 12 0 0 0-.056 0zm4.962 7.224c.1-.002.321.023.465.14a.506.506 0 0 1 .171.325c.016.093.036.306.02.472-.18 1.898-.962 6.502-1.36 8.627-.168.9-.499 1.201-.82 1.23-.696.065-1.225-.46-1.9-.902-1.056-.693-1.653-1.124-2.678-1.8-1.185-.78-.417-1.21.258-1.91.177-.184 3.247-2.977 3.307-3.23.007-.032.014-.15-.056-.212s-.174-.041-.249-.024c-.106.024-1.793 1.14-5.061 3.345-.48.33-.913.49-1.302.48-.428-.008-1.252-.241-1.865-.44-.752-.245-1.349-.374-1.297-.789.027-.216.325-.437.893-.663 3.498-1.524 5.83-2.529 6.998-3.014 3.332-1.386 4.025-1.627 4.476-1.635z"/></svg>

After

Width:  |  Height:  |  Size: 742 B

+1
View File
@@ -0,0 +1 @@
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>TypeScript</title><path d="M1.125 0C.502 0 0 .502 0 1.125v21.75C0 23.498.502 24 1.125 24h21.75c.623 0 1.125-.502 1.125-1.125V1.125C24 .502 23.498 0 22.875 0zm17.363 9.75c.612 0 1.154.037 1.627.111a6.38 6.38 0 0 1 1.306.34v2.458a3.95 3.95 0 0 0-.643-.361 5.093 5.093 0 0 0-.717-.26 5.453 5.453 0 0 0-1.426-.2c-.3 0-.573.028-.819.086a2.1 2.1 0 0 0-.623.242c-.17.104-.3.229-.393.374a.888.888 0 0 0-.14.49c0 .196.053.373.156.529.104.156.252.304.443.444s.423.276.696.41c.273.135.582.274.926.416.47.197.892.407 1.266.628.374.222.695.473.963.753.268.279.472.598.614.957.142.359.214.776.214 1.253 0 .657-.125 1.21-.373 1.656a3.033 3.033 0 0 1-1.012 1.085 4.38 4.38 0 0 1-1.487.596c-.566.12-1.163.18-1.79.18a9.916 9.916 0 0 1-1.84-.164 5.544 5.544 0 0 1-1.512-.493v-2.63a5.033 5.033 0 0 0 3.237 1.2c.333 0 .624-.03.872-.09.249-.06.456-.144.623-.25.166-.108.29-.234.373-.38a1.023 1.023 0 0 0-.074-1.089 2.12 2.12 0 0 0-.537-.5 5.597 5.597 0 0 0-.807-.444 27.72 27.72 0 0 0-1.007-.436c-.918-.383-1.602-.852-2.053-1.405-.45-.553-.676-1.222-.676-2.005 0-.614.123-1.141.369-1.582.246-.441.58-.804 1.004-1.089a4.494 4.494 0 0 1 1.47-.629 7.536 7.536 0 0 1 1.77-.201zm-15.113.188h9.563v2.166H9.506v9.646H6.789v-9.646H3.375z"/></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

+68
View File
@@ -0,0 +1,68 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="./styles/main.css" />
<link rel="stylesheet" href="./styles/hero.css" />
<link rel="stylesheet" href="./styles/stack.css" />
<link rel="stylesheet" href="./styles/projects.css" />
<link rel="stylesheet" href="./styles/links.css" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Barlow+Condensed: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&family=Barlow: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"
rel="stylesheet"
/>
<script src="./js/data.js" defer></script>
<script src="./js/stack.js" defer></script>
<script src="./js/projects.js" defer></script>
<script src="./js/links.js" defer></script>
<title>ScuroNeko</title>
</head>
<body>
<header class="site-hero">
<div class="site-hero__main">
<p class="site-pill">scuroneko.dev · self-hosted</p>
<div class="site-title">
<h1>ScuroNeko</h1>
<span class="site-mark"></span>
</div>
<p class="site-subtitle">Go and JS developer</p>
<nav class="site-nav" aria-label="Page sections">
<a href="#stack-section">Stack</a>
<a href="#projects-section">Projects</a>
<a href="#links-section">Links</a>
</nav>
</div>
</header>
<section class="block" id="stack-section">
<div class="section-heading">
<span class="section-index">01</span>
<h2>Stack</h2>
</div>
<p class="block-subtitle">Tools I reach for when the task needs to ship.</p>
<div class="stack-grid" id="stack"></div>
</section>
<section class="block" id="projects-section">
<div class="section-heading">
<span class="section-index">02</span>
<h2>Projects</h2>
</div>
<p class="block-subtitle">Things with enough shape to point at.</p>
<div class="project-grid" id="projects"></div>
</section>
<section class="block" id="links-section">
<div class="section-heading">
<span class="section-index">03</span>
<h2>Links</h2>
</div>
<p class="block-subtitle">Places where I answer, publish, or keep code.</p>
<div class="link-grid" id="links"></div>
</section>
</body>
</html>
+29
View File
@@ -0,0 +1,29 @@
let stackList = [];
let projectsList = [];
let linksList = [];
const fetchJson = async (path) => {
const response = await fetch(path);
if (!response.ok) {
throw new Error(`Failed to load ${path}: ${response.status}`);
}
return response.json();
};
const loadIcon = async (key) => {
const response = await fetch(`./icons/${key}.svg`);
if (!response.ok) {
return key;
}
return response.text();
};
const formatIndex = (index) => String(index + 1).padStart(2, "0");
document.addEventListener("DOMContentLoaded", () => {
loadStack().then(loadProjects).then(loadLinks).catch(console.error);
});
+48
View File
@@ -0,0 +1,48 @@
const loadLinks = async () => {
const linkContainer = document.getElementById("links");
if (!linkContainer) {
return;
}
linksList = await fetchJson("./data/links.json");
const linkCards = linksList.map(buildLinkCard);
linkContainer.replaceChildren(...linkCards);
};
const buildLinkCard = (item, index) => {
const card = document.createElement("a");
card.classList.add("link-card", `tone-${item.tone ?? "mint"}`);
card.href = item.url;
card.target = "_blank";
card.rel = "noreferrer";
const indexBadge = document.createElement("span");
indexBadge.classList.add("link-card__index");
indexBadge.textContent = formatIndex(index);
const badge = document.createElement("span");
badge.classList.add("link-card__badge");
badge.textContent = item.key;
loadIcon(item.key).then((svg) => (badge.innerHTML = svg));
const body = document.createElement("span");
body.classList.add("link-card__body");
const name = document.createElement("span");
name.classList.add("link-card__name");
name.textContent = item.name;
const label = document.createElement("span");
label.classList.add("link-card__label");
label.textContent = item.label;
const arrow = document.createElement("span");
arrow.classList.add("link-card__arrow");
arrow.textContent = "open";
body.append(name, label);
card.append(indexBadge, badge, body, arrow);
return card;
};
+94
View File
@@ -0,0 +1,94 @@
const loadProjects = async () => {
const projectContainer = document.getElementById("projects");
if (!projectContainer) {
return;
}
projectsList = await fetchJson("./data/projects.json");
if (projectsList.length === 0) {
const empty = document.createElement("p");
empty.classList.add("project-empty");
empty.textContent = "Projects are taking shape.";
projectContainer.replaceChildren(empty);
return;
}
const projectCards = projectsList.map(buildProjectCard);
projectContainer.replaceChildren(...projectCards);
};
const buildProjectCard = (project, index) => {
const card = document.createElement("article");
card.classList.add("project-card", `project-card--${project.tone ?? "mint"}`);
const header = document.createElement("div");
header.classList.add("project-card__header");
const indexBadge = document.createElement("span");
indexBadge.classList.add("project-card__index");
indexBadge.textContent = formatIndex(index);
const key = document.createElement("span");
key.classList.add("project-card__key");
key.textContent = project.key;
const status = document.createElement("span");
status.classList.add("project-card__status");
status.textContent = project.status ?? "project";
const title = document.createElement("h3");
title.classList.add("project-card__title");
title.textContent = project.name;
const description = document.createElement("p");
description.classList.add("project-card__description");
description.textContent = project.description;
const stack = document.createElement("div");
stack.classList.add("project-card__stack");
if (project.stack) {
const badgeToStack = loadStackForProject(project.stack);
stack.append(
...project.stack.map((item) => {
const chip = document.createElement("span");
const stackItem = badgeToStack[item] ?? {
name: item,
tone: "blue",
};
chip.textContent = stackItem.name;
chip.classList.add(
"project-card__stack-chip",
`tone-${stackItem?.tone ?? "mint"}`,
);
return chip;
}),
);
}
header.append(indexBadge, key, status);
card.append(header, title, description, stack);
if (project.links) {
const links = document.createElement("div");
links.classList.add("project-card__links");
links.append(
...Object.entries(project.links).map(([label, url]) => {
const link = document.createElement("a");
link.href = url;
link.textContent = label;
link.target = "_blank";
link.rel = "noreferrer";
return link;
}),
);
card.append(links);
}
return card;
};
+75
View File
@@ -0,0 +1,75 @@
const getExperienceLevel = (years) => {
if (years >= 7) return "Core";
if (years >= 4) return "Strong";
return "Growing";
};
const loadStackForProject = (keys) => {
const stacks = stackList.filter((stack) => keys.includes(stack.key));
const output = {};
stacks.forEach((stack) => {
output[stack.key] = stack;
});
return output;
};
const loadStack = async () => {
const stackContainer = document.getElementById("stack");
if (!stackContainer) {
return;
}
stackList = await fetchJson("./data/stack.json");
const stackCards = stackList.map(buildStackCard).filter(Boolean);
stackContainer.replaceChildren(...stackCards);
};
const buildStackCard = (stack) => {
if (stack?.hide === true) {
return null;
}
const card = document.createElement("div");
card.classList.add("stack-card", `tone-${stack.tone ?? "mint"}`);
const badge = document.createElement("div");
badge.classList.add("stack-card__badge");
badge.textContent = stack.key;
loadIcon(stack.key).then((svg) => (badge.innerHTML = svg));
const body = document.createElement("div");
body.classList.add("stack-card__body");
const eyebrow = document.createElement("p");
eyebrow.classList.add("stack-card__eyebrow");
eyebrow.textContent = getExperienceLevel(stack.years);
const name = document.createElement("h3");
name.classList.add("stack-card__title");
name.textContent = stack.name;
const footer = document.createElement("div");
footer.classList.add("stack-card__footer");
const years = document.createElement("span");
years.textContent = `${stack.years}+ years`;
footer.append(years);
if (stack.tags) {
footer.append(
...stack.tags.map((tag) => {
const badge = document.createElement("span");
badge.textContent = tag;
return badge;
}),
);
}
body.append(eyebrow, name, footer);
card.append(badge, body);
return card;
};
+98
View File
@@ -0,0 +1,98 @@
.site-hero {
align-items: center;
display: grid;
min-height: calc(100vh - 96px);
width: calc(100% - 24px);
max-width: var(--block-size);
margin-bottom: 20px;
}
.site-hero__main {
justify-self: center;
min-width: 0;
width: min(100%, 460px);
}
.site-pill {
display: inline-flex;
align-items: center;
min-height: 30px;
padding: 0 12px;
border: 1px solid var(--border);
border-radius: 8px;
color: var(--text-soft);
font-family: monospace;
font-size: 0.82rem;
}
.site-title {
display: flex;
align-items: center;
gap: 14px;
margin-top: 16px;
}
.site-mark {
display: grid;
place-items: center;
width: 36px;
height: 36px;
border: 1px solid color-mix(in srgb, var(--danger) 70%, var(--border));
border-radius: 8px;
color: var(--danger);
font-family: serif;
font-size: 1.2rem;
line-height: 1;
}
.site-subtitle {
margin-top: 8px;
max-width: 640px;
color: var(--text-soft);
font-size: 1.05rem;
line-height: 1.65;
}
.site-nav {
display: flex;
flex-wrap: wrap;
gap: 12px;
margin-top: 24px;
}
.site-nav a {
min-height: 40px;
padding: 10px 18px;
border: 1px solid var(--border);
border-radius: 8px;
color: var(--text);
text-decoration: none;
transition:
background-color 160ms ease,
border-color 160ms ease,
color 160ms ease;
}
.site-nav a:hover {
border-color: var(--primary);
background-color: var(--glow-blue);
color: var(--text);
}
@media (max-width: 780px) {
.site-hero {
grid-template-columns: 1fr;
}
}
@media (max-width: 560px) {
.site-hero {
width: 100%;
}
.site-title {
align-items: flex-start;
flex-direction: column;
gap: 10px;
}
}
+96
View File
@@ -0,0 +1,96 @@
.link-grid {
display: grid;
gap: 12px;
grid-template-columns: repeat(3, minmax(0, 1fr));
margin-top: 18px;
}
.link-card {
display: grid;
grid-template-columns: auto auto minmax(0, 1fr) auto;
align-items: center;
gap: 12px;
min-height: 76px;
padding: 14px;
border: 1px solid color-mix(in srgb, var(--card-accent) 30%, var(--border));
border-radius: 8px;
background-color: rgba(42, 42, 55, 0.72);
color: var(--text);
text-decoration: none;
transition:
background-color 160ms ease,
border-color 160ms ease,
transform 160ms ease;
}
.link-card:hover {
border-color: var(--card-accent);
background-color: color-mix(in srgb, var(--card-glow) 36%, var(--surface));
color: var(--text);
transform: translateY(-2px);
}
.link-card__index {
color: var(--text-soft);
font-family: monospace;
font-size: 0.75rem;
}
.link-card__badge {
display: grid;
place-items: center;
width: 42px;
height: 42px;
border: 1px solid color-mix(in srgb, var(--card-accent) 58%, var(--border));
border-radius: 8px;
color: var(--card-accent);
font-family: "Barlow Condensed", sans-serif;
font-size: 1rem;
font-weight: 800;
text-transform: uppercase;
}
.link-card__badge svg {
width: 22px;
height: 22px;
fill: currentColor;
}
.link-card__body {
display: grid;
min-width: 0;
}
.link-card__name {
color: var(--text);
font-family: "Barlow Condensed", sans-serif;
font-size: 1.25rem;
font-weight: 700;
}
.link-card__label {
overflow: hidden;
color: var(--text-soft);
font-size: 0.92rem;
text-overflow: ellipsis;
white-space: nowrap;
}
.link-card__arrow {
color: var(--card-accent);
font-size: 0.82rem;
font-weight: 700;
text-transform: uppercase;
}
@media (max-width: 780px) {
.link-grid {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
}
@media (max-width: 560px) {
.link-grid {
grid-template-columns: 1fr;
}
}
+172
View File
@@ -0,0 +1,172 @@
:root {
--bg: #1f1f28;
--surface: #2a2a37;
--border: #4a4a61;
--text: #dcd7ba;
--text-soft: #c8c093;
--text-muted: #938056;
--primary: #7e9cd8;
--accent: #7aa89f;
--warm: #e6c384;
--danger: #c34043;
--glow-blue: rgba(126, 156, 216, 0.2);
--glow-gold: rgba(230, 195, 132, 0.2);
--glow-mint: rgba(122, 168, 159, 0.2);
--glow-purple: rgba(184, 118, 211, 0.26);
--glow-red: rgba(195, 64, 67, 0.2);
--glow-cyan: rgba(127, 180, 202, 0.2);
--glow-green: rgba(152, 187, 108, 0.18);
--glow-pink: rgba(210, 126, 153, 0.18);
--block-size: 980px;
font-size: 16px;
}
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
html,
body {
width: 100%;
height: 100%;
margin: 0;
scroll-behavior: smooth;
}
body {
padding: 48px 12px;
font-family: "Barlow", sans-serif;
background-color: var(--bg);
color: var(--text);
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: center;
min-height: 100%;
}
a {
color: var(--primary);
}
a:hover {
color: var(--accent);
}
h1 {
font-size: 3.5rem;
}
h2 {
font-size: 2rem;
}
h3 {
font-size: 1.5rem;
}
h4 {
font-size: 1.2rem;
}
h5 {
font-size: 1rem;
}
h6 {
font-size: 0.8rem;
}
h1,
h2,
h3,
h4,
h5,
h6 {
margin: 0;
padding: 0;
font-family: "Barlow Condensed", sans-serif;
}
.block {
width: calc(100% - 24px);
max-width: var(--block-size);
padding: 18px 0;
margin: 12px 24px;
border-top: 1px solid color-mix(in srgb, var(--border) 70%, transparent);
}
.section-heading {
display: flex;
align-items: baseline;
gap: 16px;
}
.section-index {
color: var(--text-soft);
font-family: monospace;
font-size: 0.82rem;
}
.block-subtitle {
color: var(--text-soft);
margin-top: 4px;
max-width: 560px;
}
.tone-blue {
--card-accent: var(--primary);
--card-glow: var(--glow-blue);
}
.tone-gold {
--card-accent: var(--warm);
--card-glow: var(--glow-gold);
}
.tone-mint {
--card-accent: var(--accent);
--card-glow: var(--glow-mint);
}
.tone-purple {
--card-accent: #b876d3;
--card-glow: var(--glow-purple);
}
.tone-red {
--card-accent: var(--danger);
--card-glow: var(--glow-red);
}
.tone-cyan {
--card-accent: #7fb4ca;
--card-glow: var(--glow-cyan);
}
.tone-green {
--card-accent: #98bb6c;
--card-glow: var(--glow-green);
}
.tone-pink {
--card-accent: #d27e99;
--card-glow: var(--glow-pink);
}
@media (max-width: 560px) {
body {
padding-top: 32px;
}
.block {
width: 100%;
margin-inline: 0;
}
}
+161
View File
@@ -0,0 +1,161 @@
.project-card.project-card--blue {
--project-accent: var(--primary);
--project-glow: var(--glow-blue);
}
.project-card.project-card--gold {
--project-accent: var(--warm);
--project-glow: var(--glow-gold);
}
.project-card.project-card--mint {
--project-accent: var(--accent);
--project-glow: var(--glow-mint);
}
.project-card.project-card--purple {
--project-accent: #b876d3;
--project-glow: var(--glow-purple);
}
.project-card.project-card--red {
--project-accent: var(--danger);
--project-glow: var(--glow-red);
}
.project-card.project-card--cyan {
--project-accent: #7fb4ca;
--project-glow: var(--glow-cyan);
}
.project-card.project-card--green {
--project-accent: #98bb6c;
--project-glow: var(--glow-green);
}
.project-card.project-card--pink {
--project-accent: #d27e99;
--project-glow: var(--glow-pink);
}
.project-grid {
display: grid;
gap: 18px;
grid-template-columns: repeat(2, minmax(0, 1fr));
margin-top: 18px;
}
.project-card {
--project-accent: var(--accent);
--project-glow: var(--glow-mint);
display: flex;
flex-direction: column;
min-height: 220px;
padding: 22px;
border: 1px solid color-mix(in srgb, var(--project-accent) 36%, var(--border));
border-radius: 8px;
background:
linear-gradient(140deg, var(--project-glow), transparent 48%),
linear-gradient(180deg, rgba(255, 255, 255, 0.04), transparent),
var(--surface);
box-shadow: 0 18px 42px rgba(0, 0, 0, 0.2);
transition:
border-color 160ms ease,
transform 160ms ease,
box-shadow 160ms ease;
}
.project-card:hover {
border-color: var(--project-accent);
box-shadow: 0 24px 52px rgba(0, 0, 0, 0.28);
transform: translateY(-2px);
}
.project-card__header {
display: flex;
align-items: center;
gap: 12px;
}
.project-card__index {
color: var(--text-soft);
font-family: monospace;
font-size: 0.82rem;
}
.project-card__key,
.project-card__status {
border-radius: 8px;
padding: 4px 8px;
font-size: 0.82rem;
font-weight: 700;
}
.project-card__key {
border: 1px solid color-mix(in srgb, var(--project-accent) 56%, var(--border));
color: var(--project-accent);
text-transform: uppercase;
}
.project-card__status {
margin-left: auto;
background-color: rgba(31, 31, 40, 0.52);
color: var(--text-soft);
}
.project-card__title {
margin-top: 22px;
color: var(--text);
font-size: 1.75rem;
}
.project-card__description {
margin-top: 8px;
color: var(--text-soft);
line-height: 1.55;
}
.project-card__stack {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-top: 18px;
}
.project-card__stack span {
border-radius: 8px;
border: 1px solid var(--card-glow);
padding: 5px 9px;
background-color: rgba(31, 31, 40, 0.42);
color: var(--card-accent);
font-size: 0.9rem;
}
.project-card__links {
display: flex;
flex-wrap: wrap;
gap: 12px;
margin-top: auto;
padding-top: 24px;
}
.project-card__links a {
border-bottom: 1px solid currentColor;
color: var(--project-accent);
font-weight: 700;
text-decoration: none;
}
.project-empty {
grid-column: 1 / -1;
border: 1px solid var(--border);
border-radius: 8px;
padding: 18px;
color: var(--text-soft);
}
@media (max-width: 780px) {
.project-grid {
grid-template-columns: 1fr;
}
}
+108
View File
@@ -0,0 +1,108 @@
.stack-grid {
display: grid;
gap: 16px;
grid-template-columns: repeat(3, minmax(0, 1fr));
margin-top: 18px;
}
.stack-card {
--card-accent: var(--accent);
--card-glow: var(--glow-mint);
position: relative;
display: grid;
grid-template-columns: auto 1fr;
gap: 16px;
min-height: 112px;
overflow: hidden;
padding: 18px;
border: 1px solid color-mix(in srgb, var(--card-accent) 44%, var(--border));
border-radius: 8px;
background:
linear-gradient(135deg, var(--card-glow), transparent 42%),
linear-gradient(180deg, rgba(255, 255, 255, 0.04), transparent),
var(--surface);
box-shadow: 0 16px 36px rgba(0, 0, 0, 0.18);
transition:
border-color 160ms ease,
transform 160ms ease,
box-shadow 160ms ease;
user-select: none;
}
.stack-card:hover {
border-color: var(--card-accent);
box-shadow: 0 20px 44px rgba(0, 0, 0, 0.26);
transform: translateY(-2px);
}
.stack-card__badge {
display: grid;
place-items: center;
width: 58px;
height: 58px;
border-radius: 8px;
background-color: rgba(31, 31, 40, 0.8);
border: 1px solid color-mix(in srgb, var(--card-accent) 64%, var(--border));
color: var(--card-accent);
font-family: "Barlow Condensed", sans-serif;
font-size: 1.45rem;
font-weight: 700;
}
.stack-card__badge svg {
width: 34px;
height: 34px;
fill: currentColor;
}
.stack-card__body {
display: flex;
flex-direction: column;
min-width: 0;
}
.stack-card__eyebrow {
color: var(--card-accent);
font-size: 0.8rem;
font-weight: 700;
letter-spacing: 0;
text-transform: uppercase;
}
.stack-card__title {
margin-top: 4px;
color: var(--text);
}
.stack-card__footer {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-top: auto;
padding-top: 12px;
color: var(--text-soft);
font-size: 0.95rem;
}
.stack-card__footer span {
border-radius: 8px;
border: 1px solid rgba(220, 215, 186, 0.16);
padding: 4px 8px;
background-color: rgba(31, 31, 40, 0.4);
}
@media (max-width: 780px) {
.stack-grid {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
}
@media (max-width: 560px) {
.stack-grid {
grid-template-columns: 1fr;
}
.stack-card {
grid-template-columns: 1fr;
}
}