All checks were successful
Build and Publish Docker Image / build-and-push (push) Successful in 40s
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
396 lines
15 KiB
CSS
396 lines
15 KiB
CSS
/* ══════════════════════════════════════════════════════════════════════
|
|
Brutalist theme — pastel palette, hard edges, bold type
|
|
Palette: Eggshell · Burnt Peach · Twilight Indigo · Muted Teal · Apricot Cream
|
|
══════════════════════════════════════════════════════════════════════ */
|
|
|
|
/* ── Palette (light-dark: see tokens.css) ─────────────────────────── */
|
|
:root[data-style="brutalist"] {
|
|
--color-text: light-dark(#3d405b, #f4f1de);
|
|
--color-text-secondary: light-dark(#5a5e80, #c8c5b2);
|
|
--color-text-muted: light-dark(#7a7e9a, #8e8c80);
|
|
--color-on-accent: light-dark(#f4f1de, #3d405b);
|
|
--color-bg: light-dark(#f4f1de, #252838);
|
|
--color-surface: light-dark(#f8f5e8, #2e3145);
|
|
--color-border: light-dark(#8a8da8, #4a4e6a);
|
|
--color-border-subtle: light-dark(rgba(61, 64, 91, 0.25), rgba(74, 78, 106, 0.4));
|
|
--color-accent: light-dark(#e07a5f, #f2cc8f);
|
|
--color-accent-hover: light-dark(#c05040, #d4a860);
|
|
--color-link: light-dark(#b85a3a, #f2cc8f);
|
|
--color-link-hover: light-dark(#943020, #d4a860);
|
|
--color-danger: light-dark(#c04030, #e07a5f);
|
|
--color-danger-bg: light-dark(#fae4e0, #3a1e18);
|
|
--color-danger-hover: light-dark(#a02820, #c85a40);
|
|
--color-success: light-dark(#3a7860, #81b29a);
|
|
--color-success-bg: light-dark(#e0f0ea, #1a2e26);
|
|
--color-success-hover: light-dark(#286048, #5a9878);
|
|
--color-overlay: light-dark(rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.6));
|
|
--color-header-user-bg: light-dark(rgba(224, 122, 95, 0.08), rgba(242, 204, 143, 0.07));
|
|
--color-header-user-bg-hover: light-dark(rgba(224, 122, 95, 0.16), rgba(242, 204, 143, 0.14));
|
|
--color-option-bg: light-dark(#ede9d4, #222436);
|
|
--color-option-border: light-dark(#e0dcc8, #252838);
|
|
}
|
|
|
|
/* ══════════════════════════════════════════════════════════════════════
|
|
Structural overrides
|
|
══════════════════════════════════════════════════════════════════════ */
|
|
|
|
/* ── Typography ──────────────────────────────────────────────────── */
|
|
[data-style="brutalist"] {
|
|
--font-body: "Space Grotesk", "Saira", sans-serif;
|
|
|
|
/* Hard edges 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;
|
|
font-family: var(--font-body);
|
|
font-weight: 500;
|
|
}
|
|
|
|
/* Only section-level headings get the uppercase treatment */
|
|
[data-style="brutalist"] h1 {
|
|
font-weight: 900;
|
|
letter-spacing: 0.03em;
|
|
}
|
|
|
|
/* Circles App.css draws with a literal 50% (not the radius scale) — square
|
|
them off too. */
|
|
[data-style="brutalist"] .avatar-img,
|
|
[data-style="brutalist"] .avatar-initials,
|
|
[data-style="brutalist"] .avatar-change-overlay,
|
|
[data-style="brutalist"] .notif-icon,
|
|
[data-style="brutalist"] .notif-dot {
|
|
border-radius: 0;
|
|
}
|
|
|
|
/* ── Buttons — square corners, modest hard shadow ────────────────── */
|
|
/* `.dump-fab` is exempt from the generic button chrome — it keeps its own
|
|
shape, shadow and animations — but this hard-edged theme squares it off. */
|
|
[data-style="brutalist"] .dump-fab,
|
|
[data-style="brutalist"] .chat-fab {
|
|
--fab-radius: 0;
|
|
}
|
|
|
|
[data-style="brutalist"] button:not(.dump-fab, .chat-fab) {
|
|
border: 2px solid var(--color-border);
|
|
font-weight: 700;
|
|
box-shadow: 2px 2px 0 var(--color-border);
|
|
transition: box-shadow 0.08s ease, transform 0.08s ease, border-color 0.1s;
|
|
}
|
|
|
|
[data-style="brutalist"] button:not(.dump-fab, .chat-fab):hover:not(:disabled) {
|
|
border-color: var(--color-border);
|
|
box-shadow: none;
|
|
transform: translate(2px, 2px);
|
|
}
|
|
|
|
/* Ghost / icon-only buttons — keep borderless, no press effect */
|
|
[data-style="brutalist"] .modal-close-btn,
|
|
[data-style="brutalist"] .playlist-remove-btn,
|
|
[data-style="brutalist"] .playlist-card-delete-btn,
|
|
[data-style="brutalist"] .vote-btn,
|
|
[data-style="brutalist"] .emoji-picker-float [frimousse-emoji],
|
|
[data-style="brutalist"] .emoji-picker-close-btn,
|
|
[data-style="brutalist"] .new-item-toggle,
|
|
[data-style="brutalist"] .btn--ghost,
|
|
[data-style="brutalist"] .audio-player-btn,
|
|
[data-style="brutalist"] .audio-player-vol-btn,
|
|
[data-style="brutalist"] .rich-content-thumbnail-btn,
|
|
[data-style="brutalist"] .user-menu-trigger,
|
|
[data-style="brutalist"] .nav-search-btn,
|
|
[data-style="brutalist"] .auth-link-btn,
|
|
[data-style="brutalist"] .form-cancel,
|
|
[data-style="brutalist"] .form-label-action {
|
|
border: none !important;
|
|
box-shadow: none !important;
|
|
}
|
|
|
|
[data-style="brutalist"] .user-menu-trigger:hover:not(:disabled),
|
|
[data-style="brutalist"] .user-menu-trigger:active,
|
|
[data-style="brutalist"] .nav-search-btn:hover:not(:disabled),
|
|
[data-style="brutalist"] .nav-search-btn:active,
|
|
[data-style="brutalist"] .auth-link-btn:hover:not(:disabled),
|
|
[data-style="brutalist"] .auth-link-btn:active,
|
|
[data-style="brutalist"] .form-cancel:hover:not(:disabled),
|
|
[data-style="brutalist"] .form-cancel:active,
|
|
[data-style="brutalist"] .form-label-action:hover:not(:disabled),
|
|
[data-style="brutalist"] .form-label-action:active {
|
|
transform: none !important;
|
|
box-shadow: none !important;
|
|
}
|
|
|
|
[data-style="brutalist"] .modal-close-btn:hover,
|
|
[data-style="brutalist"] .playlist-remove-btn:hover,
|
|
[data-style="brutalist"] .playlist-card-delete-btn:hover,
|
|
[data-style="brutalist"] .vote-btn:hover:not(:disabled),
|
|
[data-style="brutalist"] .emoji-picker-float [frimousse-emoji]:hover,
|
|
[data-style="brutalist"] .emoji-picker-close-btn:hover,
|
|
[data-style="brutalist"] .new-item-toggle:hover:not(:disabled),
|
|
[data-style="brutalist"] .btn--ghost:hover:not(:disabled),
|
|
[data-style="brutalist"] .audio-player-btn:hover:not(:disabled),
|
|
[data-style="brutalist"] .audio-player-vol-btn:hover:not(:disabled),
|
|
[data-style="brutalist"] .rich-content-thumbnail-btn:hover:not(:disabled) {
|
|
transform: none !important;
|
|
box-shadow: none !important;
|
|
}
|
|
|
|
/* ── Segmented controls / visibility-toggle ──────────────────────── */
|
|
[data-style="brutalist"] .visibility-toggle {
|
|
border: 2px solid var(--color-border);
|
|
box-shadow: 2px 2px 0 var(--color-border);
|
|
}
|
|
|
|
[data-style="brutalist"] .visibility-toggle button {
|
|
border: none;
|
|
box-shadow: none;
|
|
}
|
|
|
|
[data-style="brutalist"] .visibility-toggle button:hover:not(:disabled) {
|
|
transform: none;
|
|
box-shadow: none;
|
|
}
|
|
|
|
/* ── Cards ───────────────────────────────────────────────────────── */
|
|
[data-style="brutalist"] .dump-card,
|
|
[data-style="brutalist"] .playlist-card {
|
|
border: 2px solid var(--color-border);
|
|
box-shadow: 3px 3px 0 var(--color-border);
|
|
transition:
|
|
box-shadow 0.08s ease,
|
|
transform 0.08s ease,
|
|
border-color 0.1s,
|
|
grid-template-rows 0.32s ease,
|
|
opacity 0.25s ease,
|
|
filter 0.3s ease;
|
|
}
|
|
|
|
[data-style="brutalist"] .dump-card:hover,
|
|
[data-style="brutalist"] .playlist-card:hover {
|
|
border-color: var(--color-accent);
|
|
box-shadow: 3px 3px 0 var(--color-accent);
|
|
transform: translate(-2px, -2px);
|
|
}
|
|
|
|
/* Don't shift cards that are animating out */
|
|
[data-style="brutalist"] .dump-card--fading,
|
|
[data-style="brutalist"] .dump-card--dismissing {
|
|
transform: none;
|
|
}
|
|
|
|
/* ── Journal sub-block breaks ────────────────────────────────────── */
|
|
/* The theme already has one divider and uses it everywhere — the app header,
|
|
the modal header, a section heading all end on 2px of --color-border. So
|
|
the journal break is that same edge, not a new mark invented for it. What
|
|
separates a break from any other rule here is the air around it, which is
|
|
the one thing a heading can't spend. */
|
|
[data-style="brutalist"] .journal-break {
|
|
--journal-break-space: 2.1rem;
|
|
--journal-break-rule: 2px solid var(--color-border);
|
|
}
|
|
|
|
/* ── Dump post detail header ─────────────────────────────────────── */
|
|
[data-style="brutalist"] .dump-post-header {
|
|
border: 2px solid var(--color-border);
|
|
box-shadow: 3px 3px 0 var(--color-border);
|
|
}
|
|
|
|
/* ── App header ──────────────────────────────────────────────────── */
|
|
[data-style="brutalist"] .app-header {
|
|
border-bottom: 2px solid var(--color-border);
|
|
}
|
|
|
|
[data-style="brutalist"] .app-header-user {
|
|
border: 2px solid var(--color-border);
|
|
box-shadow: 2px 2px 0 var(--color-border);
|
|
transition: box-shadow 0.08s ease, transform 0.08s ease, background 0.1s;
|
|
}
|
|
|
|
[data-style="brutalist"] .app-header-user:hover {
|
|
box-shadow: none;
|
|
transform: translate(2px, 2px);
|
|
}
|
|
|
|
/* ── Inputs / textareas ──────────────────────────────────────────── */
|
|
[data-style="brutalist"]
|
|
input:not([type="range"]):not([type="file"]):not([type="checkbox"]):not(
|
|
[type="radio"]
|
|
),
|
|
[data-style="brutalist"] textarea {
|
|
border-radius: 0 !important;
|
|
border-width: 2px !important;
|
|
border-color: var(--color-border) !important;
|
|
}
|
|
|
|
[data-style="brutalist"] .form input:focus,
|
|
[data-style="brutalist"] .form textarea:focus,
|
|
[data-style="brutalist"] .mention-textarea-wrap textarea:focus {
|
|
box-shadow: 2px 2px 0 var(--color-accent);
|
|
}
|
|
|
|
|
|
[data-style="brutalist"] .category-editor {
|
|
box-shadow: 2px 2px 0 var(--color-accent);
|
|
}
|
|
|
|
|
|
/* ── Modals ──────────────────────────────────────────────────────── */
|
|
[data-style="brutalist"] .modal-card,
|
|
[data-style="brutalist"] .confirm-modal {
|
|
border: 2px solid var(--color-border);
|
|
box-shadow: 4px 4px 0 var(--color-border);
|
|
}
|
|
|
|
[data-style="brutalist"] .modal-header {
|
|
border-bottom: 2px solid var(--color-border);
|
|
}
|
|
|
|
/* ── Section headings ────────────────────────────────────────────── */
|
|
[data-style="brutalist"] .profile-section > h2,
|
|
[data-style="brutalist"] .profile-section-header,
|
|
[data-style="brutalist"] .comment-section-title {
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.06em;
|
|
font-weight: 700;
|
|
}
|
|
|
|
[data-style="brutalist"] .profile-section > h2,
|
|
[data-style="brutalist"] .profile-section-header {
|
|
border-bottom-width: 2px;
|
|
}
|
|
|
|
|
|
|
|
/* ── Rich content cards ──────────────────────────────────────────── */
|
|
[data-style="brutalist"] .rich-content-card {
|
|
box-shadow: 3px 3px 0 var(--color-border);
|
|
}
|
|
|
|
/* Carry the provider brand colour through both the border and the hard
|
|
offset shadow, so the brand reads instead of being flattened to grey. */
|
|
[data-style="brutalist"] .rich-content-card--youtube {
|
|
border-color: var(--color-youtube);
|
|
box-shadow: 3px 3px 0 var(--color-youtube);
|
|
}
|
|
[data-style="brutalist"] .rich-content-card--bandcamp {
|
|
border-color: var(--color-bandcamp);
|
|
box-shadow: 3px 3px 0 var(--color-bandcamp);
|
|
}
|
|
[data-style="brutalist"] .rich-content-card--soundcloud {
|
|
border-color: var(--color-soundcloud);
|
|
box-shadow: 3px 3px 0 var(--color-soundcloud);
|
|
}
|
|
|
|
[data-style="brutalist"]
|
|
.rich-content-card--youtube:has(.rich-content-body:hover),
|
|
[data-style="brutalist"]
|
|
.rich-content-card--bandcamp:has(.rich-content-body:hover),
|
|
[data-style="brutalist"]
|
|
.rich-content-card--soundcloud:has(.rich-content-body:hover) {
|
|
border-color: var(--color-accent);
|
|
box-shadow: 3px 3px 0 var(--color-accent);
|
|
}
|
|
|
|
|
|
/* ── Global persistent player ────────────────────────────────────── */
|
|
[data-style="brutalist"] .global-player {
|
|
border: 2px solid var(--color-border);
|
|
box-shadow: 0 0 0 2px var(--color-border);
|
|
}
|
|
|
|
|
|
|
|
[data-style="brutalist"] .global-player .audio-player-btn {
|
|
background: transparent;
|
|
color: var(--color-text);
|
|
}
|
|
|
|
[data-style="brutalist"] .global-player .audio-player-btn:hover {
|
|
background: var(--color-border-subtle);
|
|
color: var(--color-text);
|
|
}
|
|
|
|
[data-style="brutalist"] .global-player .audio-player-vol-btn {
|
|
color: var(--color-text);
|
|
}
|
|
|
|
[data-style="brutalist"] .global-player .btn--ghost {
|
|
color: var(--color-text);
|
|
}
|
|
|
|
/* ── Notification items ──────────────────────────────────────────── */
|
|
[data-style="brutalist"] .notification-item {
|
|
border: 2px solid var(--color-border);
|
|
box-shadow: 2px 2px 0 var(--color-border);
|
|
}
|
|
|
|
|
|
[data-style="brutalist"] .notif-dot {
|
|
box-shadow: none;
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ── User result items (search) ──────────────────────────────────── */
|
|
[data-style="brutalist"] .user-result-item {
|
|
border: 2px solid var(--color-border);
|
|
box-shadow: 2px 2px 0 var(--color-border);
|
|
transition: box-shadow 0.08s ease, transform 0.08s ease, border-color 0.1s;
|
|
}
|
|
|
|
[data-style="brutalist"] .user-result-item:hover {
|
|
border-color: var(--color-accent);
|
|
box-shadow: 2px 2px 0 var(--color-accent);
|
|
transform: translate(-2px, -2px);
|
|
}
|
|
|
|
|
|
/* ── btn-primary ─────────────────────────────────────────────────── */
|
|
[data-style="brutalist"] .btn-primary {
|
|
border: 2px solid var(--color-border);
|
|
box-shadow: 2px 2px 0 var(--color-border);
|
|
transition: box-shadow 0.08s ease, transform 0.08s ease;
|
|
}
|
|
|
|
[data-style="brutalist"] .btn-primary:hover:not(:disabled) {
|
|
box-shadow: none;
|
|
transform: translate(2px, 2px);
|
|
}
|
|
|
|
[data-style="brutalist"] .btn-primary:active {
|
|
box-shadow: none;
|
|
transform: translate(2px, 2px);
|
|
}
|
|
|
|
/* The header's dump button floats in the base theme; here it presses into the
|
|
page instead, so neither the lift nor the idle drift applies. */
|
|
[data-style="brutalist"] .app-header-nav .btn-primary:hover:not(:disabled) {
|
|
translate: none;
|
|
animation: none;
|
|
}
|
|
|
|
/* ── btn-border ──────────────────────────────────────────────────── */
|
|
[data-style="brutalist"] .btn-border {
|
|
box-shadow: 2px 2px 0 var(--color-border);
|
|
}
|
|
|
|
[data-style="brutalist"] .btn-border:hover {
|
|
box-shadow: none;
|
|
transform: translate(2px, 2px);
|
|
}
|
|
|
|
|
|
|
|
/* ── Category switcher dropdown ──────────────────────────────────── */
|
|
[data-style="brutalist"] .category-switcher-option {
|
|
border: none !important;
|
|
box-shadow: none !important;
|
|
}
|
|
[data-style="brutalist"] .category-switcher-option:hover:not(:disabled) {
|
|
transform: none !important;
|
|
box-shadow: none !important;
|
|
}
|
|
|