web theme: drop terminal leftovers (prompt hero, filename eyebrows, git command lines), make light buttons readable, remove unused assets

This commit is contained in:
Martin Dvořák 2026-09-30 12:22:15 +00:00
commit 7beb197f72
10 changed files with 129 additions and 105 deletions

View file

@ -72,7 +72,7 @@ more.
- **Fonts:** the web theme uses the system sans stack; Monocraft (self-hosted in `public/`) is - **Fonts:** the web theme uses the system sans stack; Monocraft (self-hosted in `public/`) is
used by the desktop theme's SMP menu and the in-desktop terminal. used by the desktop theme's SMP menu and the in-desktop terminal.
- **Images:** `next/image` - **Images:** `next/image`
- **Version:** `2.2.0` (see `package.json`) - **Version:** `2.2.1` (see `package.json`)
## 🚀 Running Locally ## 🚀 Running Locally

View file

@ -43,7 +43,7 @@ frosted-glass **web** site, and an alternate KDE/Plasma **desktop simulation**
utilities in the components (Tailwind is present via PostCSS but the look is utilities in the components (Tailwind is present via PostCSS but the look is
hand-written CSS). hand-written CSS).
- Path alias: `@/*` → `src/*`. - Path alias: `@/*` → `src/*`.
- Version: `2.2.0` (see `package.json`). - Version: `2.2.1` (see `package.json`).
### Scripts ### Scripts
```bash ```bash
@ -123,30 +123,44 @@ Themes: `web` = default frosted-glass website (sidebar + content, light/dark),
`skeuo` = KDE Plasma desktop simulation (desktop-only; the web sidebar's `skeuo` = KDE Plasma desktop simulation (desktop-only; the web sidebar's
"Desktop" control switches to it, and it has a "Web" control in its tray). "Desktop" control switches to it, and it has a "Web" control in its tray).
### Web theme + light/dark (v2.2.0 rework) ### Web theme + light/dark (v2.2 rework)
- `WebLayout.tsx` is the default shell. Layout is a **sticky sidebar** (brand, - `WebLayout.tsx` is the default shell. Layout is a **sticky sidebar** (brand,
section nav, light/dark switch, desktop switch, contact/clock) beside a single section nav, light/dark switch, desktop switch, contact/clock) beside a single
content column of `.glass` panels: hero (with a compact "Find me" socials row), content column of `.glass` panels: hero (with a compact "Find me" socials row),
a `.web-quick` 2-up (`now.txt` + `gym_sbd.db`), then services, activity, a `.web-quick` 2-up ("Right now" + "Gym PRs"), then services, activity,
projects, hardware, features (Revival/RustyWolf) and friends. Projects/hardware projects, hardware, features (Revival/RustyWolf) and friends. Projects/hardware
use a CSS multi-column **masonry** gallery (`.project-grid`) so short cards use a CSS multi-column **masonry** gallery (`.project-grid`) so short cards
don't leave half-empty grid slots. The old stacked TUI panel layout and the don't leave half-empty grid slots. The old stacked TUI panel layout and the
`SlBackground` ASCII train were removed with it. `SlBackground` ASCII train were removed with it.
- **Not a terminal.** The web theme deliberately has no TUI chrome: the hero is
a name + blurb (no `$ whoami` prompt, no blinking cursor), section eyebrows are
plain words (not `README.MD` / `TECH_LIST.JSON` filenames), and the activity
panel renders without the `martin@git…:~$ echo …` / `git log -n 3` command
lines. `ContributionHeatmap` takes `variant?: "terminal" | "web"` (default
`terminal`); `WebLayout` passes `variant="web"`, the desktop app keeps the
terminal look. Don't reintroduce command prompts in the web variant.
- **Grid gotcha:** the mobile column is `minmax(0, 1fr)`, never bare `1fr`. A - **Grid gotcha:** the mobile column is `minmax(0, 1fr)`, never bare `1fr`. A
`1fr` track has an automatic `min-content` floor, and with a wide child that `1fr` track has an automatic `min-content` floor, and with a wide child that
blew the single column out to ~2x the viewport (horizontal scroll + clipped blew the single column out to ~2x the viewport (horizontal scroll + clipped
content on phones). Keep the `minmax(0, …)`. content on phones). Keep the `minmax(0, …)`.
- Glassmorphism lives in one utility class, `.glass`, in `web.css`: a subtle - Glassmorphism lives in one utility class, `.glass`, in `web.css`: a subtle
`linear-gradient` over `--glass-hi`/`--glass-lo` with `linear-gradient` over `--glass-hi`/`--glass-lo` with
`backdrop-filter: blur(20px) saturate(165%)`. The page blobs behind the panels `backdrop-filter: blur(28px) saturate(180%)`. The page blobs behind the panels
are `.web-bg` (a fixed radial-gradient layer at `z-index: 0`; `.web-root` sits are `.web-bg` (a fixed radial-gradient layer at `z-index: 0`; `.web-root` sits
at `z-index: 1`). at `z-index: 1`).
- Interactive surfaces (`.web-ctl`, pills, `.service-button`, `.social-button`,
`.project-card`, `.gym-item`, `.contribution-entry`, `.heatmap-container`) read
the `--btn-bg` / `--btn-bg-hi` / `--btn-border` / `--btn-shadow` tokens with
the glass tokens as **fallbacks** (`var(--btn-bg, var(--glass-lo))`). The
tokens are only defined under `html[data-theme="web"]`, so the desktop theme
falls back to the old values and is unaffected. Light-mode buttons need the
extra opacity + a visible (dark, low-alpha) outline or they melt into the pale
background.
- Colours are tokenised in `web.css` under `:root` (light) and - Colours are tokenised in `web.css` under `:root` (light) and
`html[data-theme="web"][data-scheme="dark"]` (dark). The shared token names `html[data-theme="web"][data-scheme="dark"]` (dark). The shared token names
(`--fg`, `--gray`, `--accent`, `--green`, …) are reused so `ServiceButton` and (`--fg`, `--gray`, `--accent`, `--green`, …) are reused by `ServiceButton` and
`ContributionHeatmap` need no changes. `skeuo.css` overrides the same names `ContributionHeatmap`. `skeuo.css` overrides the same names while the desktop
while the desktop theme is active, so the two themes don't bleed into each theme is active, so the two themes don't bleed into each other.
other.
- The desktop switch (`.web-ctl-desktop`) is hidden on phones: under the - The desktop switch (`.web-ctl-desktop`) is hidden on phones: under the
`max-width: 960px` breakpoint and under `(hover: none) and (pointer: coarse)`. `max-width: 960px` breakpoint and under `(hover: none) and (pointer: coarse)`.
There is no device sniff anymore — phones just get the responsive web shell. There is no device sniff anymore — phones just get the responsive web shell.

