Files
Lumotia/src/app.css
Jake 681a9b26dc
Some checks failed
check / cargo check (macos-latest) (push) Has been cancelled
check / cargo check (ubuntu-22.04) (push) Has been cancelled
check / cargo check (windows-latest) (push) Has been cancelled
check / svelte build + lint (push) Has been cancelled
agent: lumotia-rebrand — frontend strings (svelte + i18n + design-system)
Phase 8 of the rebrand cascade. Every rendered string is now Lumotia;
no Magnotia surface visible in the UI.

Sweep replaced \bmagnotia\b -> lumotia and \bMagnotia\b -> Lumotia
across all .svelte / .ts / .js / .css / .html / .json (excluding
package-lock.json which regenerates, target/, build/, node_modules/).

Surfaces touched:
- src/app.css — design-token comment header and .magnotia-rh-* CSS
  resize-handle class selectors (also the consuming elements in
  components/ResizeHandles.svelte and src/routes/*/+layout.svelte).
- src/lib/i18n/locales/{en,de,es}.json — brand name in translations.
- src/lib/i18n/index.ts — header comment.
- src/lib/Sidebar.svelte and most pages under src/lib/pages/ +
  src/lib/components/ — title bars, document titles, default
  filenames (lumotia-YYYY-MM-DD.* etc), toast strings, error
  messages, dialog headers.
- src/routes/+layout.svelte, +page.svelte, viewer/, float/, preview/.
- src/app.html page <title>.
- src/lib/utils/settingsMigrations.ts — fallback toast copy.
- src/design-system/{colors_and_type.css,SKILL.md,README.md,
  ui_kits/{Sidebar.jsx,index.html}} — design-tokens, doc strings,
  preview wordmark in the kit.
- package.json — name + description.

NOT touched (deferred / immutable):
- package-lock.json — regenerates on next npm install.
- The two migration-call sites in stores reference the legacy magnotia
  keys deliberately; restored after the sweep clobbered them.
- docs/, README.md, HANDOVER.md — Phase 9 scope.

npm run check: 0 errors / 0 warnings (3958 files).
cargo test --workspace: 339 pass / 0 fail.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 12:29:37 +01:00

584 lines
16 KiB
CSS

/* === Bundled Fonts — offline-first ===
These @font-face declarations are mirrored in
src/design-system/colors_and_type.css for the buildless preview pages
(which load that file directly without going through Tailwind/Vite).
The two copies must keep font-family, font-weight, font-style, and
font-display in sync. The src URLs intentionally differ: this file
uses root-absolute paths served by Vite, the preview file uses
relative paths so the static HTML pages resolve fonts/ alongside. */
@font-face {
font-family: 'Lexend';
src: url('/fonts/lexend-variable.woff2') format('woff2');
font-weight: 100 900;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Instrument Serif';
src: url('/fonts/instrument-serif-italic.woff2') format('woff2');
font-weight: 400;
font-style: italic;
font-display: swap;
}
@font-face {
font-family: 'JetBrains Mono';
src: url('/fonts/jetbrains-mono.woff2') format('woff2');
font-weight: 100 800;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Atkinson Hyperlegible Next';
src: url('/fonts/atkinson-hyperlegible-next.woff2') format('woff2');
font-weight: 200 800;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'OpenDyslexic';
src: url('/fonts/opendyslexic.woff2') format('woff2');
font-weight: 400 700;
font-style: normal;
font-display: swap;
}
@import "tailwindcss";
/* === Lumotia Design Tokens === */
@theme {
/* Surfaces — warm layered depth */
--color-bg: #0f0e0c;
--color-bg-elevated: #171614;
--color-bg-card: #1b1a17;
--color-bg-input: #151412;
--color-border: #2c2923;
--color-border-subtle: #221f1b;
/* Text — warm hierarchy */
--color-text: #f0ece4;
--color-text-secondary: #9a9486;
/* Phase 10a a11y P1: lifted from #716b60 to #8c8678 to clear AA 4.5:1 on
the dark surfaces this token is used on. Used as both decorative and
body-grade label, so the token has to meet AA. */
--color-text-tertiary: #8c8678;
/* Accent — warm amber/copper.
Phase 10a a11y P2: dark accent darkened from #e8a87c to #c98555 so the
"Browse Files" filled button (white text on accent fill) clears AA in
dark theme. Phase 10b: chroma bumped to #d68450 (same lightness band,
~OKLCH C 0.12 vs prior 0.08) so the brand reads warmer without losing
the AA Large headroom on filled buttons. Subtle / hover / glow
recomputed off the new base. */
--color-accent: #d68450;
--color-accent-hover: #c47340;
--color-accent-subtle: #d6845010;
--color-accent-glow: #d6845025;
/* Amber shadow scale. Hard-coded rgba shadows in components were tied to
the dark-theme accent and stayed off-hue in light mode. These tokens
theme-switch with the accent (overrides in :root[data-theme="light"]).
Shapes correspond to existing usage sites:
sm = subtle button/toggle glow (Toggle on-state)
md = lifted card / button drop (ModelDownloader card)
lg = hero glow under record button (DictationPage record)
glow = stronger 0.4-alpha emission (progress-bar glows)
pill = small selected-pill lift (SegmentedButton, pill rows)
raised = soft raised tile (FilesPage drop tile) */
--shadow-accent-sm: 0 0 8px rgba(214, 132, 80, 0.25);
--shadow-accent-md: 0 4px 16px rgba(214, 132, 80, 0.3);
--shadow-accent-lg: 0 4px 20px rgba(214, 132, 80, 0.3);
--shadow-accent-glow: 0 0 8px rgba(214, 132, 80, 0.4);
--shadow-accent-pill: 0 1px 4px rgba(214, 132, 80, 0.3);
--shadow-accent-raised: 0 2px 8px rgba(214, 132, 80, 0.2);
/* Semantic — Phase 10b: chroma bumped on all three so success/danger/
warning read as signals, not as cream-tinted body text. AA on bg-card
(#1b1a17) verified mentally for each. */
--color-success: #5fc28a;
--color-danger: #e85f5f;
--color-warning: #e8be4a;
/* Overlays — used by modal scrims. Derived from --color-bg #0f0e0c at
0.7 alpha so the dim sits on the brand neutral, not pure black. */
--color-overlay-dim: rgba(15, 14, 12, 0.7);
/* Layout */
--color-sidebar: #13120f;
--color-nav-active: #201e1a;
--color-hover: #1e1c18;
/* === Layout Tokens === */
--radius-sm: 6px;
--radius-md: 8px;
--radius-lg: 12px;
--radius-xl: 16px;
--title-size: 26px;
/* Typography */
--font-family-body: 'Lexend', system-ui, sans-serif;
--font-family-display: 'Instrument Serif', serif;
--font-family-mono: 'JetBrains Mono', monospace;
--font-size-body: 16px;
--line-height-body: 1.5;
--letter-spacing-body: 0;
/* Motion */
--duration-ui: 150ms;
--duration-decorative: 300ms;
/* Window resize hit zones — consumed by ResizeHandles.svelte. One source
of truth so every Lumotia window feels identical. */
--lumotia-resize-edge: 12px;
--lumotia-resize-corner: 20px;
}
/* === Button Component Classes === */
.btn-sm { @apply px-2.5 py-1 text-[11px]; }
.btn-md { @apply px-3 py-1.5 text-[12px]; }
.btn-lg { @apply px-4 py-2 text-[13px]; }
/* === Light theme overrides === */
:root[data-theme="light"] {
--color-bg: #faf8f5;
--color-bg-elevated: #f3f0eb;
--color-bg-card: #ffffff;
--color-bg-input: #f0ede8;
--color-border: #ddd8d0;
--color-border-subtle: #e6e2da;
--color-text: #1a1816;
--color-text-secondary: #5c574d;
/* Phase 10a a11y P1: darkened from #8a8578 to #6b6557 to clear AA 4.5:1
on cream/card surfaces in light theme. */
--color-text-tertiary: #6b6557;
/* Phase 10a a11y P2: darkened from #b87a4a to #a06a3e so white text on
accent fill (selected pills, primary buttons) clears AA. Phase 10b:
chroma bumped to #a3683a — same lightness band, more saturation. AA
on cream surfaces re-verified. */
--color-accent: #a3683a;
--color-accent-hover: #8a542b;
--color-accent-subtle: #a3683a10;
--color-accent-glow: #a3683a20;
/* Light-theme amber shadows. Mirror the dark-theme scale but use the
light-theme accent rgba so glows stay on-hue in cream surfaces. */
--shadow-accent-sm: 0 0 8px rgba(163, 104, 58, 0.25);
--shadow-accent-md: 0 4px 16px rgba(163, 104, 58, 0.3);
--shadow-accent-lg: 0 4px 20px rgba(163, 104, 58, 0.3);
--shadow-accent-glow: 0 0 8px rgba(163, 104, 58, 0.4);
--shadow-accent-pill: 0 1px 4px rgba(163, 104, 58, 0.3);
--shadow-accent-raised: 0 2px 8px rgba(163, 104, 58, 0.2);
/* Phase 10a a11y G3: darkened success from #3d8a5a to #2f7549 so success
text on light surfaces clears AA. Phase 10a a11y FR3 / D4: darkened
danger from #c44d4d to #a83838 for the same reason. Phase 10b: chroma
bumped on all three, lightness preserved or slightly darkened to keep
AA on cream backgrounds. */
--color-success: #1f7344;
--color-danger: #b32626;
--color-warning: #a08a1f;
--color-sidebar: #f5f2ed;
--color-nav-active: #eae6e0;
--color-hover: #ede9e3;
/* Warm dim for modal scrims in light theme. Lower alpha so the cream
surface still reads through softly. */
--color-overlay-dim: rgba(26, 24, 22, 0.55);
}
:root[data-theme="light"] ::-webkit-scrollbar-thumb {
background: #d0ccc4;
}
:root[data-theme="light"] ::-webkit-scrollbar-thumb:hover {
background: #b8b3aa;
}
/* === Sensory Zones — Dark Theme === */
/* Zones tint surfaces only. Accent tokens (amber) stay constant across all zones —
the brand colour is the constant, the environment is the variable.
Phase 10b: zone tints pushed further apart so each zone feels emotionally
distinct (cool blue-grey / warm red-orange / cool green) rather than three
nearly-identical near-blacks. AA verified for body text (--color-text
#f0ece4) on every Card surface. */
:root[data-zone="cave"] {
--color-bg: #0a1218;
--color-bg-elevated: #0f1a22;
--color-bg-card: #14222b;
--color-sidebar: #080f14;
}
:root[data-zone="energy"] {
--color-bg: #160e09;
--color-bg-elevated: #20140e;
--color-bg-card: #261913;
--color-sidebar: #100806;
}
:root[data-zone="reset"] {
--color-bg: #0c130c;
--color-bg-elevated: #111a11;
--color-bg-card: #161f15;
--color-sidebar: #0a0e0a;
}
/* === Sensory Zones — Light Theme === */
/* Phase 10b: light zones likewise pushed further from default cream so the
environment shift is felt, not merely intuited. AA verified for body text
(--color-text #1a1816) on every Card surface. */
:root[data-theme="light"][data-zone="cave"] {
--color-bg: #eef4f6;
--color-bg-elevated: #e2eef0;
--color-bg-card: #f5fafc;
--color-sidebar: #e8f0f2;
}
:root[data-theme="light"][data-zone="energy"] {
--color-bg: #fdf3eb;
--color-bg-elevated: #f8e8d8;
--color-bg-card: #fff8ef;
--color-sidebar: #f5e8d4;
}
:root[data-theme="light"][data-zone="reset"] {
--color-bg: #eff6ed;
--color-bg-elevated: #e4f0e0;
--color-bg-card: #f7fcf5;
--color-sidebar: #e8f3e4;
}
/* === Base === */
html, body {
margin: 0;
padding: 0;
height: 100%;
overflow: hidden;
background: var(--color-bg);
color: var(--color-text);
font-family: var(--font-family-body);
font-size: var(--font-size-body);
line-height: var(--line-height-body);
letter-spacing: var(--letter-spacing-body);
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
/* Selection allowed on content by default. Users need to copy error
strings, model paths, profile names, transcripts, etc. Chrome
elements opt out below. */
user-select: text;
}
/* Chrome elements opt out of selection so a click on a button label
doesn't drag-select. data-no-select is an escape hatch for app
surfaces (titlebar, drag handles) that should never select. */
button,
summary,
[role="button"],
[role="switch"],
[role="tab"],
[role="menuitem"],
[data-no-select] {
user-select: none;
}
/* === Display font === */
.font-display {
font-family: var(--font-family-display);
}
/* === Transcript font — optimised for reading === */
.font-transcript {
font-family: var(--font-family-body);
font-size: var(--text-transcript, 16px);
line-height: 1.85;
letter-spacing: 0.01em;
font-feature-settings: "liga" 1, "kern" 1;
}
/* === Grain texture overlay === */
.grain::after {
content: "";
position: fixed;
inset: 0;
pointer-events: none;
opacity: 0.025;
background-image: url('/textures/grain.png');
background-repeat: repeat;
background-size: 200px 200px;
z-index: 50;
}
:root[data-theme="light"] .grain::after {
opacity: 0.015;
}
/* === Scrollbar — thin, appears on hover === */
::-webkit-scrollbar {
width: 5px;
}
::-webkit-scrollbar-track {
background: transparent;
}
::-webkit-scrollbar-thumb {
background: #2c2923;
border-radius: 999px;
}
::-webkit-scrollbar-thumb:hover {
background: #3d3830;
}
/* === Smooth transitions (global) === */
* {
transition-property: background-color, border-color, color, opacity, box-shadow;
transition-duration: var(--duration-ui);
transition-timing-function: cubic-bezier(0.2, 0.8, 0.2, 1);
}
/* Opt out for inputs */
textarea, input, [data-no-transition] {
transition: none;
}
/* === Focus ring — consistent, accessible === */
:focus-visible {
outline: 2px solid var(--color-accent);
outline-offset: 3px;
border-radius: var(--radius-md);
}
/* === Selection colour === */
::selection {
background: var(--color-accent-glow);
color: var(--color-text);
}
/* === Animations === */
@keyframes fade-in {
from { opacity: 0; transform: translateY(4px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes pulse-soft {
0%, 100% { opacity: 1; }
50% { opacity: 0.4; }
}
@keyframes pulse-warm {
0%, 100% { box-shadow: 0 0 24px rgba(232, 168, 124, 0.25), 0 0 48px rgba(232, 168, 124, 0.08); }
50% { box-shadow: 0 0 32px rgba(232, 168, 124, 0.4), 0 0 64px rgba(232, 168, 124, 0.15); }
}
@keyframes slide-up {
from { opacity: 0; transform: translateY(8px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes breathe {
0%, 100% { transform: scale(1); }
50% { transform: scale(1.04); }
}
.animate-fade-in {
animation: fade-in var(--duration-decorative) ease-out;
}
.animate-pulse-soft {
animation: pulse-soft 1.5s ease-in-out infinite;
}
.animate-pulse-warm {
animation: pulse-warm 2s ease-in-out infinite;
}
.animate-slide-up {
animation: slide-up var(--duration-decorative) ease-out;
}
.animate-breathe {
animation: breathe 3s ease-in-out infinite;
}
/* === Task sidebar slide === */
@keyframes slide-in-right {
from { transform: translateX(100%); opacity: 0; }
to { transform: translateX(0); opacity: 1; }
}
@keyframes slide-out-right {
from { transform: translateX(0); opacity: 1; }
to { transform: translateX(100%); opacity: 0; }
}
/* Task extraction highlight */
@keyframes highlight-warm {
0% { border-left-color: var(--color-accent); }
100% { border-left-color: transparent; }
}
/* Checkbox pop */
@keyframes scale-pop {
0% { transform: scale(0.95); }
100% { transform: scale(1); }
}
.animate-slide-in-right {
animation: slide-in-right var(--duration-decorative) ease-out;
}
.animate-highlight-warm {
border-left: 3px solid transparent;
animation: highlight-warm 2s ease-out;
}
.animate-scale-pop {
animation: scale-pop 50ms ease-out;
}
/* Window focus glow */
@keyframes glow-pulse {
0% { box-shadow: 0 0 0 0 rgba(232, 168, 124, 0); }
30% { box-shadow: 0 0 20px 4px rgba(232, 168, 124, 0.35), inset 0 0 12px rgba(232, 168, 124, 0.08); }
100% { box-shadow: 0 0 0 0 rgba(232, 168, 124, 0); }
}
.animate-glow-pulse {
animation: glow-pulse 700ms ease-out;
}
:root[data-theme="light"] .animate-glow-pulse {
animation: glow-pulse-light 700ms ease-out;
}
@keyframes glow-pulse-light {
0% { box-shadow: 0 0 0 0 rgba(184, 122, 74, 0); }
30% { box-shadow: 0 0 20px 4px rgba(184, 122, 74, 0.3), inset 0 0 12px rgba(184, 122, 74, 0.06); }
100% { box-shadow: 0 0 0 0 rgba(184, 122, 74, 0); }
}
/* Float window entrance */
@keyframes float-enter {
from { opacity: 0; transform: scale(0.97); }
to { opacity: 1; transform: scale(1); }
}
.animate-float-enter {
animation: float-enter var(--duration-decorative) ease-out;
}
/* === Custom titlebar buttons === */
.titlebar-btn {
display: flex;
align-items: center;
justify-content: center;
width: 46px;
height: 32px;
color: var(--color-text-secondary);
}
/* Sinhala character spin (decorative, during recording) */
@keyframes sinhala-spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.animate-sinhala-spin {
animation: sinhala-spin 2s linear infinite;
}
/* === Reduced Motion === */
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
/* === Data-attribute reduce-motion support === */
:root[data-reduce-motion="true"],
:root[data-reduce-motion="true"] *,
:root[data-reduce-motion="true"] *::before,
:root[data-reduce-motion="true"] *::after {
--duration-ui: 0ms;
--duration-decorative: 0ms;
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
/* === Window resize handles (see ResizeHandles.svelte) ===
Lives in the global sheet so @tailwindcss/vite does not try to
parse it as a per-component virtual CSS module, which triggers an
"Invalid declaration" error on plain CSS inputs in some Tailwind v4
+ Svelte 5 combinations. */
.lumotia-rh {
position: fixed;
z-index: 2147483646;
background: transparent;
pointer-events: auto;
touch-action: none;
user-select: none;
-webkit-user-select: none;
}
.lumotia-rh-nw,
.lumotia-rh-ne,
.lumotia-rh-sw,
.lumotia-rh-se {
z-index: 2147483647;
}
.lumotia-rh-n {
top: 0;
left: var(--lumotia-resize-corner);
right: var(--lumotia-resize-corner);
height: var(--lumotia-resize-edge);
cursor: n-resize;
}
.lumotia-rh-s {
bottom: 0;
left: var(--lumotia-resize-corner);
right: var(--lumotia-resize-corner);
height: var(--lumotia-resize-edge);
cursor: s-resize;
}
.lumotia-rh-w {
top: var(--lumotia-resize-corner);
bottom: var(--lumotia-resize-corner);
left: 0;
width: var(--lumotia-resize-edge);
cursor: w-resize;
}
.lumotia-rh-e {
top: var(--lumotia-resize-corner);
bottom: var(--lumotia-resize-corner);
right: 0;
width: var(--lumotia-resize-edge);
cursor: e-resize;
}
.lumotia-rh-nw {
top: 0;
left: 0;
width: var(--lumotia-resize-corner);
height: var(--lumotia-resize-corner);
cursor: nw-resize;
}
.lumotia-rh-ne {
top: 0;
right: 0;
width: var(--lumotia-resize-corner);
height: var(--lumotia-resize-corner);
cursor: ne-resize;
}
.lumotia-rh-sw {
bottom: 0;
left: 0;
width: var(--lumotia-resize-corner);
height: var(--lumotia-resize-corner);
cursor: sw-resize;
}
.lumotia-rh-se {
bottom: 0;
right: 0;
width: var(--lumotia-resize-corner);
height: var(--lumotia-resize-corner);
cursor: se-resize;
}