CI & Build / Python lint (push) Successful in 9s
CI & Build / Plugin hooks (push) Successful in 22s
CI & Build / TypeScript typecheck (push) Successful in 1m0s
CI & Build / integration (push) Successful in 1m55s
CI & Build / Python tests (push) Successful in 2m20s
CI & Build / Build & push image (push) Successful in 1m7s
Components, stores, api clients, router, types and shared CSS now state what each piece is and why, without the milestone that introduced it. diff.ts names its consumers instead of the copy history; stores/notes and tasks state their current scope instead of the cleanup that set it; theme.css states the token practice instead of the sweep that established it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
331 lines
13 KiB
CSS
331 lines
13 KiB
CSS
@import url('https://fonts.googleapis.com/css2?family=Fraunces:ital,opsz,wght@0,9..144,300..900;1,9..144,300..900&family=Inter:ital,wght@0,400;0,500;1,400&family=JetBrains+Mono:ital,wght@0,400;1,400&display=swap');
|
|
|
|
/* ==========================================================================
|
|
GENERATED FROM THE DESIGN SYSTEM — Scribe (design system 2), which inherits
|
|
the FabledSword house style (design system 1).
|
|
|
|
Do not hand-edit the --fs-* block below. Edit the design system in the app
|
|
and regenerate: /design-systems -> Master stylesheet -> Copy.
|
|
|
|
DARK IS THE BASE LAYER. The kit is dark-mode-first, so :root carries the dark
|
|
palette and [data-theme="light"] overrides it. That is the inverse of how this
|
|
file used to read, and it is deliberate: the light palette was never specified
|
|
by any rule, so it is recorded as a departure rather than as the default.
|
|
|
|
The -fg tokens are a badge's TEXT colour, added because the ladder used its
|
|
raw hue as text on a 12% tint of the same hue — measured 1.60-2.97:1 on the
|
|
dark palette against the kit's AA floor of 4.5. Each is the hue mixed toward
|
|
--fs-text-primary until it clears 4.5:1 worst-case over surface-raised and
|
|
surface-hover in BOTH modes. Mixing toward that token is what makes one
|
|
declaration cover both: it inverts, so the text follows the mode.
|
|
|
|
Only 12 tokens differ between modes. Everything else — spacing, type, motion,
|
|
radius, and every derived colour — is stated once, because a value built with
|
|
var() resolves where it is USED, not where it is written.
|
|
========================================================================== */
|
|
|
|
:root {
|
|
/* accent */
|
|
--fs-accent: #5B4A8A; /* Scribe's signature colour */
|
|
--fs-accent-soft: color-mix(in srgb, var(--fs-accent) 15%, transparent); /* Pill, tag and badge backgrounds */
|
|
--fs-accent-faint: color-mix(in srgb, var(--fs-accent) 8%, transparent); /* The faintest accent wash */
|
|
--fs-accent-deep: color-mix(in srgb, var(--fs-accent) 70%, black); /* The accent, darkened */
|
|
--fs-accent-wash: color-mix(in srgb, var(--fs-accent) 22%, transparent); /* Heaviest accent tint */
|
|
--fs-accent-fg: color-mix(in srgb, var(--fs-accent) 45%, var(--fs-text-primary)); /* Accent TEXT on an accent tint */
|
|
--fs-gradient-cta: linear-gradient(135deg, var(--fs-accent), var(--fs-accent-deep));
|
|
--fs-glow-cta: 0 2px 10px color-mix(in srgb, var(--fs-accent) 35%, transparent);
|
|
--fs-glow-cta-hover: 0 4px 24px color-mix(in srgb, var(--fs-accent) 65%, transparent);
|
|
|
|
/* action */
|
|
--fs-action-primary: #4A5D3F; /* Save, Submit, Confirm */
|
|
--fs-action-secondary: #8B7355; /* Non-destructive alternates */
|
|
--fs-action-tertiary: var(--fs-border-color); /* Ghost / outline actions */
|
|
--fs-action-destructive: var(--fs-destructive);
|
|
--fs-action-primary-hover: color-mix(in srgb, var(--fs-action-primary) 88%, white);
|
|
--fs-action-secondary-hover: color-mix(in srgb, var(--fs-action-secondary) 88%, white);
|
|
--fs-action-destructive-hover: color-mix(in srgb, var(--fs-action-destructive) 88%, white);
|
|
|
|
/* border */
|
|
--fs-border-color: #3F4651; /* Borders, dividers and ghost outlines */
|
|
--fs-border: 0.5px solid var(--fs-border-color);
|
|
--fs-border-hover: 0.5px solid color-mix(in srgb, var(--fs-text-secondary) 30%, transparent);
|
|
--fs-border-active: 2px solid var(--fs-accent); /* Selected card or active tab only */
|
|
|
|
/* editor */
|
|
--fs-wikilink: var(--fs-accent);
|
|
|
|
/* elevation */
|
|
--fs-shadow-1: 0 1px 0 rgba(0,0,0,0.4); /* Hairline lift */
|
|
--fs-shadow-2: 0 4px 12px rgba(0,0,0,0.35); /* Dropdowns, popovers */
|
|
--fs-shadow-3: 0 16px 40px rgba(0,0,0,0.5); /* Modals */
|
|
|
|
/* focus */
|
|
--fs-focus-ring: 0 0 0 2px var(--fs-accent);
|
|
|
|
/* font */
|
|
--fs-font-display: 'Fraunces', Georgia, serif;
|
|
--fs-font-body: 'Inter', system-ui, sans-serif;
|
|
--fs-font-mono: 'JetBrains Mono', ui-monospace, Menlo, Consolas, monospace;
|
|
|
|
/* icon */
|
|
--fs-icon-stroke: 1.5px; /* at 24px */
|
|
--fs-icon-stroke-sm: 1px; /* at 16px */
|
|
|
|
/* layout */
|
|
--fs-layout-page-max: 1200px;
|
|
--fs-layout-page-pad: 1rem;
|
|
--fs-layout-sidebar: 260px;
|
|
--fs-layout-header: 52px;
|
|
|
|
/* motion */
|
|
--fs-ease: cubic-bezier(0.2, 0.6, 0.2, 1); /* the one curve */
|
|
--fs-dur-fast: 120ms;
|
|
--fs-dur-base: 180ms;
|
|
--fs-dur-slow: 280ms;
|
|
|
|
/* priority */
|
|
--fs-priority-low: var(--fs-info);
|
|
--fs-priority-low-bg: color-mix(in srgb, var(--fs-priority-low) 12%, transparent);
|
|
--fs-priority-low-fg: color-mix(in srgb, var(--fs-priority-low) 45%, var(--fs-text-primary)); /* Badge TEXT for low priority — the readable partner of the -bg tint */
|
|
--fs-priority-medium: var(--fs-warning);
|
|
--fs-priority-medium-bg: color-mix(in srgb, var(--fs-priority-medium) 12%, transparent);
|
|
--fs-priority-medium-fg: color-mix(in srgb, var(--fs-priority-medium) 55%, var(--fs-text-primary)); /* Badge TEXT for medium priority */
|
|
--fs-priority-high: var(--fs-error);
|
|
--fs-priority-high-bg: color-mix(in srgb, var(--fs-priority-high) 12%, transparent);
|
|
--fs-priority-high-fg: color-mix(in srgb, var(--fs-priority-high) 55%, var(--fs-text-primary)); /* Badge TEXT for high priority */
|
|
|
|
/* radius */
|
|
--fs-radius-sm: 4px; /* pills, tags, code spans */
|
|
--fs-radius-md: 8px; /* buttons, inputs, small cards */
|
|
--fs-radius-lg: 12px; /* cards, panels, modals */
|
|
--fs-radius-xl: 16px; /* hero containers */
|
|
--fs-radius-pill: 9999px;
|
|
|
|
/* semantic */
|
|
--fs-success: var(--fs-action-primary);
|
|
--fs-success-fg: color-mix(in srgb, var(--fs-success) 45%, var(--fs-text-primary)); /* Success TEXT on a success tint */
|
|
--fs-warning: #8B6F1E;
|
|
--fs-warning-fg: color-mix(in srgb, var(--fs-warning) 50%, var(--fs-text-primary)); /* Warning TEXT on a warning tint */
|
|
--fs-error: #C04A1F;
|
|
--fs-error-fg: color-mix(in srgb, var(--fs-error) 50%, var(--fs-text-primary)); /* Error TEXT on an error tint */
|
|
--fs-info: #3D5A6E;
|
|
--fs-destructive: #6B2118; /* irreversible — deliberately not the error colour */
|
|
|
|
/* space */
|
|
--fs-space-1: 4px;
|
|
--fs-space-2: 8px;
|
|
--fs-space-3: 12px;
|
|
--fs-space-4: 16px;
|
|
--fs-space-5: 20px;
|
|
--fs-space-6: 24px;
|
|
--fs-space-7: 32px;
|
|
--fs-space-8: 48px;
|
|
--fs-space-9: 64px;
|
|
--fs-space-10: 96px;
|
|
|
|
/* state */
|
|
--fs-disabled-opacity: 0.5;
|
|
--fs-overlay: rgba(0, 0, 0, 0.65);
|
|
|
|
/* status */
|
|
--fs-status-todo: var(--fs-border-color);
|
|
--fs-status-todo-bg: color-mix(in srgb, var(--fs-status-todo) 12%, transparent);
|
|
--fs-status-todo-fg: color-mix(in srgb, var(--fs-status-todo) 40%, var(--fs-text-primary)); /* Badge TEXT for a not-started task */
|
|
--fs-status-in-progress: var(--fs-accent);
|
|
--fs-status-in-progress-bg: color-mix(in srgb, var(--fs-status-in-progress) 12%, transparent);
|
|
--fs-status-in-progress-fg: color-mix(in srgb, var(--fs-status-in-progress) 45%, var(--fs-text-primary)); /* Badge TEXT for a task underway */
|
|
--fs-status-done: var(--fs-success);
|
|
--fs-status-done-bg: color-mix(in srgb, var(--fs-status-done) 12%, transparent);
|
|
--fs-status-done-fg: color-mix(in srgb, var(--fs-status-done) 50%, var(--fs-text-primary)); /* Badge TEXT for a completed task */
|
|
--fs-overdue: var(--fs-error);
|
|
--fs-status-cancelled: var(--fs-text-tertiary); /* set aside, not failed */
|
|
--fs-status-cancelled-fg: color-mix(in srgb, var(--fs-status-cancelled) 60%, var(--fs-text-primary)); /* Badge TEXT for a cancelled task */
|
|
|
|
/* surface */
|
|
--fs-surface-page: #14171A; /* page bg, deepest surface */
|
|
--fs-surface-raised: #1E2228; /* cards, raised elements */
|
|
--fs-surface-hover: #2C313A; /* hovered surfaces */
|
|
--fs-surface-code: var(--fs-surface-page);
|
|
--fs-surface-code-inline: var(--fs-surface-raised);
|
|
--fs-table-stripe: color-mix(in srgb, var(--fs-text-primary) 3%, transparent);
|
|
|
|
/* text */
|
|
--fs-text-primary: #E8E4D8; /* body, headings, labels — inverts by mode */
|
|
--fs-text-secondary: #C2BFB4;
|
|
--fs-text-secondary-fg: color-mix(in srgb, var(--fs-text-secondary) 90%, var(--fs-text-primary)); /* Secondary TEXT on a secondary tint (barely moves; no exceptions) */
|
|
--fs-text-tertiary: #9C9A92;
|
|
--fs-text-tertiary-fg: color-mix(in srgb, var(--fs-text-tertiary) 55%, var(--fs-text-primary)); /* Tertiary TEXT on a tertiary tint */
|
|
--fs-text-on-action: #E8E4D8; /* text on a filled colour — NOT mode-dependent */
|
|
|
|
/* type */
|
|
--fs-size-display: 40px;
|
|
--fs-size-h1: 32px;
|
|
--fs-size-h2: 24px;
|
|
--fs-size-h3: 18px;
|
|
--fs-size-body: 15px;
|
|
--fs-size-body-sm: 13px;
|
|
--fs-size-label: 12px;
|
|
--fs-size-code: 13px;
|
|
--fs-size-tiny: 11px; /* the only ALL CAPS, the only non-default tracking */
|
|
--fs-weight-regular: 400;
|
|
--fs-weight-medium: 500; /* the heaviest the system goes */
|
|
--fs-leading-heading: 1.3;
|
|
--fs-leading-body: 1.5;
|
|
--fs-leading-longform: 1.7;
|
|
--fs-tracking-tiny: 0.08em;
|
|
}
|
|
|
|
[data-theme="light"] {
|
|
/* accent */
|
|
--fs-accent-wash: color-mix(in srgb, var(--fs-accent) 20%, transparent);
|
|
--fs-glow-cta-hover: 0 4px 20px color-mix(in srgb, var(--fs-accent) 55%, transparent);
|
|
|
|
/* border */
|
|
--fs-border-color: #D9D6CE;
|
|
|
|
/* state */
|
|
--fs-overlay: rgba(0, 0, 0, 0.45);
|
|
|
|
/* surface */
|
|
--fs-surface-page: #F5F1E8;
|
|
--fs-surface-raised: #FBF8F0;
|
|
--fs-surface-hover: #EFEAE0;
|
|
--fs-surface-code: #EBEDF0;
|
|
--fs-surface-code-inline: #EBEDF0;
|
|
|
|
/* text */
|
|
--fs-text-primary: #14171A;
|
|
--fs-text-secondary: #5A5852;
|
|
--fs-text-tertiary: #9A9890;
|
|
}
|
|
|
|
/* SUPERSEDES — write the token, not the literal.
|
|
* #fff -> --fs-text-on-action
|
|
* #ffffff -> --fs-text-on-action
|
|
* white -> --fs-text-on-action
|
|
* bold -> --fs-weight-medium
|
|
* bolder -> --fs-weight-medium
|
|
*/
|
|
|
|
/* ==========================================================================
|
|
Every component references the design system's --fs-* tokens directly.
|
|
Do not introduce app-local alias names — the design system's tokens are the
|
|
vocabulary, and check_snippets_against_design_system can only see through
|
|
names the system actually declares.
|
|
========================================================================== */
|
|
|
|
:root {
|
|
/* A VALUE, not an alias — the one survivor of the alias block. The design
|
|
system has no shadow-colour token yet, so this is a recorded gap: when a
|
|
second app needs it, promote it to an --fs-* token in the system and
|
|
regenerate, rather than copying this line. */
|
|
--color-shadow: rgba(0, 0, 0, 0.4);
|
|
}
|
|
|
|
/* ==========================================================================
|
|
Base element styles
|
|
========================================================================== */
|
|
|
|
*,
|
|
*::before,
|
|
*::after {
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
body {
|
|
margin: 0;
|
|
background: var(--fs-surface-page);
|
|
color: var(--fs-text-primary);
|
|
font-family: var(--fs-font-body);
|
|
font-feature-settings: "cv11";
|
|
line-height: var(--fs-leading-body);
|
|
transition: background-color var(--fs-dur-base) var(--fs-ease),
|
|
color var(--fs-dur-base) var(--fs-ease);
|
|
}
|
|
|
|
h1, h2 {
|
|
font-family: var(--fs-font-display);
|
|
font-optical-sizing: auto;
|
|
font-weight: var(--fs-weight-medium);
|
|
line-height: var(--fs-leading-heading);
|
|
}
|
|
|
|
h3 {
|
|
font-family: var(--fs-font-body);
|
|
font-weight: var(--fs-weight-medium);
|
|
line-height: var(--fs-leading-heading);
|
|
}
|
|
|
|
code, pre, kbd, samp {
|
|
font-family: var(--fs-font-mono);
|
|
font-feature-settings: "liga", "calt";
|
|
}
|
|
|
|
::selection {
|
|
background: var(--fs-accent-wash);
|
|
color: var(--fs-text-primary);
|
|
}
|
|
|
|
input:focus-visible,
|
|
textarea:focus-visible,
|
|
select:focus-visible,
|
|
button:focus-visible,
|
|
a:focus-visible {
|
|
outline: none;
|
|
box-shadow: var(--fs-focus-ring);
|
|
border-radius: var(--fs-radius-sm);
|
|
}
|
|
|
|
button:not(:disabled):active,
|
|
.btn:not(:disabled):active,
|
|
[role="button"]:not(:disabled):active {
|
|
transform: scale(0.97);
|
|
transition: transform 0.08s var(--fs-ease);
|
|
}
|
|
|
|
/* Responsive breakpoints: 480px (phone), 768px (tablet), 1024px (desktop) */
|
|
@media (max-width: 768px) {
|
|
.hide-mobile {
|
|
display: none !important;
|
|
}
|
|
button,
|
|
[role="button"] {
|
|
min-height: 44px;
|
|
}
|
|
}
|
|
|
|
/* Neutral hairline scrollbars — chrome is structural, not branded */
|
|
::-webkit-scrollbar {
|
|
width: 4px;
|
|
height: 4px;
|
|
}
|
|
::-webkit-scrollbar-track {
|
|
background: transparent;
|
|
}
|
|
::-webkit-scrollbar-thumb {
|
|
background: var(--fs-border-color);
|
|
border-radius: var(--fs-radius-pill);
|
|
}
|
|
::-webkit-scrollbar-thumb:hover {
|
|
background: var(--fs-text-tertiary);
|
|
}
|
|
|
|
/* Floating inline assist button (teleported to body, cannot be scoped) */
|
|
.inline-assist-btn {
|
|
position: fixed;
|
|
z-index: 150;
|
|
transform: translateX(-50%);
|
|
background: var(--fs-accent);
|
|
color: var(--fs-text-primary);
|
|
border: none;
|
|
border-radius: var(--fs-radius-pill);
|
|
padding: 0.3rem 0.8rem;
|
|
font-size: var(--fs-size-body-sm);
|
|
cursor: pointer;
|
|
box-shadow: var(--fs-shadow-2);
|
|
white-space: nowrap;
|
|
}
|
|
.inline-assist-btn:hover {
|
|
filter: brightness(1.1);
|
|
}
|