/* ══════════════════════════════════════════════════════════════════════ 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 Variable", "Saira Variable", 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; /* Heavy, square-cut icon lines, like the borders. */ --nav-icon-stroke: 2.5; --nav-icon-linecap: square; --nav-icon-linejoin: miter; 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"] .index-presence-more, [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"] .text-editor-emoji-btn, [data-style="brutalist"] .emoji-picker-float [frimousse-skin-tone-selector], [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"] .user-menu-item, [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"] .user-menu-item:hover:not(:disabled), [data-style="brutalist"] .user-menu-item: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([aria-disabled="true"]), [data-style="brutalist"] .emoji-picker-float [frimousse-emoji]:hover, [data-style="brutalist"] .emoji-picker-close-btn:hover, [data-style="brutalist"] .text-editor-emoji-btn:hover:not(:disabled), [data-style="brutalist"] .emoji-picker-float [frimousse-skin-tone-selector]: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); } /* A pointed-at headline over a photo becomes a label slapped on it: a solid accent block, hard offset shadow, no glass — the same stamp every button here is made of. */ [data-style="brutalist"] .journal-card--image .journal-card-title { --journal-title-hover-bg: var(--color-accent); --journal-title-hover-color: var(--color-on-accent); --journal-title-hover-radius: 0; --journal-title-hover-shadow: 3px 3px 0 var(--color-text); } /* ── 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 and page cards ─────────────────────────── */ [data-style="brutalist"] .notification-item, [data-style="brutalist"] .page-card { 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; }