# Terminal theme — codeless .bnp manifest (WO-TF-025, Wave A). # Synthesized into manifest.pb by `ninja plugin build` (no plugin.wasm). theme_presets: presets.json bundled_fonts: fonts.json master_pages: master_pages.json required_icon_packs: ["lucide", "simple-icons"] system_templates: - key: terminal title: Terminal description: "Phosphor-on-black TTY theme for dev tools and OSS docs — window chrome, man-page article layouts, keybind tables, boot logs, monospace type, and a typed-terminal canvas hero. Paper-teletype light, phosphor dark." page_templates: - system: terminal key: default title: Default description: "Centered 80-col TTY page with window chrome and a sticky header" slots: [header, main, footer] - system: terminal key: full-width title: Full Width description: "Edge-to-edge layout for tool dashboards and status pages" slots: [header, main, footer] - system: terminal key: landing title: Landing description: "Typed-terminal canvas hero, feature grid, boot log, and CTA for README-style project sites" slots: [header, main, footer] - system: terminal key: article title: Article (man-page) description: "Man-page two-column layout with a section rail, ideal for docs and writeups" slots: [header, main, aside, footer] - system: terminal key: blog-index title: Blog Index description: "Changelog-style post feed with a sidebar" slots: [header, main, footer] - system: terminal key: contact title: Contact description: "Terminal contact console — form panel plus a contact card" slots: [header, main, footer] - system: terminal key: auth title: Auth description: "Centered login/register/reset console in a TTY window" slots: [header, main, footer] template_overrides: # Chrome (4) - { template: terminal, block: navbar } - { template: terminal, block: footer } - { template: terminal, block: utility-bar } - { template: terminal, block: announcement-bar } # Marketing (12) - { template: terminal, block: hero } - { template: terminal, block: feature-grid } - { template: terminal, block: rich-section } - { template: terminal, block: stats } - { template: terminal, block: testimonial } - { template: terminal, block: logo-strip } - { template: terminal, block: pricing } - { template: terminal, block: team } - { template: terminal, block: faq } - { template: terminal, block: timeline } - { template: terminal, block: cta } - { template: terminal, block: countdown } # Primitives (11) - { template: terminal, block: heading } - { template: terminal, block: text } - { template: terminal, block: rich-text } - { template: terminal, block: image } - { template: terminal, block: quote } - { template: terminal, block: divider } - { template: terminal, block: button } - { template: terminal, block: card } - { template: terminal, block: gallery } - { template: terminal, block: video-embed } - { template: terminal, block: audio-embed } # Commerce / local (6) - { template: terminal, block: menu-list } - { template: terminal, block: event-list } - { template: terminal, block: contact-form } - { template: terminal, block: contact-card } - { template: terminal, block: hours-location } - { template: terminal, block: social-links } # Blog family (12) - { template: terminal, block: blog-hero } - { template: terminal, block: featured-posts } - { template: terminal, block: related-posts } - { template: terminal, block: popular-posts } - { template: terminal, block: category-list } - { template: terminal, block: post-hero } - { template: terminal, block: post-metadata } - { template: terminal, block: author-bio } - { template: terminal, block: author-bio-hero } - { template: terminal, block: newsletter-signup } - { template: terminal, block: breadcrumbs } - { template: terminal, block: sidebar-nav } # Auth surface (3) - { template: terminal, block: auth-form } - { template: terminal, block: password-reset-form } - { template: terminal, block: auth-status } # System (1) - { template: terminal, block: page-suggestions } email_wrappers: - terminal css: input_css_append: | /* ============================================================ Terminal — Phosphor-on-black TTY theme (WO-TF-025). All colours consume the host shadcn HSL tokens via hsl(var(--token)). No hardcoded hex / rgb / named colours. Dual-mode: light = paper teletype, dark = phosphor CRT. ============================================================ */ /* --- Globals: square corners, mono stack ------------------ */ :root { --radius: 0; } .terminal-page { font-family: var(--font-body, "IBM Plex Mono", "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace); letter-spacing: 0.01em; } .terminal-page * { border-radius: 0 !important; } /* --- Typography helpers ----------------------------------- */ .terminal-heading { font-family: var(--font-heading, "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace); text-transform: uppercase; letter-spacing: 0.06em; } .terminal-mono { font-family: var(--font-mono, "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace); } .terminal-eyebrow { font-family: var(--font-mono, "JetBrains Mono", ui-monospace, monospace); text-transform: uppercase; letter-spacing: 0.2em; font-size: 0.75rem; color: hsl(var(--accent)); } .terminal-prose, .terminal-prose p, .terminal-prose li { font-family: var(--font-body, "IBM Plex Mono", ui-monospace, monospace); line-height: 1.7; } .terminal-prose a { color: hsl(var(--accent)); text-decoration: underline; text-underline-offset: 0.2em; } .terminal-prose code, code.terminal-mono { color: hsl(var(--accent)); background-color: hsl(var(--muted)); padding: 0.1rem 0.35rem; border: 1px solid hsl(var(--border)); font-family: var(--font-mono, "JetBrains Mono", ui-monospace, monospace); font-size: 0.875em; } /* --- Caret blink (element opacity; used as _) --- */ @keyframes caret-blink { 0%, 50% { opacity: 1; } 50.01%, 100% { opacity: 0; } } .caret-blink { display: inline-block; animation: caret-blink 1s step-end infinite; } /* --- TTY window chrome (signature) ------------------------ */ .tty-window { border: 1px solid hsl(var(--border)); background-color: hsl(var(--card)); color: hsl(var(--card-foreground)); } .tty-titlebar { display: flex; align-items: center; gap: 0.5rem; padding: 0.4rem 0.75rem; border-bottom: 1px solid hsl(var(--border)); background-color: hsl(var(--muted)); color: hsl(var(--muted-foreground)); font-family: var(--font-mono, "JetBrains Mono", ui-monospace, monospace); font-size: 0.75rem; letter-spacing: 0.08em; text-transform: uppercase; } .tty-dot { display: inline-block; width: 0.6rem; height: 0.6rem; border: 1px solid hsl(var(--border)); background-color: hsl(var(--secondary)); } /* --- TTY frame: bordered panel with hover glow ------------ */ .tty-frame { border: 1px solid hsl(var(--border)); background-color: hsl(var(--card)); transition: box-shadow 180ms ease, border-color 180ms ease; } .tty-frame:hover, .tty-frame:focus-within { border-color: hsl(var(--primary)); box-shadow: 0 0 0 1px hsl(var(--primary) / 0.5), 0 0 18px hsl(var(--primary) / 0.18); } /* --- ASCII corner brackets (accent + on the corners) ------ */ .tty-corners { position: relative; } .tty-corners::before, .tty-corners::after { content: "+"; position: absolute; color: hsl(var(--primary)); font-family: var(--font-mono, ui-monospace, monospace); font-weight: 700; line-height: 1; pointer-events: none; } .tty-corners::before { top: -0.55em; left: -0.35em; } .tty-corners::after { bottom: -0.55em; right: -0.35em; } /* --- ASCII figure frame (image override) ------------------ */ .ascii-frame { display: inline-block; padding: 0.5rem; border: 1px solid hsl(var(--border)); background-color: hsl(var(--card)); position: relative; } .ascii-frame figcaption { display: block; margin-top: 0.5rem; color: hsl(var(--muted-foreground)); font-family: var(--font-mono, ui-monospace, monospace); font-size: 0.875rem; text-align: center; } /* --- TTY scanlines overlay element (hero/landing) --------- */ .tty-scanlines { opacity: 0.06; background-image: linear-gradient( to bottom, hsl(var(--foreground)) 0px, hsl(var(--foreground)) 1px, transparent 1px, transparent 3px ); background-size: 100% 3px; animation: tty-scan-drift 6s linear infinite; } @keyframes tty-scan-drift { 0% { background-position: 0 0; } 100% { background-position: 0 3px; } } /* --- Page-level CRT scanline wash (subtle, whole page) ---- */ .crt-scanlines { position: relative; } .crt-scanlines::before { content: ""; position: fixed; inset: 0; pointer-events: none; z-index: 1000; background: repeating-linear-gradient( to bottom, transparent 0, transparent 2px, hsl(var(--foreground) / 0.04) 2px, hsl(var(--foreground) / 0.04) 3px ); } /* --- Status dot pulse ------------------------------------- */ .terminal-status-dot { animation: terminal-pulse 2.2s ease-in-out infinite; } @keyframes terminal-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.4; } } /* --- Typed-terminal canvas showpiece (hero override only) - */ .tty-rain-wrap { position: absolute; inset: 0; overflow: hidden; pointer-events: none; } .tty-rain-canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; opacity: 0.45; } .tty-rain-fallback { position: absolute; inset: 0; background: radial-gradient(120% 80% at 50% 0%, hsl(var(--primary) / 0.16), transparent 60%), linear-gradient(to bottom, transparent, hsl(var(--background) / 0.7)); } /* --- Man-page header block -------------------------------- */ .manpage-header { font-family: var(--font-mono, ui-monospace, monospace); border-top: 1px solid hsl(var(--border)); border-bottom: 1px solid hsl(var(--border)); padding: 0.6rem 0; margin-bottom: 1rem; display: flex; justify-content: space-between; gap: 1rem; text-transform: uppercase; letter-spacing: 0.1em; color: hsl(var(--foreground)); } .manpage-header .left, .manpage-header .center, .manpage-header .right { flex: 1; } .manpage-header .center { text-align: center; } .manpage-header .right { text-align: right; } /* --- Section rail (article aside furniture) --------------- */ .terminal-toc { font-family: var(--font-mono, ui-monospace, monospace); color: hsl(var(--muted-foreground)); padding: 1rem; border: 1px solid hsl(var(--border)); background: hsl(var(--card)); position: sticky; top: 1rem; } .terminal-toc h4 { text-transform: uppercase; letter-spacing: 0.1em; color: hsl(var(--foreground)); margin: 0 0 0.5rem; font-size: 0.875rem; } .terminal-toc ul { list-style: none; margin: 0; padding: 0; } .terminal-toc li { margin: 0.2rem 0; } .terminal-toc a { color: hsl(var(--muted-foreground)); text-decoration: none; } .terminal-toc a:hover { color: hsl(var(--foreground)); } @media (max-width: 768px) { .terminal-toc { display: none; } } /* --- Code console block ----------------------------------- */ .code-console { font-family: var(--font-mono, ui-monospace, monospace); background: hsl(var(--card)); border: 1px solid hsl(var(--border)); padding: 0.75rem 1rem; margin: 1rem 0; overflow-x: auto; color: hsl(var(--card-foreground)); } .code-console .cmd-line { display: flex; align-items: baseline; gap: 0.5em; margin: 0; } .code-console .cmd-prompt { color: hsl(var(--accent)); } .code-console .cmd-text { color: hsl(var(--foreground)); } .code-console pre { margin: 0.5rem 0 0; white-space: pre-wrap; color: hsl(var(--muted-foreground)); font-family: inherit; } /* --- Keybinding table ------------------------------------- */ .keybind-table { font-family: var(--font-mono, ui-monospace, monospace); border-collapse: collapse; margin: 1rem 0; width: 100%; max-width: 80ch; color: hsl(var(--foreground)); } .keybind-table th, .keybind-table td { border-bottom: 1px dashed hsl(var(--border)); padding: 0.4rem 0.6rem; text-align: left; vertical-align: top; } .keybind-table th { text-transform: uppercase; letter-spacing: 0.08em; color: hsl(var(--accent)); font-weight: 600; } .keybind-table kbd { font-family: inherit; background: hsl(var(--muted)); color: hsl(var(--foreground)); border: 1px solid hsl(var(--border)); padding: 0.05rem 0.4rem; margin-right: 0.25rem; font-size: 0.875em; } /* --- Boot log --------------------------------------------- */ .boot-log { font-family: var(--font-mono, ui-monospace, monospace); background: hsl(var(--background)); color: hsl(var(--foreground)); padding: 1rem; border: 1px solid hsl(var(--border)); margin: 1rem 0; white-space: pre-wrap; overflow-x: auto; } .boot-log .boot-line { display: block; opacity: 0; animation: boot-line-in 0.2s ease-out forwards; } @keyframes boot-line-in { from { opacity: 0; transform: translateY(2px); } to { opacity: 1; transform: translateY(0); } } .boot-log .boot-cursor { display: inline-block; color: hsl(var(--accent)); animation: caret-blink 1s step-end infinite; } /* --- Layout helpers --------------------------------------- */ .terminal-main-80 { max-width: 80ch; margin: 0 auto; } .terminal-article-grid { display: grid; grid-template-columns: 20ch 1fr; gap: 2rem; align-items: start; } @media (max-width: 768px) { .terminal-article-grid { grid-template-columns: 1fr; } } /* --- Reliable responsive grids ---------------------------- The host scans rendered block HTML, not theme override .ninjatpl files, so responsive Tailwind grid utilities used only in overrides (lg:grid-cols-*, sm:grid-cols-2) are purge-fragile and can silently collapse to one column on desktop. Multi-column layout is therefore defined here as plain CSS, which is compiled into the Tailwind input and can never be purged. minmax(0,1fr) stops long/unbreakable content from forcing horizontal overflow on mobile. */ .tty-grid, .tty-grid-2, .tty-grid-3, .tty-grid-4 { display: grid; gap: 1.5rem; grid-template-columns: repeat(1, minmax(0, 1fr)); } @media (min-width: 640px) { .tty-grid-2, .tty-grid-3, .tty-grid-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); } } @media (min-width: 1024px) { .tty-grid-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); } .tty-grid-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); } } .tty-grid-stats2, .tty-grid-stats3, .tty-grid-stats4 { display: grid; gap: 2rem; grid-template-columns: repeat(2, minmax(0, 1fr)); } @media (min-width: 768px) { .tty-grid-stats3 { grid-template-columns: repeat(3, minmax(0, 1fr)); } .tty-grid-stats4 { grid-template-columns: repeat(4, minmax(0, 1fr)); } } /* --- Two-column form grid (col-span utilities in overrides are purge-fragile; pin the grid in CSS) ------------------- */ .tty-form-grid { display: grid; gap: 1.25rem; grid-template-columns: repeat(1, minmax(0, 1fr)); } .tty-form-grid > .tty-col-full { grid-column: 1 / -1; } @media (min-width: 640px) { .tty-form-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } } /* --- Contained console shell ------------------------------ The persona code-console / boot-log blocks ship no max-width wrapper, so on a full-width landing page they run edge-to-edge while the neighbouring sections are contained. This shell centres them and keeps a mobile side gutter. */ .tty-console-shell { width: 100%; max-width: 56rem; margin: 1.5rem auto; padding-inline: 1rem; } /* --- Hero heights (min-h-screen / arbitrary min-h-[..] are purge-fragile utilities; pin them in CSS) ----------------- */ .tty-hero { position: relative; } .tty-hero-screen { min-height: 100vh; } .tty-hero-tall { min-height: 75vh; } .tty-hero-half { min-height: 50vh; } .tty-hero-auto { min-height: 24rem; } .tty-hero-media { min-height: 20rem; } /* --- Reduced motion: kill all motion ---------------------- */ @media (prefers-reduced-motion: reduce) { .caret-blink, .tty-scanlines, .terminal-status-dot, .tty-rain-canvas, .boot-log .boot-line, .boot-log .boot-cursor { animation: none !important; animation-duration: 0.01ms !important; } .boot-log .boot-line { opacity: 1; transform: none; } .tty-scanlines { opacity: 0; } .tty-rain-canvas { display: none; } } /* --- High contrast: drop the CRT overlays ----------------- */ @media (prefers-contrast: more) { .tty-scanlines, .crt-scanlines::before, .tty-rain-canvas { display: none; } }