br-home.jsx
1 // Brutalist HOMEPAGE — newspaper-style broadsheet masthead for the fleet catalog. 2 // Above the fold: giant feature lot. Below: featured classes, market indices, 3 // dispatches, and manufacturer index. Typographic, dense, editorial. 4 5 function BRHome({ onNav, onShip }) { 6 const feature = makeShip("FEAT-DR-0001-AA"); 7 const feature2 = makeShip("FEAT-IC-0022-BK"); 8 const lots = Array.from({length:6}).map((_,i) => makeShip("HOME-LOT-"+i)); 9 const dispatches = [ 10 ["2396.114", "COALITION", "Export tariffs on Tier-2 interceptors formally repealed. Effective immediately."], 11 ["2396.113", "MARKET", "Pleasure-yacht index holds at 112.4 despite Kepler Ring volatility."], 12 ["2396.112", "YARD", "Krovas Yards announce 18% throughput expansion at Ceres-II."], 13 ["2396.111", "RECALL", "Obsidian Forge issues voluntary recall on MN-class drive bolts, serials 44xx-46xx."], 14 ["2396.110", "SYNDICATE", "Fleet liquidation releases 41 lots to open market via bonded brokerage."], 15 ]; 16 17 return ( 18 <BRPage minHeight={2200}> 19 <BRNav active="home" cartCount={2} onNav={onNav}/> 20 21 {/* MASTHEAD SUBLINE */} 22 <div style={{padding:"8px 40px", borderBottom:`1px solid ${BR.ink}`, fontFamily:"IBM Plex Mono", fontSize:10, letterSpacing:2, color:BR.mute, textTransform:"uppercase", display:"flex", justifyContent:"space-between"}}> 23 <span>14,208 BONDED UNITS · 148 MANUFACTURERS · 92 SECTORS</span> 24 <span style={{color:BR.rust, fontWeight:700}}>◆ DRY-DOCK MOVEMENT UPDATED · 14 MIN AGO</span> 25 <span>TODAY: DR-CLASS +1.4% · IC-CLASS −0.6% · YT-CLASS HOLD</span> 26 </div> 27 28 {/* HERO — broadsheet headline */} 29 <div style={{padding:"28px 40px 24px", borderBottom:`4px double ${BR.ink}`}}> 30 <div style={{display:"flex", alignItems:"baseline", gap:16, fontFamily:"IBM Plex Mono", fontSize:10, letterSpacing:3, color:BR.mute, textTransform:"uppercase", marginBottom:12}}> 31 <span style={{background:BR.ink, color:BR.paper, padding:"3px 10px"}}>EDITORIAL No. 412</span> 32 <span>FEATURE LOT / WEEK 46</span> 33 <span>— PRESENTED BY THE DESK AT SECTOR G-4 —</span> 34 </div> 35 <div style={{fontFamily:"Oswald", fontWeight:900, fontSize:120, lineHeight:0.88, letterSpacing:-3, color:BR.ink, textTransform:"uppercase", maxWidth:1100}}> 36 Fourteen thousand hulls. One unbroken ledger. 37 </div> 38 <div style={{marginTop:18, display:"grid", gridTemplateColumns:"2fr 1.3fr", gap:40}}> 39 <div style={{fontFamily:"IBM Plex Sans", fontSize:16, lineHeight:1.55, color:BR.ink2, columnCount:2, columnGap:28, textAlign:"justify"}}> 40 Strata⁄Fleet is the Coalition's bonded registrar for civilian, commercial, and auxiliary vessels. Every hull listed here has passed three-stage hull inspection, transponder re-coding, and escrow bonding through Stellar Bank. We do not list speculative units. We do not list reconstructed hulls without the stamp of a certified yard. What you see is what you fly — or what your fleet flies home. Browse the index below, or ask the desk for a brokered introduction. 41 </div> 42 <div> 43 <div style={{border:`2px solid ${BR.ink}`, padding:"14px 16px", background:BR.paper2}}> 44 <div style={{fontFamily:"Oswald", fontWeight:700, fontSize:12, letterSpacing:3, borderBottom:`1px solid ${BR.ink}`, paddingBottom:4}}>DESK QUICK-FIND</div> 45 <div style={{display:"flex", gap:8, marginTop:10, border:`2px solid ${BR.ink}`, background:BR.paper}}> 46 <div style={{padding:"10px 12px", borderRight:`2px solid ${BR.ink}`, fontFamily:"IBM Plex Mono", fontSize:11, color:BR.mute}}>SN ▸</div> 47 <input placeholder="KRV-IC-2849-AX" style={{flex:1, border:"none", background:"transparent", fontFamily:"IBM Plex Mono", fontSize:13, outline:"none"}}/> 48 <div style={{background:BR.ink, color:BR.paper, padding:"10px 16px", fontFamily:"Oswald", fontSize:12, letterSpacing:3, cursor:"pointer"}} onClick={() => onNav && onNav("catalog")}>LOOKUP</div> 49 </div> 50 <div style={{marginTop:10, fontFamily:"IBM Plex Mono", fontSize:10, color:BR.mute, letterSpacing:1, lineHeight:1.7}}> 51 OR BROWSE BY — <a onClick={() => onNav("catalog")} style={{color:BR.ink, borderBottom:`1px solid ${BR.ink}`, cursor:"pointer"}}>CLASS</a> 52 · <a onClick={() => onNav("catalog")} style={{color:BR.ink, borderBottom:`1px solid ${BR.ink}`, cursor:"pointer"}}>FORGE</a> 53 · <a onClick={() => onNav("catalog")} style={{color:BR.ink, borderBottom:`1px solid ${BR.ink}`, cursor:"pointer"}}>DRIVE</a> 54 · <a onClick={() => onNav("catalog")} style={{color:BR.ink, borderBottom:`1px solid ${BR.ink}`, cursor:"pointer"}}>SECTOR</a> 55 </div> 56 </div> 57 <div style={{marginTop:12, border:`2px solid ${BR.rust}`, padding:"10px 14px", fontFamily:"IBM Plex Mono", fontSize:11, color:BR.rust, letterSpacing:1.5, textTransform:"uppercase"}}> 58 ⚑ Commodore tier required for hulls ≥ 2000 t 59 </div> 60 </div> 61 </div> 62 </div> 63 64 {/* FEATURE LOT — full-bleed */} 65 <div style={{padding:"28px 40px", borderBottom:`1px solid ${BR.ink}`}}> 66 <div style={{display:"grid", gridTemplateColumns:"1.4fr 1fr", gap:32, alignItems:"stretch"}}> 67 <div style={{position:"relative", border:`2px solid ${BR.ink}`, background:BR.paper2, padding:20}}> 68 <div style={{display:"flex", justifyContent:"space-between", fontFamily:"IBM Plex Mono", fontSize:10, letterSpacing:2, color:BR.mute, textTransform:"uppercase"}}> 69 <span>Plate I · Feature Lot</span> 70 <span>Plate 1:{Math.round(feature.length_m/10)}</span> 71 </div> 72 <div style={{position:"relative", height:380, marginTop:10, background:`repeating-linear-gradient(0deg, transparent 0 23px, ${BR.ink}11 23px 24px), repeating-linear-gradient(90deg, transparent 0 23px, ${BR.ink}11 23px 24px)`, border:`1px solid ${BR.ink}`}}> 73 <div style={{position:"absolute", inset:"10% 8%"}}> 74 <ShipSilhouette ship={feature} stroke={BR.ink} glow={false} strokeWidth={1.6}/> 75 </div> 76 <svg style={{position:"absolute", inset:0, pointerEvents:"none"}} width="100%" height="100%"> 77 <line x1="8%" y1="94%" x2="92%" y2="94%" stroke={BR.ink}/> 78 <line x1="8%" y1="91%" x2="8%" y2="97%" stroke={BR.ink}/> 79 <line x1="92%" y1="91%" x2="92%" y2="97%" stroke={BR.ink}/> 80 </svg> 81 <div style={{position:"absolute", bottom:6, left:"50%", transform:"translateX(-50%)", fontFamily:"IBM Plex Mono", fontSize:10, color:BR.mute}}>{feature.length_m} m overall</div> 82 </div> 83 <BRStamp style={{position:"absolute", top:20, right:20}}>LOT OF THE WEEK</BRStamp> 84 </div> 85 <div style={{display:"flex", flexDirection:"column"}}> 86 <div style={{fontFamily:"IBM Plex Mono", fontSize:11, letterSpacing:3, color:BR.mute, textTransform:"uppercase"}}>{feature.cls.code} · {feature.cls.name}</div> 87 <div style={{fontFamily:"Oswald", fontWeight:900, fontSize:68, lineHeight:0.92, letterSpacing:-1, marginTop:4, textTransform:"uppercase"}}>{feature.model}</div> 88 <div style={{fontFamily:"IBM Plex Mono", fontSize:12, letterSpacing:2, color:BR.ink, marginTop:6}}>{feature.serial} · {feature.mfg.name}</div> 89 <div style={{fontFamily:"IBM Plex Sans", fontSize:14, lineHeight:1.55, color:BR.ink2, marginTop:14, maxWidth:440}}> 90 Flagship of the {feature.mfg.name.split(" ")[0]} line. Triple-redundant {feature.drive.toLowerCase()} propulsion, {feature.crew}-crew accommodation, certified for deep-sector expedition. Hull is {feature.cond.toLowerCase().replace("_"," ")}; transponder re-coded at intake. Bonded by Stellar Bank. 91 </div> 92 <div style={{display:"flex", gap:8, marginTop:14, flexWrap:"wrap"}}> 93 <BRChip rust>{feature.avail}</BRChip> 94 <BRChip>{feature.cond}</BRChip> 95 <BRChip>{feature.faction}</BRChip> 96 <BRChip>{feature.drive}</BRChip> 97 </div> 98 99 <div style={{marginTop:18, display:"grid", gridTemplateColumns:"1fr 1fr 1fr", gap:0, border:`2px solid ${BR.ink}`}}> 100 {[ 101 ["LENGTH", `${feature.length_m} m`], 102 ["MASS", `${feature.mass.toLocaleString()} t`], 103 ["JUMP", `${feature.jumpRange} ly`], 104 ["CREW", feature.crew], 105 ["ARMOR", `${feature.armor.toLocaleString()} mm`], 106 ["DELIV.", `${feature.delivery} cyc`], 107 ].map(([k,v], i) => ( 108 <div key={k} style={{padding:"10px 12px", borderRight:(i%3!==2)?`1px solid ${BR.ink}`:"none", borderBottom: i<3 ? `1px solid ${BR.ink}` : "none"}}> 109 <div style={{fontFamily:"IBM Plex Mono", fontSize:9, letterSpacing:2, color:BR.mute, textTransform:"uppercase"}}>{k}</div> 110 <div style={{fontFamily:"Oswald", fontWeight:700, fontSize:18, color:BR.ink, marginTop:2}}>{v}</div> 111 </div> 112 ))} 113 </div> 114 115 <div style={{marginTop:"auto", paddingTop:20, display:"flex", alignItems:"flex-end", justifyContent:"space-between", gap:14}}> 116 <div> 117 <div style={{fontFamily:"IBM Plex Mono", fontSize:10, letterSpacing:2, color:BR.mute, textTransform:"uppercase"}}>UNIT PRICE</div> 118 <div style={{fontFamily:"Oswald", fontWeight:900, fontSize:44, color:BR.ink, lineHeight:1}}>₵{formatCred(feature.price)}</div> 119 </div> 120 <button onClick={() => onShip && onShip(feature.seed)} style={{ 121 padding:"16px 24px", background:BR.ink, color:BR.paper, border:`2px solid ${BR.ink}`, 122 fontFamily:"Oswald", fontWeight:700, fontSize:14, letterSpacing:3, cursor:"pointer", 123 }}>▸ OPEN DOSSIER</button> 124 </div> 125 </div> 126 </div> 127 </div> 128 129 {/* BROWSE BY CLASS — giant typographic tiles */} 130 <div style={{padding:"28px 40px", borderBottom:`1px solid ${BR.ink}`}}> 131 <BRH n="02" size={16}>Browse by Class</BRH> 132 <div style={{display:"grid", gridTemplateColumns:"repeat(5, 1fr)", gap:0, border:`2px solid ${BR.ink}`}}> 133 {[ 134 ["IC","Interceptor","2,104","Light combat"], 135 ["CH","Hauler","3,772","Logistics"], 136 ["YT","Yacht","941","Civilian"], 137 ["CR","Cruiser","612","Heavy combat"], 138 ["DR","Dreadnought","88","Capital"], 139 ].map(([code,name,count,role], i) => ( 140 <div key={code} onClick={() => onNav && onNav("catalog")} style={{ 141 padding:"22px 18px", borderRight: i<4 ? `1px solid ${BR.ink}` : "none", 142 cursor:"pointer", position:"relative", minHeight:180, 143 background: i===0 ? BR.ink : BR.paper, color: i===0 ? BR.paper : BR.ink, 144 }}> 145 <div style={{fontFamily:"Oswald", fontWeight:900, fontSize:92, lineHeight:0.85, letterSpacing:-2}}>{code}</div> 146 <div style={{fontFamily:"IBM Plex Mono", fontSize:10, letterSpacing:2, marginTop:8, opacity:0.75, textTransform:"uppercase"}}>{role}</div> 147 <div style={{fontFamily:"Oswald", fontWeight:700, fontSize:18, marginTop:2, letterSpacing:1}}>{name}</div> 148 <div style={{position:"absolute", bottom:16, right:18, fontFamily:"IBM Plex Mono", fontSize:11, letterSpacing:1.5}}>{count} lots ▸</div> 149 </div> 150 ))} 151 </div> 152 </div> 153 154 {/* DUAL PANEL — market indices + dispatches */} 155 <div style={{padding:"28px 40px", borderBottom:`1px solid ${BR.ink}`, display:"grid", gridTemplateColumns:"1.4fr 1fr", gap:40}}> 156 <div> 157 <BRH n="03" size={16}>Market Indices · 30 Cycles</BRH> 158 <div style={{border:`2px solid ${BR.ink}`}}> 159 <div style={{display:"grid", gridTemplateColumns:"80px 1fr 100px 80px 140px", padding:"6px 12px", borderBottom:`1px solid ${BR.ink}`, fontFamily:"IBM Plex Mono", fontSize:10, letterSpacing:2, color:BR.mute, textTransform:"uppercase", background:BR.paper2}}> 160 <span>Idx</span><span>Class</span><span style={{textAlign:"right"}}>Last</span><span style={{textAlign:"right"}}>Δ</span><span>Trend</span> 161 </div> 162 {[ 163 ["IC-IDX", "Interceptor Composite", "112.4", "+1.2%", true], 164 ["CH-IDX", "Hauler Composite", "087.8", "−0.4%", false], 165 ["YT-IDX", "Yacht Composite", "142.9", "+0.1%", true], 166 ["CR-IDX", "Cruiser Composite", "204.1", "+2.8%", true], 167 ["MN-IDX", "Mining Rig Composite", "061.2", "−1.6%", false], 168 ["DR-IDX", "Dreadnought Composite", "388.4", "+1.4%", true], 169 ].map((row, i) => ( 170 <div key={i} style={{display:"grid", gridTemplateColumns:"80px 1fr 100px 80px 140px", padding:"8px 12px", borderBottom: i<5 ? `1px dotted ${BR.ink}33` : "none", alignItems:"center", fontFamily:"IBM Plex Mono", fontSize:12}}> 171 <span style={{letterSpacing:1.5, fontWeight:700}}>{row[0]}</span> 172 <span>{row[1]}</span> 173 <span style={{textAlign:"right", fontWeight:600}}>{row[2]}</span> 174 <span style={{textAlign:"right", color: row[4] ? BR.green : BR.rust, fontWeight:700}}>{row[3]}</span> 175 <span><MiniTrend up={row[4]} seed={row[0]}/></span> 176 </div> 177 ))} 178 </div> 179 </div> 180 <div> 181 <BRH n="04" size={16}>Desk Dispatches</BRH> 182 <div> 183 {dispatches.map((d, i) => ( 184 <div key={i} style={{padding:"10px 0", borderBottom: i<dispatches.length-1 ? `1px solid ${BR.ink}33` : "none"}}> 185 <div style={{display:"flex", gap:10, fontFamily:"IBM Plex Mono", fontSize:10, letterSpacing:2, color:BR.mute, textTransform:"uppercase"}}> 186 <span>{d[0]}</span> 187 <span style={{color: d[1]==="RECALL" ? BR.rust : BR.ink, fontWeight:700}}>◆ {d[1]}</span> 188 </div> 189 <div style={{fontFamily:"IBM Plex Sans", fontSize:13, color:BR.ink2, marginTop:4, lineHeight:1.4}}>{d[2]}</div> 190 </div> 191 ))} 192 </div> 193 </div> 194 </div> 195 196 {/* RECENT LOTS — grid */} 197 <div style={{padding:"28px 40px", borderBottom:`1px solid ${BR.ink}`}}> 198 <div style={{display:"flex", justifyContent:"space-between", alignItems:"baseline"}}> 199 <BRH n="05" size={16}>Recent Lots</BRH> 200 <div style={{fontFamily:"IBM Plex Mono", fontSize:10, color:BR.mute, letterSpacing:2, marginTop:-20, textTransform:"uppercase"}}>SHOWING 6 OF 14,208</div> 201 </div> 202 <div style={{display:"grid", gridTemplateColumns:"repeat(3, 1fr)", gap:0, border:`2px solid ${BR.ink}`}}> 203 {lots.map((s, i) => ( 204 <LotCard key={i} ship={s} borderR={i%3!==2} borderB={i<3} onOpen={() => onShip && onShip(s.seed)}/> 205 ))} 206 </div> 207 <div style={{display:"flex", justifyContent:"center", marginTop:18}}> 208 <button onClick={() => onNav && onNav("catalog")} style={{padding:"14px 36px", background:"transparent", border:`2px solid ${BR.ink}`, fontFamily:"Oswald", fontWeight:700, fontSize:13, letterSpacing:4, cursor:"pointer"}}>VIEW FULL CATALOG ▸</button> 209 </div> 210 </div> 211 212 {/* MANUFACTURER INDEX */} 213 <div style={{padding:"28px 40px", borderBottom:`1px solid ${BR.ink}`}}> 214 <BRH n="06" size={16}>Manufacturer Index</BRH> 215 <div style={{display:"grid", gridTemplateColumns:"repeat(4, 1fr)", gap:0, border:`2px solid ${BR.ink}`}}> 216 {[ 217 ["KRV", "Krovas Yards", "Ceres-II", "2,104"], 218 ["AUR", "Aurelia Dynamics", "High Solis", "1,821"], 219 ["OBS", "Obsidian Forge", "Erebus Belt", "996"], 220 ["HEL", "Helion Shipworks", "Tau-Ceti", "1,412"], 221 ["VNT", "Vantari Collective", "Kepler Ring", "2,660"], 222 ["NXS", "Nexus Propulsion", "Luna-4", "881"], 223 ["KNT", "Kontos & Sons", "Mars Orb.", "740"], 224 ["IOTA","Iota Stellar", "Proxima", "1,203"], 225 ].map(([code,name,loc,count],i)=>( 226 <div key={code} style={{padding:"14px 16px", borderRight: (i%4!==3) ? `1px solid ${BR.ink}` : "none", borderBottom: i<4 ? `1px solid ${BR.ink}` : "none"}}> 227 <div style={{display:"flex", justifyContent:"space-between", alignItems:"baseline"}}> 228 <div style={{fontFamily:"Oswald", fontWeight:900, fontSize:32, letterSpacing:-0.5}}>{code}</div> 229 <div style={{fontFamily:"IBM Plex Mono", fontSize:10, color:BR.mute, letterSpacing:1.5}}>{count}</div> 230 </div> 231 <div style={{fontFamily:"IBM Plex Sans", fontSize:13, fontWeight:600}}>{name}</div> 232 <div style={{fontFamily:"IBM Plex Mono", fontSize:10, color:BR.mute, letterSpacing:1, marginTop:2}}>{loc.toUpperCase()}</div> 233 </div> 234 ))} 235 </div> 236 </div> 237 238 <BRFooter/> 239 </BRPage> 240 ); 241 } 242 243 function MiniTrend({ up, seed }) { 244 const rng = mulberry32(hashStr(seed)); 245 const pts = []; 246 let y = 0.5; 247 for (let i = 0; i < 20; i++) { 248 y += (rng() - (up ? 0.4 : 0.6)) * 0.12; 249 y = Math.max(0.1, Math.min(0.9, y)); 250 pts.push([i/19*100, 20-y*20]); 251 } 252 return ( 253 <svg width={100} height={20} style={{display:"block"}}> 254 <polyline points={pts.map(p=>p.join(",")).join(" ")} fill="none" stroke={up ? BR.green : BR.rust} strokeWidth={1.2}/> 255 </svg> 256 ); 257 } 258 259 function LotCard({ ship, borderR, borderB, onOpen }) { 260 return ( 261 <div onClick={onOpen} style={{ 262 padding:"14px 16px", cursor:"pointer", 263 borderRight: borderR ? `1px solid ${BR.ink}` : "none", 264 borderBottom: borderB ? `1px solid ${BR.ink}` : "none", 265 background:BR.paper, 266 }}> 267 <div style={{display:"flex", justifyContent:"space-between", fontFamily:"IBM Plex Mono", fontSize:10, letterSpacing:2, color:BR.mute, textTransform:"uppercase"}}> 268 <span>{ship.serial}</span> 269 <span>{ship.cls.code}</span> 270 </div> 271 <div style={{height:110, marginTop:8, border:`1px solid ${BR.ink}33`, position:"relative", background:`repeating-linear-gradient(0deg, transparent 0 15px, ${BR.ink}0d 15px 16px)`}}> 272 <div style={{position:"absolute", inset:"10% 8%"}}> 273 <ShipSilhouette ship={ship} stroke={BR.ink} glow={false} strokeWidth={1.2}/> 274 </div> 275 </div> 276 <div style={{fontFamily:"Oswald", fontWeight:700, fontSize:22, letterSpacing:0, marginTop:10, lineHeight:1.1, textTransform:"uppercase"}}>{ship.model}</div> 277 <div style={{fontFamily:"IBM Plex Mono", fontSize:11, color:BR.ink2, marginTop:4, letterSpacing:1}}>{ship.mfg.name} · {ship.year}</div> 278 <div style={{display:"flex", justifyContent:"space-between", alignItems:"baseline", marginTop:10, paddingTop:8, borderTop:`1px dotted ${BR.ink}33`}}> 279 <div style={{fontFamily:"Oswald", fontWeight:900, fontSize:24}}>₵{formatCred(ship.price)}</div> 280 <BRChip rust>{ship.avail}</BRChip> 281 </div> 282 </div> 283 ); 284 } 285 286 Object.assign(window, { BRHome });