| 1 |
|
- |
/* ============================================================================
|
|
1 |
+ |
/*
|
| 2 |
2 |
|
GoingsOn: Neobrute Theme
|
| 3 |
3 |
|
|
| 4 |
4 |
|
Build new UI by COMPOSING the existing vocabulary, in this order of preference:
|
| 13 |
13 |
|
4. Extend a primitive with a modifier (.btn-primary, .btn-sm,
|
| 14 |
14 |
|
.form-select--compact,
|
| 15 |
15 |
|
.subtask-item--linked)
|
| 16 |
|
- |
5. ONLY THEN consider a new class — and add it to the right
|
|
16 |
+ |
5. ONLY THEN consider a new class | and add it to the right
|
| 17 |
17 |
|
BAND below
|
| 18 |
18 |
|
|
| 19 |
19 |
|
A new class is a smell, not a goal. Before writing one:
|
| 26 |
26 |
|
others size to content) belongs in a NAMED LAYOUT with an explicit
|
| 27 |
27 |
|
`grid-template-columns`, not in `.row-flex` + utilities. The utility form
|
| 28 |
28 |
|
encodes intent in browser flex-shrink math rather than in CSS that reads
|
| 29 |
|
- |
as intent — especially fragile when the row contains a native `<select>`,
|
|
29 |
+ |
as intent, especially fragile when the row contains a native `<select>`,
|
| 30 |
30 |
|
whose intrinsic-min-content sizing fights `flex: 1`. Smell test: if you
|
| 31 |
31 |
|
find yourself reaching for `.form-select--compact`, `style="width: auto;"`,
|
| 32 |
32 |
|
or `min-width: 0 !important` to make a row lay out right, the layout
|
| 33 |
33 |
|
itself wants a name. See `.email-filter-row`, `.contacts-filter-row`, and
|
| 34 |
34 |
|
`.work-hours-row` (all 2026-05-24) for the canonical form.
|
| 35 |
35 |
|
|
| 36 |
|
- |
----------------------------------------------------------------------------
|
| 37 |
36 |
|
FILE STRUCTURE: search by BAND name (uppercase anchors) to navigate.
|
| 38 |
37 |
|
Per-section titles use `/* N. Title */` headers; numbered for stability,
|
| 39 |
38 |
|
not because order matters. Bands group related sections; cascade order is
|
| 42 |
41 |
|
BAND: FOUNDATIONS
|
| 43 |
42 |
|
1. Font Face
|
| 44 |
43 |
|
2. CSS Reset & Base
|
| 45 |
|
- |
3. Design System Variables (Neobrute) — tokens (:root)
|
| 46 |
|
- |
4. Utility Classes — shadow/hover/border,
|
|
44 |
+ |
3. Design System Variables (Neobrute) | tokens (:root)
|
|
45 |
+ |
4. Utility Classes | shadow/hover/border,
|
| 47 |
46 |
|
layout, form sizing,
|
| 48 |
47 |
|
settings, subtask
|
| 49 |
48 |
|
|
| 54 |
53 |
|
8. Main Content & Page Header
|
| 55 |
54 |
|
|
| 56 |
55 |
|
BAND: COMPONENT PRIMITIVES & WIDGETS
|
| 57 |
|
- |
9. Buttons — .btn + variants/sizes
|
|
56 |
+ |
9. Buttons | .btn + variants/sizes
|
| 58 |
57 |
|
10. Quick Add Input
|
| 59 |
58 |
|
11. Cards
|
| 60 |
59 |
|
12. Tags & Badges
|
| 65 |
64 |
|
17. Email List
|
| 66 |
65 |
|
18. Toast Notifications
|
| 67 |
66 |
|
19. Modals
|
| 68 |
|
- |
20. Form Elements — .form-input,
|
|
67 |
+ |
20. Form Elements | .form-input,
|
| 69 |
68 |
|
.form-select, +
|
| 70 |
69 |
|
JS-rendered layout
|
| 71 |
70 |
|
utilities tail
|
| 132 |
131 |
|
BAND: SCOPED STYLESHEETS
|
| 133 |
132 |
|
Compose window (compose.html standalone Tauri window)
|
| 134 |
133 |
|
|
| 135 |
|
- |
----------------------------------------------------------------------------
|
| 136 |
|
- |
EXISTING VOCABULARY — grep before inventing a new class.
|
|
134 |
+ |
EXISTING VOCABULARY: grep before inventing a new class.
|
| 137 |
135 |
|
|
| 138 |
136 |
|
UTILITIES
|
| 139 |
137 |
|
Layout .flex-1, .row, .row-flex + .row-flex-{2,3,4},
|
| 169 |
167 |
|
Intents: .btn-primary / -secondary / -danger
|
| 170 |
168 |
|
Shapes: .form-select--compact / --ghost, .form-input--ghost
|
| 171 |
169 |
|
|
| 172 |
|
- |
----------------------------------------------------------------------------
|
| 173 |
170 |
|
UI MODE STRATEGY (do not casually merge)
|
| 174 |
171 |
|
|
| 175 |
172 |
|
UI mode is set ONCE at boot by index.html's inline script and exposed
|
| 176 |
173 |
|
as `<html class="ui-mode-desktop">` or `<html class="ui-mode-mobile">`.
|
| 177 |
|
- |
Viewport width does NOT switch UI mode — desktop binaries stay desktop
|
|
174 |
+ |
Viewport width does NOT switch UI mode; desktop binaries stay desktop
|
| 178 |
175 |
|
even when the window is narrowed.
|
| 179 |
176 |
|
|
| 180 |
|
- |
§25 Mobile (base pass) — early `.ui-mode-mobile` rules; applies before
|
|
177 |
+ |
§25 Mobile (base pass) | early `.ui-mode-mobile` rules; applies before
|
| 181 |
178 |
|
feature CSS so feature rules can override.
|
| 182 |
|
- |
§59 Mobile (late pass) — late `.ui-mode-mobile` rules; runs AFTER
|
|
179 |
+ |
§59 Mobile (late pass) | late `.ui-mode-mobile` rules; runs AFTER
|
| 183 |
180 |
|
feature CSS so it wins conflicts. Add new
|
| 184 |
181 |
|
mobile overrides here unless you need them
|
| 185 |
182 |
|
early.
|
| 186 |
|
- |
§60 Touch hover disable — `@media (hover: none)`. INPUT-CAPABILITY axis,
|
|
183 |
+ |
§60 Touch hover disable | `@media (hover: none)`. INPUT-CAPABILITY axis,
|
| 187 |
184 |
|
not UI mode. Reserved for hover suppression
|
| 188 |
185 |
|
only. Never put visibility or layout rules
|
| 189 |
|
- |
here — they belong under `.ui-mode-mobile`.
|
|
186 |
+ |
here; they belong under `.ui-mode-mobile`.
|
| 190 |
187 |
|
|
| 191 |
188 |
|
Intra-mode responsive: `@media (max-width: ...)` queries are allowed
|
| 192 |
189 |
|
INSIDE a UI mode (e.g. `.ui-mode-desktop` rules at narrow desktop
|
| 193 |
190 |
|
widths). Do not use a media query to switch BETWEEN UI modes.
|
| 194 |
191 |
|
|
| 195 |
192 |
|
PRINT STRATEGY
|
| 196 |
|
- |
§48 Global print rules — early.
|
| 197 |
|
- |
§52 Weekly Review print — placed after §49/§50 so V2 grid resets win.
|
|
193 |
+ |
§48 Global print rules | early.
|
|
194 |
+ |
§52 Weekly Review print | placed after §49/§50 so V2 grid resets win.
|
| 198 |
195 |
|
|
| 199 |
|
- |
----------------------------------------------------------------------------
|
| 200 |
196 |
|
WEEKLY REVIEW V1 + V2 COEXISTENCE
|
| 201 |
197 |
|
|
| 202 |
198 |
|
§49 (V1: .weekly-review-content, .weekly-review-header, ...) and
|
| 204 |
200 |
|
and mobile.js still render V1 classes; the V2 grid is used by newer
|
| 205 |
201 |
|
review surfaces. Do not delete §49 until those JS render paths migrate.
|
| 206 |
202 |
|
|
| 207 |
|
- |
============================================================================ */
|
|
203 |
+ |
*/
|
| 208 |
204 |
|
|
| 209 |
205 |
|
/* 1. Font Face */
|
| 210 |
206 |
|
@font-face {
|
| 229 |
225 |
|
positioning math in day-planning-render.js / day-planning.js. */
|
| 230 |
226 |
|
--timeline-slot-h: 12px;
|
| 231 |
227 |
|
|
| 232 |
|
- |
/* === NEOBRUTE DESIGN SYSTEM === */
|
|
228 |
+ |
/* --- NEOBRUTE DESIGN SYSTEM */
|
| 233 |
229 |
|
/* Clean neobrutalism: bold borders, flat by default, offset shadows on actions + floats */
|
| 234 |
230 |
|
|
| 235 |
|
- |
/* === INTENT LAYER (themeable) ===
|
|
231 |
+ |
/* --- INTENT LAYER (themeable)
|
| 236 |
232 |
|
Resolved intent tokens, applied at runtime by js/themes.js (setProperty
|
| 237 |
233 |
|
on :root). Defaults below are the "goingson" titular theme for first
|
| 238 |
|
- |
paint; theme-common resolves every theme — including the derived states
|
| 239 |
|
- |
(action-hover/active, selection, row-stripe, status surfaces) — so this
|
|
234 |
+ |
paint; theme-common resolves every theme, including the derived states
|
|
235 |
+ |
(action-hover/active, selection, row-stripe, status surfaces), so this
|
| 240 |
236 |
|
is one shared mapping across audiofiles / Balanced Breakfast / MNW. */
|
| 241 |
237 |
|
--surface-page: #E0E4FA;
|
| 242 |
238 |
|
--surface-raised: #FFFFFF;
|
| 264 |
260 |
|
--category-six: #17A2B8;
|
| 265 |
261 |
|
--overlay: rgba(1, 1, 8, 0.5);
|
| 266 |
262 |
|
|
| 267 |
|
- |
/* === APP-LOCAL (not theme intents) ===
|
| 268 |
|
- |
GoingsOn's component CSS references the intent tokens above directly —
|
|
263 |
+ |
/* --- APP-LOCAL (not theme intents)
|
|
264 |
+ |
GoingsOn's component CSS references the intent tokens above directly;
|
| 269 |
265 |
|
no brand aliases. Only the neobrute border width is app-local now;
|
| 270 |
266 |
|
overlay/scrim is a theme intent (theme-common 0.7.0). */
|
| 271 |
267 |
|
--border-width: 2px;
|
| 348 |
344 |
|
}
|
| 349 |
345 |
|
|
| 350 |
346 |
|
/* 4. Utility Classes (Shadow, Hover, Border) */
|
| 351 |
|
- |
/* === LAYOUT UTILITIES === */
|
|
347 |
+ |
/* --- LAYOUT UTILITIES */
|
| 352 |
348 |
|
/* Compose: .row-flex + .row-flex-{2,3,4} for align-items:center rows.
|
| 353 |
349 |
|
.row for raw flex with no align. .flex-1 to grow a child. */
|
| 354 |
350 |
|
.flex-1 { flex: 1; }
|
| 359 |
355 |
|
.mb-1 { margin-bottom: 1rem; }
|
| 360 |
356 |
|
.mb-2 { margin-bottom: var(--space-2); }
|
| 361 |
357 |
|
|
| 362 |
|
- |
/* === FORM SIZING UTILITIES === */
|
|
358 |
+ |
/* --- FORM SIZING UTILITIES */
|
| 363 |
359 |
|
.form-select--compact { width: auto; min-width: 120px; }
|
| 364 |
360 |
|
|
| 365 |
|
- |
/* === SETTINGS UTILITIES === */
|
|
361 |
+ |
/* --- SETTINGS UTILITIES */
|
| 366 |
362 |
|
.settings-divider { margin-top: 1.5rem; padding-top: 1.5rem; border-top: 2px solid var(--border); }
|
| 367 |
363 |
|
.settings-heading { margin-bottom: 1rem; font-family: var(--font-heading); }
|
| 368 |
364 |
|
.settings-desc { font-size: 0.875rem; color: var(--content-secondary); margin-bottom: 1rem; }
|
| 369 |
365 |
|
|
| 370 |
|
- |
/* === SUBTASK UTILITIES === */
|
|
366 |
+ |
/* --- SUBTASK UTILITIES */
|
| 371 |
367 |
|
/* .subtask-item is the base row; --linked is a modifier for subtasks that
|
| 372 |
368 |
|
reference another task (raised bg + accent border). Use both classes
|
| 373 |
369 |
|
together: <div class="subtask-item subtask-item--linked">. */
|
| 403 |
399 |
|
/* Interactive chrome is not text. Buttons, tabs, nav, badges, and labels
|
| 404 |
400 |
|
shouldn't show a text selection on press-and-hold (notably the mobile
|
| 405 |
401 |
|
bottom tab bar, where a long-press otherwise highlights the label and
|
| 406 |
|
- |
you have to dodge it). Content text — inputs, textareas, contenteditable,
|
|
402 |
+ |
you have to dodge it). Content text: inputs, textareas, contenteditable,
|
| 407 |
403 |
|
and anything explicitly marked .selectable, stays selectable. */
|
| 408 |
404 |
|
.btn,
|
| 409 |
405 |
|
.tab,
|
| 1896 |
1892 |
|
/* Pin a form's action row to the bottom of the modal's scroll area so
|
| 1897 |
1893 |
|
primary/cancel buttons stay visible even on short viewports. Without
|
| 1898 |
1894 |
|
this, on small windows or iOS with the keyboard up the button row sits
|
| 1899 |
|
- |
below the fold and looks cut off — there's no visible scrollbar on
|
|
1895 |
+ |
below the fold and looks cut off; there's no visible scrollbar on
|
| 1900 |
1896 |
|
macOS by default so users don't realize they can scroll to it. */
|
| 1901 |
1897 |
|
.modal-content > .form-actions:last-child,
|
| 1902 |
1898 |
|
.modal-content form > .form-actions:last-child {
|
| 2980 |
2976 |
|
}
|
| 2981 |
2977 |
|
|
| 2982 |
2978 |
|
/* Hide the List / Board toggle in mobile UI. Kanban drag-drop has no touch
|
| 2983 |
|
- |
fallback (Phase 6 #1) — showing the toggle would expose a broken feature.
|
|
2979 |
+ |
fallback (Phase 6 #1): showing the toggle would expose a broken feature.
|
| 2984 |
2980 |
|
Keyed off UI mode rather than `hover: none` so a desktop touch laptop
|
| 2985 |
2981 |
|
with a working mouse still gets the toggle. Re-enable when touch-drag lands. */
|
| 2986 |
2982 |
|
.ui-mode-mobile #task-view-toggle { display: none; }
|
| 5213 |
5209 |
|
}
|
| 5214 |
5210 |
|
|
| 5215 |
5211 |
|
/* Work-hours row in Settings: two small selects with a "to" label
|
| 5216 |
|
- |
between. Same lens as .email-filter-row — selects size to their
|
|
5212 |
+ |
between. Same lens as .email-filter-row: selects size to their
|
| 5217 |
5213 |
|
short content; the grid columns express the intent explicitly. */
|
| 5218 |
5214 |
|
.work-hours-row {
|
| 5219 |
5215 |
|
display: grid;
|
| 5230 |
5226 |
|
flex-shrink: 0;
|
| 5231 |
5227 |
|
}
|
| 5232 |
5228 |
|
|
| 5233 |
|
- |
/* 46. Saved Views Sidebar (desktop UI only — hidden on mobile) */
|
|
5229 |
+ |
/* 46. Saved Views Sidebar (desktop UI only, hidden on mobile) */
|
| 5234 |
5230 |
|
.ui-mode-desktop .saved-views-sidebar {
|
| 5235 |
5231 |
|
width: 200px;
|
| 5236 |
5232 |
|
flex-shrink: 0;
|
| 7704 |
7700 |
|
display: none;
|
| 7705 |
7701 |
|
}
|
| 7706 |
7702 |
|
|
| 7707 |
|
- |
/* === Mobile toolbar grids ===
|
|
7703 |
+ |
/* --- mobile toolbar grids
|
| 7708 |
7704 |
|
Toolbar rows become equal-column grids on mobile so children share
|
| 7709 |
7705 |
|
the row predictably (no orphans, no ragged wrapping). Search inputs
|
| 7710 |
7706 |
|
always span the full grid row. */
|
| 7996 |
7992 |
|
}
|
| 7997 |
7993 |
|
|
| 7998 |
7994 |
|
/* Mobile uses different modal animations (slide up/down from bottom rather
|
| 7999 |
|
- |
than fade-and-scale). @keyframes can't be scoped — defined globally under
|
|
7995 |
+ |
than fade-and-scale). @keyframes can't be scoped; defined globally under
|
| 8000 |
7996 |
|
distinct names and applied via animation-name override below. */
|
| 8001 |
7997 |
|
@keyframes modalSlideInMobile {
|
| 8002 |
7998 |
|
from { transform: translateY(100%); }
|