max / makenotwork
- Co-Authored-By
- Claude Opus 4.7 (1M context) <noreply@anthropic.com>
161 files changed,
+1624 insertions,
-1160 deletions
| @@ -3551,7 +3551,7 @@ | |||
| 3551 | 3551 | ||
| 3552 | 3552 | [[package]] | |
| 3553 | 3553 | name = "makenotwork" | |
| 3554 | - | version = "0.6.6" | |
| 3554 | + | version = "0.6.9" | |
| 3555 | 3555 | dependencies = [ | |
| 3556 | 3556 | "anyhow", | |
| 3557 | 3557 | "argon2", |
| @@ -1,6 +1,6 @@ | |||
| 1 | 1 | [package] | |
| 2 | 2 | name = "makenotwork" | |
| 3 | - | version = "0.6.6" | |
| 3 | + | version = "0.6.9" | |
| 4 | 4 | edition = "2024" | |
| 5 | 5 | license-file = "LICENSE" | |
| 6 | 6 |
| @@ -39,7 +39,7 @@ | |||
| 39 | 39 | | Container | `.container` | `--narrow` (600px), `--medium` (800px), `--wide` (900px) | Default `max-width: 1200px` | | |
| 40 | 40 | | Toolbar / header bar | `.stack-row` | `--bordered`, `--tight`, `--top` | Title-left + actions-right | | |
| 41 | 41 | | Inline form row | `.field-row` | child `.form-group.is-grow` / `.is-grow-2` | Input(s) + button bottom-aligned | | |
| 42 | - | | Vertical list row | `.list-row` | parts: `__title`, `__meta` | Flex with bottom border | | |
| 42 | + | | Vertical list row | `.list-row` | parts: `-title`, `-meta` | Flex with bottom border | | |
| 43 | 43 | | Two-col form grid | `.form-row` | (none) | `grid-template-columns: 1fr 1fr` | | |
| 44 | 44 | | Cover-image row | `.cover-row` + `.cover-thumb` + `.cover-empty` | (none) | 120×120 thumbnail picker | | |
| 45 | 45 | ||
| @@ -49,10 +49,10 @@ | |||
| 49 | 49 | |---|---|---|---| | |
| 50 | 50 | | Page section box | `.content-section` | (none) | — | | |
| 51 | 51 | | Card | `.card` | `.card-muted` (surface-muted fill), `.card--bordered`, `.card--selectable` | `:hover`, `:focus-within`, `.is-selected` | | |
| 52 | - | | Button | `button.primary` / `.secondary` / `.danger` | `.small`, `.btn-compact`, `.btn-link`, `.saved` | `:hover`, `:focus-visible`, `:disabled`, `.htmx-request` | | |
| 52 | + | | Button | `.btn-primary` / `.btn-secondary` / `.btn-danger` | `.btn--large`, `.btn--icon`, `.btn--link`, `.small`, `.saved` | `:hover`, `:focus-visible`, `:disabled`, `.htmx-request` | | |
| 53 | + | | Heading | `.brand-h1` (wordmark), `.page-title` (h1), `.subtitle-h2` (auth/wizard h2), `.subsection-title` (default h2), `.section-header` (h2 with bottom border) | — | — | | |
| 53 | 54 | | Input shape | (base `input`/`textarea`/`select`) | `.input--xs`, `.input--sm`, `.input--mono`, `.input--upper`, `.input--numeric` | `:focus`, `:disabled` | | |
| 54 | 55 | | Form field | `.form-group` + `.hint` | `.form-group--error` + `.field-error` | (via `_ui.html` macro `form_field`) | | |
| 55 | - | | Section header | `.section-header` (h2 with bottom-border) | — | — | | |
| 56 | 56 | | Section lead | `.section-lead` | with `.mb-3` / `.text-sm` / `.dimmed` utilities | — | | |
| 57 | 57 | | Section divider | `.section-divider` | — | — | | |
| 58 | 58 | | Section grouping label | `.section-group-label` | — | — | | |
| @@ -67,7 +67,7 @@ | |||
| 67 | 67 | | Empty state | `.empty-state` (or `_ui.html` macro) | `--compact`, `--chart`, `--lg` | — | | |
| 68 | 68 | | Loading skeleton | `partials/loading_skeleton.html` | row, card, list | — | | |
| 69 | 69 | | Progress bar | `.progress-bar-container` + `.progress-bar` | `--slim` (6px), `--rounded`, `.progress-bar--highlight` (purple, default green) | — | | |
| 70 | - | | Upload status block | `.upload-status` + `__row` | `__msg.is-success`, `__msg.is-error` | — | | |
| 70 | + | | Upload status block | `.upload-status` + `-row` | `-msg.is-success`, `-msg.is-error` | — | | |
| 71 | 71 | | Status pill | `.field-status` / `.save-status` | `.success`, `.error`, `.saving` | — | | |
| 72 | 72 | | Table | `.data-table` (rich), `.compact-table` (small mono) | `.minw-300..800` for horizontal scroll min-width | `.sortable.ascending`, `.sortable.descending` | | |
| 73 | 73 | | Tabs | `.tabs` + `.tab` | — | `.tab.is-selected` | | |
| @@ -139,6 +139,9 @@ | |||
| 139 | 139 | 7. **Destructive actions** use `.danger` button class plus the `confirm_dialog` macro. No bare destructive buttons. | |
| 140 | 140 | 8. **Spacing values come from `--space-*` tokens.** Off-scale values are bugs. | |
| 141 | 141 | 9. **Page-scoped CSS is a last resort.** Default to composing layout + component primitives. Page-scoped sections exist for genuinely page-specific layout (grids, long-form typography, marketing heroes) — not for shapes that are cards or list rows in disguise. | |
| 142 | + | 10. **No bare `<h1>` / `<h2>` in templates.** Pick a heading class: `.brand-h1` (wordmark), `.page-title` (page h1), `.subtitle-h2` (page subtitle on auth/wizards), `.subsection-title` (default h2 inside dashboards/tabs/partials), or `.section-header` (prose sub-section with bottom border). Bare tags inside server-rendered markdown / user content (e.g. `partials/item_text_editor.html` JS preview) are the only exception. | |
| 143 | + | 11. **Button class is `.btn-primary` / `.btn-secondary` / `.btn-danger`.** Works on both `<button>` and `<a>` (the `<a><button>` antipattern is banned — use `<a class="btn-primary">…</a>`). The bare `button.primary` shorthand has been retired. | |
| 144 | + | 12. **Class names use kebab-case only.** No BEM `__` separator (retired 2026-05-20 — was 112 sites across 20 prefixes, now flattened to single-dash). Modifier `--` (e.g. `.card--bordered`) is still allowed. | |
| 142 | 145 | ||
| 143 | 146 | ## How to extend | |
| 144 | 147 |
| @@ -8,7 +8,7 @@ | |||
| 8 | 8 | ||
| 9 | 9 | **Stripe webhook delivery: RESOLVED 2026-05-17.** `evt_1TY98u0AcRNJbwd4vkSfLZZI` landed at 18:10:25 UTC, transaction completed, 0 pending in DB. Whatever was fixed in the Stripe Dashboard between 2026-05-16 and 2026-05-17 cleared it. No code change involved. | |
| 10 | 10 | ||
| 11 | - | **Next code work (LLM-doable):** Phase 1 of the UX audit sweep against the consolidated state (see `## UX audit sweep` below). Run `/ux-audit` skill scoped to `pages/index.html`, `use_cases.html`, `pricing.html`, `creators.html`, `fan_plus.html`, `changelog.html`, `policy.html`. The Phase 0 charter + remediation pre-plan are both complete — surface audits can now run. | |
| 11 | + | **Next code work (LLM-doable):** UX audit sweep phases 0-8 complete (2026-05-20). 16 remediations landed across three same-day sessions (see `## UX audit sweep (phased)` § "UX audit remediations" → "Landed 2026-05-20"). All three charter decisions (button class, heading classes, BEM separator) resolved and codified as charter rules 10-12. Two original findings retracted as incorrect data. Remaining items are three cleanup tasks (`.sr-only` upgrade on file inputs, `.landing-founder-banner` fate, orphan CSS sweep). None are launch blockers. | |
| 12 | 12 | ||
| 13 | 13 | --- | |
| 14 | 14 | ||
| @@ -194,19 +194,56 @@ | |||
| 194 | 194 | - [ ] Delete `.landing-founder-banner` if folded into hero-callout primitive (currently kept separate per charter). | |
| 195 | 195 | - [ ] Orphan CSS cleanup — ~30 truly unused class names in `style.css` deferred (e.g. `.tier-grid`, `.search-box`, `.signup-container`, `.button-stack`). Per-class judgement; revisit when bandwidth allows. | |
| 196 | 196 | ||
| 197 | - | - [ ] **Phase 0 — Design-system conformance audit.** *(Complete 2026-05-19.)* Before auditing surfaces, audit the *primitives*. The site should behave like an OS: a small set of design rules (spacing scale, type scale, color tokens, button/input/card/dialog/table/form/empty-state shapes, hover/focus/selected/disabled state recipes, loading/error/empty triad) that compose every screen. Read `static/style.css`, `static/media-player.css`, `static/wizard.css`, `_meta/docs/brand.md`, and a representative span of `templates/partials/*` + `pages/*`. Produce: (a) the inferred primitive set — what tokens and components *actually* exist in CSS/markup today; (b) divergence map — places where a screen reinvents a primitive (one-off `<div class="...">` shapes, ad-hoc spacing, bespoke buttons, duplicated empty/error states); (c) gaps — primitives the system *should* have but doesn't (e.g. no shared empty-state component, no destructive-button variant, no loading-skeleton recipe); (d) a written design-system charter (≤2 pages, `docs/design-system.md`) that names every primitive and its single canonical class/partial. Output gates the rest of the sweep: Phases 1–8 audit *conformance to the charter*, not just universal principles. Fixes in Phase 0 land as CSS/partial consolidation before any surface phase runs. | |
| 197 | + | - [x] **Phase 0 — Design-system conformance audit.** *(Complete 2026-05-19.)* Produced `docs/ux-audit/phase-0.md` (inventory + divergence map) and `docs/design-system.md` (charter). | |
| 198 | 198 | ||
| 199 | - | - [ ] **Phase 1 — Public landing & marketing.** `pages/index.html`, `use_cases.html`, `pricing.html`, `creators.html`, `fan_plus.html`, `changelog.html`, `policy.html`. First impression + conversion surface. | |
| 200 | - | - [ ] **Phase 2 — Discovery & browse.** `pages/discover.html`, `feed.html`, `tag_tree.html`, `user.html`, `project.html`, `collection.html`. Public browse path, post-discover funnel. | |
| 201 | - | - [ ] **Phase 3 — Item & library (consume).** `pages/item.html`, `library.html`, `library_audio.html`, `library_video.html`, `library_text.html`, `library_downloads.html`, `library_locked.html`, `audio_player.html`, `video_player.html`, `text_reader.html`, `blog_post.html`, `project_blog.html`, `project_paywall.html`. Soft-launch critical journey end. | |
| 202 | - | - [ ] **Phase 4 — Auth & onboarding.** `pages/login.html`, `forgot_password.html`, `reset_password.html`, `two_factor.html`, `oauth_authorize.html`, `account-deleted.html`, `confirm_delete.html`, `wizards/wizard_join.html`. Account-state transitions; forgiveness + error-message review. | |
| 203 | - | - [ ] **Phase 5 — Checkout & receipts.** `pages/buy.html`, `cart.html`, `purchase.html`, `receipt.html`, `stripe_disclaimer.html`. Commerce flow; feedback + trust cues + Stripe handoff. | |
| 204 | - | - [ ] **Phase 6 — Creator dashboard & wizards.** `dashboards/dashboard-user.html`, `dashboard-project.html`, `dashboard-item.html`, `dashboard-blog-editor.html`, `dashboard-export.html`, `dashboard-import.html`, `dashboard-delete-account.html`, `wizards/wizard_item.html`, `wizard_project.html`, plus `wizards/steps/*` and `wizards/partials/*`. Densest interaction surface — expect the most findings. | |
| 205 | - | - [ ] **Phase 7 — Admin.** `dashboards/admin-appeals.html`, `admin-metrics.html`, `admin-reports.html`, `admin-signups.html`, `admin-uploads.html`, `admin-users.html`, `admin-waitlist.html`. Internal but still has destructive actions — forgiveness + confirmation review matters. | |
| 206 | - | - [ ] **Phase 8 — Cross-cutting & utility.** `pages/error.html`, `health.html`, `sandbox.html`, `doc.html`, `doc_index.html`, `email_result.html`, `pages/git/*` (G1 browser), `partials/*`, `partials/tabs/*`. Plus a full flat-design sweep over `static/style.css`, `static/media-player.css`, `static/wizard.css`. Closes with a roll-up summary across all 8 phases. | |
| 199 | + | - [x] **Phase 1 — Public landing & marketing.** *(Complete 2026-05-20, `docs/ux-audit/phase-1.md`.)* | |
| 200 | + | - [x] **Phase 2 — Discovery & feed.** *(Complete 2026-05-20, `docs/ux-audit/phase-2.md`.)* | |
| 201 | + | - [x] **Phase 3 — Content viewing.** *(Complete 2026-05-20, `docs/ux-audit/phase-3.md`.)* | |
| 202 | + | - [x] **Phase 4 — Purchase flow.** *(Complete 2026-05-20, `docs/ux-audit/phase-4.md`.)* | |
| 203 | + | - [x] **Phase 5 — Library and media players.** *(Complete 2026-05-20, `docs/ux-audit/phase-5.md`.)* | |
| 204 | + | - [x] **Phase 6 — Auth and account.** *(Complete 2026-05-20, `docs/ux-audit/phase-6.md`.)* | |
| 205 | + | - [x] **Phase 7 — Dashboard and admin.** *(Complete 2026-05-20, `docs/ux-audit/phase-7.md`.)* | |
| 206 | + | - [x] **Phase 8 — Wizards, docs, source browser, errors.** *(Complete 2026-05-20, `docs/ux-audit/phase-8.md`.)* | |
| 207 | 207 | ||
| 208 | 208 | Out of scope for this sweep: per-tier capability decisions, brand/aesthetic direction (see `_meta/docs/brand.md`), full WCAG audit (run axe/Lighthouse separately). | |
| 209 | 209 | ||
| 210 | + | ### UX audit remediations (by site section) | |
| 211 | + | ||
| 212 | + | Findings from phases 1-8, grouped by the website area they affect. Six items landed in the audit session on 2026-05-20; seven more landed in a follow-up session the same day; two original findings were retracted (incorrect data). Remaining items are charter decisions or cleanup tasks. | |
| 213 | + | ||
| 214 | + | **Landed 2026-05-20 (audit session)** *(crossed off; kept here as a record)* | |
| 215 | + | - [x] `pricing.html` tier-picker keyboard-accessibility fix — radio visually-hidden but focusable; `:focus-within` outline on label; JS listens on `change` so keyboard navigation updates styling. | |
| 216 | + | - [x] `pricing.html` `.tier-option.selected` → `.is-selected` (last pre-charter `.selected` survivor; template, JS, and CSS all updated). | |
| 217 | + | - [x] `<a><button>` antipattern sweep — all 44 sites across 13 files converted to `<a class="btn-primary">…</a>`. Added `display: inline-block` and `text-decoration: none` to the button base rules so anchors render correctly. | |
| 218 | + | - [x] Four page-isolated `<style>` blocks migrated — `user.html` (deleted dead duplicate; rules already in style.css), `dashboard-user.html` (scoped under `.dashboard-user-page` to resolve name collision with `user.html` and the user_projects tab partial; body class updated to `padded-page dashboard-page dashboard-user-page`), `library_feed.html` (scoped under `.library-page`; added `library-page` body class to library.html), `user_settings.html` (migrated as global primitives). | |
| 219 | + | - [x] Follow-state synonyms → `.is-selected` — `.tag-follow-btn.following` and `.follow-btn.is-following` across discover.html, user.html, project.html, follow_button.html, tag_follow_toggle.html + 4 CSS rules. Also fixed a latent bug in `follow_button.html` where two `class=` attributes on the same `<button>` meant `.is-following` never actually applied. | |
| 220 | + | - [x] `.intro` lifted to `.page-intro` primitive — canonical rule added near `.section-lead`; four scoped copies dropped; four templates migrated. | |
| 221 | + | ||
| 222 | + | **Landed 2026-05-20 (follow-up session)** *(crossed off; kept here as a record)* | |
| 223 | + | - [x] **Heading convention for prose pages — decided + applied.** Picked `.section-header` over bare `<h2>` for prose-page sub-section headings. ~25 bare h2s converted across creators.html, policy.html, changelog.html, fan_plus.html, stripe_disclaimer.html, purchase.html, cart.html, library_downloads.html, doc_index.html, git/repo.html, git/settings.html. `library_locked.html:22` skipped intentionally (h2 lives inside a `.purchase-box` notification card; section-header mono-bottom-border styling would clash). Auth flow + wizards keep bare `<h2>` as the documented page-subtitle pattern. | |
| 224 | + | - [x] **`dashboard-user.html`** — "Account Deactivated" and "Account Paused" rewrapped from `.card-muted`/`<h2>` to `.alert.alert-warning`/`<p class="alert-title">`. `.banner--warning` was the audit suggestion but it's a single-line page-top primitive and doesn't fit multi-paragraph + action-buttons content. | |
| 225 | + | - [x] **`git/settings.html` delete-repo** — `onsubmit="return confirm(...)"` form replaced with htmx button (`hx-post` + `hx-confirm`). `repo_settings_delete` handler now returns `HX-Redirect` instead of `Redirect::to()`; CSRF flows via the global `htmx:configRequest` X-CSRF-Token wiring in `mnw.js`. | |
| 226 | + | - [x] **`project.html:208` `.login-cta-btn`** — class removed; `width: 100%` folded into the existing `.project-page .tier-card button` rule by extending the selector to also match `.btn-primary` anchors. | |
| 227 | + | - [x] **`dashboard-export.html` `.export-card-*` family** — documented as intentionally page-scoped (audit's other explicit option). Added a CSS comment block explaining the row-layout pattern doesn't fit `.card-muted` cleanly and the `--light-background` fill is deliberate for surface distinction from the surrounding dashboard. | |
| 228 | + | - [x] **`wizard.css` consolidation** — `.monetization-card{,-cards,.info-only}` rules deleted as dead CSS (zero template references; ~25 lines removed including responsive override). `.content-choice-card` anchor-link override + `.muted` modifier moved to style.css under the canonical `.card--selectable` recipe; renamed `.muted` → `.is-disabled` to align with `.is-selected` naming. Sole template using it (`wizards/steps/project/first_content.html`) migrated. | |
| 229 | + | - [x] **`discover_results.html` empty-state hint markup** — accepted as-is per the audit's own recommendation. Four identical inline blocks consolidated within one file; a fifth macro variant for the inline-anchor hint would be overengineered. | |
| 230 | + | ||
| 231 | + | **Retracted findings** *(audit data was wrong; no action needed)* | |
| 232 | + | - ~~`.coming-soon` modifier has no CSS rule~~ — rule exists at `style.css:6489` (`border-style: dashed; opacity: 0.6`). Original Phase 1 grep was too narrow. | |
| 233 | + | - ~~`cart-group__title` BEM `__` is the only `__` separator in the codebase~~ — actually 112 template usages across 20 block prefixes (cart-empty, cart-multi-bar, cart-group, store-cta, suspension-banner, upload-status, proj-overview-setup, bundle-picker-row, psection-row, sandbox-banner, etc.). It's an established convention. Either document in charter or schedule a separate larger rename pass — not a small fix. | |
| 234 | + | ||
| 235 | + | **Remaining items** | |
| 236 | + | ||
| 237 | + | **Charter decisions — resolved 2026-05-20** | |
| 238 | + | - [x] **Button class shorthand → `.btn-primary` / `.btn-secondary` / `.btn-danger`.** Migrated all 67 shorthand sites (`class="primary"` etc.) to `.btn-*` form across templates + JS. Dropped `button.primary` / `.secondary` / `.danger` from CSS selectors (kept `.btn-*` only) — base style.css + four scoped overrides (`.item-page`, `.project-page .item-content`, `.purchase-page`, `.link-row`). Rationale: only `.btn-*` works on both `<button>` and `<a>` (after the `<a><button>` antipattern fix), shorthand was element-scoped. Charter rule 11 codifies. | |
| 239 | + | - [x] **Heading classes — no bare `<h1>` / `<h2>`.** Added four explicit classes: `.brand-h1` (Makenot.work wordmark), `.page-title` (page h1), `.subtitle-h2` (auth/wizard subtitle), `.subsection-title` (default h2 in dashboards/tabs/partials). Existing `.section-header` (h2 with border) kept for prose sub-sections. Migrated 93 templates; only remaining bare tags are inside the JS markdown-renderer string in `partials/item_text_editor.html` (user content). Charter rule 10 codifies. | |
| 240 | + | - [x] **BEM `__` separator retired.** Renamed 76 distinct `block__elem` tokens (15 files: templates + style.css + JS) to single-dash kebab-case. Modifier `--` (`.card--bordered`) preserved. No collisions. Charter rule 12 codifies. | |
| 241 | + | ||
| 242 | + | **Cleanup tasks** (deferred from consolidation pass) | |
| 243 | + | - [x] **`.sr-only` accessibility upgrade on file inputs** *(landed 2026-05-20)* — 13 `<input type="file">` sites swapped from `class="hidden"` / `class="wizard-file-input"` to `class="sr-only"`. Trigger buttons unchanged (they `.click()` the input programmatically); screen readers and keyboard now reach the input. `.wizard-file-input { display: none }` rule removed from `wizard.css`. One file input (`dashboard-import.html#import-file`) intentionally left visible — has a proper visible label. | |
| 244 | + | - [ ] **`.landing-founder-banner`** — delete if folded into hero-callout primitive (currently kept separate per charter). | |
| 245 | + | - [ ] **Orphan CSS cleanup** — ~30 truly unused class names in `style.css` deferred (e.g. `.tier-grid`, `.search-box`, `.signup-container`, `.button-stack`). Per-class judgement; revisit when bandwidth allows. | |
| 246 | + | ||
| 210 | 247 | --- | |
| 211 | 248 | ||
| 212 | 249 | ## Infra & Quality |
| @@ -29,7 +29,7 @@ | |||
| 29 | 29 | + '<div class="collection-picker-create">' | |
| 30 | 30 | + '<form>' | |
| 31 | 31 | + '<input type="text" name="title" placeholder="New collection" required maxlength="100" autocomplete="off">' | |
| 32 | - | + '<button class="secondary" type="submit">Create</button>' | |
| 32 | + | + '<button class="btn-secondary" type="submit">Create</button>' | |
| 33 | 33 | + '</form></div>'; | |
| 34 | 34 | ||
| 35 | 35 | wrapper.appendChild(picker); |
| @@ -62,8 +62,8 @@ | |||
| 62 | 62 | '<input type="text" class="bundle-new-title" placeholder="Item name" autocomplete="off">' + | |
| 63 | 63 | '<input type="text" class="bundle-new-desc" placeholder="Description (optional)" autocomplete="off">' + | |
| 64 | 64 | '<div style="display: flex; gap: 0.25rem;">' + | |
| 65 | - | '<button type="button" class="primary bundle-create-btn" style="padding: 0.3rem 0.7rem; font-size: 0.85rem;">Create</button>' + | |
| 66 | - | '<button type="button" class="secondary bundle-cancel-btn" style="padding: 0.3rem 0.5rem; font-size: 0.85rem;">Cancel</button>' + | |
| 65 | + | '<button type="button" class="btn-primary bundle-create-btn" style="padding: 0.3rem 0.7rem; font-size: 0.85rem;">Create</button>' + | |
| 66 | + | '<button type="button" class="btn-secondary bundle-cancel-btn" style="padding: 0.3rem 0.5rem; font-size: 0.85rem;">Cancel</button>' + | |
| 67 | 67 | '</div>'; | |
| 68 | 68 | container.appendChild(row); | |
| 69 | 69 | ||
| @@ -106,7 +106,7 @@ | |||
| 106 | 106 | '<td style="padding: 0.5rem 0.5rem 0.5rem 0;"><a href="/dashboard/item/' + data.item_id + '">' + escapeHtml(data.title) + '</a></td>' + | |
| 107 | 107 | '<td style="padding: 0.5rem; font-size: 0.85rem; opacity: 0.8;">' + escapeHtml(desc) + '</td>' + | |
| 108 | 108 | '<td style="padding: 0.5rem; font-size: 0.85rem;"><a href="/dashboard/item/' + data.item_id + '" style="font-size: 0.8rem;">Manage files</a></td>' + | |
| 109 | - | '<td style="padding: 0.5rem;"><button type="button" class="secondary bundle-remove-btn" data-child-id="' + data.item_id + '" style="padding: 0.2rem 0.5rem; font-size: 0.75rem;">Remove</button></td>'; | |
| 109 | + | '<td style="padding: 0.5rem;"><button type="button" class="btn-secondary bundle-remove-btn" data-child-id="' + data.item_id + '" style="padding: 0.2rem 0.5rem; font-size: 0.75rem;">Remove</button></td>'; | |
| 110 | 110 | tbody.appendChild(tr); | |
| 111 | 111 | attachBundleRowHandlers(tr, bundleId); | |
| 112 | 112 | updateBundleCount(1); | |
| @@ -191,8 +191,8 @@ | |||
| 191 | 191 | row.innerHTML = | |
| 192 | 192 | '<span style="flex:1;font-weight:bold;">' + escapeHtml(sec.title) + '</span>' + | |
| 193 | 193 | '<span style="font-size:0.8rem;opacity:0.6;">' + (sec.body || '').length + ' chars</span>' + | |
| 194 | - | '<button type="button" class="secondary section-edit-btn" data-id="' + sec.id + '" style="padding:0.25rem 0.6rem;font-size:0.8rem;">Edit</button>' + | |
| 195 | - | '<button type="button" class="secondary section-del-btn" data-id="' + sec.id + '" style="padding:0.25rem 0.6rem;font-size:0.8rem;">Delete</button>'; | |
| 194 | + | '<button type="button" class="btn-secondary section-edit-btn" data-id="' + sec.id + '" style="padding:0.25rem 0.6rem;font-size:0.8rem;">Edit</button>' + | |
| 195 | + | '<button type="button" class="btn-secondary section-del-btn" data-id="' + sec.id + '" style="padding:0.25rem 0.6rem;font-size:0.8rem;">Delete</button>'; | |
| 196 | 196 | document.getElementById('sections-list').appendChild(row); | |
| 197 | 197 | attachSectionRowHandlers(row, itemId); | |
| 198 | 198 | updateSectionCount(1); |
| @@ -180,7 +180,7 @@ | |||
| 180 | 180 | tr.innerHTML = | |
| 181 | 181 | '<td style="padding: 0.4rem 0.5rem 0.4rem 0; font-size: 0.85rem; max-width: 200px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;" title="' + file.name.replace(/"/g, '"') + '">' + escapeHtml(file.name) + '</td>' + | |
| 182 | 182 | '<td style="padding: 0.4rem 0.5rem;"><input type="text" class="version-label-input" data-idx="' + idx + '" value="' + escapeAttr(guessLabel(file.name)) + '" placeholder="e.g., macOS (arm)" style="width: 100%; padding: 0.25rem 0.4rem; font-size: 0.85rem;"></td>' + | |
| 183 | - | '<td style="padding: 0.4rem 0.5rem;"><button type="button" class="secondary version-remove-file" data-idx="' + idx + '" style="padding: 0.2rem 0.5rem; font-size: 0.75rem;">Remove</button></td>'; | |
| 183 | + | '<td style="padding: 0.4rem 0.5rem;"><button type="button" class="btn-secondary version-remove-file" data-idx="' + idx + '" style="padding: 0.2rem 0.5rem; font-size: 0.75rem;">Remove</button></td>'; | |
| 184 | 184 | fileRows.appendChild(tr); | |
| 185 | 185 | ||
| 186 | 186 | tr.querySelector('.version-remove-file').addEventListener('click', function() { |
| @@ -91,11 +91,11 @@ | |||
| 91 | 91 | row.className = 'psection-row'; | |
| 92 | 92 | row.dataset.id = sec.id; | |
| 93 | 93 | row.innerHTML = | |
| 94 | - | '<span class="psection-row__title">' + escapeHtml(sec.title) + '</span>' + | |
| 95 | - | '<code class="psection-row__anchor">#section-' + escapeHtml(sec.slug) + '</code>' + | |
| 96 | - | '<span class="psection-row__length">' + (sec.body || '').length + ' chars</span>' + | |
| 97 | - | '<button type="button" class="secondary psection-edit-btn" data-id="' + sec.id + '" data-title="' + escapeHtml(sec.title) + '">Edit</button>' + | |
| 98 | - | '<button type="button" class="secondary psection-del-btn" data-id="' + sec.id + '">Delete</button>'; | |
| 94 | + | '<span class="psection-row-title">' + escapeHtml(sec.title) + '</span>' + | |
| 95 | + | '<code class="psection-row-anchor">#section-' + escapeHtml(sec.slug) + '</code>' + | |
| 96 | + | '<span class="psection-row-length">' + (sec.body || '').length + ' chars</span>' + | |
| 97 | + | '<button type="button" class="btn-secondary psection-edit-btn" data-id="' + sec.id + '" data-title="' + escapeHtml(sec.title) + '">Edit</button>' + | |
| 98 | + | '<button type="button" class="btn-secondary psection-del-btn" data-id="' + sec.id + '">Delete</button>'; | |
| 99 | 99 | list.appendChild(row); | |
| 100 | 100 | var hidden = document.createElement('textarea'); | |
| 101 | 101 | hidden.className = 'hidden'; | |
| @@ -132,9 +132,9 @@ | |||
| 132 | 132 | .then(function(sec) { | |
| 133 | 133 | var row = document.querySelector('.psection-row[data-id="' + id + '"]'); | |
| 134 | 134 | if (row) { | |
| 135 | - | row.querySelector('.psection-row__title').textContent = sec.title; | |
| 136 | - | row.querySelector('.psection-row__anchor').textContent = '#section-' + sec.slug; | |
| 137 | - | row.querySelector('.psection-row__length').textContent = (sec.body || '').length + ' chars'; | |
| 135 | + | row.querySelector('.psection-row-title').textContent = sec.title; | |
| 136 | + | row.querySelector('.psection-row-anchor').textContent = '#section-' + sec.slug; | |
| 137 | + | row.querySelector('.psection-row-length').textContent = (sec.body || '').length + ' chars'; | |
| 138 | 138 | row.querySelector('.psection-edit-btn').dataset.title = sec.title; | |
| 139 | 139 | } | |
| 140 | 140 | var hidden = document.querySelector('textarea[data-body-for="' + id + '"]'); |
| @@ -35,7 +35,7 @@ | |||
| 35 | 35 | .container + .container--narrow / --medium / --wide | |
| 36 | 36 | .stack-row + --bordered / --tight / --top — toolbar / header bar | |
| 37 | 37 | .field-row + .form-group.is-grow — inline form row | |
| 38 | - | .list-row + .list-row__title — vertical item list | |
| 38 | + | .list-row + .list-row-title — vertical item list | |
| 39 | 39 | .form-row — 2-col grid form | |
| 40 | 40 | .cover-row + .cover-thumb + .cover-empty — image picker | |
| 41 | 41 | ||
| @@ -271,6 +271,39 @@ | |||
| 271 | 271 | color: var(--detail); | |
| 272 | 272 | } | |
| 273 | 273 | ||
| 274 | + | /* Heading classes (charter: docs/design-system.md — every h1/h2 in a | |
| 275 | + | template must carry one of these so the role is explicit). | |
| 276 | + | ||
| 277 | + | .brand-h1 — the "Makenot.work" wordmark on auth/wizard pages. | |
| 278 | + | .page-title — page-level h1 (Young Serif, centered). | |
| 279 | + | .subtitle-h2 — page subtitle h2 used under .brand-h1 in auth/wizards. | |
| 280 | + | .subsection-title — h2 inside dashboards, tabs, and prose partials | |
| 281 | + | (mono, no border — the default-h2 role made explicit). | |
| 282 | + | .section-header — h2 prose sub-section heading with bottom border | |
| 283 | + | (existing rule, see SECTIONS block). */ | |
| 284 | + | .brand-h1, | |
| 285 | + | .page-title { | |
| 286 | + | font-family: var(--font-heading); | |
| 287 | + | font-weight: normal; | |
| 288 | + | color: var(--detail); | |
| 289 | + | text-align: center; | |
| 290 | + | font-size: 2.5rem; | |
| 291 | + | } | |
| 292 | + | ||
| 293 | + | .subtitle-h2 { | |
| 294 | + | font-family: var(--font-mono); | |
| 295 | + | font-weight: normal; | |
| 296 | + | color: var(--detail); | |
| 297 | + | text-align: center; | |
| 298 | + | font-size: 1.5rem; | |
| 299 | + | } | |
| 300 | + | ||
| 301 | + | .subsection-title { | |
| 302 | + | font-family: var(--font-mono); | |
| 303 | + | font-weight: normal; | |
| 304 | + | color: var(--detail); | |
| 305 | + | } | |
| 306 | + | ||
| 274 | 307 | p { | |
| 275 | 308 | font-family: var(--font-body); | |
| 276 | 309 | color: var(--detail); | |
| @@ -333,7 +366,6 @@ | |||
| 333 | 366 | opacity: 0.8; | |
| 334 | 367 | } | |
| 335 | 368 | ||
| 336 | - | button.primary, | |
| 337 | 369 | .btn-primary { | |
| 338 | 370 | background: var(--primary-dark); | |
| 339 | 371 | color: var(--primary-light); | |
| @@ -343,14 +375,15 @@ | |||
| 343 | 375 | font-size: 1rem; | |
| 344 | 376 | cursor: pointer; | |
| 345 | 377 | transition: opacity 0.2s ease; | |
| 378 | + | display: inline-block; | |
| 379 | + | text-decoration: none; | |
| 346 | 380 | } | |
| 347 | 381 | ||
| 348 | - | button.primary:hover, | |
| 349 | 382 | .btn-primary:hover { | |
| 350 | 383 | opacity: 0.8; | |
| 384 | + | text-decoration: none; | |
| 351 | 385 | } | |
| 352 | 386 | ||
| 353 | - | button.secondary, | |
| 354 | 387 | .btn-secondary { | |
| 355 | 388 | background: var(--surface-muted); | |
| 356 | 389 | color: var(--detail); | |
| @@ -360,14 +393,15 @@ | |||
| 360 | 393 | font-size: 1rem; | |
| 361 | 394 | cursor: pointer; | |
| 362 | 395 | transition: opacity 0.2s ease; | |
| 396 | + | display: inline-block; | |
| 397 | + | text-decoration: none; | |
| 363 | 398 | } | |
| 364 | 399 | ||
| 365 | - | button.secondary:hover, | |
| 366 | 400 | .btn-secondary:hover { | |
| 367 | 401 | opacity: 0.8; | |
| 402 | + | text-decoration: none; | |
| 368 | 403 | } | |
| 369 | 404 | ||
| 370 | - | button.danger, | |
| 371 | 405 | .btn-danger { | |
| 372 | 406 | background: var(--danger); | |
| 373 | 407 | color: var(--primary-light); | |
| @@ -377,11 +411,13 @@ | |||
| 377 | 411 | font-size: 1rem; | |
| 378 | 412 | cursor: pointer; | |
| 379 | 413 | transition: opacity 0.2s ease; | |
| 414 | + | display: inline-block; | |
| 415 | + | text-decoration: none; | |
| 380 | 416 | } | |
| 381 | 417 | ||
| 382 | - | button.danger:hover, | |
| 383 | 418 | .btn-danger:hover { | |
| 384 | 419 | opacity: 0.8; | |
| 420 | + | text-decoration: none; | |
| 385 | 421 | } | |
| 386 | 422 | ||
| 387 | 423 | /* Disabled state for all button variants (charter rule). | |
| @@ -407,8 +443,6 @@ | |||
| 407 | 443 | Some surfaces have tuned button variants that are NOT compositions | |
| 408 | 444 | of these modifiers and keep their own classes: | |
| 409 | 445 | .big-button — Young Serif 200×60 anchor on splash pages. | |
| 410 | - | .paywall-btn — wider primary CTA (anchor) on paywalls. | |
| 411 | - | .notify-btn — small inverted notify pill in dashboards. | |
| 412 | 446 | .order-btn — list reorder up/down (with active flash). | |
| 413 | 447 | .play-button — circular media-player play control. | |
| 414 | 448 | .speed-button — segment in media-player speed group. | |
| @@ -1182,6 +1216,21 @@ | |||
| 1182 | 1216 | INFO & WARNING BOXES | |
| 1183 | 1217 | =========================================== */ | |
| 1184 | 1218 | ||
| 1219 | + | /* Notification surface roles (charter: docs/design-system.md). | |
| 1220 | + | Five distinct components — keep them distinct, don't merge: | |
| 1221 | + | .toast — transient, JS-dismissible, bottom-right corner. | |
| 1222 | + | .banner — full-bleed page-top notice (sandbox, restart, | |
| 1223 | + | founder pricing). One short sentence + optional link. | |
| 1224 | + | .alert — inline directive callout with uppercase mono title | |
| 1225 | + | (NOTE / TIP / IMPORTANT / WARNING / CAUTION). Used in | |
| 1226 | + | docs and longer-form bodies. | |
| 1227 | + | .info-box — informational headed block with h3 + bullet list | |
| 1228 | + | inside forms / wizards (distinct register from .alert). | |
| 1229 | + | .warning-box — loud yellow-on-yellow attention-grabber for | |
| 1230 | + | page-level warnings (delete confirms, account | |
| 1231 | + | warnings). Louder than .alert-warning intentionally. | |
| 1232 | + | .error-message — inline form-field error; hidden by default, shown | |
| 1233 | + | with .is-active. Distinct from page-level .alert. */ | |
| 1185 | 1234 | .info-box { | |
| 1186 | 1235 | background: var(--surface-muted); | |
| 1187 | 1236 | padding: 1rem; | |
| @@ -1526,13 +1575,13 @@ | |||
| 1526 | 1575 | opacity: 0.5; | |
| 1527 | 1576 | } | |
| 1528 | 1577 | ||
| 1529 | - | .item-page button.primary { | |
| 1578 | + | .item-page .btn-primary { | |
| 1530 | 1579 | width: 100%; | |
| 1531 | 1580 | padding: var(--space-4) var(--space-6); | |
| 1532 | 1581 | font-size: 1.1rem; | |
| 1533 | 1582 | } | |
| 1534 | 1583 | ||
| 1535 | - | .item-page button.secondary { | |
| 1584 | + | .item-page .btn-secondary { | |
| 1536 | 1585 | width: 100%; | |
| 1537 | 1586 | margin-top: var(--space-2); | |
| 1538 | 1587 | } | |
| @@ -1751,8 +1800,8 @@ | |||
| 1751 | 1800 | ||
| 1752 | 1801 | .project-page .store-footer a { color: var(--detail); } | |
| 1753 | 1802 | ||
| 1754 | - | .project-page .item-content button.primary, | |
| 1755 | - | .project-page .item-content button.secondary { | |
| 1803 | + | .project-page .item-content .btn-primary, | |
| 1804 | + | .project-page .item-content .btn-secondary { | |
| 1756 | 1805 | width: 100%; | |
| 1757 | 1806 | margin-top: var(--space-4); | |
| 1758 | 1807 | } | |
| @@ -1796,7 +1845,8 @@ | |||
| 1796 | 1845 | } | |
| 1797 | 1846 | ||
| 1798 | 1847 | .project-page .tier-card form { margin-top: auto; } | |
| 1799 | - | .project-page .tier-card button { width: 100%; } | |
| 1848 | + | .project-page .tier-card button, | |
| 1849 | + | .project-page .tier-card .btn-primary { width: 100%; } | |
| 1800 | 1850 | ||
| 1801 | 1851 | .project-page .tier-active-badge { | |
| 1802 | 1852 | font-size: 0.85rem; | |
| @@ -2600,7 +2650,12 @@ | |||
| 2600 | 2650 | .delete-account-page .form-status.error { color: var(--danger); } | |
| 2601 | 2651 | .delete-account-page .form-status.success { color: var(--success); } | |
| 2602 | 2652 | ||
| 2603 | - | /* Export data page (templates/dashboards/dashboard-export.html). */ | |
| 2653 | + | /* Export data page (templates/dashboards/dashboard-export.html). | |
| 2654 | + | `.export-card` and its inner classes (`-info`, `-title`, `-desc`, `-meta`) | |
| 2655 | + | are intentionally page-scoped: this is a row-layout card (info on left, | |
| 2656 | + | action button on right, flex justify-between) that doesn't fit `.card-muted` | |
| 2657 | + | cleanly. Background uses `--light-background` rather than `--surface-muted` | |
| 2658 | + | for visual distinction from the surrounding dashboard surface. */ | |
| 2604 | 2659 | ||
| 2605 | 2660 | .export-page .export-cards { | |
| 2606 | 2661 | display: grid; | |
| @@ -2724,11 +2779,6 @@ | |||
| 2724 | 2779 | .fan-plus-page h1 { font-size: 2.5rem; margin-bottom: var(--space-2); } | |
| 2725 | 2780 | .fan-plus-page h2 { font-size: 1.5rem; margin-top: var(--space-6); margin-bottom: var(--space-4); } | |
| 2726 | 2781 | ||
| 2727 | - | .fan-plus-page .intro { | |
| 2728 | - | font-size: 1.1rem; | |
| 2729 | - | margin-bottom: var(--space-6); | |
| 2730 | - | line-height: 1.6; | |
| 2731 | - | } | |
| 2732 | 2782 | ||
| 2733 | 2783 | .fan-plus-page .fan-plus-section { margin-bottom: var(--space-6); line-height: 1.7; } | |
| 2734 | 2784 | .fan-plus-page .fan-plus-section ul { padding-left: var(--space-5); margin: var(--space-3) 0; } | |
| @@ -2862,8 +2912,8 @@ | |||
| 2862 | 2912 | .purchase-page .payment-section { margin-bottom: var(--space-5); } | |
| 2863 | 2913 | .purchase-page .payment-section h2 { font-size: 1.1rem; margin-bottom: var(--space-4); } | |
| 2864 | 2914 | ||
| 2865 | - | .purchase-page button.primary { width: 100%; } | |
| 2866 | - | .purchase-page button.secondary { width: 100%; margin-top: var(--space-4); } | |
| 2915 | + | .purchase-page .btn-primary { width: 100%; } | |
| 2916 | + | .purchase-page .btn-secondary { width: 100%; margin-top: var(--space-4); } | |
| 2867 | 2917 | ||
| 2868 | 2918 | .purchase-page .security-note { | |
| 2869 | 2919 | font-size: 0.85rem; | |
| @@ -3033,6 +3083,13 @@ | |||
| 3033 | 3083 | text-align: left; | |
| 3034 | 3084 | } | |
| 3035 | 3085 | ||
| 3086 | + | /* Large intro paragraph under a page h1 (creators, policy, changelog, fan_plus). */ | |
| 3087 | + | .page-intro { | |
| 3088 | + | font-size: 1.1rem; | |
| 3089 | + | margin-bottom: var(--space-6); | |
| 3090 | + | line-height: 1.6; | |
| 3091 | + | } | |
| 3092 | + | ||
| 3036 | 3093 | .subscription-note p { | |
| 3037 | 3094 | opacity: 0.7; | |
| 3038 | 3095 | font-size: 0.9rem; | |
| @@ -3055,9 +3112,9 @@ | |||
| 3055 | 3112 | ||
| 3056 | 3113 | /* psection-* mirrors section-mgmt-* (used by item_details) but psection | |
| 3057 | 3114 | class hooks are also queried by static/project-sections.js. */ | |
| 3058 | - | .psection-row__title { flex: 1; font-weight: bold; } | |
| 3059 | - | .psection-row__anchor { font-size: 0.75rem; opacity: 0.6; } | |
| 3060 | - | .psection-row__length { font-size: 0.8rem; opacity: 0.6; } | |
| 3115 | + | .psection-row-title { flex: 1; font-weight: bold; } | |
| 3116 | + | .psection-row-anchor { font-size: 0.75rem; opacity: 0.6; } | |
| 3117 | + | .psection-row-length { font-size: 0.8rem; opacity: 0.6; } | |
| 3061 | 3118 | ||
| 3062 | 3119 | .psection-edit-btn, | |
| 3063 | 3120 | .psection-del-btn { | |
| @@ -3090,18 +3147,18 @@ | |||
| 3090 | 3147 | text-align: center; | |
| 3091 | 3148 | padding: 3rem 1rem; | |
| 3092 | 3149 | } | |
| 3093 | - | .cart-empty__hint { | |
| 3150 | + | .cart-empty-hint { | |
| 3094 | 3151 | font-size: 0.9rem; | |
| 3095 | 3152 | opacity: 0.7; | |
| 3096 | 3153 | margin-bottom: var(--space-5); | |
| 3097 | 3154 | } | |
| 3098 | 3155 | ||
| 3099 | 3156 | /* Multi-creator summary bar (only renders when seller_groups.len() > 1). */ | |
| 3100 | - | .cart-multi-bar__note { | |
| 3157 | + | .cart-multi-bar-note { | |
| 3101 | 3158 | opacity: 0.7; | |
| 3102 | 3159 | margin-left: var(--space-2); | |
| 3103 | 3160 | } | |
| 3104 | - | .cart-multi-bar__form { | |
| 3161 | + | .cart-multi-bar-form { | |
| 3105 | 3162 | display: flex; | |
| 3106 | 3163 | align-items: center; | |
| 3107 | 3164 | gap: var(--space-3); | |
| @@ -3115,8 +3172,8 @@ | |||
| 3115 | 3172 | ||
| 3116 | 3173 | /* Per-seller group card. */ | |
| 3117 | 3174 | .cart-group { margin-bottom: var(--space-6); } | |
| 3118 | - | .cart-group__title { margin-bottom: 0.25rem; } | |
| 3119 | - | .cart-group__count { | |
| 3175 | + | .cart-group-title { margin-bottom: 0.25rem; } | |
| 3176 | + | .cart-group-count { | |
| 3120 | 3177 | font-size: 0.85rem; | |
| 3121 | 3178 | opacity: 0.6; | |
| 3122 | 3179 | margin-bottom: var(--space-4); | |
| @@ -3134,7 +3191,7 @@ | |||
| 3134 | 3191 | /* Compact action button used in cart/wishlist tables. */ | |
| 3135 | 3192 | ||
| 3136 | 3193 | /* Bottom summary row of each seller group. */ | |
| 3137 | - | .cart-group__summary { | |
| 3194 | + | .cart-group-summary { | |
| 3138 | 3195 | margin-top: var(--space-4); | |
| 3139 | 3196 | display: flex; | |
| 3140 | 3197 | justify-content: space-between; | |
| @@ -3208,16 +3265,16 @@ | |||
| 3208 | 3265 | margin-bottom: var(--space-2); | |
| 3209 | 3266 | } | |
| 3210 | 3267 | .dns-row:last-of-type { margin-bottom: 0; } | |
| 3211 | - | .dns-row__label { | |
| 3268 | + | .dns-row-label { | |
| 3212 | 3269 | font-size: 0.8rem; | |
| 3213 | 3270 | opacity: 0.7; | |
| 3214 | 3271 | min-width: 70px; | |
| 3215 | 3272 | } | |
| 3216 | - | .dns-row__value { | |
| 3273 | + | .dns-row-value { | |
| 3217 | 3274 | font-size: 0.85rem; | |
| 3218 | 3275 | flex: 1; | |
| 3219 | 3276 | } | |
| 3220 | - | .dns-row__copy { | |
| 3277 | + | .dns-row-copy { | |
| 3221 | 3278 | padding: 0.15rem 0.5rem; | |
| 3222 | 3279 | font-size: 0.75rem; | |
| 3223 | 3280 | } | |
| @@ -3437,12 +3494,6 @@ | |||
| 3437 | 3494 | .creators-page h1 { font-size: 2.5rem; margin-bottom: var(--space-2); } | |
| 3438 | 3495 | .creators-page h2 { font-size: 1.5rem; margin-top: var(--space-6); margin-bottom: var(--space-4); } | |
| 3439 | 3496 | ||
| 3440 | - | .creators-page .intro { | |
| 3441 | - | font-size: 1.1rem; | |
| 3442 | - | margin-bottom: var(--space-6); | |
| 3443 | - | line-height: 1.6; | |
| 3444 | - | } | |
| 3445 | - | ||
| 3446 | 3497 | .creators-page .how-it-works { margin-bottom: var(--space-6); } | |
| 3447 | 3498 | .creators-page .how-it-works ol { padding-left: var(--space-5); line-height: 1.8; } | |
| 3448 | 3499 | ||
| @@ -3724,10 +3775,117 @@ | |||
| 3724 | 3775 | } | |
| 3725 | 3776 | .health-page .subtitle { text-align: center; } | |
| 3726 | 3777 | ||
| 3727 | - | /* User-level dashboard (templates/dashboards/dashboard-user.html). */ | |
| 3728 | - | .stat-value { font-size: 2rem; margin-bottom: var(--space-1); } | |
| 3778 | + | /* User Settings tab (templates/partials/tabs/user_settings.html). | |
| 3779 | + | Left-rail nav layout for the Settings dashboard tab. Selection uses the | |
| 3780 | + | canonical .is-selected modifier. */ | |
| 3781 | + | .settings-layout { display: flex; gap: var(--space-6); } | |
| 3782 | + | .settings-nav { flex-shrink: 0; min-width: 140px; } | |
| 3783 | + | .settings-nav a { | |
| 3784 | + | display: block; | |
| 3785 | + | padding: var(--space-2) var(--space-3); | |
| 3786 | + | text-decoration: none; | |
| 3787 | + | color: var(--detail); | |
| 3788 | + | opacity: 0.6; | |
| 3789 | + | font-family: var(--font-mono); | |
| 3790 | + | font-size: 0.9rem; | |
| 3791 | + | transition: opacity 0.15s ease; | |
| 3792 | + | } | |
| 3793 | + | .settings-nav a:hover { opacity: 1; } | |
| 3794 | + | .settings-nav a.is-selected { opacity: 1; background: var(--surface-muted); } | |
| 3795 | + | .settings-body { flex: 1; min-width: 0; } | |
| 3796 | + | @media (max-width: 768px) { | |
| 3797 | + | .settings-layout { flex-direction: column; gap: var(--space-4); } | |
| 3798 | + | .settings-nav { display: flex; flex-wrap: wrap; gap: 0; min-width: 0; } | |
| 3799 | + | .settings-nav a { padding: 0.4rem 0.6rem; font-size: 0.85rem; } | |
| 3800 | + | } | |
| 3729 | 3801 | ||
| 3730 | - | .project-card { | |
| 3802 | + | /* Library "Feed" tab (templates/partials/tabs/library_feed.html). | |
| 3803 | + | Scoped under .library-page so rules don't bleed onto the standalone | |
| 3804 | + | /feed page (which has its own .feed-page-scoped rules). */ | |
| 3805 | + | .library-page .feed-meta { font-size: 0.8rem; opacity: 0.6; margin-bottom: var(--space-3); } | |
| 3806 | + | .library-page .feed-table-header { | |
| 3807 | + | display: grid; | |
| 3808 | + | grid-template-columns: 50px 1fr 100px 70px 70px; | |
| 3809 | + | gap: var(--space-2); | |
| 3810 | + | padding: var(--space-2) var(--space-3); | |
| 3811 | + | background: var(--surface-alt); | |
| 3812 | + | font-size: 0.75rem; | |
| 3813 | + | opacity: 0.7; | |
| 3814 | + | text-transform: uppercase; | |
| 3815 | + | letter-spacing: 0.03em; | |
| 3816 | + | } | |
| 3817 | + | .library-page .feed-col-right { text-align: right; } | |
| 3818 | + | .library-page .feed-results-table { border: 1px solid var(--border); border-top: none; } | |
| 3819 | + | .library-page .feed-table-row { | |
| 3820 | + | display: grid; | |
| 3821 | + | grid-template-columns: 50px 1fr 100px 70px 70px; | |
| 3822 | + | gap: var(--space-2); | |
| 3823 | + | padding: 0.4rem var(--space-3); | |
| 3824 | + | align-items: center; | |
| 3825 | + | text-decoration: none; | |
| 3826 | + | color: var(--detail); | |
| 3827 | + | font-size: 0.85rem; | |
| 3828 | + | border-bottom: 1px solid var(--border); | |
| 3829 | + | transition: background 0.1s ease; | |
| 3830 | + | } | |
| 3831 | + | .library-page .feed-table-row:last-child { border-bottom: none; } | |
| 3832 | + | .library-page .feed-table-row:nth-child(odd) { background: var(--light-background); } | |
| 3833 | + | .library-page .feed-table-row:nth-child(even) { background: var(--surface-alt); } | |
| 3834 | + | .library-page .feed-table-row:hover { background: var(--surface-muted); } | |
| 3835 | + | .library-page .feed-item-name-cell { | |
| 3836 | + | display: flex; | |
| 3837 | + | flex-direction: column; | |
| 3838 | + | gap: 0.1rem; | |
| 3839 | + | min-width: 0; | |
| 3840 | + | } | |
| 3841 | + | .library-page .feed-item-name { | |
| 3842 | + | white-space: nowrap; | |
| 3843 | + | overflow: hidden; | |
| 3844 | + | text-overflow: ellipsis; | |
| 3845 | + | } | |
| 3846 | + | .library-page .feed-item-creator { font-size: 0.75rem; opacity: 0.5; } | |
| 3847 | + | .library-page .feed-pagination { | |
| 3848 | + | display: flex; | |
| 3849 | + | gap: var(--space-1); | |
| 3850 | + | justify-content: center; | |
| 3851 | + | margin-top: var(--space-4); | |
| 3852 | + | } | |
| 3853 | + | .library-page .feed-pagination a, | |
| 3854 | + | .library-page .feed-pagination span { | |
| 3855 | + | padding: 0.4rem 0.7rem; | |
| 3856 | + | font-size: 0.85rem; | |
| 3857 | + | text-decoration: none; | |
| 3858 | + | color: var(--detail); | |
| 3859 | + | border: 1px solid var(--border); | |
| 3860 | + | } | |
| 3861 | + | .library-page .feed-pagination span.current { | |
| 3862 | + | background: var(--primary-dark); | |
| 3863 | + | color: var(--primary-light); | |
| 3864 | + | border-color: var(--primary-dark); | |
| 3865 | + | } | |
| 3866 | + | .library-page .feed-pagination a:hover { background: var(--surface-muted); } | |
| 3867 | + | @media (max-width: 600px) { | |
| 3868 | + | .library-page .feed-table-header, | |
| 3869 | + | .library-page .feed-table-row { | |
| 3870 | + | grid-template-columns: 1fr 70px; | |
| 3871 | + | } | |
| 3872 | + | .library-page .feed-table-header span:nth-child(1), | |
| 3873 | + | .library-page .feed-table-row .badge:first-child, | |
| 3874 | + | .library-page .feed-table-header span:nth-child(3), | |
| 3875 | + | .library-page .feed-table-header span:nth-child(4), | |
| 3876 | + | .library-page .feed-table-row span:nth-child(3), | |
| 3877 | + | .library-page .feed-table-row span:nth-child(4) { | |
| 3878 | + | display: none; | |
| 3879 | + | } | |
| 3880 | + | } | |
| 3881 | + | ||
| 3882 | + | /* User-level dashboard (templates/dashboards/dashboard-user.html). | |
| 3883 | + | Scoped under .dashboard-user-page to avoid colliding with .project-card | |
| 3884 | + | / .project-title / .project-meta on the public profile (user.html) and | |
| 3885 | + | the user_projects tab partial. */ | |
| 3886 | + | .dashboard-user-page .stat-value { font-size: 2rem; margin-bottom: var(--space-1); } | |
| 3887 | + | ||
| 3888 | + | .dashboard-user-page .project-card { | |
| 3731 | 3889 | background: var(--light-background); | |
| 3732 | 3890 | padding: var(--space-5); | |
| 3733 | 3891 | margin-bottom: var(--space-4); | |
| @@ -3736,33 +3894,33 @@ | |||
| 3736 | 3894 | align-items: flex-start; | |
| 3737 | 3895 | } | |
| 3738 | 3896 | ||
| 3739 | - | .project-info { flex: 1; } | |
| 3897 | + | .dashboard-user-page .project-info { flex: 1; } | |
| 3740 | 3898 | ||
| 3741 | - | .project-title { | |
| 3899 | + | .dashboard-user-page .project-title { | |
| 3742 | 3900 | font-family: var(--font-heading); | |
| 3743 | 3901 | font-weight: bold; | |
| 3744 | 3902 | font-size: 1.2rem; | |
| 3745 | 3903 | margin-bottom: var(--space-1); | |
| 3746 | 3904 | } | |
| 3747 | 3905 | ||
| 3748 | - | .project-meta { | |
| 3906 | + | .dashboard-user-page .project-meta { | |
| 3749 | 3907 | font-size: 0.85rem; | |
| 3750 | 3908 | opacity: 0.7; | |
| 3751 | 3909 | margin-bottom: var(--space-2); | |
| 3752 | 3910 | } | |
| 3753 | 3911 | ||
| 3754 | - | .project-stats { font-size: 0.9rem; } | |
| 3755 | - | .project-actions { | |
| 3912 | + | .dashboard-user-page .project-stats { font-size: 0.9rem; } | |
| 3913 | + | .dashboard-user-page .project-actions { | |
| 3756 | 3914 | display: flex; | |
| 3757 | 3915 | gap: var(--space-2); | |
| 3758 | 3916 | } | |
| 3759 | 3917 | ||
| 3760 | - | .project-actions button { | |
| 3918 | + | .dashboard-user-page .project-actions button { | |
| 3761 | 3919 | padding: 0.4rem 0.8rem; | |
| 3762 | 3920 | font-size: 0.85rem; | |
| 3763 | 3921 | } | |
| 3764 | 3922 | ||
| 3765 | - | .summary-row { | |
| 3923 | + | .dashboard-user-page .summary-row { | |
| 3766 | 3924 | background: var(--surface-muted); | |
| 3767 | 3925 | padding: var(--space-4); | |
| 3768 | 3926 | margin-top: var(--space-4); | |
| @@ -3770,8 +3928,8 @@ | |||
| 3770 | 3928 | } | |
| 3771 | 3929 | ||
| 3772 | 3930 | @media (max-width: 768px) { | |
| 3773 | - | .project-card { flex-direction: column; } | |
| 3774 | - | .project-actions { margin-top: var(--space-3); } | |
| 3931 | + | .dashboard-user-page .project-card { flex-direction: column; } | |
| 3932 | + | .dashboard-user-page .project-actions { margin-top: var(--space-3); } | |
| 3775 | 3933 | } | |
| 3776 | 3934 | ||
| 3777 | 3935 | /* Project dashboard (templates/dashboards/dashboard-project.html). */ | |
| @@ -3859,11 +4017,6 @@ | |||
| 3859 | 4017 | /* Changelog page (templates/pages/changelog.html). */ | |
| 3860 | 4018 | .changelog-page .container { max-width: 900px; margin: 0 auto; } | |
| 3861 | 4019 | .changelog-page h1 { font-size: 2.5rem; margin-bottom: var(--space-2); } | |
| 3862 | - | .changelog-page .intro { | |
| 3863 | - | font-size: 1.1rem; | |
| 3864 | - | margin-bottom: var(--space-6); | |
| 3865 | - | line-height: 1.6; | |
| 3866 | - | } | |
| 3867 | 4020 | .changelog-page .changelog-entry { | |
| 3868 | 4021 | margin-bottom: 2.5rem; | |
| 3869 | 4022 | padding-bottom: var(--space-6); | |
| @@ -3892,11 +4045,6 @@ | |||
| 3892 | 4045 | margin-top: var(--space-6); | |
| 3893 | 4046 | margin-bottom: var(--space-4); | |
| 3894 | 4047 | } | |
| 3895 | - | .policy-page .intro { | |
| 3896 | - | font-size: 1.1rem; | |
| 3897 | - | margin-bottom: var(--space-6); | |
| 3898 | - | line-height: 1.6; | |
| 3899 | - | } | |
| 3900 | 4048 | .policy-page .policy-section { margin-bottom: var(--space-6); line-height: 1.7; } | |
| 3901 | 4049 | .policy-page .policy-section ul { | |
| 3902 | 4050 | padding-left: var(--space-5); | |
| @@ -4557,7 +4705,6 @@ | |||
| 4557 | 4705 | opacity: 0.6; | |
| 4558 | 4706 | } | |
| 4559 | 4707 | ||
| 4560 | - | .time-selector button.active, | |
| 4561 | 4708 | .time-selector button.is-selected { | |
| 4562 | 4709 | opacity: 1; | |
| 4563 | 4710 | background: var(--primary-dark); | |
| @@ -4952,11 +5099,10 @@ | |||
| 4952 | 5099 | ||
| 4953 | 5100 | /* Canonical "selected" recipe (charter: docs/design-system.md). | |
| 4954 | 5101 | Apply `.is-selected` to any interactive container to mark it as the | |
| 4955 | - | currently-selected option. Component-specific rules below (`.tab`, | |
| 4956 | - | `.filter-item`, `.view-btn`, `.type-card`/`.pricing-card` :checked) | |
| 4957 | - | also accept `.is-selected` as an alias for `.active` so templates can | |
| 4958 | - | migrate incrementally. `.badge.active` is intentionally NOT aliased |
Lines truncated
| @@ -186,37 +186,9 @@ | |||
| 186 | 186 | border-top: 1px solid var(--border); | |
| 187 | 187 | } | |
| 188 | 188 | ||
| 189 | - | /* Monetization Cards */ | |
| 190 | - | ||
| 191 | - | .monetization-cards { | |
| 192 | - | display: grid; | |
| 193 | - | grid-template-columns: 1fr 1fr; | |
| 194 | - | gap: 1rem; | |
| 195 | - | margin-bottom: 1.5rem; | |
| 196 | - | } | |
| 197 | - | ||
| 198 | - | .monetization-card { | |
| 199 | - | background: var(--background); | |
| 200 | - | padding: 1.25rem; | |
| 201 | - | border: 1px solid var(--border); | |
| 202 | - | border-radius: 4px; | |
| 203 | - | } | |
| 204 | - | ||
| 205 | - | .monetization-card h3 { | |
| 206 | - | font-family: var(--font-mono); | |
| 207 | - | font-size: 0.95rem; | |
| 208 | - | margin-bottom: 0.5rem; | |
| 209 | - | } | |
| 210 | - | ||
| 211 | - | .monetization-card p { | |
| 212 | - | font-size: 0.85rem; | |
| 213 | - | color: var(--text-muted); | |
| 214 | - | margin-bottom: 0.5rem; | |
| 215 | - | } | |
| 216 | - | ||
| 217 | - | .monetization-card.info-only { | |
| 218 | - | opacity: 0.85; | |
| 219 | - | } | |
| 189 | + | /* (`.monetization-card{,-cards,.info-only}` removed 2026-05-20 — dead CSS, | |
| 190 | + | no template references. Selectable monetization choices use the canonical | |
| 191 | + | `.card--selectable` recipe in style.css.) */ | |
| 220 | 192 | ||
| 221 | 193 | .tier-row { | |
| 222 | 194 | display: flex; | |
| @@ -245,9 +217,8 @@ | |||
| 245 | 217 | margin-bottom: 1.5rem; | |
| 246 | 218 | } | |
| 247 | 219 | ||
| 248 | - | /* (.pricing-card and .content-choice-card primitives live in style.css under | |
| 249 | - | the .card--selectable canonical recipe. The "muted" pointer-events override | |
| 250 | - | and content-choice anchor-link styling remain here.) */ | |
| 220 | + | /* (`.pricing-card`, `.content-choice-card`, and the `.is-disabled` modifier | |
| 221 | + | all live in style.css under the canonical `.card--selectable` recipe.) */ | |
| 251 | 222 | .pricing-fields { | |
| 252 | 223 | margin-top: 1rem; | |
| 253 | 224 | } | |
| @@ -259,16 +230,6 @@ | |||
| 259 | 230 | margin-bottom: 1.5rem; | |
| 260 | 231 | } | |
| 261 | 232 | ||
| 262 | - | .content-choice-card { | |
| 263 | - | text-decoration: none; | |
| 264 | - | color: inherit; | |
| 265 | - | } | |
| 266 | - | ||
| 267 | - | .content-choice-card.muted { | |
| 268 | - | opacity: 0.7; | |
| 269 | - | pointer-events: none; | |
| 270 | - | } | |
| 271 | - | ||
| 272 | 233 | /* Preview Summary */ | |
| 273 | 234 | ||
| 274 | 235 | .preview-summary { | |
| @@ -544,7 +505,6 @@ | |||
| 544 | 505 | white-space: nowrap; | |
| 545 | 506 | } | |
| 546 | 507 | ||
| 547 | - | .monetization-cards, | |
| 548 | 508 | .pricing-cards, | |
| 549 | 509 | .content-choice-cards { | |
| 550 | 510 | grid-template-columns: 1fr; | |
| @@ -620,9 +580,6 @@ | |||
| 620 | 580 | object-fit: cover; | |
| 621 | 581 | } | |
| 622 | 582 | ||
| 623 | - | /* Native file input hidden behind a styled "Choose File" button. */ | |
| 624 | - | .wizard-file-input { display: none; } | |
| 625 | - | ||
| 626 | 583 | /* Stripe-step layout. */ | |
| 627 | 584 | .stripe-connect-box { | |
| 628 | 585 | background: var(--surface-muted); | |
| @@ -646,11 +603,11 @@ | |||
| 646 | 603 | text-decoration: none; | |
| 647 | 604 | background: var(--stripe); | |
| 648 | 605 | border: none; | |
| 649 | - | color: #fff; | |
| 606 | + | color: var(--primary-light); | |
| 650 | 607 | } | |
| 651 | 608 | ||
| 652 | 609 | .stripe-connect-cta:hover { | |
| 653 | - | background: #5147e5; | |
| 610 | + | opacity: 0.85; | |
| 654 | 611 | } | |
| 655 | 612 | ||
| 656 | 613 | .stripe-connect-note { | |
| @@ -677,7 +634,7 @@ | |||
| 677 | 634 | } | |
| 678 | 635 | ||
| 679 | 636 | .benefit-item::before { | |
| 680 | - | content: "\2713"; | |
| 637 | + | content: "•"; | |
| 681 | 638 | position: absolute; | |
| 682 | 639 | left: 0; | |
| 683 | 640 | color: var(--success); |