SectionBanner.astro (2867B)
1 --- 2 interface Stat { 3 label: string; 4 value: string | number; 5 /** Paint the value in the banner's accent — one per banner, the number 6 * worth reading first. */ 7 accent?: boolean; 8 } 9 10 interface Props { 11 /** Mono lockup before the rule, e.g. `03 ^: ACTIVE DIRECTORY`. */ 12 n: string; 13 label: string; 14 title: string; 15 blurb?: string; 16 stats?: Stat[]; 17 accent?: 'iris' | 'foam' | 'love' | 'gold' | 'rose' | 'pine'; 18 } 19 const { n, label, title, blurb, stats = [], accent = 'foam' } = Astro.props; 20 21 /** 22 * The page header every route below the home page lands on: dark plate, 23 * live signal field, left scrim, and a ledger on the right. 24 * 25 * Legibility on the plate is carried by two layers, not one — the canvas 26 * erases its own top and bottom bands, AND the scrim gradient sits over 27 * the noise and under the content. Either alone leaves the title sitting 28 * on a bright filament some fraction of the loop. 29 */ 30 --- 31 <header class="banner plate bleed" style={`--acc: var(--${accent});`}> 32 <canvas class="banner__field" data-fuzz aria-hidden="true"></canvas> 33 <span class="banner__scrim" aria-hidden="true"></span> 34 <span class="grain grain--local" aria-hidden="true"></span> 35 <!-- CRT film over the signal field — the body row is already z-index 2, 36 so the type stays above the scanlines. --> 37 <span class="scanlines" aria-hidden="true"></span> 38 39 <div class="wrap banner__body"> 40 <div> 41 <p class="eyebrow" style={`--acc: var(--${accent});`}> 42 <span class="eyebrow__n">{n}</span> 43 <span class="eyebrow__mark">^:</span> 44 <span>{label}</span> 45 <span class="eyebrow__rule" aria-hidden="true"></span> 46 </p> 47 <h1 class="banner__title" data-unscramble={title}>{title}</h1> 48 {blurb && <p class="banner__blurb">{blurb}</p>} 49 </div> 50 51 {stats.length > 0 && ( 52 <dl class="banner__ledger"> 53 {stats.map((s) => ( 54 <div class={`banner__row${s.accent ? ' banner__row--acc' : ''}`}> 55 <dt>{s.label}</dt> 56 <dd><b>{s.value}</b></dd> 57 </div> 58 ))} 59 </dl> 60 )} 61 </div> 62 </header> 63 64 <style> 65 /* ---- Cyberdeck chrome for the banner ----------------------------------- 66 Hairline frame + CRT film over the dark plate. The plate pins the night 67 palette (`.plate`), so `--rule`/`--rule-hi` below resolve to the night 68 hairlines in both modes — the frame belongs to the plate, not the page. */ 69 .banner { border-top: 1px solid var(--rule); } 70 /* Kept faint: the signal field and the grain already texture the plate, 71 and the title has to win every layer stack it sits in. */ 72 .banner > .scanlines { opacity: 0.45; } 73 /* The ledger is terminal furniture — JetBrains Mono, same as the segbar. */ 74 .banner__ledger { 75 font-family: var(--font-term, 'JetBrains Mono', 'IBM Plex Mono', ui-monospace, monospace); 76 } 77 </style> 78