/* ============================================================================ MNW global stylesheet. Charter: docs/design-system.md. Build new features by COMPOSING these primitives, in this order of preference: 1. Use a UTILITY class for one-off adjustments (.mb-4, .text-sm, .nowrap) 2. Use a LAYOUT PRIMITIVE to position content (.container, .stack-row, .field-row, .list-row) 3. Use a COMPONENT PRIMITIVE for a UI element (.card, .callout, .badge, .progress-bar, .empty-state, .input--sm, .small) 4. Extend a primitive with a modifier (.card--bordered, .callout--warning, .stack-row--bordered) 5. ONLY THEN consider a new class — and add it to the right section below A new class is a smell, not a goal. Before writing one: • grep this file for the visual shape you want; almost everything is here • if you can't find it, consider whether the shape belongs in the design system (then add it to the appropriate section here AND to docs/design-system.md) • page-scoped rules (`.foo-page .bar`) are a last resort, not a first move -------------------------------------------------------------------------- FILE STRUCTURE (search by section name for anchor) FOUNDATIONS @font-face declarations (top of file) :root tokens — color, type, space, radius, shadow Element base — h1/h2/h3, p, a, button, input, table UTILITIES Spacing (.m-0, .mt-*, .mb-*, .ml-*, .my-*) Sizing (.col-*, .w-*, .maxw-*, .minw-*) Text (.text-sm, .text-xs, .text-center, .text-right, .fw-bold, .nowrap, .muted, .dimmed, .dimmer, .is-faded, .danger-text) State (.hidden, .is-selected, .is-active, .unstyled-link) Shapes (.square-cover, .scroll-x) LAYOUT PRIMITIVES (page-scaffolding shapes) .container + .container--narrow / --medium / --wide .stack-row + --bordered / --tight / --top — toolbar / header bar .field-row + .form-group.is-grow — inline form row .list-row + .list-row-title — vertical item list .form-row — 2-col grid form .cover-row + .cover-thumb + .cover-empty — image picker COMPONENT PRIMITIVES (reusable UI blocks) .content-section — light-bg page section box .card / .card-muted / .card--bordered / .card--selectable .form-group / .form-section / details.form-section .section-header / .section-lead / .section-group-label .badge + variants (-success/-warning/-danger) .callout + --danger / --warning / --solid-warning .banner + --info / --warning — full-bleed page-top notice .alert + -note / -tip / -warning / -caution — left-border inline notice .modal + .modal-overlay .empty-state + --compact / --chart / --lg .progress-bar-container + .progress-bar (--slim, --rounded, --highlight) .upload-status + __row + __msg.is-success / .is-error .field-status / .save-status + .success / .error / .saving .toast + .toast--success / --error / --warning .breadcrumb / .pagination .tabs + .tab.is-selected CONTROL MODIFIERS (compose onto buttons/inputs) .small / .btn-compact / .btn-link / .btn-tiny — button sizes .primary / .secondary / .danger / .saved — button intents .input--xs / --sm / --mono / --upper / --numeric — input sizes/shapes FEATURE SUBAPPS (their own CSS scope) .git-* (git source browser at /source/*) Pricing calculator on /pricing Markdown preview / docs-ui in /docs/* PAGE-SCOPED LAYOUTS (when truly page-specific) .item-page / .project-page / .article-page / .purchase-page / .cart-* / .library-page / .feed-page / .discover-page / .landing / .creators-page / .health-page / .import-page / .delete-account-page / .export-page / .receipt-page / .fan-plus-page / .stripe-disclaimer-page / .buy-page / .user-page / .collection-page / .changelog-page / .policy-page / .tag-tree-page / .project-blog-page / .project-paywall-page / .confirm-delete-page / .admin-page / .dashboard-page DASHBOARD TABS (one section per tab partial) Per-tab classes scoped under their canonical body class. Use modifier composition where possible; only add tab-specific rules when the shape genuinely diverges from a primitive. RESPONSIVE (@media at end of file) 768px tablet 480px phone -------------------------------------------------------------------------- When in doubt: read docs/design-system.md first. Update both files together when you add a primitive. ============================================================================ */ @font-face { font-family: "Young Serif"; src: url("/static/fonts/ysrf.woff2") format("woff2"), url("/static/fonts/ysrf.ttf") format("truetype"); font-display: swap; } @font-face { font-family: "IBM Plex Mono"; src: url("/static/fonts/IBMPlexMono-Regular.woff2") format("woff2"), url("/static/fonts/IBMPlexMono-Regular.ttf") format("truetype"); font-weight: normal; font-display: swap; } @font-face { font-family: "IBM Plex Mono"; src: url("/static/fonts/IBMPlexMono-Bold.woff2") format("woff2"), url("/static/fonts/IBMPlexMono-Bold.ttf") format("truetype"); font-weight: bold; font-display: swap; } @font-face { font-family: "Lato"; src: url("/static/fonts/Lato-Regular.woff2") format("woff2"), url("/static/fonts/Lato-Regular.ttf") format("truetype"); font-weight: normal; font-display: swap; } @font-face { font-family: "Lato"; src: url("/static/fonts/Lato-Bold.woff2") format("woff2"), url("/static/fonts/Lato-Bold.ttf") format("truetype"); font-weight: bold; font-display: swap; } :root { /* Typography (three-tier system) */ --font-heading: "Young Serif", serif; --font-mono: "IBM Plex Mono", monospace; --font-body: "Lato", sans-serif; /* Brand colors per style guide */ --background: #ede8e1; --detail: #3d3530; --highlight: #6c5ce7; --light-background: #f4f0eb; /* Extended palette */ --surface-muted: #ddd7c5; --surface-alt: #ebe7db; --surface-border: #d0cbb8; --surface-raised: #f5f0eb; --border: #d0cbb8; --text-muted: #8a8480; --input-background: #e2dad2; --overlay: rgba(0, 0, 0, 0.5); /* Semantic colors */ --primary-dark: #000000; --primary-light: #ffffff; --success: #27ae60; --success-bg: #e8fde8; --warning: #8b7355; --warning-bg: #fff3cd; --warning-border: #ffc107; --danger: #c0392b; --danger-bg: #fde8e8; --error: #d62828; --error-bg: #fef2f2; --stripe: #635BFF; /* Health status indicators */ --health-ok: #22c55e; --health-warn: #f59e0b; --health-error: #ef4444; --health-unknown: #9ca3af; /* Focus ring color for accessibility */ --focus-ring: #6c5ce7; --highlight-faint: rgba(108, 92, 231, 0.08); /* Diff / code review */ --diff-add: #2d7d2d; --diff-add-bg: rgba(45, 125, 45, 0.08); --diff-del: #a83232; --diff-del-bg: rgba(168, 50, 50, 0.08); /* Aliases used by git browser */ --secondary-bg: #f4f0eb; --text: #3d3530; /* Legacy aliases — defined to end silent var() fallback failures in inline-styled templates. Consolidate during phase 2.12. */ --accent: var(--highlight); --accent-color: var(--highlight); --border-color: var(--border); --background-color: var(--background); /* Spacing scale (charter: docs/design-system.md) */ --space-1: 0.25rem; --space-2: 0.5rem; --space-3: 0.75rem; --space-4: 1rem; --space-5: 1.5rem; --space-6: 2rem; /* Radius scale */ --radius-sm: 2px; --radius-md: 4px; --radius-round: 50%; /* Shadow scale. --shadow-1/-2/-3 are blurred elevation (true floating: popovers, dropdowns, modals). --shadow-raised/-card/-inset are hard-offset "sticker on paper" depth for everyday affordance — buttons feel pressable, cards feel layered, inputs feel recessed. Pick by role: blurred = floats over page, hard-offset = is part of page. */ --shadow-edge: #bbb; /* heavier — pressable (button, tab) */ --shadow-edge-soft: #ddd; /* lighter — surface (card, input) */ --shadow-raised: 2px 2px var(--shadow-edge); --shadow-card: 2px 2px var(--shadow-edge-soft); --shadow-inset: inset 2px 2px var(--shadow-edge-soft); --shadow-1: 0 1px 3px rgba(0, 0, 0, 0.06); --shadow-2: 0 2px 8px rgba(0, 0, 0, 0.10); --shadow-3: 0 4px 12px rgba(0, 0, 0, 0.15); } /* Reset */ * { margin: 0; padding: 0; box-sizing: border-box; } /* Base styles */ body { margin: 0; background-color: var(--background); color: var(--detail); font-family: var(--font-body); line-height: 1.6; } /* Padded page layout for most content pages */ .padded-page { padding: 1.5rem; } /* Centered page layout for landing, login, signup */ .centered-page { display: flex; flex-direction: column; justify-content: center; align-items: center; min-height: 100vh; gap: 2rem; } .centered-page h1 { font-size: 4.5rem; } .message-container { max-width: 500px; text-align: center; } .centered-wrapper { justify-content: center; text-align: center; } h1 { font-family: var(--font-heading); font-weight: normal; color: var(--detail); text-align: center; font-size: 2.5rem; } h2, h3 { font-family: var(--font-mono); font-weight: normal; color: var(--detail); } /* Heading classes (charter: docs/design-system.md — every h1/h2 in a template must carry one of these so the role is explicit). .brand-h1 — the "Makenot.work" wordmark on auth/wizard pages. .page-title — page-level h1 (Young Serif, centered). .subtitle-h2 — page subtitle h2 used under .brand-h1 in auth/wizards. .subsection-title — h2 inside dashboards, tabs, and prose partials (mono, no border — the default-h2 role made explicit). .section-header — h2 prose sub-section heading with bottom border (existing rule, see SECTIONS block). */ .brand-h1, .page-title { font-family: var(--font-heading); font-weight: normal; color: var(--detail); text-align: center; font-size: 2.5rem; } .subtitle-h2 { font-family: var(--font-mono); font-weight: normal; color: var(--detail); text-align: center; font-size: 1.5rem; } .subsection-title { font-family: var(--font-mono); font-weight: normal; color: var(--detail); } p { font-family: var(--font-body); color: var(--detail); } a { color: var(--detail); text-decoration: none; } a:hover { text-decoration: underline; } /* The signature dot */ .dot { color: var(--highlight); } /* Container — default 1200px max-width. Modifier classes for narrower pages, or comma-grouped page-scoped overrides below for body-class-based control. */ .container { max-width: 1200px; margin: 0 auto; padding: 2rem; } .container--narrow { max-width: 600px; } .container--medium { max-width: 800px; } .container--wide { max-width: 900px; } /* Per-page container width overrides (selected via body class). One rule per width tier; new pages should add their body class here rather than defining a new .foo-page .container rule. */ .delete-account-page .container, .receipt-page .container, .user-page .container { max-width: 600px; margin: 0 auto; } .import-page .container, .export-page .container { max-width: 800px; margin: 0 auto; } .fan-plus-page .container, .feed-page .container, .creators-page .container { max-width: 900px; margin: 0 auto; } /* =========================================== BUTTONS =========================================== */ button { color: var(--detail); background: var(--light-background); padding: 6px 12px; border: 1px solid var(--detail); font-family: inherit; cursor: pointer; box-shadow: var(--shadow-raised); transition: box-shadow 0.1s ease, transform 0.05s ease; } button:hover { box-shadow: 3px 3px var(--shadow-edge); } button:active { box-shadow: none; transform: translate(2px, 2px); } .btn-primary { background: var(--primary-dark); color: var(--primary-light); border: none; padding: 0.75rem 1.5rem; font-family: inherit; font-size: 1rem; cursor: pointer; box-shadow: var(--shadow-raised); transition: box-shadow 0.1s ease, transform 0.05s ease; display: inline-block; text-decoration: none; } .btn-primary:hover { box-shadow: 3px 3px var(--shadow-edge); text-decoration: none; } .btn-primary:active { box-shadow: none; transform: translate(2px, 2px); } .btn-secondary { background: var(--surface-muted); color: var(--detail); border: none; padding: 0.75rem 1.5rem; font-family: var(--font-mono); font-size: 1rem; cursor: pointer; box-shadow: var(--shadow-raised); transition: box-shadow 0.1s ease, transform 0.05s ease; display: inline-block; text-decoration: none; } .btn-secondary:hover { box-shadow: 3px 3px var(--shadow-edge); text-decoration: none; } .btn-secondary:active { box-shadow: none; transform: translate(2px, 2px); } .btn-danger { background: var(--danger); color: var(--primary-light); border: none; padding: 0.75rem 1.5rem; font-family: var(--font-mono); font-size: 1rem; cursor: pointer; box-shadow: var(--shadow-raised); transition: box-shadow 0.1s ease, transform 0.05s ease; display: inline-block; text-decoration: none; } .btn-danger:hover { box-shadow: 3px 3px var(--shadow-edge); text-decoration: none; } .btn-danger:active { box-shadow: none; transform: translate(2px, 2px); } /* Disabled state for all button variants (charter rule). Applies whether disabled via attribute or aria-disabled. */ button:disabled, button[aria-disabled="true"], .btn-primary:disabled, .btn-secondary:disabled, .btn-danger:disabled { opacity: 0.5; cursor: not-allowed; box-shadow: none; transform: none; } /* Button size + style modifiers (charter: docs/design-system.md). Use these on top of .btn-primary / -secondary / -danger. .btn--large — large CTA padding bump. .btn--icon — square icon-only / micro button (small padding, tight line-height). .btn--link — visually a link, semantically a button (no bg/ border, opacity-fade hover, mono). Some surfaces have tuned button variants that are NOT compositions of these modifiers and keep their own classes: .big-button — Young Serif 200×60 anchor on splash pages. .order-btn — list reorder up/down (with active flash). .play-button — circular media-player play control. .speed-button — segment in media-player speed group. .shortcuts-help-btn — 1.5rem square help glyph in toolbars. .toast-retry-btn — inline bordered button inside a toast, uses currentColor to inherit toast tone. These are documented variants, not deprecation targets. */ .btn--large { padding: 1rem 2.25rem; font-size: 1.125rem; } .btn--icon { padding: var(--space-1) var(--space-2); font-size: 0.85rem; line-height: 1; min-width: 1.75rem; } .btn--link { background: none; color: var(--detail); border: none; padding: 0; font-family: var(--font-mono); font-size: 1rem; cursor: pointer; /* Link semantics — flat, no depth. Overrides the shadow that would otherwise cascade from `button` / `form button` when a .btn--link happens to be a