From 5cf87074a480ab38d7a912e79a756b05bc06b1b5 Mon Sep 17 00:00:00 2001 From: Victor Westerlund Date: Sun, 23 Nov 2025 12:34:55 +0100 Subject: [PATCH] wip: 2025-11-23T12:34:55+0100 (1763897695) --- assets/css/pages/about.css | 366 ++++++++++++++++++----------------- assets/css/pages/contact.css | 354 ++++++++++++++++----------------- assets/css/pages/error.css | 4 - assets/css/pages/index.css | 206 ++++++++++---------- 4 files changed, 462 insertions(+), 468 deletions(-) diff --git a/assets/css/pages/about.css b/assets/css/pages/about.css index 7e89f2d..51e6ded 100644 --- a/assets/css/pages/about.css +++ b/assets/css/pages/about.css @@ -28,211 +28,225 @@ vv-shell { display: flex; flex-direction: column; gap: var(--padding); + + > hr { + border-color: rgba(255, 255, 255, .1); + } } -/* # Sections */ +section { + &.about { + gap: calc(var(--padding) / 2); + display: flex; + flex-direction: column; -/* ## Divider */ + p { + &:first-of-type:first-letter { + color: var(--color-accent); + font-size: 1.8rem; + font-weight: bold; + margin-right: .1rem; + } + } -vv-shell > hr { - border-color: rgba(255, 255, 255, .1); -} + span { + &.interests { + color: var(--color-accent); + animation: interests-hue 5s infinite linear; + user-select: none; + -webkit-user-select: none; + } + } + } -/* ## About */ + &.languages { + margin: calc(var(--padding) / 1.5) 0; -section.about { - display: flex; - flex-direction: column; - gap: calc(var(--padding) / 2); -} + stacked-bar-chart { + gap: 3px; + width: 100%; + height: var(--padding); + display: flex; + border-radius: 100px; + background-color: rgba(255, 255, 255, 0); -section.about p:first-of-type:first-letter { - font-size: 1.8rem; - font-weight: bold; - margin-right: .1rem; - color: var(--color-accent); -} + @media (hover: hover) { + &:hover chart-segment { + opacity: .5; + } + } -section.about span.interests { - -webkit-user-select: none; - user-select: none; - color: var(--color-accent); - animation: interests-hue 5s infinite linear; -} + &:last-of-type { + flex-direction: row-reverse; + } -/* ## Languages */ + chart-segment { + --border-corner-radius: 100px; -section.languages { - margin: calc(var(--padding) / 1.5) 0; -} + width: var(--size, 0%); + color: white; + height: 100%; + display: flex; + position: relative; + min-width: 3%; + transition: 150ms opacity; + align-items: center; + border-radius: 2px; + justify-content: center; + background-color: rgba(255, 255, 255, .1); -section.languages stacked-bar-chart { - gap: 3px; - width: 100%; - display: flex; - border-radius: 100px; - height: var(--padding); - background-color: rgba(255, 255, 255, 0); -} + &[data-lang="Go"] { background-color: var(--color-go); } + &[data-lang="PHP"] { background-color: var(--color-php); } + &[data-lang="CSS"] { background-color: var(--color-css); } + &[data-lang="HTML"] { background-color: var(--color-html); } + &[data-lang="Python"] { background-color: var(--color-python); } + &[data-lang="TypeScript"] { background-color: var(--color-typescript); } + &[data-lang="Shell"] { background-color: var(--color-shell); color: black; } + &[data-lang="JavaScript"] { background-color: var(--color-javascript); color: black; } -section.languages stacked-bar-chart:last-of-type { - flex-direction: row-reverse; -} + &[data-hover] { + display: none; + } -section.languages stacked-bar-chart:hover chart-segment { - opacity: .5; -} + a:first-child & { + border-top-left-radius: var(--border-corner-radius); + border-top-right-radius: var(--padding); + border-bottom-left-radius: var(--border-corner-radius); + border-bottom-right-radius: var(--padding); + } -section.languages stacked-bar-chart chart-segment { - --border-corner-radius: 100px; + a:last-child & { + border-top-left-radius: var(--padding); + border-top-right-radius: var(--border-corner-radius); + border-bottom-left-radius: var(--padding); + border-bottom-right-radius: var(--border-corner-radius); + } - transition: 150ms opacity; - width: var(--size, 0%); - min-width: 3%; - height: 100%; - color: white; - position: relative; - display: flex; - align-items: center; - justify-content: center; - background-color: rgba(255, 255, 255, .1); - border-radius: 2px; -} + stacked-bar-chart:last-of-type a:first-child & { + border-top-left-radius: var(--padding); + border-top-right-radius: var(--border-corner-radius); + border-bottom-left-radius: var(--padding); + border-bottom-right-radius: var(--border-corner-radius); + } -section.languages stacked-bar-chart a:nth-child(odd) chart-segment { - background-color: rgba(255, 255, 255, .3); -} + stacked-bar-chart:last-of-type a:last-child & { + border-top-left-radius: var(--border-corner-radius); + border-top-right-radius: var(--padding); + border-bottom-right-radius: var(--padding); + border-bottom-left-radius: var(--border-corner-radius); + } -/* ### Round corners */ + p { + color: inherit; + padding: 0 3px; + overflow: hidden; + text-align: center; + white-space: nowrap; + pointer-events: none; + text-overflow: ellipsis; -section.languages stacked-bar-chart a:first-child chart-segment { - border-top-right-radius: var(--padding); - border-bottom-right-radius: var(--padding); - border-top-left-radius: var(--border-corner-radius); - border-bottom-left-radius: var(--border-corner-radius); -} + chart-segment[style="--size:0%;"] & { + &::before { + content: "<1%"; + opacity: .5; + } -section.languages stacked-bar-chart a:last-child chart-segment { - border-top-left-radius: var(--padding); - border-bottom-left-radius: var(--padding); - border-top-right-radius: var(--border-corner-radius); - border-bottom-right-radius: var(--border-corner-radius); -} + span { + display: none; + } + } + } -section.languages stacked-bar-chart:last-of-type a:first-child chart-segment { - border-top-left-radius: var(--padding); - border-bottom-left-radius: var(--padding); - border-top-right-radius: var(--border-corner-radius); - border-bottom-right-radius: var(--border-corner-radius); -} + @media (hover: hover) { + opacity: 1; -section.languages stacked-bar-chart:last-of-type a:last-child chart-segment { - border-top-right-radius: var(--padding); - border-bottom-right-radius: var(--padding); - border-top-left-radius: var(--border-corner-radius); - border-bottom-left-radius: var(--border-corner-radius); -} + &[data-hover] { + display: none; + position: absolute; + top: 0; + left: 0; + text-align: center; + transform: translate(0, 0); + background-color: inherit; + padding: 5px 10px; + white-space: nowrap; + pointer-events: none; + border-radius: 6px; + z-index: 2000; + -webkit-backdrop-filter: brightness(.2) blur(20px); + backdrop-filter: brightness(.2) blur(20px); + } + } + } + } -/* ### Texts */ + languages-list { + gap: calc(var(--padding) / 2); + margin: var(--padding) 0; + display: grid; + grid-template-columns: repeat(3, 1fr); -section.languages stacked-bar-chart chart-segment p { - text-align: center; - color: inherit; - overflow: hidden; - white-space: nowrap; - pointer-events: none; - text-overflow: ellipsis; - padding: 0 3px; -} + language-item { + gap: 10px; + fill: var(--color-php); + border: solid 1px rgba(255, 255, 255, .1); + padding: calc(var(--padding) / 1.5); + display: flex; + background: linear-gradient(139deg, rgba(0, 0, 0, 0) 0%, rgba(79, 93, 144, .2) 100%); + align-items: center; + border-radius: 8px; -section.languages stacked-bar-chart chart-segment[style="--size:0%;"] p span { - display: none; -} + svg { + width: 2em; + margin-left: auto; + transform: rotate(-90deg); + } + } + } -section.languages stacked-bar-chart chart-segment[style="--size:0%;"] p::before { - content: "<1%"; - opacity: .5; -} + button { + p { + &.lang { + font-size: 1.3em; + font-weight: 900; + } + } + } + } -section.languages stacked-bar-chart chart-segment [data-hover] { - display: none; -} + &.interests { + --text-shadow-blur: 30px; -/* ### Colors */ + top: 0; + left: 0; + width: 100%; + color: var(--color-accent); + height: 100%; + opacity: 0; + z-index: 200; + overflow: hidden; + position: fixed; + font-size: clamp(16px, 15vw, 50px); + transition: 300ms opacity; + font-weight: bold; + pointer-events: none; -section.languages stacked-bar-chart a chart-segment[data-lang="Go"] { background-color: var(--color-go); } -section.languages stacked-bar-chart a chart-segment[data-lang="PHP"] { background-color: var(--color-php); } -section.languages stacked-bar-chart a chart-segment[data-lang="CSS"] { background-color: var(--color-css); } -section.languages stacked-bar-chart a chart-segment[data-lang="HTML"] { background-color: var(--color-html); } -section.languages stacked-bar-chart a chart-segment[data-lang="Python"] { background-color: var(--color-python); } -section.languages stacked-bar-chart a chart-segment[data-lang="TypeScript"] { background-color: var(--color-typescript); } -section.languages stacked-bar-chart a chart-segment[data-lang="Shell"] { background-color: var(--color-shell); color: black; } -section.languages stacked-bar-chart a chart-segment[data-lang="JavaScript"] { background-color: var(--color-javascript); color: black; } + &.active { + opacity: 1; + } -/* ### Legend */ - -section.languages languages-list { - gap: calc(var(--padding) / 2); - display: grid; - grid-template-columns: repeat(3, 1fr); - margin: var(--padding) 0; -} - -section.languages languages-list language-item { - gap: 10px; - display: flex; - border-radius: 8px; - align-items: center; - fill: var(--color-php); - padding: calc(var(--padding) / 1.5); - border: solid 1px rgba(255, 255, 255, .1); - background: linear-gradient(139deg, rgba(0, 0, 0, 0) 0%, rgba(79, 93, 144, .2) 100%); -} - -section.languages languages-list language-item svg { - width: 2em; - margin-left: auto; - transform: rotate(-90deg); -} - -section.languages button p.lang { - font-size: 1.3em; - font-weight: 900; -} - -/* # Interests */ - -div.interests { - --text-shadow-blur: 30px; - - transition: 300ms opacity; - position: fixed; - top: 0; - left: 0; - width: 100%; - height: 100%; - font-weight: bold; - pointer-events: none; - font-size: clamp(16px, 15vw, 50px); - color: var(--color-accent); - overflow: hidden; - opacity: 0; - z-index: 200; -} - -div.interests.active { - opacity: 1; -} - -div.interests p { - transition: 500ms transform cubic-bezier(.34,0,0,.99); - position: absolute; - text-shadow: - 0 0 var(--text-shadow-blur) black, - 0 0 var(--text-shadow-blur) black, - 0 0 var(--text-shadow-blur) black, - 0 0 var(--text-shadow-blur) black, - 0 0 var(--text-shadow-blur) black; + p { + position: absolute; + transition: 500ms transform cubic-bezier(.34,0,0,.99); + text-shadow: + 0 0 var(--text-shadow-blur) black, + 0 0 var(--text-shadow-blur) black, + 0 0 var(--text-shadow-blur) black, + 0 0 var(--text-shadow-blur) black, + 0 0 var(--text-shadow-blur) black + ; + } + } } @keyframes interests-hue { diff --git a/assets/css/pages/contact.css b/assets/css/pages/contact.css index fe25c6f..92d3479 100644 --- a/assets/css/pages/contact.css +++ b/assets/css/pages/contact.css @@ -3,111 +3,184 @@ :root { --primer-color-accent: 255, 195, 255; --color-accent: rgb(var(--primer-color-accent)); + --hue-accent: 200deg; } vv-shell { - display: flex; - flex-direction: column; - align-items: center; gap: var(--padding); + display: flex; + align-items: center; + flex-direction: column; + + > svg { + margin: var(--padding) 0; + } } .fingerprint { word-break: break-all; } -/* # Sections */ +section { + &.center { + text-align: center; + } -vv-shell > svg { - margin: var(--padding) 0; + &.social { + --icon-size: 60px; + + gap: var(--padding); + fill: white; + display: grid; + align-items: center; + grid-template-rows: var(--icon-size); + grid-template-columns: repeat(3, var(--icon-size)); + + social { + position: relative; + transition: 200ms fill; + + p { + top: 0; + left: 0; + display: none; + padding: 5px 10px; + position: absolute; + transform: translate(0, 0); + white-space: nowrap; + border-radius: 6px; + pointer-events: none; + backdrop-filter: brightness(.2) blur(20px); + background-color: rgba(var(--primer-color-accent), .1); + -webkit-backdrop-filter: brightness(.2) blur(20px); + + @media (hover: hover) { + & { + fill: var(--color-accent); + } + + &.hovering { + display: initial; + } + } + } + } + } + + &.pgp { + gap: var(--padding); + display: flex; + padding: var(--padding); + position: relative; + max-width: 800px; + transform: rotate(-1.5deg); + text-align: center; + border-radius: 12px; + flex-direction: column; + background-color: rgba(var(--primer-color-accent), .15); + + > svg { + top: -30px; + fill: var(--color-accent); + right: -20px; + width: 60px; + position: absolute; + } + + > p { + padding: 0 var(--padding); + } + + .buttons { + gap: var(--padding); + display: flex; + margin-top: var(--padding); + flex-direction: column; + } + } + + &.form { + gap: var(--padding); + width: 100%; + display: flex; + flex-direction: column; + align-items: center; + + :is(input, textarea) { + color: black; + border: none; + outline: none; + padding: var(--padding); + min-width: 100%; + max-width: 100%; + border-radius: 4px; + } + + input { + height: calc(var(--running-size) - var(--padding)); + } + + textarea { + min-height: calc(var(--running-size) * 1.5); + } + + form { + display: contents; + + input-group { + gap: calc(var(--padding) / 2); + width: 100%; + display: flex; + flex-direction: column; + + label { + color: var(--color-accent); + } + } + } + + button { + width: 100%; + max-width: 500px; + } + } + + &.form-message { + gap: calc(var(--padding) / 2); + width: 100%; + color: black; + margin: var(--padding) 0; + display: flex; + padding: var(--padding); + flex-direction: column; + background-color: white; + + &.error { + color: white; + background-color: #ec4444; + + & + section.form { + display: none; + } + } + + &.sent { + background-color: var(--color-accent); + } + + h3 { + text-align: center; + } + + pre { + padding: var(--padding); + white-space: pre-wrap; + background-color: rgba(0, 0, 0, .15); + } + } } -/* ## Modifiers */ - -section.center { - text-align: center; -} - -/* ## Social */ - -section.social { - --icon-size: 60px; - - display: grid; - grid-template-columns: repeat(3, var(--icon-size)); - grid-template-rows: var(--icon-size); - align-items: center; - fill: white; - gap: var(--padding); -} - -section.social social { - transition: 200ms fill; - position: relative; -} - -/* ### Hover tooltip */ - -section.social social p { - display: none; - position: absolute; - top: 0; - left: 0; - transform: translate(0, 0); - background-color: rgba(var(--primer-color-accent), .1); - padding: 5px 10px; - white-space: nowrap; - pointer-events: none; - border-radius: 6px; - -webkit-backdrop-filter: brightness(.2) blur(20px); - backdrop-filter: brightness(.2) blur(20px); -} - -section.social social:hover { - fill: var(--color-accent); -} - -section.social social p.hovering { - display: initial; -} - -/* ## PGP key */ - -section.pgp { - max-width: 800px; - position: relative; - display: flex; - border-radius: 12px; - flex-direction: column; - gap: var(--padding); - text-align: center; - background-color: rgba(var(--primer-color-accent), .15); - padding: var(--padding); - transform: rotate(-1.5deg); -} - -section.pgp > svg { - position: absolute; - top: -30px; - right: -20px; - width: 60px; - fill: var(--color-accent); -} - -section.pgp > p { - padding: 0 var(--padding); -} - -section.pgp .buttons { - display: flex; - flex-direction: column; - margin-top: var(--padding); - gap: var(--padding); -} - -/* ## Blockquote */ - cite { text-decoration: underline; text-decoration-style: dotted; @@ -119,100 +192,17 @@ cite { } } -/* ## Contact form */ - -section.form :is(input, textarea) { - min-width: 100%; - max-width: 100%; - color: black; - padding: var(--padding); - border-radius: 4px; - border: none; - outline: none; -} - -section.form input { - height: calc(var(--running-size) - var(--padding)); -} - -section.form textarea { - min-height: calc(var(--running-size) * 1.5); -} - -section.form { - width: 100%; - display: flex; - flex-direction: column; - align-items: center; - gap: var(--padding); - width: 100%; -} - -section.form form { - display: contents; -} - -section.form input-group { - width: 100%; - display: flex; - flex-direction: column; - gap: calc(var(--padding) / 2); -} - -section.form input-group label { - color: var(--color-accent); -} - -section.form button { - width: 100%; - max-width: 500px; -} - -/* ### Contact form messages */ - -section.form-message { - width: 100%; - display: flex; - flex-direction: column; - gap: calc(var(--padding) / 2); - padding: var(--padding); - background-color: white; - margin: var(--padding) 0; - color: black; -} - -section.form-message h3 { - text-align: center; -} - -section.form-message pre { - white-space: pre-wrap; - padding: var(--padding); - background-color: rgba(0, 0, 0, .15); -} - -section.form-message.error { - background-color: #ec4444; - color: white; -} - -section.form-message.sent { - background-color: var(--color-accent); -} - -section.form-message.sent + section.form { - display: none; -} - /* # Size queries */ @media (min-width: 460px) { - section.pgp { - padding: calc(var(--padding) * 1.5); - } + section { + &.pgp { + padding: calc(var(--padding) * 1.5); - section.pgp .buttons { - flex-direction: row; - justify-content: center; + .buttons { + flex-direction: row; + justify-content: center; + } + } } } \ No newline at end of file diff --git a/assets/css/pages/error.css b/assets/css/pages/error.css index c3beedb..25d6edf 100644 --- a/assets/css/pages/error.css +++ b/assets/css/pages/error.css @@ -42,10 +42,6 @@ section.error h1 { opacity: .2; } -section.error h1 span { - -} - @keyframes rumble { to { transform: translateX(1px); } } \ No newline at end of file diff --git a/assets/css/pages/index.css b/assets/css/pages/index.css index d9836ca..10e1246 100644 --- a/assets/css/pages/index.css +++ b/assets/css/pages/index.css @@ -1,121 +1,140 @@ -/* # Overrides */ - -body[vv-top-page="/"]::before { - opacity: 0; -} - -/* # vv-shell styles */ - /* ## Picture */ vv-shell { display: flex; align-items: center; - justify-content: space-between; flex-direction: column-reverse; -} + justify-content: space-between; -vv-shell img { - margin: auto; - width: 25vh; - pointer-events: none; - -webkit-filter: hue-rotate(var(--hue-accent)); - filter: hue-rotate(var(--hue-accent)); + img { + width: 25vh; + margin: auto; + filter: hue-rotate(var(--hue-accent)); + pointer-events: none; + -webkit-filter: hue-rotate(var(--hue-accent)); + } } /* ## Menu */ .menu { width: 100%; - max-width: 300px; display: flex; + max-width: 300px; flex-direction: column; -} -.menu menu { - margin: var(--padding) 0; - list-style: none; - padding: unset; - text-align: right; - font-size: clamp(20px, 8vh, 60px); - font-weight: bold; - line-height: clamp(20px, 8vh, 60px); - color: var(--color-accent); -} + svg { + width: 100%; + animation: dash 1500ms linear infinite; + } -.menu menu li { - transition: 200ms opacity, 200ms color; -} + menu { + color: var(--color-accent); + margin: var(--padding) 0; + padding: unset; + font-size: clamp(20px, 8vh, 60px); + list-style: none; + text-align: right; + font-weight: bold; + line-height: clamp(20px, 8vh, 60px); -.menu svg { - width: 100%; - animation: dash 1500ms linear infinite; + @media (hover: hover) { + &:hover li { + opacity: .6; + } + } + + li { + transition: 200ms opacity, 200ms color; + + @media (hover: hover) { + /* enable font-weight hover animation */ + @media not (prefers-reduced-motion: reduce) { + & { + transition: 200ms opacity, 200ms color, 300ms font-weight; + } + } + + &:hover { + opacity: 1; + font-weight: 100; + text-shadow: 0 0 10px rgba(var(--primer-color-accent), .4); + } + } + } + } + + button { + border: unset; + padding: var(--padding) 0; + text-align: right; + + p { + &:first-of-type { + color: var(--color-accent); + } + } + + .email { + @media (hover: hover) { + &:hover { + background-color: transparent; + } + } + } + } } @keyframes dash { to { stroke-dashoffset: 32; } } -/* ### Copy email button */ - -.menu button { - text-align: right; - border: unset; - padding: var(--padding) 0; -} - -.menu button p:first-of-type { - color: var(--color-accent); -} - /* # Email-copied splash */ splash { --confetti: unset; --text-shadow: 0 0 30px black; - display: initial !important; - transition: 300ms opacity; - position: fixed; top: 50%; left: 50%; - transform: translate(-50%, -50%); - font-size: 80px; color: white; z-index: 200; + display: initial !important; + position: fixed; + font-size: 80px; + animation: splash-reveal 1s ease; + transform: translate(-50%, -50%); + transition: 300ms opacity; font-weight: 900; - pointer-events: none; perspective: 300px; - text-shadow: - var(--text-shadow), - var(--text-shadow), - var(--text-shadow), + text-shadow: + var(--text-shadow), + var(--text-shadow), + var(--text-shadow), var(--text-shadow) ; - animation: splash-reveal 1s ease; -} + pointer-events: none; -splash.hide { - opacity: 0; -} + &::after { + top: 50%; + left: 50%; + width: 8px; + height: 16px; + content: ""; + opacity: 0; + position: absolute; + animation: splash-confetti 1s ease; + box-shadow: var(--confetti); + background-color: transparent; + } -splash::after { - content: ""; - top: 50%; - left: 50%; - position: absolute; - width: 8px; - height: 16px; - background-color: transparent; - box-shadow: var(--confetti); - animation: splash-confetti 1s ease; - opacity: 0; + &.hide { + opacity: 0; + } } -/* ## Keyframes */ - @keyframes splash-confetti { - 0% { + 0% { transform: rotate(12deg) scale(0); opacity: 1; } @@ -124,7 +143,7 @@ splash::after { opacity: 1; } - 100% { + 100% { transform: rotate(-10deg) scale(1); opacity: 0; } @@ -138,37 +157,12 @@ splash::after { /* # Features */ -.cta::before { +.cta { content: "tap "; -} -@media (pointer: fine) { - .cta::before { - content: "click "; - } -} - -/* # Feature queries */ - -@media (hover: hover) { - .menu menu:hover li { - opacity: .6; - } - - .menu menu li:hover { - opacity: 1; - font-weight: 100; - text-shadow: 0 0 10px rgba(var(--primer-color-accent), .4); - } - - button.email:hover { - background-color: transparent; - } - - /* enable font-weight hover animation */ - @media not (prefers-reduced-motion: reduce) { - .menu menu li { - transition: 200ms opacity, 200ms color, 300ms font-weight; + @media (pointer: fine) { + &::before { + content: "click "; } } } @@ -182,7 +176,7 @@ splash::after { justify-items: center; align-items: center; } - + vv-shell img { width: 35vh; }