mirror of
https://github.com/bretzel-app/crumbs.git
synced 2026-10-13 04:06:57 +02:00
Separates --hover-wash from --border so the softened dark-mode border grey no longer collapses hover/active tint washes to near-invisibility (measured 5% wash on --bg-surface: 4.7 -> 17.0 RGB distance). Light mode is unaffected since --hover-wash falls back to var(--border) in :root. Also fixes stale/incorrect claims surfaced by the final review: the checkbox rule and missing CSS variables in CLAUDE.md, the "warm parchment" description of dark mode in FEATURES.md, the chip contrast claim in the palette design doc (chips are 3:1 UI, not 4:1 text), and adds a measured lightness-floor test guarding against chips regressing to card lightness.
266 lines
5.7 KiB
CSS
266 lines
5.7 KiB
CSS
@import url('https://fonts.googleapis.com/css2?family=Press+Start+2P&family=JetBrains+Mono:ital,wght@0,100..800;1,100..800&display=swap');
|
|
|
|
@import 'tailwindcss';
|
|
@plugin '@tailwindcss/typography';
|
|
|
|
:root {
|
|
--bg-base: #f0e6d3;
|
|
--bg-surface: #faf5eb;
|
|
--primary: #C8860A;
|
|
--primary-hover: #E8A020;
|
|
--text: #1a1a2e;
|
|
--text-muted: #6b6272;
|
|
--border: #1a1a2e;
|
|
--border-subtle: #d4cabb;
|
|
--destructive: #a63d2f;
|
|
--error-bg: #f5e0db;
|
|
--error-border: #d4a69e;
|
|
--error-text: #8b2e1f;
|
|
--success-bg: #dce8d4;
|
|
--success-text: #3a5a2e;
|
|
--card-shadow: 2px 2px 0px var(--border-subtle);
|
|
--card-shadow-hover: 3px 3px 0px var(--primary);
|
|
--grid-dot: #1a1a2e;
|
|
--accent-check: var(--primary);
|
|
/* Tint source for hover/active washes. Light mode reuses the ink border, so
|
|
light styling is byte-identical; dark mode keeps the cream that --border
|
|
used to supply, because a mid-grey wash is invisible on a dark surface. */
|
|
--hover-wash: var(--border);
|
|
}
|
|
|
|
[data-theme="dark"] {
|
|
--bg-base: #141312;
|
|
--bg-surface: #1e1c1b;
|
|
--primary: #e0a030;
|
|
--primary-hover: #f2b855;
|
|
--text: #ece3d3;
|
|
--text-muted: #b3a695;
|
|
--border: #57514b;
|
|
--border-subtle: #302d2b;
|
|
--destructive: #e2705c;
|
|
--error-bg: #3a2320;
|
|
--error-border: #5c3a34;
|
|
--error-text: #f0a898;
|
|
--success-bg: #1f2e1f;
|
|
--success-text: #8fc97a;
|
|
--card-shadow: 2px 2px 0px var(--border-subtle);
|
|
--card-shadow-hover: 3px 3px 0px var(--primary);
|
|
--grid-dot: #ece3d3;
|
|
/* Dimmed so a long done-list of gold checkboxes doesn't shout. */
|
|
--accent-check: #c8a44a;
|
|
--hover-wash: #ece3d3;
|
|
}
|
|
|
|
html, body {
|
|
font-family: 'JetBrains Mono', monospace;
|
|
accent-color: var(--accent-check);
|
|
overscroll-behavior-y: none;
|
|
}
|
|
|
|
body.editor-scroll-locked {
|
|
overflow: hidden;
|
|
}
|
|
|
|
body::before {
|
|
content: '';
|
|
position: fixed;
|
|
inset: 0;
|
|
pointer-events: none;
|
|
opacity: 0.03;
|
|
background-image: repeating-conic-gradient(var(--grid-dot) 0% 25%, transparent 0% 50%);
|
|
background-size: 4px 4px;
|
|
z-index: 0;
|
|
}
|
|
|
|
/* Editor entrance animations */
|
|
@keyframes fade-in {
|
|
from { opacity: 0; }
|
|
to { opacity: 1; }
|
|
}
|
|
|
|
@keyframes pop-in {
|
|
from { opacity: 0; transform: scale(0.95) translateY(8px); }
|
|
to { opacity: 1; transform: scale(1) translateY(0); }
|
|
}
|
|
|
|
@keyframes slide-up {
|
|
from { transform: translateY(100%); }
|
|
to { transform: translateY(0); }
|
|
}
|
|
|
|
/* Prose overrides for parchment theme */
|
|
.prose {
|
|
--tw-prose-body: var(--text);
|
|
--tw-prose-headings: var(--text);
|
|
--tw-prose-links: var(--primary);
|
|
--tw-prose-code: var(--text);
|
|
--tw-prose-pre-bg: var(--bg-surface);
|
|
--tw-prose-pre-code: var(--text);
|
|
}
|
|
|
|
.prose :where(code):not(:where([class~="not-prose"] *)) {
|
|
background-color: var(--bg-surface);
|
|
border-radius: 2px;
|
|
padding: 0.125rem 0.25rem;
|
|
}
|
|
|
|
.prose :where(a):not(:where([class~="not-prose"] *)) {
|
|
color: var(--primary);
|
|
}
|
|
|
|
.prose :where(a):not(:where([class~="not-prose"] *)):hover {
|
|
color: var(--primary-hover);
|
|
}
|
|
|
|
/* Table styles for TipTap editor */
|
|
.tiptap table {
|
|
border-collapse: collapse;
|
|
width: 100%;
|
|
margin: 0.5rem 0;
|
|
}
|
|
|
|
.tiptap th,
|
|
.tiptap td {
|
|
border: 1px solid var(--border-subtle);
|
|
padding: 0.375rem 0.625rem;
|
|
text-align: left;
|
|
vertical-align: top;
|
|
min-width: 4rem;
|
|
}
|
|
|
|
.tiptap th {
|
|
font-weight: 600;
|
|
background-color: color-mix(in srgb, var(--bg-base) 60%, transparent);
|
|
}
|
|
|
|
.tiptap td p,
|
|
.tiptap th p {
|
|
margin: 0;
|
|
}
|
|
|
|
.tiptap .selectedCell {
|
|
background-color: color-mix(in srgb, var(--primary) 12%, transparent);
|
|
}
|
|
|
|
/* Task list styles — shared between TipTap editor and markdown-it preview */
|
|
|
|
/* TipTap: ul[data-type="taskList"] | markdown-it: ul.task-list */
|
|
.tiptap ul[data-type="taskList"],
|
|
.prose ul.task-list {
|
|
list-style: none;
|
|
padding-left: 0;
|
|
margin: 0.25rem 0;
|
|
}
|
|
|
|
.tiptap ul[data-type="taskList"] li,
|
|
.prose ul.task-list li {
|
|
display: flex;
|
|
align-items: flex-start;
|
|
flex-wrap: wrap;
|
|
gap: 0.375rem;
|
|
margin: 0;
|
|
padding: 0;
|
|
}
|
|
|
|
/* Nested task lists take full width below the parent item */
|
|
.tiptap ul[data-type="taskList"] li > ul[data-type="taskList"],
|
|
.prose ul.task-list li > ul.task-list {
|
|
flex-basis: 100%;
|
|
padding-left: 1.5rem;
|
|
}
|
|
|
|
.tiptap ul[data-type="taskList"] li::marker,
|
|
.prose ul.task-list li::marker {
|
|
content: none;
|
|
}
|
|
|
|
/* TipTap: checkbox is inside a label */
|
|
.tiptap ul[data-type="taskList"] li label {
|
|
display: flex;
|
|
align-items: center;
|
|
flex-shrink: 0;
|
|
margin-top: 0.125rem;
|
|
}
|
|
|
|
/* Shared checkbox styles */
|
|
.tiptap ul[data-type="taskList"] li label input[type="checkbox"],
|
|
.prose ul.task-list .task-checkbox {
|
|
cursor: pointer;
|
|
margin: 0;
|
|
margin-top: 0.2em;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
/* TipTap: text content is in a div>p */
|
|
.tiptap ul[data-type="taskList"] li > div {
|
|
flex: 1;
|
|
min-width: 0;
|
|
}
|
|
|
|
.tiptap ul[data-type="taskList"] li > div p {
|
|
margin: 0;
|
|
}
|
|
|
|
/* Checked item styling */
|
|
.tiptap ul[data-type="taskList"] li[data-checked="true"] > div {
|
|
text-decoration: line-through;
|
|
color: var(--text-muted);
|
|
}
|
|
|
|
/* Override prose spacing for task lists */
|
|
.prose ul[data-type="taskList"],
|
|
.prose ul.task-list {
|
|
padding-left: 0;
|
|
margin-top: 0.25rem;
|
|
margin-bottom: 0.25rem;
|
|
}
|
|
|
|
.prose ul[data-type="taskList"] li,
|
|
.prose ul.task-list li {
|
|
padding-left: 0;
|
|
margin-top: 0;
|
|
margin-bottom: 0;
|
|
}
|
|
|
|
.prose ul.task-list li p {
|
|
margin: 0;
|
|
}
|
|
|
|
/* Checklist link styles */
|
|
.checklist-link {
|
|
color: var(--primary);
|
|
text-decoration: underline;
|
|
text-underline-offset: 2px;
|
|
}
|
|
|
|
.checklist-link:hover {
|
|
color: var(--primary-hover);
|
|
}
|
|
|
|
[data-placeholder]:empty::before {
|
|
content: attr(data-placeholder);
|
|
color: var(--text-muted);
|
|
pointer-events: none;
|
|
}
|
|
|
|
/* Custom tooltips */
|
|
.tooltip-popup {
|
|
position: fixed;
|
|
z-index: 9999;
|
|
padding: 0.25rem 0.5rem;
|
|
font-family: 'JetBrains Mono', monospace;
|
|
font-size: 0.7rem;
|
|
line-height: 1.2;
|
|
color: var(--bg-surface);
|
|
background: var(--text);
|
|
border-radius: 2px;
|
|
pointer-events: none;
|
|
white-space: nowrap;
|
|
opacity: 0;
|
|
transition: opacity 100ms ease-out;
|
|
}
|
|
|
|
.tooltip-visible {
|
|
opacity: 1;
|
|
}
|