Files
gerbeur/src/themes/geocities.css
khannurien 85d0703077 v3: the editors stop fighting the person typing — a review of every edit box turned up an Enter that sent a chat message mid-IME, an emoji picker that grabbed focus on ":D" and never went away, markdown that folded every line break, and limits that were counted but not kept. TextEditor: an Enter confirming an IME candidate no longer also sends, saves or picks. The : trigger wants two letters (Unicode ones too), not one, so emoticons, "note:" and "12:30" type through, and it keeps focus in the textarea — the picker's search follows what's typed, Enter or Tab takes the best match (a name equal to the query, then one starting with it, rather than frimousse's first in emoji order, which made ":rocket" an astronaut), the arrows step into the grid and typing there carries on in the textarea, and Escape closes just the picker, not the chat around it. It closes on a press outside, which it never did, and neither autocomplete fires inside code or a ``` fence. A ☺ button in each editor's corner opens the picker for mouse users, with a skin-tone selector that's remembered, and its search takes focus only once the picker is placed (a hidden field can't). Emoji, mentions and pasted images go in through execCommand, so Ctrl+Z takes back the insertion instead of wrecking the undo stack. Uploading an image made the textarea disabled, which dropped focus for good; it's read-only now, says "Uploading image…" under the box rather than only in an empty one's placeholder, reports a failed upload instead of swallowing it, and holds Enter until it's done. Any dropped file is caught — a non-image used to be opened by the browser in place of the page, draft and all — and a paste carrying text (a spreadsheet's cells come with a picture of themselves) pastes the text. The mention list follows the caret (a stale lookup can't close a newer one, lookups abort), wraps, scrolls its selection into view, closes on blur, and is a real listbox with aria-activedescendant. The counter shows from 80% of the limit by default rather than a standing "0 / 5000". Limits: chat Send and edit Save refused nothing over 2000 and let the server bounce it; they're disabled past it now. RichTextField's bare maxLength rule failed without a message, so an over-long "Why?" made Save do nothing and say nothing; it says so now. Inline editors answer Escape through a new onCancel (comment reply and edit, profile description, playlist description and title), the playlist editor takes Ctrl+Enter and can't be saved without a title, and saving a comment unchanged no longer stamps it edited. Markdown: a single newline is a line break, so a message written over three lines stops reading as one; links into the app route in place instead of opening a tab; headings are sized for prose instead of 2em page titles, and dropped from card teasers; GFM tables scroll in their own box and task lists lose the bullet; images load lazily. A chat message of only an emoji or three is shown large. Themes: brutalist and geocities give the new buttons no chrome, and geocities' ghost-button list, split in two by the placeholder-thumbnail rules in 1cb904d, is whole again, so its modal ✕, emoji cells and the picker's ✕ are flat as intended.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 10:24:30 +00:00

467 lines
18 KiB
CSS

/* ══════════════════════════════════════════════════════════════════════
GeoCities / NeoCities theme — turn-of-the-millennium personal-homepage
maximalism: tiled starfield wallpaper, Comic Sans, ridged 3D boxes,
clashing neon accents, rainbow dividers, blinking badges.
Dark scheme → NeoCities "neon on black" revival.
Light scheme → classic GeoCities pastel-on-wallpaper.
══════════════════════════════════════════════════════════════════════ */
/* ── Palette (light-dark: see tokens.css) ─────────────────────────── */
:root[data-style="geocities"] {
/* Square corners everywhere App.css uses the radius scale. */
--radius-xs: 0;
--radius-sm: 0;
--radius-md: 0;
--radius-lg: 0;
--radius-xl: 0;
--radius-full: 0;
--color-text: light-dark(#2a1a4e, #f2f0ff);
--color-text-secondary: light-dark(#aa00aa, #7fdbff);
--color-text-muted: light-dark(#7a6a9a, #a99ad6);
--color-on-accent: light-dark(#ffffff, #000000);
--color-bg: light-dark(#fff0f8, #0a0a2e);
--color-surface: light-dark(#ffffff, #1b1b46);
--color-border: light-dark(#d000d0, #00ffff);
--color-border-subtle: light-dark(rgba(208, 0, 208, 0.25), rgba(0, 255, 255, 0.28));
--color-accent: light-dark(#d000d0, #ff00ff);
--color-accent-hover: light-dark(#a000a0, #ff5cff);
--color-link: light-dark(#0000ee, #00ffff);
--color-link-hover: light-dark(#551a8b, #ffff00);
--color-danger: light-dark(#cc0033, #ff3860);
--color-danger-bg: light-dark(#ffe0e8, #3a0a1a);
--color-danger-hover: light-dark(#990022, #ff6b8a);
--color-success: light-dark(#008800, #39ff14);
--color-success-bg: light-dark(#e0ffe0, #0a2e0a);
--color-success-hover: light-dark(#006600, #6fff52);
--color-overlay: light-dark(rgba(40, 0, 40, 0.4), rgba(8, 0, 28, 0.72));
--color-header-user-bg: light-dark(rgba(208, 0, 208, 0.08), rgba(0, 255, 255, 0.1));
--color-header-user-bg-hover: light-dark(rgba(208, 0, 208, 0.16), rgba(0, 255, 255, 0.2));
--color-option-bg: light-dark(#fff0fb, #14143a);
--color-option-border: light-dark(#d000d0, #00ffff);
--geo-rainbow: linear-gradient(
90deg,
#ff004d,
#ff8a00,
#ffee00,
#00d11a,
#00b3ff,
#b300ff
);
--geo-pattern: radial-gradient(1px 1px at 20px 30px, #ffffff, transparent),
radial-gradient(1px 1px at 130px 80px, #ffffff, transparent),
radial-gradient(1.5px 1.5px at 80px 150px, #00ffff, transparent),
radial-gradient(1.5px 1.5px at 170px 40px, #ff00ff, transparent),
radial-gradient(1px 1px at 50px 190px, #ffee00, transparent);
--geo-pattern-size: 200px 200px;
}
/* Non-colour values can't go through light-dark(), so the light variants
of these still need their own scheme selectors. */
@media (prefers-color-scheme: light) {
:root[data-style="geocities"]:not([data-color-scheme]) {
--geo-rainbow: linear-gradient(
90deg,
#ff004d,
#ff8a00,
#ffcc00,
#00aa1a,
#0077dd,
#8800cc
);
--geo-pattern: radial-gradient(rgba(208, 0, 208, 0.16) 1.5px, transparent 1.5px),
radial-gradient(rgba(0, 179, 255, 0.14) 1.5px, transparent 1.5px);
--geo-pattern-size: 22px 22px, 22px 22px;
}
}
:root[data-style="geocities"][data-color-scheme="light"] {
--geo-rainbow: linear-gradient(
90deg,
#ff004d,
#ff8a00,
#ffcc00,
#00aa1a,
#0077dd,
#8800cc
);
--geo-pattern: radial-gradient(rgba(208, 0, 208, 0.16) 1.5px, transparent 1.5px),
radial-gradient(rgba(0, 179, 255, 0.14) 1.5px, transparent 1.5px);
--geo-pattern-size: 22px 22px, 22px 22px;
}
/* ══════════════════════════════════════════════════════════════════════
Structural overrides
══════════════════════════════════════════════════════════════════════ */
/* ── Typography — the one true homepage font ──────────────────────── */
[data-style="geocities"] {
--font-body: "Comic Sans MS", "Comic Sans", "Chalkboard SE", "Comic Neue",
"Marker Felt", cursive;
font-family: var(--font-body);
font-weight: 400;
}
/* ── Tiled wallpaper, fixed so content scrolls over it ────────────── */
[data-style="geocities"] body {
background-color: var(--color-bg);
background-image: var(--geo-pattern);
background-size: var(--geo-pattern-size);
background-attachment: fixed;
}
/* ── Loud headings with a soft glow ──────────────────────────────── */
[data-style="geocities"] h1,
[data-style="geocities"] .app-header-brand {
font-weight: 700;
letter-spacing: 0.02em;
text-shadow: 0 0 6px color-mix(in srgb, var(--color-accent) 60%, transparent);
}
/* ── Links — always underlined, bold ─────────────────────────────── */
[data-style="geocities"] a,
[data-style="geocities"] .md a {
text-decoration: underline;
font-weight: 700;
}
/* …except navigation chrome and avatar links, which aren't prose. */
[data-style="geocities"] a:has(.avatar-img),
[data-style="geocities"] a:has(.avatar-initials),
[data-style="geocities"] .index-presence-avatar,
[data-style="geocities"] .app-header-brand,
[data-style="geocities"] .app-header-user,
[data-style="geocities"] .nav-search-btn,
[data-style="geocities"] .user-menu-item,
[data-style="geocities"] .user-list-popover-item {
text-decoration: none;
}
/* ── Blink + marquee-ish keyframes ───────────────────────────────── */
@keyframes geo-blink {
50% {
opacity: 0;
}
}
/* ── Buttons — chunky Win95 outset bevel, press = inset ──────────── */
/* `.dump-fab` is exempt from the generic button chrome — it keeps its own
shape, glow and animations — but this squared-off retro theme squares it. */
[data-style="geocities"] .dump-fab,
[data-style="geocities"] .chat-fab {
--fab-radius: 0;
}
[data-style="geocities"] button:not(.dump-fab, .chat-fab) {
border: 3px outset var(--color-border);
box-shadow: none;
font-weight: 700;
transition: border-color 0.1s, background 0.12s;
}
[data-style="geocities"] button:active:not(:disabled) {
border-style: inset;
}
[data-style="geocities"] .btn-primary,
[data-style="geocities"] .btn-secondary,
[data-style="geocities"] .btn-danger,
[data-style="geocities"] .btn-border,
[data-style="geocities"] .follow-btn,
[data-style="geocities"] .vote-btn,
[data-style="geocities"] .feed-sort-btn,
[data-style="geocities"] .invite-btn,
[data-style="geocities"] .btn-add-playlist,
[data-style="geocities"] .load-more-btn,
[data-style="geocities"] .comment-submit-btn,
[data-style="geocities"] .comment-cancel-btn,
[data-style="geocities"] .search-bar-btn {
border: 3px outset var(--color-border);
box-shadow: none;
}
/* The shared .vote-btn declares `background: transparent`, which leaves the
chunky outset bevel see-through against the card. Give the resting state a
solid raised-panel fill; the voted (--active) state keeps its accent
background, so scope this to non-active buttons. */
[data-style="geocities"] .vote-btn:not(.vote-btn--active) {
background: var(--color-surface);
}
/* Turn the tint up and give it hard diagonal bands — a flat wash reads as an
unstyled gap in a theme built on saturation. */
[data-style="geocities"] {
--thumb-tint-strength: 55%;
}
[data-style="geocities"] .thumb-placeholder {
background-image: repeating-linear-gradient(
135deg,
rgba(255, 255, 255, 0.14) 0 8px,
rgba(0, 0, 0, 0.14) 8px 16px
);
}
/* Ghost / icon-only buttons stay flat */
[data-style="geocities"] .modal-close-btn,
[data-style="geocities"] .playlist-remove-btn,
[data-style="geocities"] .playlist-card-delete-btn,
[data-style="geocities"] .emoji-picker-float [frimousse-emoji],
[data-style="geocities"] .emoji-picker-close-btn,
[data-style="geocities"] .text-editor-emoji-btn,
[data-style="geocities"] .emoji-picker-float [frimousse-skin-tone-selector],
[data-style="geocities"] .btn--ghost,
[data-style="geocities"] .new-item-toggle,
[data-style="geocities"] .audio-player-btn,
[data-style="geocities"] .audio-player-vol-btn,
[data-style="geocities"] .rich-content-thumbnail-btn,
[data-style="geocities"] .user-menu-trigger,
[data-style="geocities"] .nav-search-btn,
[data-style="geocities"] .auth-link-btn,
[data-style="geocities"] .form-cancel,
[data-style="geocities"] .form-label-action,
[data-style="geocities"] .category-editor-btn {
border: none !important;
box-shadow: none !important;
}
/* ── Segmented controls ──────────────────────────────────────────── */
[data-style="geocities"] .visibility-toggle {
border: 3px ridge var(--color-border);
}
[data-style="geocities"] .visibility-toggle button {
/* Zero the width (not just the style): the generic `button:active` rule flips
border-style to `inset`, and a `none` border keeps its `medium` width — so
on press a 3px border would reappear inside the toggle's own frame. */
border: 0;
}
/* ── Cards & panels — ridged "table border" with a soft neon halo ─── */
[data-style="geocities"] .dump-card,
[data-style="geocities"] .playlist-card,
[data-style="geocities"] .dump-post-header,
[data-style="geocities"] .auth-card,
[data-style="geocities"] .notification-item,
[data-style="geocities"] .user-result-item,
[data-style="geocities"] .journal-card {
border: 3px ridge var(--color-border);
box-shadow: 0 0 9px color-mix(in srgb, var(--color-border) 38%, transparent);
}
[data-style="geocities"] .dump-card-comment {
padding-bottom: .1rem;
}
/* Comments nest deeply, so the full frame piled up. Keep the squared retro
edge but lighten it: thin flat border, just a whisper of the same halo. */
[data-style="geocities"] .comment-node-inner,
[data-style="geocities"] .comment-top-form {
border: 2px solid var(--color-border-subtle);
box-shadow: 0 0 6px var(--color-border-subtle);
}
[data-style="geocities"] .dump-card:hover,
[data-style="geocities"] .playlist-card:hover,
[data-style="geocities"] .user-result-item:hover,
[data-style="geocities"] .journal-card:hover {
border-color: var(--color-accent);
box-shadow: 0 0 16px color-mix(in srgb, var(--color-accent) 75%, transparent);
}
/* A pointed-at headline over a photo lights up like a marquee: neon yellow
on a black plate, ringed and glowing in the accent. */
[data-style="geocities"] .journal-card--image .journal-card-title {
--journal-title-hover-bg: rgb(0 0 0 / 0.82);
--journal-title-hover-color: #ffff00;
--journal-title-hover-shadow: 0 0 0 2px var(--color-accent),
0 0 10px var(--color-accent);
--journal-title-hover-text-shadow: 0 0 6px rgb(255 255 0 / 0.6);
}
/* The divider GIF, minus the GIF: the rainbow the header ends on, run again
between sub-blocks with a sparkle sitting in the middle of it. */
[data-style="geocities"] .journal-break {
--journal-break-space: 1.5rem;
--journal-break-rule: 4px solid;
--journal-break-ornament: "✦ ✦ ✦";
border-image: var(--geo-rainbow) 1;
}
[data-style="geocities"] .journal-break::before {
color: var(--color-accent);
letter-spacing: 0.15em;
}
/* ── App header — rainbow divider ────────────────────────────────── */
[data-style="geocities"] .app-header,
[data-style="geocities"] .header-search-below {
border-bottom: 4px solid;
border-image: var(--geo-rainbow) 1;
}
[data-style="geocities"] .app-header-user {
border: 3px outset var(--color-border);
}
/* ── Rainbow dividers — on each element's real edge ──────────────── */
[data-style="geocities"] .profile-section > h2,
[data-style="geocities"] .profile-section-header,
[data-style="geocities"] .profile-tabs-scroller {
border-bottom: 3px solid;
border-image: var(--geo-rainbow) 1;
}
[data-style="geocities"] .comment-section,
[data-style="geocities"] .related-section {
border-top: 3px solid;
border-image: var(--geo-rainbow) 1;
}
[data-style="geocities"] .comment-section-title,
[data-style="geocities"] .related-section-title {
text-transform: uppercase;
letter-spacing: 0.06em;
}
/* ── Inputs / textareas — sunken inset field ─────────────────────── */
[data-style="geocities"]
input:not([type="range"]):not([type="file"]):not([type="checkbox"]):not(
[type="radio"]
),
[data-style="geocities"] textarea {
border-radius: 0 !important;
border: 2px inset var(--color-border) !important;
background-color: var(--color-bg);
}
/* ── Modals — heavy ridged frame ─────────────────────────────────── */
[data-style="geocities"] .modal-card,
[data-style="geocities"] .confirm-modal,
[data-style="geocities"] .user-menu-dropdown,
[data-style="geocities"] .user-list-popover,
[data-style="geocities"] .mention-dropdown,
[data-style="geocities"] .emoji-picker-float {
border: 3px ridge var(--color-border);
box-shadow: 0 0 18px color-mix(in srgb, var(--color-border) 45%, transparent);
}
[data-style="geocities"] .modal-header {
border-bottom: 2px solid var(--color-border-subtle);
}
/* ── Avatars — framed snapshots ──────────────────────────────────── */
[data-style="geocities"] .avatar-img {
border: 2px ridge var(--color-border);
}
/* ── Rich content cards — keep brand borders, add neon hover glow ── */
[data-style="geocities"] .rich-content-card {
border-width: 3px;
border-style: ridge;
box-shadow: 0 0 9px color-mix(in srgb, var(--color-border) 38%, transparent);
}
[data-style="geocities"] .rich-content-card:has(.rich-content-body:hover),
[data-style="geocities"]
.rich-content-card--youtube:has(.rich-content-body:hover),
[data-style="geocities"]
.rich-content-card--bandcamp:has(.rich-content-body:hover),
[data-style="geocities"]
.rich-content-card--soundcloud:has(.rich-content-body:hover) {
box-shadow: 0 0 10px color-mix(in srgb, var(--color-accent) 70%, transparent);
}
/* ── Global player — neon console ────────────────────────────────── */
[data-style="geocities"] .global-player {
border: 3px ridge var(--color-accent);
box-shadow: 0 0 16px color-mix(in srgb, var(--color-accent) 55%, transparent);
}
/* Queue UI: square off the artwork and the stream progress bar. */
[data-style="geocities"] .global-player .audio-player-btn {
color: var(--color-on-accent);
}
[data-style="geocities"] .global-player .audio-player-vol-btn,
[data-style="geocities"] .global-player .btn--ghost {
color: var(--color-text);
}
/* ── File drop zone ──────────────────────────────────────────────── */
[data-style="geocities"] .fdz {
border-style: dashed;
}
/* ── Pills / badges — squared, and the unread bits blink ─────────── */
/* The editor is one squared box; flatten its fields (geocities otherwise
forces a sunken inset border on every input) and drop the soft glow. */
[data-style="geocities"] .category-editor {
border: 2px solid var(--color-accent);
box-shadow: none;
}
[data-style="geocities"] .category-editor-input {
border: none !important;
background: transparent !important;
}
/* Chips are tags, not raised Win95 buttons — keep a clean flat border
instead of the generic 3px outset bevel. */
[data-style="geocities"] .category-chip {
border: 2px solid var(--color-border);
box-shadow: none;
}
[data-style="geocities"] .notification-badge {
animation: geo-blink 1.1s step-start infinite;
}
[data-style="geocities"] .notif-dot,
[data-style="geocities"] .unread-dot {
animation: geo-blink 1.3s step-start infinite;
}
/* ── Floating "new" affordance / FAB-style accents ───────────────── */
[data-style="geocities"] .fdz__upload-icon {
opacity: 0.7;
}
/* ── Casual web-1.0 voice: lowercase everything (code excepted) ──── */
[data-style="geocities"],
[data-style="geocities"] * {
text-transform: lowercase;
}
[data-style="geocities"] input,
[data-style="geocities"] textarea,
[data-style="geocities"] .md code,
[data-style="geocities"] .md pre,
[data-style="geocities"] .invite-url {
text-transform: none;
}
/* ── Category switcher dropdown ──────────────────────────────────── */
/* Same ridged frame as the other popovers; option buttons flattened so the
chunky Win95 button bevel doesn't apply to menu rows. (The trigger reuses
.feed-sort-btn and keeps the bevel, matching the sort tabs.) */
[data-style="geocities"] .category-switcher-menu {
border: 3px ridge var(--color-border);
box-shadow: 0 0 18px color-mix(in srgb, var(--color-border) 45%, transparent);
}
[data-style="geocities"] .category-switcher-option {
border: none !important;
box-shadow: none !important;
}
/* Circles App.css draws with a literal 50% (not the radius scale). */
[data-style="geocities"] .notif-icon,
[data-style="geocities"] .notif-dot {
border-radius: 0;
}