- Reveal: shorten scroll-reveal safety timeout below the capture settle and reveal-all when viewport height is unknown (headless), so main content is no longer stranded mid-fade at ~0.25 opacity in both modes; give the article template the robust reveal script it was missing. Fixes the washed-out light-mode body/quote copy AND the H1-over-first-line overlap (the translateY mid-transition was dropping the heading onto the body). - Headings: add bottom margin per level so H1 no longer butts the first paragraph. - Article: collapse the aside rail (and its divider border) when empty; populate each case article's aside with case-file marginalia. - Light mode: bump muted-foreground contrast across all five presets (~L38->L30) for comfortable AA on secondary text; dark palettes untouched. - Media: wire 6 licensed noir stock shots as seed media — harbour-night hero (with readable light-on-scrim hero text in both modes), per-article lead photos, typewriter on About. - SVG geometry guard: explicit width/height on 26 <use> icon SVGs; replace 15 unsized ::icon:: shortcodes with sized <svg><use> markup. - Declare required_icon_packs (lucide, simple-icons). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
241 lines
17 KiB
JSON
241 lines
17 KiB
JSON
{
|
|
"demo": true,
|
|
"settings": {
|
|
"merge": {
|
|
"companyName": "The Cold File",
|
|
"tagline": "Cases that were never closed."
|
|
}
|
|
},
|
|
"media": [
|
|
{ "id": "7a1c0001-0000-4000-8000-000000000001", "file": "media/harbour-night.jpg", "alt": "A working harbour at night under sodium light", "folder": "noir" },
|
|
{ "id": "7a1c0001-0000-4000-8000-000000000002", "file": "media/foggy-night.jpg", "alt": "A deserted street lost in night fog", "folder": "noir" },
|
|
{ "id": "7a1c0001-0000-4000-8000-000000000003", "file": "media/typewriter.jpg", "alt": "An old typewriter on a desk", "folder": "noir" },
|
|
{ "id": "7a1c0001-0000-4000-8000-000000000004", "file": "media/streetlamp.jpg", "alt": "A single streetlamp in the dark", "folder": "noir" },
|
|
{ "id": "7a1c0001-0000-4000-8000-000000000005", "file": "media/foggy-street.jpg", "alt": "A wet street under fog and lamplight", "folder": "noir" },
|
|
{ "id": "7a1c0001-0000-4000-8000-000000000006", "file": "media/typewriter-keys.jpg", "alt": "Close detail of typewriter keys", "folder": "noir" }
|
|
],
|
|
"data_tables": [
|
|
{
|
|
"key": "case_tips",
|
|
"name": "Case Tips",
|
|
"description": "Seeded tip-line submissions for The Cold File demo. A submission becomes a row here and emails the site admins.",
|
|
"columns": [
|
|
{ "key": "name", "label": "Name", "type": "text", "required": false },
|
|
{ "key": "email", "label": "Email", "type": "email", "required": true },
|
|
{ "key": "subject", "label": "Case or subject", "type": "text", "required": false },
|
|
{ "key": "message", "label": "Message", "type": "text", "required": true }
|
|
]
|
|
}
|
|
],
|
|
"pages": [
|
|
{
|
|
"slug": "/",
|
|
"title": "The Cold File",
|
|
"template_key": "landing",
|
|
"blocks": [
|
|
{
|
|
"block_key": "hero",
|
|
"title": "Hero",
|
|
"slot": "main",
|
|
"sort_order": 1,
|
|
"content": {
|
|
"template": "centered",
|
|
"backgroundImage": "7a1c0001-0000-4000-8000-000000000001",
|
|
"overlayColor": "dark",
|
|
"overlayOpacity": 55,
|
|
"eyebrow": "A true-crime file",
|
|
"headline": "The Cold File",
|
|
"subheadline": "Cases that were never closed.",
|
|
"description": "We read the record, walk the ground, and lay out what is known. One case at a time. You decide what it adds up to.",
|
|
"ctaPrimary": { "text": "Read the files", "url": "/blog" },
|
|
"ctaSecondary": { "text": "Submit a tip", "url": "/contact" }
|
|
}
|
|
},
|
|
{
|
|
"block_key": "noir:case_file",
|
|
"title": "Featured case",
|
|
"slot": "main",
|
|
"sort_order": 2,
|
|
"content": {
|
|
"caseNumber": "CF-0451",
|
|
"subject": "The Harbour Light",
|
|
"status": "cold",
|
|
"summary": "A night watchman clocked out at two and never reached the gate. His lamp was still burning at dawn. The tide had turned twice.",
|
|
"fields": [
|
|
{ "label": "Filed", "value": "March 1998" },
|
|
{ "label": "Location", "value": "Pier 9, East Dock" },
|
|
{ "label": "Last contact", "value": "02:04, radio check" },
|
|
{ "label": "Status", "value": "Open, unsolved" }
|
|
]
|
|
}
|
|
},
|
|
{
|
|
"block_key": "feature-grid",
|
|
"title": "How we work",
|
|
"slot": "main",
|
|
"sort_order": 3,
|
|
"content": {
|
|
"eyebrow": "Method",
|
|
"heading": "How we work a file",
|
|
"intro": "No theory before the record. We build the case from what can be checked.",
|
|
"columns": 3,
|
|
"layout": "card",
|
|
"items": [
|
|
{ "icon": "lucide:file-text", "title": "Read the record", "text": "Reports, transcripts, and the file as it was left. We start where the paper starts." },
|
|
{ "icon": "lucide:map-pin", "title": "Walk the ground", "text": "We stand where it happened and check the file against the place." },
|
|
{ "icon": "lucide:search", "title": "Follow the thread", "text": "One fact at a time. We show our work and mark what stays unknown." }
|
|
]
|
|
}
|
|
},
|
|
{
|
|
"block_key": "noir:redacted_quote",
|
|
"title": "Transcript",
|
|
"slot": "main",
|
|
"sort_order": 4,
|
|
"content": {
|
|
"label": "Interview 3, page 12",
|
|
"quote": "I told them what I saw at the water. They wrote it down and the name came back",
|
|
"redacted": "withheld pending review",
|
|
"attribution": "Witness statement",
|
|
"source": "Case CF-0451, sealed appendix"
|
|
}
|
|
},
|
|
{
|
|
"block_key": "cta",
|
|
"title": "Closing CTA",
|
|
"slot": "main",
|
|
"sort_order": 5,
|
|
"content": {
|
|
"background": "band",
|
|
"heading": "Know something we don't?",
|
|
"text": "Tips are read in confidence. Names stay off the page unless you ask otherwise.",
|
|
"primaryLabel": "Submit a tip",
|
|
"primaryUrl": "/contact",
|
|
"secondaryLabel": "Read the files",
|
|
"secondaryUrl": "/blog"
|
|
}
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"slug": "/about",
|
|
"title": "About the File",
|
|
"template_key": "default",
|
|
"blocks": [
|
|
{ "block_key": "heading", "title": "Heading", "slot": "main", "sort_order": 1, "content": { "text": "About the File", "level": 1 } },
|
|
{ "block_key": "rich-text", "title": "Story", "slot": "main", "sort_order": 2, "content": { "html": "<p>The Cold File is a true-crime publication. We take one unsolved case at a time and set it out plainly, from the record up.</p><p>We do not name the guilty. We do not sell a theory. We show what is known, mark what is not, and leave the reader to weigh it. When new facts arrive, the file is updated in the open.</p>" } },
|
|
{ "block_key": "image", "title": "The desk", "slot": "main", "sort_order": 3, "content": { "src": "7a1c0001-0000-4000-8000-000000000003", "alt": "The desk where the files are read", "caption": "The desk. Every file starts here.", "aspectRatio": "video", "size": "full", "objectFit": "cover" } },
|
|
{ "block_key": "divider", "title": "Divider", "slot": "main", "sort_order": 4, "content": { "variant": "line", "weight": "thick", "width": "narrow" } },
|
|
{ "block_key": "quote", "title": "Quote", "slot": "main", "sort_order": 5, "content": { "style": "pull", "align": "center", "quote": "A cold case is not a closed one. It is a file waiting for one more fact.", "attribution": "The Cold File" } }
|
|
]
|
|
},
|
|
{
|
|
"slug": "/blog",
|
|
"title": "The Case Files",
|
|
"template_key": "blog-index",
|
|
"blocks": [
|
|
{ "block_key": "card", "title": "Case: Harbour Light", "slot": "main", "sort_order": 1, "content": { "layout": "vertical", "title": "The Harbour Light", "text": "<p>A watchman clocked out and never reached the gate. The lamp burned until dawn.</p>", "link": "/blog/the-harbour-light", "linkLabel": "Open the file" } },
|
|
{ "block_key": "card", "title": "Case: Room 14", "slot": "main", "sort_order": 2, "content": { "layout": "vertical", "title": "Room 14", "text": "<p>A guest checked in under a false name and left one suitcase behind. Nobody saw the door open.</p>", "link": "/blog/room-14", "linkLabel": "Open the file" } },
|
|
{ "block_key": "card", "title": "Case: The Last Bus", "slot": "main", "sort_order": 3, "content": { "layout": "vertical", "title": "The Last Bus", "text": "<p>The driver logged the final stop on time. The bus reached the depot empty and locked from inside.</p>", "link": "/blog/the-last-bus", "linkLabel": "Open the file" } }
|
|
]
|
|
},
|
|
{
|
|
"slug": "/blog/the-harbour-light",
|
|
"title": "The Harbour Light",
|
|
"template_key": "article",
|
|
"parent_slug": "/blog",
|
|
"blocks": [
|
|
{ "block_key": "heading", "title": "Title", "slot": "main", "sort_order": 1, "content": { "text": "The Harbour Light", "level": 1 } },
|
|
{ "block_key": "image", "title": "The pier", "slot": "main", "sort_order": 2, "content": { "src": "7a1c0001-0000-4000-8000-000000000002", "alt": "The East Dock lost in night fog", "caption": "Pier 9, East Dock — the same hour we walked it.", "aspectRatio": "video", "size": "full", "objectFit": "cover" } },
|
|
{ "block_key": "rich-text", "title": "Body", "slot": "main", "sort_order": 3, "content": { "html": "<p>The watchman made his last radio check at four minutes past two. He was due at the gate by half past. He never signed out.</p><p>The lamp on Pier 9 was still lit at dawn. The tide had turned twice. No boat was reported missing. No body was found. The file was opened, worked for a season, and set aside.</p><p>We pulled the harbour master's log and the tide tables for that week. The two do not agree on when the water turned. One of them was written up after the fact, and we think we know which.</p><p>We walked the pier at the same hour. The lamp throws light about forty feet. The gate is ninety. For six of those steps a man is in the dark. We are still checking what stands in them.</p>" } },
|
|
{ "block_key": "heading", "title": "Rail heading", "slot": "aside", "sort_order": 1, "content": { "text": "Case File", "level": 3 } },
|
|
{ "block_key": "text", "title": "Case metadata", "slot": "aside", "sort_order": 2, "content": { "text": "<dl class=\"not-prose space-y-4\"><div><dt class=\"noir-label text-muted-foreground\">Case No.</dt><dd class=\"noir-mono text-sm text-foreground\">CF-0451</dd></div><div><dt class=\"noir-label text-muted-foreground\">Filed</dt><dd class=\"noir-mono text-sm text-foreground\">March 1998</dd></div><div><dt class=\"noir-label text-muted-foreground\">Location</dt><dd class=\"noir-mono text-sm text-foreground\">Pier 9, East Dock</dd></div><div><dt class=\"noir-label text-muted-foreground\">Last contact</dt><dd class=\"noir-mono text-sm text-foreground\">02:04, radio check</dd></div><div><dt class=\"noir-label text-muted-foreground\">Status</dt><dd class=\"noir-mono text-sm text-foreground\">Open, unsolved</dd></div></dl>" } }
|
|
]
|
|
},
|
|
{
|
|
"slug": "/blog/room-14",
|
|
"title": "Room 14",
|
|
"template_key": "article",
|
|
"parent_slug": "/blog",
|
|
"blocks": [
|
|
{ "block_key": "heading", "title": "Title", "slot": "main", "sort_order": 1, "content": { "text": "Room 14", "level": 1 } },
|
|
{ "block_key": "image", "title": "The hall", "slot": "main", "sort_order": 2, "content": { "src": "7a1c0001-0000-4000-8000-000000000004", "alt": "A single lamp at the quiet end of the hall", "caption": "The quiet end of the hall. One lamp, kept lit.", "aspectRatio": "video", "size": "full", "objectFit": "cover" } },
|
|
{ "block_key": "rich-text", "title": "Body", "slot": "main", "sort_order": 3, "content": { "html": "<p>The guest signed the register in a hand that did not match the name. He paid a week in advance and asked for the quiet end of the hall.</p><p>On the fourth night the room went dark and stayed that way. The suitcase was still there. The bed was made. The window was latched from the inside.</p><p>The file lists three people who saw him arrive and none who saw him leave. The night porter swears the corridor was watched the whole shift. The register says otherwise, in the same hand that signed the wrong name.</p><p>We are trying to reconcile that. So far the only thing everyone agrees on is the smell of a struck match, and no one who admits to lighting one.</p>" } },
|
|
{ "block_key": "heading", "title": "Rail heading", "slot": "aside", "sort_order": 1, "content": { "text": "Case File", "level": 3 } },
|
|
{ "block_key": "text", "title": "Case metadata", "slot": "aside", "sort_order": 2, "content": { "text": "<dl class=\"not-prose space-y-4\"><div><dt class=\"noir-label text-muted-foreground\">Case No.</dt><dd class=\"noir-mono text-sm text-foreground\">CF-0212</dd></div><div><dt class=\"noir-label text-muted-foreground\">Filed</dt><dd class=\"noir-mono text-sm text-foreground\">November 2003</dd></div><div><dt class=\"noir-label text-muted-foreground\">Location</dt><dd class=\"noir-mono text-sm text-foreground\">The Old Exchange</dd></div><div><dt class=\"noir-label text-muted-foreground\">Last seen</dt><dd class=\"noir-mono text-sm text-foreground\">Night four, 21:10</dd></div><div><dt class=\"noir-label text-muted-foreground\">Status</dt><dd class=\"noir-mono text-sm text-foreground\">Open, unsolved</dd></div></dl>" } }
|
|
]
|
|
},
|
|
{
|
|
"slug": "/blog/the-last-bus",
|
|
"title": "The Last Bus",
|
|
"template_key": "article",
|
|
"parent_slug": "/blog",
|
|
"blocks": [
|
|
{ "block_key": "heading", "title": "Title", "slot": "main", "sort_order": 1, "content": { "text": "The Last Bus", "level": 1 } },
|
|
{ "block_key": "image", "title": "The route", "slot": "main", "sort_order": 2, "content": { "src": "7a1c0001-0000-4000-8000-000000000005", "alt": "A wet street under lamplight on the last route", "caption": "The last route, run again at the same hour.", "aspectRatio": "video", "size": "full", "objectFit": "cover" } },
|
|
{ "block_key": "rich-text", "title": "Body", "slot": "main", "sort_order": 3, "content": { "html": "<p>The driver logged the final stop on schedule. Twelve minutes later the bus rolled into the depot. It was empty and the doors were locked from inside.</p><p>The fare box held the right count for a full run. The seats were cold. The last passenger on the ticket record never reached home.</p><p>We drove the route ourselves at the same hour and clocked every stop. Between the second-last and the depot there is a stretch with no lights and no camera. It takes about twelve minutes.</p><p>We have the route, the timing, and the log. What we do not have is what happened in those twelve minutes, or why the doors were locked from the inside.</p>" } },
|
|
{ "block_key": "heading", "title": "Rail heading", "slot": "aside", "sort_order": 1, "content": { "text": "Case File", "level": 3 } },
|
|
{ "block_key": "text", "title": "Case metadata", "slot": "aside", "sort_order": 2, "content": { "text": "<dl class=\"not-prose space-y-4\"><div><dt class=\"noir-label text-muted-foreground\">Case No.</dt><dd class=\"noir-mono text-sm text-foreground\">CF-0388</dd></div><div><dt class=\"noir-label text-muted-foreground\">Filed</dt><dd class=\"noir-mono text-sm text-foreground\">July 2009</dd></div><div><dt class=\"noir-label text-muted-foreground\">Route</dt><dd class=\"noir-mono text-sm text-foreground\">Night 9, outbound</dd></div><div><dt class=\"noir-label text-muted-foreground\">Depot</dt><dd class=\"noir-mono text-sm text-foreground\">00:12, locked</dd></div><div><dt class=\"noir-label text-muted-foreground\">Status</dt><dd class=\"noir-mono text-sm text-foreground\">Open, unsolved</dd></div></dl>" } }
|
|
]
|
|
},
|
|
{
|
|
"slug": "/contact",
|
|
"title": "Tip Line",
|
|
"template_key": "contact",
|
|
"blocks": [
|
|
{
|
|
"block_key": "contact-form",
|
|
"title": "Tip Line",
|
|
"slot": "main",
|
|
"sort_order": 1,
|
|
"content": {
|
|
"heading": "Submit a tip",
|
|
"description": "Tips are read in confidence. Tell us the case and what you know. Leave contact details only if you want a reply.",
|
|
"submitLabel": "Send tip",
|
|
"successMessage": "Thank you. Your tip has been logged. We read every one.",
|
|
"fields": [
|
|
{ "name": "name", "label": "Your name", "type": "text", "required": false, "width": "half" },
|
|
{ "name": "email", "label": "Email", "type": "email", "required": true, "width": "half" },
|
|
{ "name": "subject", "label": "Case or subject", "type": "text", "required": false, "width": "full" },
|
|
{ "name": "message", "label": "What do you know?", "type": "textarea", "required": true, "width": "full" }
|
|
],
|
|
"formConfig": { "enabled": true, "captchaEnabled": false, "targetTable": "case_tips" }
|
|
}
|
|
},
|
|
{
|
|
"block_key": "hours-location",
|
|
"title": "Where to find us",
|
|
"slot": "aside",
|
|
"sort_order": 1,
|
|
"content": {
|
|
"heading": "The Desk",
|
|
"hours": [
|
|
{ "day": "Monday to Friday", "hours": "9am to 6pm" },
|
|
{ "day": "Saturday", "hours": "By appointment" },
|
|
{ "day": "Sunday", "closed": true }
|
|
],
|
|
"specialHoursNote": "Tips are read outside these hours. Replies are not.",
|
|
"address": "Room 14, The Old Exchange\nEast Dock",
|
|
"phone": "+1 555 0199"
|
|
}
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"slug": "/login",
|
|
"title": "Access",
|
|
"template_key": "auth",
|
|
"blocks": [
|
|
{ "block_key": "auth-form", "title": "Sign in", "slot": "main", "sort_order": 1, "content": { "default_tab": "login", "show_social": false } },
|
|
{ "block_key": "text", "title": "Foot", "slot": "footer", "sort_order": 1, "content": { "text": "<p>Registered readers get new files first and the sealed appendices as they clear review.</p>" } }
|
|
]
|
|
}
|
|
],
|
|
"menu_items": [
|
|
{ "menu": "main", "label": "Home", "page_slug": "/", "sort_order": 1 },
|
|
{ "menu": "main", "label": "The Case Files", "page_slug": "/blog", "sort_order": 2 },
|
|
{ "menu": "main", "label": "About the File", "page_slug": "/about", "sort_order": 3 },
|
|
{ "menu": "main", "label": "Tip Line", "page_slug": "/contact", "sort_order": 4 }
|
|
]
|
|
}
|