4
package-lock.json generated
View file

@ -1,12 +1,12 @@
{ {
"name": "dvorakmortonxd", "name": "dvorakmortonxd",
"version": "2.2.0", "version": "2.2.1",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "dvorakmortonxd", "name": "dvorakmortonxd",
"version": "2.2.0", "version": "2.2.1",
"dependencies": { "dependencies": {
"next": "^16.3.5", "next": "^16.3.5",
"react": "^19.3.0", "react": "^19.3.0",

View file

@ -1,6 +1,6 @@
{ {
"name": "dvorakmortonxd", "name": "dvorakmortonxd",
"version": "2.2.0", "version": "2.2.1",
"private": true, "private": true,
"scripts": { "scripts": {
"dev": "node scripts/dev-server.mjs", "dev": "node scripts/dev-server.mjs",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 234 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 783 KiB

View file

@ -25,7 +25,8 @@ interface ActivityPayload {
}; };
} }
export default function ContributionHeatmap() { export default function ContributionHeatmap({ variant = "terminal" }: { variant?: "terminal" | "web" }) {
const isWeb = variant === "web";
const [weeks, setWeeks] = useState<{ date: string; contribs: number; level: number }[][]>([]); const [weeks, setWeeks] = useState<{ date: string; contribs: number; level: number }[][]>([]);
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const [error, setError] = useState(false); const [error, setError] = useState(false);
@ -123,11 +124,13 @@ export default function ContributionHeatmap() {
return ( return (
<div className="contribution-heatmap"> <div className="contribution-heatmap">
<div className="contribution-command-row"> {!isWeb && (
<div className="contribution-command"> <div className="contribution-command-row">
<span style={{ color: "var(--green)" }}>martin@git.dvorakmortonxd.dev</span>:<span style={{ color: "var(--gray)" }}>~</span>$ echo &#34;<span style={{ color: "var(--accent)" }}>{totalContribs}</span> contributions in the last year&#34; <div className="contribution-command">
<span style={{ color: "var(--green)" }}>martin@git.dvorakmortonxd.dev</span>:<span style={{ color: "var(--gray)" }}>~</span>$ echo &#34;<span style={{ color: "var(--accent)" }}>{totalContribs}</span> contributions in the last year&#34;
</div>
</div> </div>
</div> )}
<div className="contribution-total-title"> <div className="contribution-total-title">
<span style={{ color: "var(--accent)" }}>{totalContribs}</span> contributions in the last year <span style={{ color: "var(--accent)" }}>{totalContribs}</span> contributions in the last year
</div> </div>
@ -169,9 +172,13 @@ export default function ContributionHeatmap() {
{activities.length > 0 && ( {activities.length > 0 && (
<div className="contribution-log"> <div className="contribution-log">
<div className="contribution-command contribution-log-command"> {isWeb ? (
<span style={{ color: "var(--green)" }}>martin@git.dvorakmortonxd.dev</span>:<span style={{ color: "var(--gray)" }}>~</span>$ git log -n 3 <span style={{ color: "var(--gray)" }}>#displays my 3 latest contributions</span> <div className="contribution-log-title">Latest commits</div>
</div> ) : (
<div className="contribution-command contribution-log-command">
<span style={{ color: "var(--green)" }}>martin@git.dvorakmortonxd.dev</span>:<span style={{ color: "var(--gray)" }}>~</span>$ git log -n 3 <span style={{ color: "var(--gray)" }}>#displays my 3 latest contributions</span>
</div>
)}
{activities.map((act, idx) => { {activities.map((act, idx) => {
let msg = "No message"; let msg = "No message";
try { try {
@ -190,7 +197,7 @@ export default function ContributionHeatmap() {
return ( return (
<div key={idx} className="contribution-entry"> <div key={idx} className="contribution-entry">
<div className="contribution-entry-header"> <div className="contribution-entry-header">
<span className="contribution-repo">repo: {act.repo?.full_name || "unknown"}</span> <span className="contribution-repo">{isWeb ? "" : "repo: "}{act.repo?.full_name || "unknown"}</span>
<span className="contribution-date"> <span className="contribution-date">
{created.toLocaleDateString()}-{created.toLocaleTimeString()} {created.toLocaleDateString()}-{created.toLocaleTimeString()}
</span> </span>

View file

@ -228,12 +228,11 @@ export default function WebLayout() {
<main className="web-main"> <main className="web-main">
<header id="overview" className="web-hero glass"> <header id="overview" className="web-hero glass">
<span className="web-eyebrow">README.MD</span> <span className="web-eyebrow">About me</span>
<h1 className="web-title">$ whoami</h1> <h1 className="web-title">Martin Dvořák</h1>
<p className="web-lead"> <p className="web-lead">
Welcome to my personal website! Here I show off my projects and the hardware I Welcome to my personal website! Here I show off my projects and the hardware I
own, as well as my self-hosted services. own, as well as my self-hosted services.
<span className="cursor-blink" />
</p> </p>
<div className="web-hero-actions"> <div className="web-hero-actions">
<a className="web-pill" href="#projects"> <a className="web-pill" href="#projects">
@ -252,7 +251,7 @@ export default function WebLayout() {
<div className="web-quick"> <div className="web-quick">
<article id="now" className="web-tile glass"> <article id="now" className="web-tile glass">
<h3 className="web-tile-title">now.txt</h3> <h3 className="web-tile-title">Right now</h3>
<p className="web-tile-text"> <p className="web-tile-text">
I&#39;m currently hosting an SMP (dm me on discord). Also I&#39;m pretty much I&#39;m currently hosting an SMP (dm me on discord). Also I&#39;m pretty much
cooking daily, because im bulking through out the non-summer seasons. And me cooking daily, because im bulking through out the non-summer seasons. And me
@ -263,7 +262,7 @@ export default function WebLayout() {
</article> </article>
<article className="web-tile glass"> <article className="web-tile glass">
<h3 className="web-tile-title">gym_sbd.db</h3> <h3 className="web-tile-title">Gym PRs</h3>
<Gym /> <Gym />
<p className="web-tile-note">Current squat / bench / deadlift PRs at ~73kg BW.</p> <p className="web-tile-note">Current squat / bench / deadlift PRs at ~73kg BW.</p>
</article> </article>
@ -273,11 +272,11 @@ export default function WebLayout() {
<Services /> <Services />
</Section> </Section>
<Section id="activity" eyebrow="GITDXD.GIT" title="Contribution activity"> <Section id="activity" eyebrow="GitDXD" title="Contribution activity">
<ContributionHeatmap /> <ContributionHeatmap variant="web" />
</Section> </Section>
<Section id="projects" eyebrow="PROJECTS.DOCX" title="Things I've worked on"> <Section id="projects" eyebrow="Portfolio" title="Things I've worked on">
<div className="project-grid"> <div className="project-grid">
{codingProjects.map((project, idx) => ( {codingProjects.map((project, idx) => (
<a <a
@ -298,7 +297,7 @@ export default function WebLayout() {
</div> </div>
</Section> </Section>
<Section id="hardware" eyebrow="TECH_LIST.JSON" title="Hardware I own"> <Section id="hardware" eyebrow="My gear" title="Hardware I own">
<div className="project-grid"> <div className="project-grid">
{techProjects.map((project) => ( {techProjects.map((project) => (
<div key={project.title} className="project-card"> <div key={project.title} className="project-card">
@ -330,7 +329,7 @@ export default function WebLayout() {
</p> </p>
</Section> </Section>
<Section eyebrow="RUSTYWOLF.RS" title="Introducing RustyWolf" className="web-feature"> <Section eyebrow="RustyWolf" title="Introducing RustyWolf" className="web-feature">
<FeatureShot <FeatureShot
src="/RustyWolfPreview.webp" src="/RustyWolfPreview.webp"
alt="RustyWolf Browser Preview" alt="RustyWolf Browser Preview"
@ -347,7 +346,7 @@ export default function WebLayout() {
</Section> </Section>
</div> </div>
<Section id="friends" eyebrow="FRIENDS.TSX" title="Friend's websites and projects"> <Section id="friends" eyebrow="Links" title="Friend's websites and projects">
<div className="services-buttons"> <div className="services-buttons">
{friends.map((friend, idx) => ( {friends.map((friend, idx) => (
<ServiceButton <ServiceButton
@ -372,7 +371,7 @@ export default function WebLayout() {
</Section> </Section>
<footer className="web-footer glass"> <footer className="web-footer glass">
<span className="web-footer-label">v2.2.0</span> <span className="web-footer-label">v2.2.1</span>
© 2025-2026 Martin Dvořák. All rights reserved (not really I dont care, just © 2025-2026 Martin Dvořák. All rights reserved (not really I dont care, just
follow the GPL3.0 License) follow the GPL3.0 License)
</footer> </footer>

View file

@ -1,5 +1,27 @@
@import "tailwindcss"; @import "tailwindcss";
/* Monocraft is the desktop theme's pixel font (SMP menu + in-desktop terminal).
It is declared globally because the desktop shell is mounting/unmounting
alongside the web shell. */
@font-face {
font-family: "Monocraft";
src: url("/Monocraft.ttf") format("truetype");
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: "Monocraft";
src: url("/Monocraft-Bold.ttf") format("truetype");
font-weight: bold;
font-style: normal;
}
@font-face {
font-family: "Monocraft";
src: url("/Monocraft-Italic.ttf") format("truetype");
font-weight: normal;
font-style: italic;
}
:root { :root {
--background: #1d2021; --background: #1d2021;
--foreground: #ebdbb2; --foreground: #ebdbb2;

View file

@ -1,29 +1,3 @@
/* ============================================================
FONT FACES
------------------------------------------------------------
Monocraft is no longer the web theme's font, but it is still
used by the desktop theme's Minecraft-style SMP menu and the
in-desktop terminal, so the faces stay registered here.
============================================================ */
@font-face {
font-family: "Monocraft";
src: url("/Monocraft.ttf") format("truetype");
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: "Monocraft";
src: url("/Monocraft-Bold.ttf") format("truetype");
font-weight: bold;
font-style: normal;
}
@font-face {
font-family: "Monocraft";
src: url("/Monocraft-Italic.ttf") format("truetype");
font-weight: normal;
font-style: italic;
}
/* ============================================================ /* ============================================================
WEB THEME — light frosted-glass website shell. WEB THEME — light frosted-glass website shell.
------------------------------------------------------------ ------------------------------------------------------------
@ -95,6 +69,11 @@ html[data-theme="web"][data-scheme="dark"] {
--blob-c: rgba(236, 72, 153, 0.18); --blob-c: rgba(236, 72, 153, 0.18);
--blob-d: rgba(45, 212, 191, 0.16); --blob-d: rgba(45, 212, 191, 0.16);
--btn-bg: rgba(255, 255, 255, 0.06);
--btn-bg-hi: rgba(255, 255, 255, 0.12);
--btn-border: rgba(255, 255, 255, 0.16);
--btn-shadow: 0 10px 24px -14px rgba(0, 0, 0, 0.9);
--bg-hard: rgba(255, 255, 255, 0.08); --bg-hard: rgba(255, 255, 255, 0.08);
--green: #34d399; --green: #34d399;
--aqua: #2dd4bf; --aqua: #2dd4bf;
@ -106,6 +85,15 @@ html[data-theme="web"][data-scheme="dark"] {
html[data-theme="web"] { html[data-theme="web"] {
scroll-behavior: smooth; scroll-behavior: smooth;
/* Interactive surfaces (buttons, cards, chips). Kept a step more opaque and
more clearly outlined than the glass panels, so they don't melt into the
light background. The base rules read these with the old glass tokens as
fallbacks, which keeps the desktop theme untouched. */
--btn-bg: rgba(255, 255, 255, 0.62);
--btn-bg-hi: rgba(255, 255, 255, 0.92);
--btn-border: rgba(20, 28, 52, 0.14);
--btn-shadow: 0 8px 20px -12px rgba(23, 32, 60, 0.45);
} }
html[data-theme="web"] body { html[data-theme="web"] body {
@ -261,8 +249,9 @@ html[data-theme="web"] body {
gap: 10px; gap: 10px;
padding: 9px 12px; padding: 9px 12px;
border-radius: 12px; border-radius: 12px;
border: 1px solid var(--glass-border); border: 1px solid var(--btn-border, var(--glass-border));
background: var(--glass-lo); background: var(--btn-bg, var(--glass-lo));
box-shadow: var(--btn-shadow, none);
color: var(--fg); color: var(--fg);
font: inherit; font: inherit;
font-size: 0.82rem; font-size: 0.82rem;
@ -272,7 +261,7 @@ html[data-theme="web"] body {
} }
.web-ctl:hover { .web-ctl:hover {
border-color: var(--accent-line); border-color: var(--accent-line);
background: var(--glass-hi); background: var(--btn-bg-hi, var(--glass-hi));
box-shadow: 0 0 0 1px var(--accent-soft); box-shadow: 0 0 0 1px var(--accent-soft);
} }
.web-ctl-icon { .web-ctl-icon {
@ -290,7 +279,7 @@ html[data-theme="web"] body {
height: 20px; height: 20px;
border-radius: 999px; border-radius: 999px;
background: var(--bg-hard); background: var(--bg-hard);
border: 1px solid var(--glass-border); border: 1px solid var(--btn-border, var(--glass-border));
transition: background-color 0.2s ease, border-color 0.2s ease; transition: background-color 0.2s ease, border-color 0.2s ease;
flex-shrink: 0; flex-shrink: 0;
} }
@ -385,13 +374,13 @@ html[data-theme="web"] body {
box-shadow: 0 16px 30px -12px var(--accent); box-shadow: 0 16px 30px -12px var(--accent);
} }
.web-pill.ghost { .web-pill.ghost {
background: var(--glass-lo); background: var(--btn-bg, var(--glass-lo));
color: var(--fg); color: var(--fg);
border: 1px solid var(--glass-border); border: 1px solid var(--btn-border, var(--glass-border));
box-shadow: none; box-shadow: var(--btn-shadow, none);
} }
.web-pill.ghost:hover { .web-pill.ghost:hover {
background: var(--glass-hi); background: var(--btn-bg-hi, var(--glass-hi));
border-color: var(--accent-line); border-color: var(--accent-line);
} }
@ -514,8 +503,9 @@ html[data-theme="web"] body {
gap: 12px; gap: 12px;
padding: 14px 16px; padding: 14px 16px;
border-radius: 16px; border-radius: 16px;
border: 1px solid var(--glass-border); border: 1px solid var(--btn-border, var(--glass-border));
background: var(--glass-lo); background: var(--btn-bg, var(--glass-lo));
box-shadow: var(--btn-shadow, none);
color: var(--fg); color: var(--fg);
text-decoration: none; text-decoration: none;
min-width: 0; min-width: 0;
@ -525,7 +515,7 @@ html[data-theme="web"] body {
.service-button:hover { .service-button:hover {
transform: translateY(-3px); transform: translateY(-3px);
border-color: var(--accent-line); border-color: var(--accent-line);
background: var(--glass-hi); background: var(--btn-bg-hi, var(--glass-hi));
box-shadow: 0 18px 34px -18px rgba(23, 32, 60, 0.5), 0 0 0 1px var(--accent-soft); box-shadow: 0 18px 34px -18px rgba(23, 32, 60, 0.5), 0 0 0 1px var(--accent-soft);
} }
.service-button.disabled { .service-button.disabled {
@ -533,9 +523,9 @@ html[data-theme="web"] body {
} }
.service-button.disabled:hover { .service-button.disabled:hover {
transform: none; transform: none;
border-color: var(--glass-border); border-color: var(--btn-border, var(--glass-border));
background: var(--glass-lo); background: var(--btn-bg, var(--glass-lo));
box-shadow: none; box-shadow: var(--btn-shadow, none);
} }
.service-button.disabled:hover .service-icon { .service-button.disabled:hover .service-icon {
transform: none; transform: none;
@ -651,8 +641,9 @@ html[data-theme="web"][data-scheme="dark"] .friend-icon {
margin-bottom: 14px; margin-bottom: 14px;
padding: 12px; padding: 12px;
border-radius: 16px; border-radius: 16px;
border: 1px solid var(--glass-border); border: 1px solid var(--btn-border, var(--glass-border));
background: var(--glass-lo); background: var(--btn-bg, var(--glass-lo));
box-shadow: var(--btn-shadow, none);
color: inherit; color: inherit;
text-decoration: none; text-decoration: none;
transition: transform 0.22s ease, border-color 0.22s ease, box-shadow 0.22s ease, transition: transform 0.22s ease, border-color 0.22s ease, box-shadow 0.22s ease,
@ -661,7 +652,7 @@ html[data-theme="web"][data-scheme="dark"] .friend-icon {
.project-card:hover { .project-card:hover {
transform: translateY(-4px); transform: translateY(-4px);
border-color: var(--accent-line); border-color: var(--accent-line);
background: var(--glass-hi); background: var(--btn-bg-hi, var(--glass-hi));
box-shadow: 0 20px 38px -20px rgba(23, 32, 60, 0.55); box-shadow: 0 20px 38px -20px rgba(23, 32, 60, 0.55);
} }
.project-image { .project-image {
@ -701,8 +692,9 @@ html[data-theme="web"][data-scheme="dark"] .friend-icon {
gap: 9px; gap: 9px;
padding: 9px 12px; padding: 9px 12px;
border-radius: 12px; border-radius: 12px;
border: 1px solid transparent; border: 1px solid var(--btn-border, transparent);
background: var(--glass-lo); background: var(--btn-bg, var(--glass-lo));
box-shadow: var(--btn-shadow, none);
color: var(--fg); color: var(--fg);
font-size: 0.82rem; font-size: 0.82rem;
font-weight: 550; font-weight: 550;
@ -711,8 +703,8 @@ html[data-theme="web"][data-scheme="dark"] .friend-icon {
} }
.social-button:hover { .social-button:hover {
transform: translateY(-2px); transform: translateY(-2px);
background: var(--glass-hi); background: var(--btn-bg-hi, var(--glass-hi));
border-color: var(--glass-border); border-color: var(--btn-border, var(--glass-border));
color: var(--accent); color: var(--accent);
} }
.social-icon { .social-icon {
@ -750,8 +742,9 @@ html[data-theme="web"][data-scheme="dark"] .social-icon {
gap: 6px; gap: 6px;
padding: 12px 8px; padding: 12px 8px;
border-radius: 14px; border-radius: 14px;
border: 1px solid var(--glass-border); border: 1px solid var(--btn-border, var(--glass-border));
background: var(--glass-lo); background: var(--btn-bg, var(--glass-lo));
box-shadow: var(--btn-shadow, none);
text-align: center; text-align: center;
transition: border-color 0.18s ease, transform 0.18s ease; transition: border-color 0.18s ease, transform 0.18s ease;
} }
@ -806,9 +799,9 @@ html[data-theme="web"][data-scheme="dark"] .social-icon {
display: flex; display: flex;
gap: 3px; gap: 3px;
padding: 6px; padding: 6px;
border: 1px solid var(--glass-border); border: 1px solid var(--btn-border, var(--glass-border));
border-radius: 14px; border-radius: 14px;
background: var(--glass-lo); background: var(--btn-bg, var(--glass-lo));
overflow-x: auto; overflow-x: auto;
scrollbar-width: none; scrollbar-width: none;
} }
@ -912,6 +905,13 @@ html[data-theme="web"][data-scheme="dark"] .heatmap-legend-cell[data-level="4"]
min-width: 0; min-width: 0;
margin-top: 4px; margin-top: 4px;
} }
.contribution-log-title {
font-size: 0.68rem;
font-weight: 700;
letter-spacing: 0.14em;
text-transform: uppercase;
color: var(--web-muted);
}
.contribution-entry { .contribution-entry {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -919,8 +919,9 @@ html[data-theme="web"][data-scheme="dark"] .heatmap-legend-cell[data-level="4"]
min-width: 0; min-width: 0;
padding: 10px 12px; padding: 10px 12px;
border-radius: 12px; border-radius: 12px;
border: 1px solid var(--glass-border); border: 1px solid var(--btn-border, var(--glass-border));
background: var(--glass-lo); background: var(--btn-bg, var(--glass-lo));
box-shadow: var(--btn-shadow, none);
font-size: 0.78rem; font-size: 0.78rem;
} }
.contribution-entry-header { .contribution-entry-header {
@ -982,25 +983,6 @@ html[data-theme="web"][data-scheme="dark"] .heatmap-legend-cell[data-level="4"]
/* ============================================================ /* ============================================================
SHARED BITS SHARED BITS
============================================================ */ ============================================================ */
.cursor-blink {
display: inline-block;
width: 7px;
height: 1.05em;
margin-left: 4px;
vertical-align: text-bottom;
background: var(--accent);
animation: cursorBlink 1s step-end infinite;
}
@keyframes cursorBlink {
0%,
100% {
opacity: 1;
}
50% {
opacity: 0;
}
}
.joker-flash-overlay { .joker-flash-overlay {
position: fixed; position: fixed;
inset: 0; inset: 0;