design: neobrutalist_theme into main

This commit is contained in:
Per Stark
2025-09-17 10:00:55 +02:00
parent 62d909bb7e
commit 6ea51095e8
57 changed files with 1791 additions and 951 deletions

View File

@@ -1,29 +1,108 @@
@import 'tailwindcss' source(none);
@import 'tailwindcss';
@source './templates/**/*.html';
@plugin "daisyui" {
exclude: rootscrollbargutter;
logs: false;
themes: false;
include: [ "properties",
"scrollbar",
"rootscrolllock",
"rootcolor",
"svg",
"button",
"menu",
"navbar",
"drawer",
"modal",
"chat",
"card",
"loading",
"validator",
"fileinput",
"alert",
"swap"
];
}
@plugin "@tailwindcss/typography";
@config './tailwind.config.js';
/*
The default border color has changed to `currentColor` in Tailwind CSS v4,
so we've added these compatibility styles to make sure everything still
looks the same as it did with Tailwind CSS v3.
If we ever want to remove these styles, we need to add an explicit border
color utility to any element that depends on these defaults.
*/
@view-transition {
navigation: auto;
}
@layer base {
:root {
--nb-shadow: 4px 4px 0 0 #000;
--nb-shadow-hover: 6px 6px 0 0 #000;
}
[data-theme="light"] {
color-scheme: light;
--color-base-100: oklch(98.42% 0.012 96.42);
--color-base-200: oklch(94.52% 0.0122 96.43);
--color-base-300: oklch(90.96% 0.0125 91.53);
--color-base-content: oklch(17.76% 0 89.88);
--color-primary: oklch(20.77% 0.0398 265.75);
--color-primary-content: oklch(100% 0 89.88);
--color-secondary: oklch(54.61% 0.2152 262.88);
--color-secondary-content: oklch(100% 0 89.88);
--color-accent: oklch(72% 0.19 80);
--color-accent-content: oklch(21% 0.035 80);
--color-neutral: oklch(17.76% 0 89.88);
--color-neutral-content: oklch(96.99% 0.0013 106.42);
--color-info: oklch(60.89% 0.1109 221.72);
--color-info-content: oklch(96.99% 0.0013 106.42);
--color-success: oklch(62.71% 0.1699 149.21);
--color-success-content: oklch(96.99% 0.0013 106.42);
--color-warning: oklch(79.52% 0.1617 86.05);
--color-warning-content: oklch(17.76% 0 89.88);
--color-error: oklch(57.71% 0.2152 27.33);
--color-error-content: oklch(96.99% 0.0013 106.42);
--radius-selector: 0rem;
--radius-field: 0rem;
--radius-box: 0rem;
--size-selector: 0.25rem;
--size-field: 0.25rem;
--border: 2px;
}
[data-theme="dark"] {
color-scheme: dark;
--color-base-100: oklch(22% 0.015 255);
--color-base-200: oklch(18% 0.014 253);
--color-base-300: oklch(14% 0.012 251);
--color-base-content: oklch(97.2% 0.02 255);
--color-primary: oklch(58% 0.233 277.12);
--color-primary-content: oklch(96% 0.018 272.31);
--color-secondary: oklch(65% 0.241 354.31);
--color-secondary-content: oklch(94% 0.028 342.26);
--color-accent: oklch(78% 0.22 80);
--color-accent-content: oklch(20% 0.035 80);
--color-neutral: oklch(26% 0.02 255);
--color-neutral-content: oklch(97% 0.03 255);
--color-info: oklch(74% 0.16 232.66);
--color-info-content: oklch(29% 0.066 243.16);
--color-success: oklch(76% 0.177 163.22);
--color-success-content: oklch(37% 0.077 168.94);
--color-warning: oklch(82% 0.189 84.43);
--color-warning-content: oklch(41% 0.112 45.9);
--color-error: oklch(71% 0.194 13.43);
--color-error-content: oklch(27% 0.105 12.09);
--radius-selector: 0rem;
--radius-field: 0rem;
--radius-box: 0rem;
--size-selector: 0.25rem;
--size-field: 0.25rem;
--border: 2px;
}
body {
@apply font-satoshi;
background-color: var(--color-base-100);
color: var(--color-base-content);
font-family: 'Satoshi', sans-serif;
-webkit-font-smoothing: antialiased;
@apply selection:bg-yellow-300/40 selection:text-neutral;
}
html {
@@ -37,6 +116,479 @@
::file-selector-button {
border-color: var(--color-gray-200, currentColor);
}
.container {
padding-inline: 10px;
}
@media (min-width: 640px) {
.container {
padding-inline: 2rem;
}
}
@media (min-width: 1024px) {
.container {
padding-inline: 4rem;
}
}
@media (min-width: 1280px) {
.container {
padding-inline: 5rem;
}
}
@media (min-width: 1536px) {
.container {
padding-inline: 6rem;
}
}
.custom-scrollbar {
scrollbar-width: thin;
scrollbar-color: rgba(0, 0, 0, 0.2) transparent;
}
.custom-scrollbar::-webkit-scrollbar {
width: 4px;
}
.custom-scrollbar::-webkit-scrollbar-track {
background: transparent;
}
.custom-scrollbar::-webkit-scrollbar-thumb {
background-color: rgba(0, 0, 0, 0.2);
border-radius: 3px;
}
.hide-scrollbar {
-ms-overflow-style: none;
scrollbar-width: none;
}
.hide-scrollbar::-webkit-scrollbar {
display: none;
}
form.htmx-request {
opacity: 0.5;
}
}
/* Neobrutalist helpers influenced by Tufte principles */
@layer components {
/* Offset, hard-edge shadow; minimal ink with strong contrast */
.nb-shadow {
box-shadow: var(--nb-shadow);
transition: transform 150ms, box-shadow 150ms;
}
.nb-shadow-hover {
transform: translate(-1px, -1px);
box-shadow: var(--nb-shadow-hover);
}
.nb-card {
@apply bg-base-100 border-2 border-neutral p-4;
box-shadow: var(--nb-shadow);
transition: transform 150ms, box-shadow 150ms;
}
.nb-card:hover {
transform: translate(-1px, -1px);
box-shadow: var(--nb-shadow-hover);
}
.nb-panel {
@apply border-2 border-neutral;
background-color: var(--nb-panel-bg, var(--color-base-200));
box-shadow: var(--nb-shadow);
transition: transform 150ms, box-shadow 150ms;
}
.nb-panel:hover {
transform: translate(-1px, -1px);
box-shadow: var(--nb-shadow-hover);
}
.nb-panel-canvas {
--nb-panel-bg: var(--color-base-100);
}
.nb-canvas {
background-color: var(--color-base-100);
}
.nb-btn {
@apply btn rounded-none border-2 border-neutral text-base-content;
--btn-color: var(--color-base-100);
--btn-fg: var(--color-base-content);
--btn-noise: none;
background-image: none;
box-shadow: var(--nb-shadow);
transition: transform 150ms, box-shadow 150ms;
}
.nb-btn:hover {
transform: translate(-1px, -1px);
box-shadow: var(--nb-shadow-hover);
}
.nb-link {
@apply underline underline-offset-2 decoration-neutral hover:decoration-4;
}
.nb-stat {
@apply bg-base-100 border-2 border-neutral p-5 flex flex-col gap-1;
box-shadow: var(--nb-shadow);
transition: transform 150ms, box-shadow 150ms;
}
/* Hairline rules and quiet gridlines for Tufte feel */
.u-hairline {
@apply border-t border-neutral/20;
}
.prose-tufte {
@apply prose prose-neutral;
max-width: min(90ch, 100%);
line-height: 1.7;
}
.prose-tufte-compact {
@apply prose prose-neutral;
max-width: min(90ch, 100%);
font-size: 0.875rem;
line-height: 1.6;
}
/* Encourage a consistent card look app-wide */
.card {
@apply border-2 border-neutral rounded-none;
box-shadow: var(--nb-shadow);
transition: transform 150ms, box-shadow 150ms;
}
.card:hover {
transform: translate(-1px, -1px);
box-shadow: var(--nb-shadow-hover);
}
/* Input styling with good dark/light contrast */
.nb-input {
@apply rounded-none border-2 border-neutral bg-base-100 text-base-content placeholder:text-base-content/60 px-3 py-[0.5rem];
box-shadow: var(--nb-shadow);
transition: transform 150ms, box-shadow 150ms, border-color 150ms;
}
.nb-input:hover {
transform: translate(-1px, -1px);
box-shadow: var(--nb-shadow-hover);
}
.nb-input:focus {
outline: none;
box-shadow: var(--nb-shadow-hover);
}
/* Select styling parallels inputs */
.nb-select {
@apply rounded-none border-2 border-neutral bg-base-100 text-base-content px-3 py-[0.5rem];
box-shadow: var(--nb-shadow);
transition: transform 150ms, box-shadow 150ms, border-color 150ms;
}
.nb-select:hover {
transform: translate(-1px, -1px);
box-shadow: var(--nb-shadow-hover);
}
.nb-select:focus {
outline: none;
box-shadow: var(--nb-shadow-hover);
}
/* Compact variants */
.nb-input-sm {
@apply text-sm px-2 py-[0.25rem];
}
.nb-select-sm {
@apply text-sm px-2 py-[0.25rem];
}
.nb-cta {
--btn-color: var(--color-accent);
--btn-fg: var(--color-accent-content);
--btn-noise: none;
background-image: none;
background-color: var(--color-accent);
color: var(--color-accent-content);
}
.nb-cta:hover {
background-color: var(--color-accent);
color: var(--color-accent-content);
filter: saturate(1.1) brightness(1.05);
}
/* Badges */
.nb-badge {
@apply inline-flex items-center uppercase tracking-wide text-[10px] px-2 py-0.5 bg-base-100 border-2 border-neutral rounded-none;
box-shadow: 3px 3px 0 0 #000;
}
.nb-masonry {
column-count: 1;
column-gap: 1rem;
}
.nb-masonry>* {
break-inside: avoid;
display: block;
}
@media (min-width: 768px) {
.nb-masonry {
column-count: 2;
}
}
@media (min-width: 1536px) {
.nb-masonry {
column-count: 3;
}
}
/* Chat bubbles neobrutalist */
.chat .chat-bubble {
@apply rounded-none border-2 border-neutral bg-base-100 text-neutral;
box-shadow: var(--nb-shadow);
transition: transform 150ms, box-shadow 150ms;
}
/* Remove DaisyUI tail so our rectangle keeps clean borders/shadows */
.chat .chat-bubble::before,
.chat .chat-bubble::after {
display: none !important;
content: none !important;
}
.chat.chat-start .chat-bubble {
@apply bg-secondary text-secondary-content;
}
.chat.chat-end .chat-bubble {
@apply bg-base-100 text-neutral;
}
/* Tables */
.nb-table {
@apply w-full;
border-collapse: separate;
border-spacing: 0;
}
.nb-table thead th {
@apply uppercase tracking-wide text-xs border-b-2 border-neutral;
}
.nb-table th,
.nb-table td {
@apply p-3;
}
.nb-table tbody tr+tr td {
@apply border-t border-neutral/30;
}
.nb-table tbody tr:hover {
@apply bg-base-200/40;
}
.nb-table tbody tr:hover td:first-child {
box-shadow: inset 3px 0 0 0 #000;
}
.kg-overlay {
@apply absolute top-4 left-4 z-10 flex items-center gap-2;
}
.kg-search-input {
@apply pl-2;
height: 2rem;
min-width: 220px;
max-width: 320px;
}
.kg-legend {
@apply absolute bottom-2 left-2 z-10 flex flex-wrap gap-4;
}
.kg-legend-card {
@apply p-2;
}
.kg-legend-heading {
@apply mb-1 text-xs opacity-70;
}
.kg-legend-row {
@apply flex items-center gap-2 text-xs;
}
/* Checkboxes */
.nb-checkbox {
@apply appearance-none inline-block align-middle rounded-none border-2 border-neutral bg-base-100;
width: 1rem;
height: 1rem;
box-shadow: var(--nb-shadow);
transition: transform 150ms, box-shadow 150ms, border-color 150ms, background-color 150ms;
background-repeat: no-repeat;
background-position: center;
background-size: 80% 80%;
cursor: pointer;
}
.nb-checkbox:hover {
transform: translate(-1px, -1px);
box-shadow: 5px 5px 0 0 #000;
}
.nb-checkbox:focus-visible {
outline: 2px solid #000;
outline-offset: 2px;
}
.nb-checkbox:active {
transform: translate(0, 0);
box-shadow: 3px 3px 0 0 #000;
}
/* Tick mark in light mode (black) */
.nb-checkbox:checked {
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'><polyline points='20 6 9 17 4 12'/></svg>");
}
/* Tick mark in dark mode (white) */
[data-theme="dark"] .nb-checkbox:checked {
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'><polyline points='20 6 9 17 4 12'/></svg>");
}
/* Compact size */
.nb-checkbox-sm {
width: 0.875rem;
height: 0.875rem;
}
/* Placeholder style for smaller, quieter helper text */
.nb-input::placeholder {
font-size: 0.75rem;
letter-spacing: 0.02em;
opacity: 0.75;
}
.markdown-content {
line-height: 1.5;
word-wrap: break-word;
}
.markdown-content p {
margin-bottom: 0.75em;
}
.markdown-content p:last-child {
margin-bottom: 0;
}
.markdown-content ul,
.markdown-content ol {
margin-top: 0.5em;
margin-bottom: 0.75em;
padding-left: 2em;
}
.markdown-content li {
margin-bottom: 0.25em;
}
.markdown-content pre {
background-color: rgba(0, 0, 0, 0.05);
padding: 0.5em;
border-radius: 4px;
overflow-x: auto;
}
.markdown-content code {
background-color: rgba(0, 0, 0, 0.05);
padding: 0.2em 0.4em;
border-radius: 3px;
font-size: 0.9em;
}
.markdown-content table {
border-collapse: collapse;
margin: 0.75em 0;
width: 100%;
}
.markdown-content th,
.markdown-content td {
border: 1px solid rgba(0, 0, 0, 0.15);
padding: 6px 12px;
text-align: left;
}
.markdown-content blockquote {
border-left: 4px solid rgba(0, 0, 0, 0.15);
padding-left: 10px;
margin: 0.5em 0 0.5em 0.5em;
color: rgba(0, 0, 0, 0.6);
}
[data-theme="dark"] .markdown-content blockquote {
border-color: rgba(255, 255, 255, 0.3);
color: rgba(255, 255, 255, 0.8);
}
.markdown-content hr {
border: none;
border-top: 1px solid rgba(0, 0, 0, 0.15);
margin: 0.75em 0;
}
[data-theme="dark"] .markdown-content pre,
[data-theme="dark"] .markdown-content code {
background-color: rgba(255, 255, 255, 0.07);
}
.brand-mark {
letter-spacing: 0.02em;
}
.reference-tooltip {
@apply bg-base-100 text-base-content border-2 border-neutral p-3 text-sm w-72 max-w-xs;
position: fixed;
z-index: 9999;
box-shadow: var(--nb-shadow);
}
}
/* Theme-aware placeholder contrast tweaks */
@layer base {
/* Light theme keeps default neutral tone via utilities */
[data-theme="dark"] .nb-input::placeholder,
[data-theme="dark"] .input::placeholder,
[data-theme="dark"] .textarea::placeholder,
[data-theme="dark"] textarea::placeholder,
[data-theme="dark"] input::placeholder {
color: rgba(255, 255, 255, 0.78) !important;
opacity: 0.85;
}
}
/* satoshi.css */
@@ -58,4 +610,28 @@
font-weight: 300 900;
font-style: italic;
font-display: swap;
}
/* Minimal override: prevent DaisyUI .menu hover bg on our nb buttons */
@layer utilities {
/* Let plain nb-btns remain transparent on hover within menus */
.menu li>.nb-btn:hover {
background-color: transparent;
}
/* Keep CTA background on hover within menus */
.menu li>.nb-cta:hover {
background-color: var(--color-accent);
color: var(--color-accent-content);
}
.toast-alert {
@apply mt-2 flex flex-col text-left gap-1;
box-shadow: var(--nb-shadow);
}
.toast-alert-title {
@apply text-lg font-bold;
}
}