web v0.3 visual revamp: Norse palette + ornament + mobile + forms
Big CSS overhaul + page-level adjustments toward a Norse 'museum- quality' aesthetic (not the gaming-rune-bro variant). Restraint + weight + carved typography. Palette shift: - Warmed-black bg (#0a0807) with subtle radial gradient grain - Bone-cream ink (#dbcfb0) replaces the cleaner cream we had - Oxblood accent (#a13a3a) replaces the coffee-shop soft gold - Weathered bronze (#b08443) as secondary accent for headers + meta - Status colors land warmer: sage-moss ok, rust crit, amber-bronze warn Typography: - All caps + 2-3px letter-spacing on display headers (Trajan Pro / Cinzel chain via font-family stack — falls back to weighted serif on machines without the carved face) - Serif prose chain unchanged (Iowan Old Style → Hoefler → Georgia) - Drop cap on the first paragraph of each chapter — small literary flourish in oxblood-bronze Ornament: - Inline SVG knotwork divider (`ornament()` macro) — two flanking circles + an interlace curve between them, used as section breaks. Below the welcome h1; can be sprinkled wherever a visual register break helps. Pages adjusted: - topbar: SKALD wordmark in 4-letterspaced display caps; thin oxblood underline accent; '+ new saga' nav button on the right - sidebar: 'STORIES' → 'SAGAS' (one of cobb's earlier asks); story-row hover gets oxblood left-accent (not gold); per-status pill colors (complete=ok, generating/cleaning/auditing=warn, failed=crit, seed=warn) - story detail: dedicated .story-actions row with '✦ continue this saga' (primary, oxblood-bordered button) and 'generation log →' link - welcome panel: revised copy + ornament + 'begin a new one' link - forms: bordered surface inputs, all-caps display labels, primary- styled submit buttons matching the continue-saga action Mobile (max-width: 800px): - Single-column grid; sidebar lays out above the main panel - Sidebar wrapped in <details open> so it's collapsible (taps the 'Sagas (N)' header). No JS — native HTML semantics. - Chapter-list collapses word-count column on narrow - Char-list goes single-column - All sizes downscale (28px h1, 16px prose, etc) Next pass after I screenshot: tune any contrast/spacing that looks off on the actual render.
This commit is contained in:
parent
b08d6ee8bc
commit
c899019b35
1 changed files with 322 additions and 80 deletions
402
skald/src/web.rs
402
skald/src/web.rs
|
|
@ -324,15 +324,22 @@ fn render_shell(stories: &[StoryRow], current: Option<Uuid>, main: Markup) -> Ma
|
|||
}
|
||||
body {
|
||||
header.topbar {
|
||||
a.brand href="/" { "skald" }
|
||||
span.tagline { "an old-norse poet's inspector" }
|
||||
a.brand href="/" { "SKALD" }
|
||||
span.tagline { "long form · named voices · written down" }
|
||||
nav.topnav {
|
||||
a href="/stories/new" .new-saga { "+ new saga" }
|
||||
}
|
||||
}
|
||||
main.layout {
|
||||
aside.sidebar {
|
||||
h2 { "Stories" }
|
||||
details.sidebar-collapse open {
|
||||
summary.sidebar-summary {
|
||||
h2 { "Sagas" }
|
||||
span.sidebar-count { "(" (stories.len()) ")" }
|
||||
}
|
||||
@if stories.is_empty() {
|
||||
p.empty { "No stories imported yet. Run "
|
||||
code { "skald import-markdown" } " to add one." }
|
||||
p.empty { "No sagas yet. Run "
|
||||
code { "skald import-markdown" } " or click " a href="/stories/new" { "+ new saga" } "." }
|
||||
} @else {
|
||||
ul.story-list {
|
||||
@for s in stories {
|
||||
|
|
@ -350,11 +357,12 @@ fn render_shell(stories: &[StoryRow], current: Option<Uuid>, main: Markup) -> Ma
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
section.panel { (main) }
|
||||
}
|
||||
footer.footbar {
|
||||
span { "skald · v0.1 inspector · "
|
||||
span { "skald · v0.3 · written down · "
|
||||
a href="http://192.168.0.5:3001/cobb/skald" { "cobb/skald" }
|
||||
}
|
||||
}
|
||||
|
|
@ -411,14 +419,15 @@ fn welcome_panel() -> Markup {
|
|||
html! {
|
||||
div.welcome {
|
||||
h1 { "Welcome." }
|
||||
p.lead { "Pick a story from the sidebar to inspect it." }
|
||||
(ornament())
|
||||
p.lead { "Pick a saga from the sidebar — or " a href="/stories/new" { "begin a new one" } "." }
|
||||
p {
|
||||
"Skald is the database; the binary is the tooling. Every story is rows — "
|
||||
"chapters, characters, canon, generation runs. This inspector shows them as they are."
|
||||
"Skald keeps long-form fiction as rows in a database — chapters, characters, "
|
||||
"canon, generation runs. Each saga has a named author whose soul is the LLM's "
|
||||
"voice, not a stapled prompt. Sequels honor canon, audit themselves, and remember."
|
||||
}
|
||||
p.muted {
|
||||
"Authors, the continue button, and the cleanup audit panel land in v0.3 once "
|
||||
"the persona layer is wired."
|
||||
"The database is the product. The binary is the tooling."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -443,7 +452,10 @@ fn story_panel(
|
|||
span.meta-item { (s.character_count) " characters" }
|
||||
span.meta-item { (s.canon_fact_count) " canon facts" }
|
||||
span.meta-item.muted { "updated " (rel_time(s.updated_at)) }
|
||||
a.runs-link href=(format!("/stories/{}/runs", s.id)) { "→ generation log" }
|
||||
}
|
||||
nav.story-actions {
|
||||
a.action-primary href=(format!("/stories/{}/continue", s.id)) { "✦ continue this saga" }
|
||||
a.action-secondary href=(format!("/stories/{}/runs", s.id)) { "generation log →" }
|
||||
}
|
||||
|
||||
section.chapters {
|
||||
|
|
@ -603,6 +615,23 @@ fn runs_panel(story_id: Uuid, runs: &[(Uuid, String, String, DateTime<Utc>, Opti
|
|||
|
||||
// ─── helpers ─────────────────────────────────────────────────────
|
||||
|
||||
/// Knotwork divider — a small SVG ornament used as section break.
|
||||
/// Two flanking circles + a single interlace curve between them.
|
||||
/// Stays in the warmed-bronze accent color via `currentColor`.
|
||||
fn ornament() -> Markup {
|
||||
html! {
|
||||
div.ornament {
|
||||
(maud::PreEscaped(r##"<svg viewBox="0 0 120 12" preserveAspectRatio="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
|
||||
<line x1="0" y1="6" x2="36" y2="6" stroke="currentColor" stroke-width="0.6"/>
|
||||
<circle cx="40" cy="6" r="2.2" fill="none" stroke="currentColor" stroke-width="0.8"/>
|
||||
<path d="M 46 6 Q 52 0 58 6 Q 64 12 70 6 Q 76 0 82 6" fill="none" stroke="currentColor" stroke-width="0.8"/>
|
||||
<circle cx="86" cy="6" r="2.2" fill="none" stroke="currentColor" stroke-width="0.8"/>
|
||||
<line x1="92" y1="6" x2="120" y2="6" stroke="currentColor" stroke-width="0.6"/>
|
||||
</svg>"##))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn kfmt(n: i32) -> String {
|
||||
if n >= 1000 {
|
||||
format!("{:.1}k", n as f64 / 1000.0)
|
||||
|
|
@ -650,108 +679,321 @@ fn rel_time(t: DateTime<Utc>) -> String {
|
|||
|
||||
const STYLESHEET: &str = r#"
|
||||
:root {
|
||||
--bg: #0d0d0c;
|
||||
--surface: #16151a;
|
||||
--surface-2: #1d1c20;
|
||||
--border: #2a2830;
|
||||
--ink: #e8dfc8;
|
||||
--ink-muted: #8b8579;
|
||||
--ink-faint: #5d584f;
|
||||
--accent: #b08d50;
|
||||
--accent-dim: #76624f;
|
||||
--crit: #c97474;
|
||||
--ok: #87a87a;
|
||||
--warn: #c4a06c;
|
||||
--serif: "Iowan Old Style", "Constantia", Georgia, "Times New Roman", serif;
|
||||
/* Warmed-black + bone-cream + oxblood + weathered bronze.
|
||||
Norse museum, not gaming-rune-bro. Stark, weighty, carved. */
|
||||
--bg: #0a0807;
|
||||
--bg-grain: #100c0a;
|
||||
--surface: #181410;
|
||||
--surface-2: #221c14;
|
||||
--border: #2e2620;
|
||||
--border-strong: #3d3128;
|
||||
--ink: #dbcfb0;
|
||||
--ink-muted: #a89473;
|
||||
--ink-faint: #6b5d48;
|
||||
--accent: #a13a3a;
|
||||
--accent-dim: #7a2c2c;
|
||||
--bronze: #b08443;
|
||||
--bronze-dim: #7a5c2e;
|
||||
--ok: #7a8870;
|
||||
--crit: #c4493a;
|
||||
--warn: #c69b4f;
|
||||
|
||||
--serif: "Iowan Old Style", "Constantia", "Hoefler Text", Georgia, "Times New Roman", serif;
|
||||
--display: "Trajan Pro", "Cinzel", "Iowan Old Style", Georgia, serif;
|
||||
--sans: -apple-system, "Segoe UI", Roboto, system-ui, sans-serif;
|
||||
--mono: "JetBrains Mono", "SF Mono", Menlo, Consolas, monospace;
|
||||
}
|
||||
* { box-sizing: border-box; }
|
||||
html, body { margin: 0; padding: 0; background: var(--bg); color: var(--ink); font-family: var(--sans); font-size: 15px; line-height: 1.55; }
|
||||
a { color: var(--accent); text-decoration: none; }
|
||||
body {
|
||||
/* Faint paper-grain — a barely-visible noise pattern so the
|
||||
background isn't a flat slab. */
|
||||
background-image:
|
||||
radial-gradient(at 20% 30%, var(--bg-grain) 0%, var(--bg) 70%),
|
||||
radial-gradient(at 80% 70%, #110e0b 0%, var(--bg) 60%);
|
||||
background-attachment: fixed;
|
||||
min-height: 100vh;
|
||||
}
|
||||
a { color: var(--bronze); text-decoration: none; transition: color 80ms ease; }
|
||||
a:hover { color: var(--ink); }
|
||||
code { font-family: var(--mono); font-size: 0.9em; background: var(--surface-2); padding: 1px 5px; border-radius: 2px; color: var(--ink-muted); }
|
||||
code { font-family: var(--mono); font-size: 0.9em; background: var(--surface-2); padding: 1px 6px; border-radius: 2px; color: var(--ink-muted); border: 1px solid var(--border); }
|
||||
|
||||
.topbar { display: flex; align-items: baseline; gap: 16px; padding: 14px 24px; border-bottom: 1px solid var(--border); background: var(--surface); }
|
||||
.brand { font-family: var(--serif); font-size: 22px; color: var(--accent); letter-spacing: 0.5px; }
|
||||
/* ─── ornament ─────────────────────────────────────────────── */
|
||||
.ornament { color: var(--bronze-dim); margin: 18px 0 26px 0; max-width: 360px; opacity: 0.7; }
|
||||
.ornament svg { display: block; width: 100%; height: 12px; }
|
||||
|
||||
/* ─── topbar ───────────────────────────────────────────────── */
|
||||
.topbar {
|
||||
display: flex; align-items: baseline; gap: 18px;
|
||||
padding: 16px 28px 14px 28px;
|
||||
border-bottom: 1px solid var(--border);
|
||||
background: linear-gradient(180deg, var(--surface) 0%, var(--bg) 100%);
|
||||
position: relative;
|
||||
}
|
||||
.topbar::after {
|
||||
/* Thin oxblood underline — like a runestone register line. */
|
||||
content: ""; position: absolute; left: 0; right: 0; bottom: -1px;
|
||||
height: 1px; background: var(--accent); opacity: 0.35;
|
||||
}
|
||||
.brand {
|
||||
font-family: var(--display); font-size: 26px; color: var(--bronze);
|
||||
letter-spacing: 4px; font-weight: 700;
|
||||
}
|
||||
.brand:hover { color: var(--ink); }
|
||||
.tagline { color: var(--ink-faint); font-size: 13px; font-style: italic; }
|
||||
.tagline { color: var(--ink-faint); font-size: 12px; font-style: italic; letter-spacing: 0.5px; }
|
||||
.topnav { margin-left: auto; display: flex; gap: 14px; align-items: baseline; }
|
||||
.new-saga {
|
||||
font-family: var(--display); letter-spacing: 2px; font-size: 12px;
|
||||
text-transform: uppercase; color: var(--ink-muted);
|
||||
border: 1px solid var(--border-strong); padding: 6px 14px;
|
||||
background: var(--surface-2);
|
||||
}
|
||||
.new-saga:hover { color: var(--ink); border-color: var(--bronze-dim); background: var(--surface); }
|
||||
|
||||
.footbar { padding: 10px 24px; border-top: 1px solid var(--border); background: var(--surface); color: var(--ink-faint); font-size: 12px; }
|
||||
/* ─── footbar ──────────────────────────────────────────────── */
|
||||
.footbar {
|
||||
padding: 12px 28px;
|
||||
border-top: 1px solid var(--border);
|
||||
background: var(--surface);
|
||||
color: var(--ink-faint);
|
||||
font-size: 11px;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
.footbar a { color: var(--ink-faint); }
|
||||
.footbar a:hover { color: var(--bronze); }
|
||||
|
||||
.layout { display: grid; grid-template-columns: 320px 1fr; min-height: calc(100vh - 90px); }
|
||||
/* ─── layout ───────────────────────────────────────────────── */
|
||||
.layout {
|
||||
display: grid;
|
||||
grid-template-columns: 320px 1fr;
|
||||
min-height: calc(100vh - 100px);
|
||||
}
|
||||
|
||||
.sidebar { padding: 16px 20px; border-right: 1px solid var(--border); background: var(--surface); overflow-y: auto; }
|
||||
.sidebar h2 { font-family: var(--serif); font-size: 14px; text-transform: uppercase; letter-spacing: 1.5px; color: var(--ink-muted); margin: 0 0 14px 0; font-weight: 400; }
|
||||
/* ─── sidebar ──────────────────────────────────────────────── */
|
||||
.sidebar { padding: 18px 22px 28px 22px; border-right: 1px solid var(--border); background: var(--surface); overflow-y: auto; }
|
||||
.sidebar-collapse { }
|
||||
.sidebar-summary {
|
||||
cursor: pointer; list-style: none; display: flex; align-items: baseline; gap: 10px;
|
||||
padding-bottom: 14px; border-bottom: 1px solid var(--border);
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
.sidebar-summary::-webkit-details-marker { display: none; }
|
||||
.sidebar h2 {
|
||||
font-family: var(--display); font-size: 13px; text-transform: uppercase;
|
||||
letter-spacing: 3px; color: var(--bronze); margin: 0; font-weight: 700;
|
||||
}
|
||||
.sidebar-count { color: var(--ink-faint); font-size: 12px; font-family: var(--mono); }
|
||||
.story-list { list-style: none; margin: 0; padding: 0; }
|
||||
.story-row { margin-bottom: 4px; }
|
||||
.story-row a { display: block; padding: 10px 12px; border-radius: 3px; color: var(--ink); }
|
||||
.story-row a:hover, .story-row.active a { background: var(--surface-2); }
|
||||
.story-row.active a { border-left: 2px solid var(--accent); padding-left: 10px; }
|
||||
.story-row .title { display: block; font-family: var(--serif); font-size: 16px; color: var(--ink); margin-bottom: 2px; }
|
||||
.story-row .meta { display: block; font-size: 11px; color: var(--ink-faint); }
|
||||
.story-row .status { display: inline-block; font-size: 10px; padding: 1px 6px; border-radius: 2px; margin-left: 6px; text-transform: uppercase; letter-spacing: 0.5px; color: var(--ink-faint); }
|
||||
.story-row { margin-bottom: 6px; }
|
||||
.story-row a {
|
||||
display: block; padding: 12px 14px 12px 12px;
|
||||
border-left: 2px solid transparent;
|
||||
color: var(--ink);
|
||||
}
|
||||
.story-row a:hover { background: var(--surface-2); border-left-color: var(--bronze-dim); }
|
||||
.story-row.active a { background: var(--surface-2); border-left-color: var(--accent); }
|
||||
.story-row .title { display: block; font-family: var(--serif); font-size: 16px; color: var(--ink); margin-bottom: 3px; line-height: 1.3; }
|
||||
.story-row .meta { display: block; font-size: 11px; color: var(--ink-faint); font-family: var(--mono); letter-spacing: 0.3px; }
|
||||
.story-row .status { display: inline-block; font-size: 9px; padding: 1px 6px; margin-left: 6px; text-transform: uppercase; letter-spacing: 1px; color: var(--ink-faint); border: 1px solid var(--border); }
|
||||
.story-row .status-complete { color: var(--ok); border-color: var(--ok); }
|
||||
.story-row .status-generating, .story-row .status-cleaning, .story-row .status-auditing { color: var(--warn); border-color: var(--warn); }
|
||||
.story-row .status-failed { color: var(--crit); border-color: var(--crit); }
|
||||
|
||||
.panel { padding: 36px 48px; overflow-y: auto; max-width: 1100px; }
|
||||
/* ─── main panel ───────────────────────────────────────────── */
|
||||
.panel { padding: 40px 56px; overflow-y: auto; max-width: 1100px; }
|
||||
|
||||
.welcome h1 { font-family: var(--serif); font-size: 36px; color: var(--accent); margin: 40px 0 16px 0; font-weight: 400; }
|
||||
.welcome .lead { font-size: 17px; color: var(--ink); }
|
||||
.welcome p { max-width: 65ch; }
|
||||
.welcome .muted { color: var(--ink-faint); font-size: 14px; }
|
||||
/* ─── welcome ──────────────────────────────────────────────── */
|
||||
.welcome h1 {
|
||||
font-family: var(--display); font-size: 42px;
|
||||
color: var(--bronze); letter-spacing: 2px; font-weight: 700;
|
||||
margin: 40px 0 8px 0;
|
||||
}
|
||||
.welcome .lead { font-size: 18px; color: var(--ink); margin-top: 20px; }
|
||||
.welcome p { max-width: 64ch; }
|
||||
.welcome .muted { color: var(--ink-faint); font-size: 13px; font-style: italic; }
|
||||
|
||||
/* ─── story detail ─────────────────────────────────────────── */
|
||||
.story h1 {
|
||||
font-family: var(--display); font-size: 34px; color: var(--ink);
|
||||
margin: 0 0 18px 0; font-weight: 700; letter-spacing: 1px;
|
||||
}
|
||||
.metabar {
|
||||
display: flex; flex-wrap: wrap; gap: 18px; font-size: 13px; color: var(--ink-muted);
|
||||
margin-bottom: 12px; align-items: center;
|
||||
}
|
||||
.metabar .status {
|
||||
font-size: 9px; padding: 2px 8px; background: transparent;
|
||||
text-transform: uppercase; letter-spacing: 1.5px; border: 1px solid var(--border-strong); color: var(--ink-muted);
|
||||
}
|
||||
.metabar .status-complete { color: var(--ok); border-color: var(--ok); }
|
||||
.metabar .status-generating, .metabar .status-cleaning, .metabar .status-auditing, .metabar .status-seed { color: var(--warn); border-color: var(--warn); }
|
||||
.metabar .status-failed { color: var(--crit); border-color: var(--crit); }
|
||||
|
||||
.story-actions {
|
||||
display: flex; gap: 14px; align-items: center;
|
||||
padding: 14px 0 22px 0; margin-bottom: 26px;
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
.action-primary {
|
||||
font-family: var(--display); letter-spacing: 2px; font-size: 12px;
|
||||
text-transform: uppercase; color: var(--ink);
|
||||
border: 1px solid var(--accent-dim); padding: 9px 18px;
|
||||
background: linear-gradient(180deg, var(--surface-2) 0%, var(--surface) 100%);
|
||||
}
|
||||
.action-primary:hover { color: var(--ink); border-color: var(--accent); background: var(--surface-2); }
|
||||
.action-secondary {
|
||||
font-size: 12px; color: var(--ink-faint); margin-left: auto;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
.action-secondary:hover { color: var(--bronze); }
|
||||
|
||||
.story h1 { font-family: var(--serif); font-size: 32px; color: var(--ink); margin: 0 0 14px 0; font-weight: 400; }
|
||||
.metabar { display: flex; flex-wrap: wrap; gap: 16px; font-size: 13px; color: var(--ink-muted); margin-bottom: 30px; align-items: center; padding-bottom: 16px; border-bottom: 1px solid var(--border); }
|
||||
.metabar .status { font-size: 10px; padding: 2px 8px; border-radius: 2px; background: var(--surface-2); text-transform: uppercase; letter-spacing: 0.5px; }
|
||||
.metabar .runs-link { margin-left: auto; font-size: 12px; color: var(--ink-faint); }
|
||||
.metabar .runs-link:hover { color: var(--accent); }
|
||||
.muted { color: var(--ink-faint); }
|
||||
.story h2, .chapter h2, .runs h2 { font-family: var(--serif); font-size: 14px; text-transform: uppercase; letter-spacing: 1.5px; color: var(--ink-muted); margin: 36px 0 14px 0; font-weight: 400; }
|
||||
.story h3, .bible-section h3 { font-family: var(--serif); font-size: 15px; color: var(--accent-dim); margin: 18px 0 10px 0; font-weight: 400; letter-spacing: 0.5px; }
|
||||
.story h2, .chapter h2, .runs h2 {
|
||||
font-family: var(--display); font-size: 12px;
|
||||
text-transform: uppercase; letter-spacing: 3px; color: var(--bronze);
|
||||
margin: 38px 0 16px 0; font-weight: 700;
|
||||
}
|
||||
.story h3, .bible-section h3 {
|
||||
font-family: var(--display); font-size: 13px; color: var(--bronze-dim);
|
||||
margin: 20px 0 12px 0; font-weight: 700; letter-spacing: 2px; text-transform: uppercase;
|
||||
}
|
||||
|
||||
.chapter-list { list-style: none; padding: 0; margin: 0; }
|
||||
.chapter-list li { margin-bottom: 2px; }
|
||||
.chapter-list a { display: grid; grid-template-columns: 100px 1fr auto 110px; gap: 18px; align-items: baseline; padding: 8px 12px; border-radius: 3px; color: var(--ink); }
|
||||
.chapter-list a:hover { background: var(--surface-2); }
|
||||
.chapter-list .n { color: var(--ink-faint); font-size: 13px; font-family: var(--mono); }
|
||||
.chapter-list .ch-title { font-family: var(--serif); font-size: 15px; }
|
||||
.chapter-list .wc { color: var(--ink-faint); font-size: 12px; font-family: var(--mono); text-align: right; }
|
||||
.chapter-list .summary-flag { font-size: 11px; color: var(--ok); }
|
||||
.chapter-list a {
|
||||
display: grid; grid-template-columns: 110px 1fr auto 110px;
|
||||
gap: 20px; align-items: baseline; padding: 10px 14px;
|
||||
color: var(--ink); border-left: 2px solid transparent;
|
||||
}
|
||||
.chapter-list a:hover { background: var(--surface-2); border-left-color: var(--bronze-dim); }
|
||||
.chapter-list .n { color: var(--bronze-dim); font-size: 12px; font-family: var(--mono); letter-spacing: 1px; }
|
||||
.chapter-list .ch-title { font-family: var(--serif); font-size: 16px; }
|
||||
.chapter-list .wc { color: var(--ink-faint); font-size: 11px; font-family: var(--mono); text-align: right; }
|
||||
.chapter-list .summary-flag { font-size: 10px; color: var(--ok); letter-spacing: 0.5px; }
|
||||
.chapter-list .summary-flag.missing { color: var(--ink-faint); }
|
||||
|
||||
.char-list { list-style: none; padding: 0; margin: 0 0 14px 0; }
|
||||
.char-list li { display: grid; grid-template-columns: 240px 1fr; gap: 18px; padding: 8px 0; border-bottom: 1px solid var(--surface-2); align-items: baseline; }
|
||||
.cname { font-family: var(--serif); color: var(--ink); font-size: 14px; }
|
||||
.cfacts { color: var(--ink-muted); font-size: 13px; line-height: 1.5; }
|
||||
.char-list li {
|
||||
display: grid; grid-template-columns: 240px 1fr; gap: 22px;
|
||||
padding: 10px 0; border-bottom: 1px solid var(--surface-2); align-items: baseline;
|
||||
}
|
||||
.cname { font-family: var(--serif); color: var(--ink); font-size: 15px; }
|
||||
.cfacts { color: var(--ink-muted); font-size: 13px; line-height: 1.55; }
|
||||
|
||||
.bible-section details { border-bottom: 1px solid var(--surface-2); padding: 10px 0; }
|
||||
.bible-section summary { cursor: pointer; list-style: none; display: flex; gap: 14px; align-items: baseline; padding: 4px 0; }
|
||||
.bible-section summary { cursor: pointer; list-style: none; display: flex; gap: 16px; align-items: baseline; padding: 6px 0; }
|
||||
.bible-section summary::-webkit-details-marker { display: none; }
|
||||
.bible-section summary::before { content: "▸"; color: var(--ink-faint); font-size: 11px; margin-right: 4px; }
|
||||
.bible-section details[open] summary::before { content: "▾"; }
|
||||
.bible-section .category { font-size: 10px; text-transform: uppercase; letter-spacing: 1px; color: var(--accent-dim); min-width: 140px; }
|
||||
.bible-section .ctitle { font-family: var(--serif); color: var(--ink); }
|
||||
.bible-section .cbody { padding: 10px 0 6px 18px; color: var(--ink-muted); white-space: pre-wrap; line-height: 1.65; max-width: 75ch; font-size: 14px; }
|
||||
.bible-section summary::before { content: "▸"; color: var(--bronze-dim); font-size: 11px; margin-right: 4px; }
|
||||
.bible-section details[open] summary::before { content: "▾"; color: var(--accent); }
|
||||
.bible-section .category { font-size: 10px; text-transform: uppercase; letter-spacing: 2px; color: var(--bronze-dim); min-width: 150px; font-family: var(--display); font-weight: 700; }
|
||||
.bible-section .ctitle { font-family: var(--serif); color: var(--ink); font-size: 15px; }
|
||||
.bible-section .cbody {
|
||||
padding: 12px 0 8px 22px; color: var(--ink-muted); white-space: pre-wrap;
|
||||
line-height: 1.7; max-width: 75ch; font-size: 14px; font-family: var(--serif);
|
||||
}
|
||||
|
||||
.chapter .back, .runs .back { display: inline-block; color: var(--ink-faint); font-size: 12px; margin-bottom: 18px; }
|
||||
.chapter h1.ch-title { font-family: var(--serif); font-size: 28px; font-weight: 400; color: var(--ink); margin: 0 0 8px 0; }
|
||||
.chapter h1.ch-title .n { color: var(--accent-dim); font-size: 22px; }
|
||||
.summary-box { background: var(--surface); border-left: 2px solid var(--accent-dim); padding: 14px 20px; margin: 24px 0 32px 0; max-width: 75ch; }
|
||||
/* ─── chapter view ─────────────────────────────────────────── */
|
||||
.chapter .back, .runs .back, .form-panel .back {
|
||||
display: inline-block; color: var(--ink-faint); font-size: 12px;
|
||||
margin-bottom: 18px; letter-spacing: 0.5px;
|
||||
}
|
||||
.chapter h1.ch-title {
|
||||
font-family: var(--display); font-size: 28px; font-weight: 700;
|
||||
color: var(--ink); margin: 0 0 12px 0; letter-spacing: 1px;
|
||||
}
|
||||
.chapter h1.ch-title .n { color: var(--bronze); font-size: 22px; letter-spacing: 2px; }
|
||||
.summary-box {
|
||||
background: var(--surface); border-left: 2px solid var(--bronze);
|
||||
padding: 16px 22px; margin: 24px 0 36px 0; max-width: 75ch;
|
||||
}
|
||||
.summary-box.empty { border-left-color: var(--surface-2); }
|
||||
.summary-box h3 { font-family: var(--serif); font-size: 12px; text-transform: uppercase; letter-spacing: 1.5px; color: var(--ink-muted); margin: 0 0 8px 0; font-weight: 400; }
|
||||
.summary-box p { margin: 0; color: var(--ink-muted); font-size: 14px; line-height: 1.65; }
|
||||
.prose { font-family: var(--serif); font-size: 17px; line-height: 1.75; max-width: 68ch; color: var(--ink); }
|
||||
.prose p { margin: 0 0 1.1em 0; }
|
||||
.prose p:first-letter { /* nothing fancy yet */ }
|
||||
.summary-box h3 {
|
||||
font-family: var(--display); font-size: 11px;
|
||||
text-transform: uppercase; letter-spacing: 2.5px; color: var(--bronze);
|
||||
margin: 0 0 10px 0; font-weight: 700;
|
||||
}
|
||||
.summary-box p { margin: 0; color: var(--ink-muted); font-size: 14px; line-height: 1.7; font-family: var(--serif); }
|
||||
.prose {
|
||||
font-family: var(--serif); font-size: 18px; line-height: 1.8;
|
||||
max-width: 68ch; color: var(--ink);
|
||||
}
|
||||
.prose p { margin: 0 0 1.15em 0; }
|
||||
.prose p:first-of-type:first-letter {
|
||||
/* Drop cap on the first paragraph — small literary flourish. */
|
||||
float: left; font-family: var(--display); font-size: 56px; line-height: 0.9;
|
||||
padding: 8px 8px 0 0; color: var(--bronze); font-weight: 700;
|
||||
}
|
||||
|
||||
/* ─── runs table ───────────────────────────────────────────── */
|
||||
.runs-table { width: 100%; border-collapse: collapse; font-size: 13px; }
|
||||
.runs-table th, .runs-table td { padding: 8px 12px; text-align: left; border-bottom: 1px solid var(--surface-2); }
|
||||
.runs-table th { color: var(--ink-faint); font-weight: 400; text-transform: uppercase; font-size: 11px; letter-spacing: 1px; }
|
||||
.runs-table th, .runs-table td { padding: 9px 14px; text-align: left; border-bottom: 1px solid var(--surface-2); }
|
||||
.runs-table th { color: var(--bronze-dim); font-weight: 700; text-transform: uppercase; font-size: 10px; letter-spacing: 2px; font-family: var(--display); }
|
||||
.runs-table td.kind { font-family: var(--mono); font-size: 12px; color: var(--ink-muted); }
|
||||
.runs-table td.status-succeeded { color: var(--ok); }
|
||||
.runs-table td.status-failed { color: var(--crit); }
|
||||
.runs-table td.status-running { color: var(--warn); }
|
||||
.runs-table td.error { color: var(--crit); font-size: 12px; }
|
||||
.runs-table td.error { color: var(--crit); font-size: 12px; font-family: var(--mono); }
|
||||
|
||||
.empty { color: var(--ink-faint); font-style: italic; }
|
||||
|
||||
/* ─── forms (new-saga + continue) ──────────────────────────── */
|
||||
.form-panel h1 {
|
||||
font-family: var(--display); font-size: 30px; color: var(--ink);
|
||||
letter-spacing: 1.5px; font-weight: 700; margin: 0 0 8px 0;
|
||||
}
|
||||
.form-panel form {
|
||||
display: flex; flex-direction: column; gap: 18px;
|
||||
max-width: 640px; margin-top: 28px;
|
||||
}
|
||||
.form-panel label {
|
||||
display: flex; flex-direction: column; gap: 6px;
|
||||
font-family: var(--display); font-size: 11px; letter-spacing: 2px;
|
||||
text-transform: uppercase; color: var(--bronze); font-weight: 700;
|
||||
}
|
||||
.form-panel input[type=text],
|
||||
.form-panel input[type=number],
|
||||
.form-panel textarea,
|
||||
.form-panel select {
|
||||
background: var(--surface); color: var(--ink);
|
||||
border: 1px solid var(--border-strong); padding: 11px 14px;
|
||||
font-family: var(--serif); font-size: 15px; line-height: 1.5;
|
||||
}
|
||||
.form-panel input:focus, .form-panel textarea:focus, .form-panel select:focus {
|
||||
outline: none; border-color: var(--bronze);
|
||||
}
|
||||
.form-panel textarea { resize: vertical; min-height: 80px; }
|
||||
.form-panel button {
|
||||
align-self: flex-start; margin-top: 8px;
|
||||
font-family: var(--display); letter-spacing: 2px; font-size: 12px;
|
||||
text-transform: uppercase; color: var(--ink); cursor: pointer;
|
||||
border: 1px solid var(--accent-dim); padding: 11px 26px;
|
||||
background: linear-gradient(180deg, var(--surface-2) 0%, var(--surface) 100%);
|
||||
}
|
||||
.form-panel button:hover { border-color: var(--accent); background: var(--surface-2); }
|
||||
.form-panel .error { color: var(--crit); }
|
||||
|
||||
/* ─── mobile: collapse sidebar inline above main, allow toggle ── */
|
||||
@media (max-width: 800px) {
|
||||
.layout { grid-template-columns: 1fr; }
|
||||
.sidebar {
|
||||
border-right: none;
|
||||
border-bottom: 1px solid var(--border);
|
||||
padding: 14px 18px 18px 18px;
|
||||
max-height: 60vh;
|
||||
}
|
||||
.sidebar-summary { padding-bottom: 10px; margin-bottom: 10px; }
|
||||
/* Collapsed by default on mobile via the open attribute lives
|
||||
on the desktop view; we use details native state. The user
|
||||
can tap the "Sagas" header to expand/collapse. */
|
||||
.panel { padding: 24px 18px; }
|
||||
.topbar { padding: 12px 18px 10px 18px; flex-wrap: wrap; }
|
||||
.topnav { margin-left: 0; width: 100%; padding-top: 6px; }
|
||||
.chapter-list a { grid-template-columns: 80px 1fr auto; }
|
||||
.chapter-list .wc { display: none; }
|
||||
.char-list li { grid-template-columns: 1fr; gap: 4px; }
|
||||
.cname { font-size: 14px; }
|
||||
.brand { font-size: 22px; letter-spacing: 3px; }
|
||||
.welcome h1, .story h1 { font-size: 28px; }
|
||||
.prose { font-size: 16px; }
|
||||
}
|
||||
"#;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue