272 lines
8.0 KiB
CSS
272 lines
8.0 KiB
CSS
:root {
|
|
--bg: #0d0d0d;
|
|
--fg: #e8e8e8;
|
|
--muted: #888;
|
|
--line: #262626;
|
|
--field: #161616;
|
|
}
|
|
* { box-sizing: border-box; }
|
|
body {
|
|
margin-inline: auto;
|
|
max-width: 680px;
|
|
padding: 2rem 1.25rem;
|
|
background: var(--bg);
|
|
color: var(--fg);
|
|
font: 16px/1.6 ui-monospace, "JetBrains Mono", Menlo, monospace;
|
|
}
|
|
a { color: var(--fg); text-decoration: none; border-bottom: 1px solid var(--muted); }
|
|
a:hover { border-color: var(--fg); }
|
|
|
|
header nav {
|
|
display: flex;
|
|
gap: 1rem;
|
|
margin-bottom: 2rem;
|
|
padding-bottom: 1rem;
|
|
border-bottom: 1px solid var(--line);
|
|
}
|
|
h1 { font-size: 1.6rem; }
|
|
h1 .phonetic { color: darkgrey; font-size: 1rem; font-weight: normal; }
|
|
h2 { font-size: 1.1rem; color: var(--muted); font-weight: normal; }
|
|
footer {
|
|
margin-top: 3rem;
|
|
padding-top: 1rem;
|
|
border-top: 1px solid var(--line);
|
|
color: var(--muted);
|
|
}
|
|
.buttons88x31 {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: .4rem;
|
|
margin-bottom: .8rem;
|
|
}
|
|
.buttons88x31 a { border-bottom: none; }
|
|
.buttons88x31 img {
|
|
width: 88px;
|
|
height: 31px;
|
|
image-rendering: pixelated;
|
|
display: block;
|
|
}
|
|
|
|
.dot {
|
|
display: inline-block;
|
|
width: .6em; height: .6em;
|
|
border-radius: 50%;
|
|
background: var(--muted);
|
|
vertical-align: middle;
|
|
}
|
|
.dot-online { background: #3ba55d; }
|
|
.dot-idle { background: #faa61a; }
|
|
.dot-dnd { background: #ed4245; }
|
|
.dot-offline { background: #747f8d; }
|
|
|
|
.status-row {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
align-items: stretch;
|
|
gap: .6rem;
|
|
}
|
|
.status-card {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: .8rem;
|
|
padding: .8rem;
|
|
flex: 1 1 220px;
|
|
min-width: 0;
|
|
border: 1px solid var(--line);
|
|
border-radius: 4px;
|
|
background-size: cover;
|
|
background-position: center;
|
|
}
|
|
.status-card .avatar { border-radius: 4px; flex: none; }
|
|
.status-card .who { display: flex; flex-direction: column; gap: .15rem; }
|
|
.status-card .name { font-weight: bold; }
|
|
.status-card .state { color: var(--muted); font-size: .9rem; }
|
|
|
|
.spotify-card {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: .8rem;
|
|
padding: .7rem;
|
|
flex: 1 1 220px;
|
|
min-width: 0;
|
|
border: 1px solid var(--line);
|
|
border-radius: 4px;
|
|
color: var(--fg);
|
|
}
|
|
a.spotify-card:hover { border-color: #1db954; }
|
|
.spotify-card .album-art { border-radius: 4px; flex: none; }
|
|
.spotify-card .album-art--empty {
|
|
width: 64px; height: 64px;
|
|
display: flex; align-items: center; justify-content: center;
|
|
background: var(--field);
|
|
color: var(--muted);
|
|
font-size: 1.5rem;
|
|
}
|
|
|
|
.np-label { font-size: .72rem; letter-spacing: .02em; }
|
|
.spotify-card .np-label { color: #1db954; }
|
|
.spotify-idle .np-label { color: var(--muted); }
|
|
.dc-label { color: #5865f2; }
|
|
.spotify-card .track { display: flex; flex-direction: column; gap: .1rem; min-width: 0; }
|
|
.spotify-card .np-label { color: #1db954; font-size: .72rem; letter-spacing: .02em; }
|
|
.spotify-card .song { font-weight: bold; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
.spotify-card .artist { color: var(--muted); font-size: .85rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
|
|
form { display: flex; flex-direction: column; gap: .5rem; margin: 1.5rem 0; }
|
|
input, textarea {
|
|
background: var(--field);
|
|
border: 1px solid var(--line);
|
|
color: var(--fg);
|
|
padding: .6rem;
|
|
font: inherit;
|
|
border-radius: 4px;
|
|
}
|
|
textarea { min-height: 5rem; resize: vertical; }
|
|
button {
|
|
align-self: flex-start;
|
|
background: var(--fg);
|
|
color: var(--bg);
|
|
border: 0;
|
|
padding: .5rem 1.2rem;
|
|
font: inherit;
|
|
cursor: pointer;
|
|
border-radius: 4px;
|
|
}
|
|
.entry { border-top: 1px solid var(--line); padding: .8rem 0; }
|
|
.entry .date { color: var(--muted); font-size: .8rem; margin-left: .5rem; }
|
|
.entry p { margin: .3rem 0 0; }
|
|
|
|
.muted { color: var(--muted); }
|
|
|
|
/* post list (home widget + /blog) */
|
|
.posts-widget { margin: 2rem 0; }
|
|
.post-list { list-style: none; padding: 0; margin: 1rem 0; }
|
|
.post-list li {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: baseline;
|
|
gap: 1rem;
|
|
padding: .6rem 0;
|
|
border-top: 1px solid var(--line);
|
|
}
|
|
.post-list .date { color: var(--muted); font-size: .85rem; white-space: nowrap; }
|
|
|
|
/* single post */
|
|
.back-link { margin: .5rem 0; }
|
|
.back-link a { border-bottom: none; color: var(--muted); }
|
|
.back-link a:hover { color: var(--fg); }
|
|
.post-title { margin-bottom: .2rem; }
|
|
.post-meta { color: var(--muted); font-size: .85rem; margin-bottom: 1.5rem; }
|
|
.post-body img {
|
|
max-width: 100%;
|
|
height: auto;
|
|
display: block;
|
|
margin: 1.5rem 0;
|
|
border-radius: 4px;
|
|
}
|
|
.post-body h1, .post-body h2, .post-body h3 { margin: 1.8rem 0 .6rem; }
|
|
.post-body h2 { color: var(--fg); font-size: 1.2rem; }
|
|
.post-body pre {
|
|
background: var(--field);
|
|
border: 1px solid var(--line);
|
|
border-radius: 4px;
|
|
padding: .8rem;
|
|
overflow-x: auto;
|
|
}
|
|
.post-body code {
|
|
background: var(--field);
|
|
padding: .1rem .3rem;
|
|
border-radius: 3px;
|
|
font-size: .9em;
|
|
}
|
|
.post-body pre code { background: none; padding: 0; }
|
|
.post-body blockquote {
|
|
border-left: 3px solid var(--line);
|
|
margin: 1rem 0;
|
|
padding-left: 1rem;
|
|
color: var(--muted);
|
|
}
|
|
|
|
/* ── sky ────────────────────────────────────────────────────────────────
|
|
Generated, not photographed. tools/background.py renders every style into
|
|
img/bg/; inc/header.php enumerates that directory and emits one custom
|
|
property per style, so --bg-img follows html[data-bg]. Only the matching
|
|
rule's url() is fetched. Each is Bayer ordered-dithered to a few grey
|
|
levels and upscaled with pixelated rendering so the cells stay crunchy.
|
|
Regenerate everything: python tools/background.py all */
|
|
:root {
|
|
--bg: #060606;
|
|
/* opacity of the text-column scrim; raise for busier background styles */
|
|
--scrim: .82;
|
|
}
|
|
|
|
body { position: relative; }
|
|
|
|
/* background layer */
|
|
body::before {
|
|
content: "";
|
|
position: fixed;
|
|
inset: 0;
|
|
z-index: -2;
|
|
background: #060606 var(--bg-img) center center / cover no-repeat;
|
|
image-rendering: pixelated;
|
|
}
|
|
|
|
/* Readability scrim + diagonal hatch.
|
|
The first layer is a feathered vertical band, ~880px wide and centred on
|
|
the 680px text column, sitting above the artwork (z-index -2) but below
|
|
the content. It gives every background style a consistent dark bed to
|
|
read against instead of relying on each one being quiet in the middle,
|
|
and because the edges fade out there is no visible panel or card. */
|
|
body::after {
|
|
content: "";
|
|
position: fixed;
|
|
inset: 0;
|
|
z-index: -1;
|
|
pointer-events: none;
|
|
background:
|
|
linear-gradient(90deg,
|
|
transparent 0%,
|
|
rgba(4, 4, 4, var(--scrim)) 14%,
|
|
rgba(4, 4, 4, var(--scrim)) 86%,
|
|
transparent 100%),
|
|
radial-gradient(ellipse 70% 60% at 50% 38%, rgba(4, 4, 4, .32), transparent 82%),
|
|
repeating-linear-gradient(-45deg, rgba(240, 240, 240, .045) 0 1px, transparent 1px 8px);
|
|
background-size: 880px 100%, auto, auto;
|
|
background-position: center top, center, center;
|
|
background-repeat: no-repeat, no-repeat, repeat;
|
|
}
|
|
|
|
/* cards sat on flat #161616 before; let the sky read through them */
|
|
.status-card,
|
|
.spotify-card,
|
|
.post-body pre { background-color: rgba(6, 6, 6, .66); }
|
|
input, textarea { background: rgba(6, 6, 6, .66); }
|
|
|
|
/* guestbook sign button */
|
|
.btn-sign {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: .5rem;
|
|
background: var(--fg);
|
|
color: var(--bg);
|
|
border: 1px solid var(--fg);
|
|
padding: .5rem 1.4rem;
|
|
border-radius: 4px;
|
|
font: inherit;
|
|
cursor: pointer;
|
|
transition: background .12s ease, color .12s ease, transform .08s ease;
|
|
}
|
|
.btn-sign .arrow { transition: transform .15s ease; }
|
|
.btn-sign:hover:not(:disabled) { background: transparent; color: var(--fg); }
|
|
.btn-sign:hover:not(:disabled) .arrow { transform: translateX(3px); }
|
|
.btn-sign:active:not(:disabled) { transform: translateY(1px); }
|
|
.btn-sign:focus-visible { outline: 2px solid var(--muted); outline-offset: 2px; }
|
|
.btn-sign:disabled { opacity: .55; cursor: progress; }
|
|
|
|
/* htmx swaps the label while the request is in flight */
|
|
.btn-sign .pending { display: none; }
|
|
.btn-sign.htmx-request .idle { display: none; }
|
|
.btn-sign.htmx-request .pending { display: inline; }
|
|
.btn-sign.htmx-request .arrow { display: none; }
|