code wiki / _hdl_build / nx_kit_journal.nx

nx_kit_journal.nx source

↩ module page · 117 lines · 10009 B

1// nx_kit_journal.nx -- the JOURNAL design family: an editorial/publication grammar for blog, magazine, 2// newsletter and press briefs. Third first-class family after the marketing default and Counsel. 3// 4// ★WHY THIS EXISTS RATHER THAN REUSING nx_kit2's ke_* editorial kit (measured 2026-07-25, not assumed): 5// that kit is a genuinely good newspaper grammar but is NOT composable by the site generator -- 6// (1) it carries ZERO design tokens (every colour is a hardcoded hex) so a generated palette cannot 7// retheme it; (2) it has no prefers-reduced-motion; (3) its masthead nav is HARDCODED to /factory/ and 8// nishifamily.com, so a generated site cannot carry its OWN cross-page nav -- which would fail the 9// nav-complete and link-resolution teeth. Retrofitting it would mutate a shared file the published 10// /factory pages depend on (another lane's artifacts). So: additive family here, floor met by 11// construction, zero sibling risk. The finding itself is the reusable lesson. 12// 13// The grammar: small-caps masthead wordmark over a DOUBLE RULE · kicker + large serif headline + italic 14// deck · drop-capped two-column justified lead · ruled article list w/ small-caps meta · dark subscribe 15// band. All colour flows through --kj-* derived from the generated palette, so every brief gets its own 16// ink; both themes; reduced-motion respected. Pure emit. license_tier: ORIGINAL 17import "nx_uigen_l1.nx" 18import "nx_kit_shell.nx" 19 20func kj_styles(buf: *u8, off: i64, hue: i64) -> i64 { 21 var o: i64 = he_puts(buf, off, "<style>:root{" as *u8) 22 o = l1_tok(buf, o, "--kj-ink:" as *u8, hue, 22, 11) 23 o = l1_tok(buf, o, "--kj-paper:" as *u8, hue, 26, 96) 24 o = l1_tok(buf, o, "--kj-rule:" as *u8, hue, 18, 78) 25 o = l1_tok(buf, o, "--kj-quiet:" as *u8, hue, 12, 42) 26 o = l1_tok(buf, o, "--kj-red:" as *u8, hue, 58, 38) 27 o = he_puts(buf, o, "--kj-serif:Georgia,\"Iowan Old Style\",\"Palatino Linotype\",ui-serif,serif}" as *u8) 28 o = he_puts(buf, o, "@media(prefers-color-scheme:dark){:root{" as *u8) 29 o = l1_tok(buf, o, "--kj-ink:" as *u8, hue, 16, 91) 30 o = l1_tok(buf, o, "--kj-paper:" as *u8, hue, 20, 10) 31 o = l1_tok(buf, o, "--kj-rule:" as *u8, hue, 16, 26) 32 o = l1_tok(buf, o, "--kj-quiet:" as *u8, hue, 12, 64) 33 o = l1_tok(buf, o, "--kj-red:" as *u8, hue, 62, 66) 34 o = he_puts(buf, o, "}}" as *u8) 35 o = he_puts(buf, o, "body{background:var(--kj-paper);color:var(--kj-ink);font:17px/1.72 var(--kj-serif)}" as *u8) 36 // masthead: the site's OWN nav, small-caps, under a double rule 37 o = kx_shell_reset(buf, o) 38 o = kx_wordmark(buf, o, "var(--kj-serif)" as *u8, "700" as *u8, "font-variant:small-caps;letter-spacing:.045em;font-size:clamp(1.7rem,4.6vw,2.9rem);justify-content:center" as *u8) 39 o = he_puts(buf, o, "header.site{background:var(--kj-paper);border-bottom:3px double var(--kj-rule)}header.site .bar{display:block;text-align:center;padding:26px 24px 18px}" as *u8) 40 // the masthead nav must sit INSIDE the masthead, under the wordmark -- the base shell makes it a 41 // sticky flex bar, which dropped the nav out of the header and onto the lead's kicker line (render 42 // caught it); force static block flow and centre the inline links. 43 o = he_puts(buf, o, "header.site nav.top{position:static;display:block;justify-content:center;margin:12px 0 0;font-family:system-ui,sans-serif;line-height:1}header.site nav.top a{display:inline-block;font-size:.72rem;letter-spacing:.16em;text-transform:uppercase;font-weight:700;color:var(--kj-red);margin:0 10px}" as *u8) 44 o = he_puts(buf, o, "footer.site{border-top:3px double var(--kj-rule)}footer.site .brand{font-variant:small-caps}" as *u8) 45 // lead article 46 o = he_puts(buf, o, ".kj-lead{padding:clamp(30px,5vw,52px) 0;border-bottom:1px solid var(--kj-rule)}.kj-kick{font:700 .74rem/1 system-ui,sans-serif;letter-spacing:.22em;text-transform:uppercase;color:var(--kj-red)}" as *u8) 47 o = he_puts(buf, o, ".kj-lead h1{font-family:var(--kj-serif);font-size:clamp(2rem,5.4vw,3.6rem);line-height:1.06;font-weight:700;letter-spacing:-.012em;margin:.28em 0 .2em;text-wrap:balance}" as *u8) 48 o = he_puts(buf, o, ".kj-deck{font-size:1.2rem;font-style:italic;color:var(--kj-quiet);max-width:44ch;margin:0}" as *u8) 49 o = he_puts(buf, o, ".kj-by{margin:15px 0 22px;font:700 .72rem/1 system-ui,sans-serif;letter-spacing:.14em;text-transform:uppercase;color:var(--kj-quiet)}" as *u8) 50 o = he_puts(buf, o, ".kj-body{columns:2;column-gap:clamp(24px,4vw,44px);text-align:justify;hyphens:auto}.kj-body p{margin:0 0 1em}.kj-body p:first-of-type::first-letter{font-size:3.3em;float:left;line-height:.74;padding:.02em .09em 0 0;font-weight:700;color:var(--kj-red)}@media(max-width:760px){.kj-body{columns:1;text-align:left}}" as *u8) 51 // article list 52 o = he_puts(buf, o, ".kj-more{padding:clamp(30px,5vw,52px) 0}.kj-more h2{font:700 .88rem/1 system-ui,sans-serif;letter-spacing:.2em;text-transform:uppercase;border-bottom:2px solid var(--kj-ink);padding-bottom:8px;margin:0 0 24px}" as *u8) 53 o = he_puts(buf, o, ".kj-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:clamp(20px,3vw,34px)}@media(max-width:760px){.kj-grid{grid-template-columns:1fr}}" as *u8) 54 o = he_puts(buf, o, ".kj-art{border-top:1px solid var(--kj-rule);padding-top:14px}.kj-art h3{font-family:var(--kj-serif);font-size:1.34rem;line-height:1.16;margin:0 0 .28em;font-weight:700}.kj-art p{color:var(--kj-quiet);margin:0 0 .45em;font-size:.97rem}.kj-art .kj-m{font:700 .69rem/1 system-ui,sans-serif;letter-spacing:.13em;text-transform:uppercase;color:var(--kj-red)}" as *u8) 55 // subscribe band 56 o = he_puts(buf, o, ".kj-sub{background:var(--kj-ink);color:var(--kj-paper);padding:clamp(36px,6vw,64px) 0;margin-top:clamp(20px,3vw,36px)}.kj-sub h2{font-family:var(--kj-serif);font-size:clamp(1.5rem,3.6vw,2.2rem);margin:0 0 .3em;color:var(--kj-paper)}.kj-sub p{color:var(--kj-rule);max-width:48ch;margin:0 0 20px}.kj-sub a{display:inline-block;border:1px solid var(--kj-paper);color:var(--kj-paper);padding:12px 28px;text-decoration:none;letter-spacing:.11em;text-transform:uppercase;font:700 .78rem system-ui,sans-serif}.kj-sub a:hover{background:var(--kj-paper);color:var(--kj-ink)}.kj-sub a:focus-visible{outline:3px solid var(--kj-red);outline-offset:3px}" as *u8) 57 o = he_puts(buf, o, "@media(prefers-reduced-motion:reduce){.kj-art,.kj-sub a{transition:none;animation:none}}</style>" as *u8) 58 return o 59} 60 61func kj_lead(buf: *u8, off: i64, kick: *u8, headline: *u8, deck: *u8, byline: *u8, p1: *u8, p2: *u8, p3: *u8) -> i64 { 62 var o: i64 = he_puts(buf, off, "<section class=\"kj-lead\"><div class=\"wrap\"><p class=\"kj-kick\">" as *u8) 63 o = he_puts(buf, o, kick) 64 o = he_puts(buf, o, "</p><h1>" as *u8) 65 o = he_puts(buf, o, headline) 66 o = he_puts(buf, o, "</h1><p class=\"kj-deck\">" as *u8) 67 o = he_puts(buf, o, deck) 68 o = he_puts(buf, o, "</p><p class=\"kj-by\">" as *u8) 69 o = he_puts(buf, o, byline) 70 o = he_puts(buf, o, "</p><div class=\"kj-body\"><p>" as *u8) 71 o = he_puts(buf, o, p1) 72 o = he_puts(buf, o, "</p><p>" as *u8) 73 o = he_puts(buf, o, p2) 74 o = he_puts(buf, o, "</p><p>" as *u8) 75 o = he_puts(buf, o, p3) 76 o = he_puts(buf, o, "</p></div></div></section>" as *u8) 77 return o 78} 79func kj_more_open(buf: *u8, off: i64, label: *u8) -> i64 { 80 var o: i64 = he_puts(buf, off, "<section class=\"kj-more\"><div class=\"wrap\"><h2>" as *u8) 81 o = he_puts(buf, o, label) 82 o = he_puts(buf, o, "</h2><div class=\"kj-grid\">" as *u8) 83 return o 84} 85func kj_art(buf: *u8, off: i64, headline: *u8, dek: *u8, meta: *u8) -> i64 { 86 var o: i64 = he_puts(buf, off, "<article class=\"kj-art\"><h3>" as *u8) 87 o = he_puts(buf, o, headline) 88 o = he_puts(buf, o, "</h3><p>" as *u8) 89 o = he_puts(buf, o, dek) 90 o = he_puts(buf, o, "</p><p class=\"kj-m\">" as *u8) 91 o = he_puts(buf, o, meta) 92 o = he_puts(buf, o, "</p></article>" as *u8) 93 return o 94} 95func kj_more_close(buf: *u8, off: i64) -> i64 { return he_puts(buf, off, "</div></div></section>" as *u8) } 96func kj_sub(buf: *u8, off: i64, h2: *u8, p: *u8, label: *u8, href: *u8) -> i64 { 97 var o: i64 = he_puts(buf, off, "<section class=\"kj-sub\"><div class=\"wrap\"><h2>" as *u8) 98 o = he_puts(buf, o, h2) 99 o = he_puts(buf, o, "</h2><p>" as *u8) 100 o = he_puts(buf, o, p) 101 o = he_puts(buf, o, "</p><a href=\"" as *u8) 102 o = he_puts(buf, o, href) 103 o = he_puts(buf, o, "\">" as *u8) 104 o = he_puts(buf, o, label) 105 o = he_puts(buf, o, "</a></div></section>" as *u8) 106 return o 107} 108// doc-tier override so subpages stay in-family (the round-9 two-languages lesson, applied up front) 109func kj_doc_styles(buf: *u8, off: i64) -> i64 { 110 var o: i64 = he_puts(buf, off, "<style>.doc h1{font-family:var(--kj-serif);font-weight:700;font-size:clamp(1.9rem,4.4vw,2.9rem);letter-spacing:-.012em;line-height:1.1}.doc h2{font-family:var(--kj-serif);font-weight:700}" as *u8) 111 o = he_puts(buf, o, ".doc .lede{margin:0 0 1.1em;max-width:60ch;color:var(--kj-quiet);font-style:italic;font-size:1.08rem}" as *u8) 112 o = he_puts(buf, o, ".doc .callout{background:transparent;border-left:2px solid var(--kj-red);border-radius:0;padding:6px 0 6px 18px;box-shadow:none}" as *u8) 113 o = he_puts(buf, o, ".field label{font:700 .72rem/1 system-ui,sans-serif;letter-spacing:.13em;text-transform:uppercase;color:var(--kj-quiet)}.field input,.field textarea{border-radius:0;border:1px solid var(--kj-rule);background:var(--kj-paper);padding:13px 15px;font-family:var(--kj-serif)}.field input:focus-visible,.field textarea:focus-visible{outline:none;border-color:var(--kj-red);box-shadow:0 0 0 3px var(--kj-rule)}" as *u8) 114 o = he_puts(buf, o, ".btnp{background:var(--kj-ink);color:var(--kj-paper);border-radius:0;padding:14px 30px;font:700 .78rem system-ui,sans-serif;letter-spacing:.11em;text-transform:uppercase;box-shadow:none}.btnp:hover{transform:none;background:var(--kj-red)}" as *u8) 115 o = he_puts(buf, o, "</style>" as *u8) 116 return o 117}