br-onboard.jsx
1 // Brutalist PILOT ONBOARDING — a ship-yard "induction packet" form. 2 // Six-step stepper, left-rail identity, main form, rubber stamps, signatories. 3 4 function BROnboard({ onNav }) { 5 const [step, setStep] = React.useState(2); // show some progress 6 7 const steps = [ 8 "IDENTITY", 9 "BIOMETRICS", 10 "LICENSE", 11 "SAFETY DRILL", 12 "HULL FAMILIARIZATION", 13 "OATH", 14 ]; 15 16 return ( 17 <BRPage minHeight={2000}> 18 <BRNav active="onboard" cartCount={0} onNav={onNav}/> 19 20 {/* HEADER */} 21 <div style={{padding:"30px 40px 22px", borderBottom:`4px double ${BR.ink}`, display:"flex", justifyContent:"space-between", alignItems:"flex-end"}}> 22 <div> 23 <div style={{fontFamily:"IBM Plex Mono", fontSize:11, letterSpacing:3, color:BR.mute, textTransform:"uppercase"}}>FORM 31 · INDUCTION PACKET · PILOT OF RECORD</div> 24 <div style={{fontFamily:"Oswald", fontWeight:900, fontSize:92, lineHeight:0.9, letterSpacing:-2, textTransform:"uppercase", marginTop:6}}>Induction</div> 25 </div> 26 <BRStamp rotate={4}>PROVISIONAL</BRStamp> 27 </div> 28 29 {/* STEPPER */} 30 <div style={{padding:"18px 40px", borderBottom:`2px solid ${BR.ink}`, display:"flex", alignItems:"center", gap:8, background:BR.paper2}}> 31 {steps.map((s, i) => ( 32 <React.Fragment key={s}> 33 <div onClick={()=>setStep(i)} style={{flex:1, cursor:"pointer", textAlign:"center", padding:"10px 8px", border:`2px solid ${BR.ink}`, background: i<step ? BR.ink : i===step ? BR.rust : BR.paper, color: i<=step ? BR.paper : BR.ink}}> 34 <div style={{fontFamily:"IBM Plex Mono", fontSize:9, letterSpacing:2, opacity:0.8}}>STEP {String(i+1).padStart(2,"0")}</div> 35 <div style={{fontFamily:"Oswald", fontWeight:700, fontSize:12, letterSpacing:2, marginTop:2}}>{s}</div> 36 </div> 37 {i<steps.length-1 && <div style={{width:12, height:2, background:BR.ink}}/>} 38 </React.Fragment> 39 ))} 40 </div> 41 42 {/* BODY */} 43 <div style={{display:"grid", gridTemplateColumns:"280px 1fr 320px", minHeight:1300}}> 44 45 {/* IDENTITY CARD */} 46 <div style={{borderRight:`1px solid ${BR.ink}`, padding:"24px 24px"}}> 47 <div style={{border:`2px solid ${BR.ink}`, padding:"18px 16px", background:BR.paper2}}> 48 <div style={{fontFamily:"IBM Plex Mono", fontSize:9, letterSpacing:2, color:BR.mute, textTransform:"uppercase"}}>PILOT № PL-2396-04481</div> 49 <div style={{width:"100%", aspectRatio:"1/1.2", background:BR.paper, border:`2px solid ${BR.ink}`, marginTop:10, position:"relative", overflow:"hidden"}}> 50 {/* placeholder portrait — cross-hatched silhouette */} 51 <svg viewBox="0 0 100 120" style={{width:"100%", height:"100%"}}> 52 <defs> 53 <pattern id="hatch" width="4" height="4" patternUnits="userSpaceOnUse" patternTransform="rotate(45)"> 54 <line x1="0" y1="0" x2="0" y2="4" stroke={BR.ink} strokeOpacity="0.25" strokeWidth="1"/> 55 </pattern> 56 </defs> 57 <rect width="100" height="120" fill="url(#hatch)"/> 58 <circle cx="50" cy="48" r="22" fill={BR.paper} stroke={BR.ink} strokeWidth="2"/> 59 <path d="M18,120 C 18,84 32,72 50,72 C 68,72 82,84 82,120 Z" fill={BR.paper} stroke={BR.ink} strokeWidth="2"/> 60 <text x="50" y="115" fontFamily="IBM Plex Mono" fontSize="5" fill={BR.mute} textAnchor="middle" letterSpacing="1">PORTRAIT PENDING</text> 61 </svg> 62 <div style={{position:"absolute", top:6, right:6, background:BR.rust, color:BR.paper, padding:"2px 6px", fontFamily:"Oswald", fontWeight:700, fontSize:9, letterSpacing:1.5}}>PROV.</div> 63 </div> 64 <div style={{marginTop:12, fontFamily:"IBM Plex Mono", fontSize:10, lineHeight:1.7, color:BR.ink2, letterSpacing:0.5}}> 65 <div style={{fontFamily:"Oswald", fontWeight:700, fontSize:16, letterSpacing:1, color:BR.ink, textTransform:"uppercase"}}>Orlan Veyr</div> 66 <div><span style={{color:BR.mute}}>TIER</span> 3 · COMMODORE</div> 67 <div><span style={{color:BR.mute}}>UNIT</span> 7TH EXPEDITIONARY</div> 68 <div><span style={{color:BR.mute}}>SECTOR</span> G-4 · CERES</div> 69 <div><span style={{color:BR.mute}}>BLOOD</span> B+ / COAG 11.2</div> 70 <div><span style={{color:BR.mute}}>EMERG</span> S. VEYR · +14 774</div> 71 </div> 72 <div style={{marginTop:14, height:80, border:`2px dashed ${BR.ink}`, display:"flex", alignItems:"center", justifyContent:"center", fontFamily:"IBM Plex Mono", fontSize:10, color:BR.mute, letterSpacing:1.5, textTransform:"uppercase"}}> 73 THUMB PRINT HERE 74 </div> 75 </div> 76 77 <div style={{marginTop:18}}> 78 <BRH n="00">Progress</BRH> 79 <div style={{fontFamily:"IBM Plex Mono", fontSize:11, color:BR.ink2, letterSpacing:1}}> 80 {steps.map((s, i) => ( 81 <div key={s} style={{padding:"6px 0", display:"flex", justifyContent:"space-between", borderBottom:`1px dotted ${BR.ink}33`}}> 82 <span style={{color: i<=step ? BR.ink : BR.mute}}>{String(i+1).padStart(2,"0")} · {s}</span> 83 <span style={{color: i<step ? BR.green : i===step ? BR.rust : BR.mute, fontWeight:700}}> 84 {i<step ? "✓" : i===step ? "●" : "—"} 85 </span> 86 </div> 87 ))} 88 </div> 89 </div> 90 </div> 91 92 {/* CENTER FORM — current step */} 93 <div style={{padding:"26px 36px"}}> 94 <BRH n={String(step+1).padStart(2,"0")}>{steps[step]}</BRH> 95 96 {step === 0 && <IdentityForm/>} 97 {step === 1 && <BiometricsForm/>} 98 {step === 2 && <LicenseForm/>} 99 {step === 3 && <DrillForm/>} 100 {step === 4 && <FamiliarForm/>} 101 {step === 5 && <OathForm/>} 102 103 <div style={{marginTop:28, display:"flex", gap:10}}> 104 <button onClick={()=>setStep(Math.max(0,step-1))} style={{padding:"14px 28px", background:"transparent", color:BR.ink, border:`2px solid ${BR.ink}`, fontFamily:"Oswald", fontWeight:700, fontSize:12, letterSpacing:3, cursor:"pointer"}}>◂ PRIOR STEP</button> 105 <button onClick={()=>setStep(Math.min(steps.length-1,step+1))} style={{padding:"14px 28px", background:BR.ink, color:BR.paper, border:"none", fontFamily:"Oswald", fontWeight:900, fontSize:12, letterSpacing:3, cursor:"pointer", flex:1}}>AFFIRM & ADVANCE ▸</button> 106 </div> 107 </div> 108 109 {/* RIGHT RAIL — hull assigned + signatories */} 110 <div style={{borderLeft:`1px solid ${BR.ink}`, padding:"24px 24px", background:BR.paper2}}> 111 <BRH n="0α">Hull Assigned</BRH> 112 <div style={{border:`2px solid ${BR.ink}`, background:BR.paper, padding:"12px 14px"}}> 113 <div style={{width:"100%", height:80, border:`1px solid ${BR.ink}33`, position:"relative"}}> 114 <div style={{position:"absolute", inset:"10% 6%"}}> 115 <ShipSilhouette ship={makeShip("KRV-IC-2849-AX")} stroke={BR.ink} glow={false} strokeWidth={1.2} detail="mid"/> 116 </div> 117 </div> 118 <div style={{fontFamily:"Oswald", fontWeight:700, fontSize:16, letterSpacing:1, textTransform:"uppercase", marginTop:10}}>KRV IC-2849 Axiom</div> 119 <div style={{fontFamily:"IBM Plex Mono", fontSize:10, color:BR.mute, letterSpacing:1, marginTop:2}}>KRV-IC-2849-AX · INTERCEPTOR · TIER-3</div> 120 </div> 121 122 <div style={{height:20}}/> 123 <BRH n="0β">Signatories</BRH> 124 {[ 125 ["O. VEYR", "Pilot of record", true], 126 ["J. HOLLISTER", "Coalition notary", true], 127 ["S. ORIN", "Yard master, Ceres", false], 128 ["—", "Flight surgeon", false], 129 ].map(([n, role, done], i) => ( 130 <div key={i} style={{padding:"10px 0", borderBottom:`1px dotted ${BR.ink}33`}}> 131 <div style={{display:"flex", justifyContent:"space-between"}}> 132 <span style={{fontFamily:"Oswald", fontWeight:700, fontSize:13, letterSpacing:1.5, textTransform:"uppercase"}}>{n}</span> 133 <span style={{fontFamily:"Oswald", fontWeight:700, fontSize:11, letterSpacing:2, color: done ? BR.green : BR.mute}}>{done ? "SIGNED" : "PENDING"}</span> 134 </div> 135 <div style={{fontFamily:"IBM Plex Mono", fontSize:10, color:BR.mute, letterSpacing:1, marginTop:2}}>{role}</div> 136 {done && <div style={{fontFamily:"'Caveat','Space Grotesk',cursive", fontSize:20, color:BR.ink, marginTop:4}}>{n.split(" ").map(x=>x[0]).join(".")}. {n.split(" ").slice(-1)[0]}</div>} 137 </div> 138 ))} 139 140 <div style={{height:20}}/> 141 <div style={{border:`2px solid ${BR.rust}`, padding:"12px 14px", background:"rgba(194,66,26,0.05)", fontFamily:"IBM Plex Mono", fontSize:11, color:BR.rust, letterSpacing:1, lineHeight:1.5, textTransform:"uppercase"}}> 142 Provisional certification lapses in 30 cycles unless Oath (§06) is sworn at dry-dock C. 143 </div> 144 </div> 145 </div> 146 147 <BRFooter/> 148 </BRPage> 149 ); 150 } 151 152 function PLField({ label, value, hand }) { 153 return ( 154 <div style={{padding:"10px 0", borderBottom:`2px solid ${BR.ink}`}}> 155 <div style={{fontFamily:"IBM Plex Mono", fontSize:9, letterSpacing:2, color:BR.mute, textTransform:"uppercase"}}>{label}</div> 156 <div style={{fontFamily: hand ? "'Caveat','Space Grotesk',cursive" : "IBM Plex Mono", fontSize: hand ? 22 : 14, fontWeight: 500, color:BR.ink, marginTop: hand ? 0 : 4}}>{value}</div> 157 </div> 158 ); 159 } 160 161 function IdentityForm() { 162 return ( 163 <div> 164 <div style={{display:"grid", gridTemplateColumns:"1fr 1fr", gap:18}}> 165 <PLField label="Surname" value="VEYR" hand/> 166 <PLField label="Given names" value="Orlan Aenor" hand/> 167 <PLField label="Birth cycle" value="2354.088"/> 168 <PLField label="Birth sector" value="Tharsis · M-11"/> 169 <PLField label="Citizenship" value="Coalition · A-class"/> 170 <PLField label="Service record" value="CTR-8812 · Redacted §6"/> 171 </div> 172 </div> 173 ); 174 } 175 176 function BiometricsForm() { 177 const metrics = [ 178 ["Retina pattern", "CAPTURED", 1.0], 179 ["Palm vein scan", "CAPTURED", 1.0], 180 ["Gait signature", "CAPTURED", 0.94], 181 ["Voice print", "CAPTURED", 0.88], 182 ["G-load tolerance", "9.2 G sustained", 0.76], 183 ["Cognitive reflex", "212 ms median", 0.82], 184 ]; 185 return ( 186 <div style={{display:"grid", gridTemplateColumns:"1fr 1fr", gap:12}}> 187 {metrics.map(([k,v,p], i) => ( 188 <div key={i} style={{padding:"14px 16px", border:`2px solid ${BR.ink}`, background:BR.paper}}> 189 <div style={{display:"flex", justifyContent:"space-between"}}> 190 <div style={{fontFamily:"Oswald", fontWeight:700, fontSize:13, letterSpacing:2, textTransform:"uppercase"}}>{k}</div> 191 <BRChip ok>OK</BRChip> 192 </div> 193 <div style={{fontFamily:"IBM Plex Mono", fontSize:11, color:BR.ink2, marginTop:4}}>{v}</div> 194 <div style={{height:6, background:BR.ink + "22", marginTop:10, border:`1px solid ${BR.ink}55`}}> 195 <div style={{height:"100%", width:`${p*100}%`, background:BR.ink}}/> 196 </div> 197 </div> 198 ))} 199 </div> 200 ); 201 } 202 203 function LicenseForm() { 204 return ( 205 <> 206 <div style={{display:"grid", gridTemplateColumns:"1fr 1fr 1fr", gap:18}}> 207 <PLField label="License №" value="LIC-7-44-8812-C"/> 208 <PLField label="Tier" value="Tier-3 · Commodore"/> 209 <PLField label="Expires" value="2399.088"/> 210 <PLField label="Ratings" value="IC · CH · DR · CR"/> 211 <PLField label="Endorsements" value="Night-jump · Q-drive"/> 212 <PLField label="Last medical" value="2396.060 · Cleared"/> 213 </div> 214 <div style={{height:20}}/> 215 <div style={{padding:"14px 16px", border:`2px solid ${BR.ink}`, background:BR.paper2}}> 216 <div style={{fontFamily:"Oswald", fontWeight:700, fontSize:13, letterSpacing:2, textTransform:"uppercase", marginBottom:8}}>Endorsement Stamps</div> 217 <div style={{display:"flex", gap:18, flexWrap:"wrap"}}> 218 <BRStamp rotate={-8}>IC · CLASS</BRStamp> 219 <BRStamp rotate={5} color={BR.green}>CLEARED MED</BRStamp> 220 <BRStamp rotate={-3}>Q-DRIVE</BRStamp> 221 <BRStamp rotate={10} color={BR.ink}>NIGHT JUMP</BRStamp> 222 </div> 223 </div> 224 </> 225 ); 226 } 227 228 function DrillForm() { 229 const drills = [ 230 ["Decompression · bay loss", "PASS", "02:12"], 231 ["Drive flame-out · cold restart","PASS", "06:40"], 232 ["Transponder loss · silent run", "PASS", "04:05"], 233 ["Boarded vessel · hail procedure","PASS","03:18"], 234 ["Flare drill · close formation", "RETEST","—"], 235 ]; 236 return ( 237 <> 238 <div style={{fontFamily:"IBM Plex Sans", fontSize:13, color:BR.ink2, marginBottom:12, lineHeight:1.5}}> 239 Five mandatory drills under the §7 Safety Annex. Flare drill must be re-taken in-yard within 14 cycles. 240 </div> 241 <table style={{width:"100%", borderCollapse:"collapse", fontFamily:"IBM Plex Mono", fontSize:12}}> 242 <thead> 243 <tr style={{background:BR.paper2, borderBottom:`2px solid ${BR.ink}`}}> 244 {["#","Drill","Result","Elapsed","Invigilator"].map(h => ( 245 <th key={h} style={{padding:"10px 12px", textAlign:"left", fontSize:10, letterSpacing:2, color:BR.mute, textTransform:"uppercase", fontWeight:500}}>{h}</th> 246 ))} 247 </tr> 248 </thead> 249 <tbody> 250 {drills.map(([t,r,e], i) => ( 251 <tr key={i} style={{borderBottom:`1px dotted ${BR.ink}44`}}> 252 <td style={{padding:"10px 12px", fontWeight:700}}>{String(i+1).padStart(2,"0")}</td> 253 <td style={{padding:"10px 12px"}}>{t}</td> 254 <td style={{padding:"10px 12px"}}> 255 <span style={{fontFamily:"Oswald", fontWeight:700, fontSize:11, letterSpacing:2, color: r==="PASS" ? BR.green : BR.rust}}>{r}</span> 256 </td> 257 <td style={{padding:"10px 12px"}}>{e}</td> 258 <td style={{padding:"10px 12px"}}>LT S. TOREN</td> 259 </tr> 260 ))} 261 </tbody> 262 </table> 263 </> 264 ); 265 } 266 267 function FamiliarForm() { 268 return ( 269 <> 270 <div style={{display:"grid", gridTemplateColumns:"1fr 1fr", gap:16}}> 271 {[ 272 ["Drive subsystems", true, "K-7 Q-drive · cold & warm start procedures"], 273 ["Weapon hardpoints", true, "Tier-3 rails, lockout, disengagement"], 274 ["Life support", true, "O₂ · CO₂ · coolant loops · emergency vent"], 275 ["Sensor suite", false,"LIDAR · gravimeter · EM passive · decoys"], 276 ["Damage control", false,"Fire suppression · hull patch kit · triage"], 277 ["Emergency egress", false,"Pod launch · suit seals · beacon protocols"], 278 ].map(([t, done, d], i) => ( 279 <div key={i} style={{padding:"12px 14px", border:`2px solid ${BR.ink}`, background: done ? BR.paper2 : BR.paper}}> 280 <div style={{display:"flex", justifyContent:"space-between", alignItems:"baseline"}}> 281 <div style={{fontFamily:"Oswald", fontWeight:700, fontSize:13, letterSpacing:2, textTransform:"uppercase"}}>{t}</div> 282 <BRChip ok={done}>{done ? "COMPLETE" : "SCHEDULED"}</BRChip> 283 </div> 284 <div style={{fontFamily:"IBM Plex Sans", fontSize:12, color:BR.ink2, marginTop:4}}>{d}</div> 285 </div> 286 ))} 287 </div> 288 </> 289 ); 290 } 291 292 function OathForm() { 293 return ( 294 <div style={{border:`3px double ${BR.ink}`, padding:"24px 28px", background:BR.paper2}}> 295 <div style={{fontFamily:"Oswald", fontWeight:700, fontSize:14, letterSpacing:3, textTransform:"uppercase", borderBottom:`1px solid ${BR.ink}`, paddingBottom:6, marginBottom:14}}>Pilot's Oath — §6 Coalition Articles</div> 296 <div style={{fontFamily:"IBM Plex Sans", fontSize:15, lineHeight:1.7, color:BR.ink, maxWidth:720}}> 297 I, the undersigned, accept custody of the hull registered to my name. I will fly it with the judgement of a master and the restraint of a citizen. I will answer to the ledger before I answer to pride; to the Coalition before I answer to profit. Should I fail this standard, I submit my wings to the yard. 298 </div> 299 <div style={{marginTop:24, display:"grid", gridTemplateColumns:"1fr 1fr", gap:30}}> 300 <div> 301 <div style={{fontFamily:"'Caveat','Space Grotesk',cursive", fontSize:36, color:BR.ink, borderBottom:`2px solid ${BR.ink}`, paddingBottom:6}}>O. Veyr</div> 302 <div style={{fontFamily:"IBM Plex Mono", fontSize:10, color:BR.mute, letterSpacing:2, marginTop:4, textTransform:"uppercase"}}>Pilot signatory · 2396.116</div> 303 </div> 304 <div> 305 <div style={{fontFamily:"'Caveat','Space Grotesk',cursive", fontSize:36, color:BR.ink, borderBottom:`2px solid ${BR.ink}`, paddingBottom:6}}>J. Hollister</div> 306 <div style={{fontFamily:"IBM Plex Mono", fontSize:10, color:BR.mute, letterSpacing:2, marginTop:4, textTransform:"uppercase"}}>Coalition notary · seal 4481</div> 307 </div> 308 </div> 309 </div> 310 ); 311 } 312 313 Object.assign(window, { BROnboard });