docs/tracks.html joins the roster page: all 18 tracks with a plan view, what the console calls them, which scenarios offer them, and how big they are. There are no track maps in the game's files. The console had pictures of them and those pictures did not survive - RPConfig.xml still points at "images/red planet maps/Wiseguy's Wake.bmp" and the folder is gone. So the plans are drawn from the tracks themselves. A map's instance stream places its scenery: 76-byte records carrying a position at +48 and a unit quaternion at +60, a few of them longer, so the reader resyncs on an unexpected class id rather than trusting the stride. The quaternion doubles as a checksum - a mis-read almost never yields a unit one - and 17 of the 18 decode every instance the header promises. Trough gives up 631 of 633 and the card says so. Seen this way the tracks have obvious shapes: Brewer's Bane turns two corners, Tour De Mars is one 23,000-unit run, and both arenas are a regular lattice of obstacles rather than a route at all. The eras come from the resource-file archaeology rather than a guess: 9 tracks shipped in the 4.10 cabinets, headoff and headmf arrived with 4.11, and 7 were built by the community afterwards. Scenario legality is read out of the front end's own kMaps and kFootballMaps, so the page cannot claim a track is offered when the menu does not offer it. tools/pages carries the generators for both reference pages, with a README covering the two formats they read and the id-alignment the listing is needed for. They were scratch scripts until now, which made a committed page harder to regenerate than to rebuild by hand. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
168 lines
6.1 KiB
CSS
168 lines
6.1 KiB
CSS
|
|
*, *::before, *::after { box-sizing: border-box; }
|
|
|
|
:root {
|
|
/* The pod's own lamp fills - MUNGA_L4/L4MFDVIEW.cpp:112 */
|
|
--amber: #ffd230;
|
|
--red: #ff482c;
|
|
--phosphor: #6fdc8c;
|
|
|
|
--ground: #0d0b07;
|
|
--panel: #16130d;
|
|
--rule: #2f2819;
|
|
--ink: #f3ead6;
|
|
--ink-mid: #b3a68a;
|
|
--ink-low: #7d7360;
|
|
|
|
--sys: var(--amber);
|
|
--wep: var(--red);
|
|
--pilot: var(--phosphor);
|
|
--on-accent: #0d0b07;
|
|
|
|
--step--1: clamp(.72rem, .70rem + .1vw, .78rem);
|
|
--step-0: clamp(.88rem, .85rem + .15vw, .95rem);
|
|
--step-1: clamp(1.05rem, 1rem + .3vw, 1.2rem);
|
|
--step-2: clamp(1.25rem, 1.1rem + .6vw, 1.6rem);
|
|
--step-3: clamp(1.9rem, 1.5rem + 2vw, 3.1rem);
|
|
|
|
--mono: ui-monospace, "Cascadia Mono", "SF Mono", Menlo, Consolas, monospace;
|
|
--sans: ui-sans-serif, system-ui, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
|
}
|
|
|
|
@media (prefers-color-scheme: light) {
|
|
:root {
|
|
--ground: #f7f3e8; --panel: #fffdf7; --rule: #ddd2b8;
|
|
--ink: #17140d; --ink-mid: #5c5340; --ink-low: #857a63;
|
|
--sys: #8a6400; --wep: #b3260f; --pilot: #1c7a3f;
|
|
--on-accent: #fffdf7;
|
|
}
|
|
}
|
|
:root[data-theme="light"] {
|
|
--ground: #f7f3e8; --panel: #fffdf7; --rule: #ddd2b8;
|
|
--ink: #17140d; --ink-mid: #5c5340; --ink-low: #857a63;
|
|
--sys: #8a6400; --wep: #b3260f; --pilot: #1c7a3f;
|
|
--on-accent: #fffdf7;
|
|
}
|
|
:root[data-theme="dark"] {
|
|
--ground: #0d0b07; --panel: #16130d; --rule: #2f2819;
|
|
--ink: #f3ead6; --ink-mid: #b3a68a; --ink-low: #7d7360;
|
|
--sys: #ffd230; --wep: #ff482c; --pilot: #6fdc8c;
|
|
--on-accent: #0d0b07;
|
|
}
|
|
|
|
body {
|
|
margin: 0; background: var(--ground); color: var(--ink);
|
|
font: 400 var(--step-0)/1.6 var(--sans); -webkit-font-smoothing: antialiased;
|
|
}
|
|
.wrap { max-width: 82rem; margin: 0 auto; padding: 0 clamp(1rem, 4vw, 3rem); }
|
|
.sr-only {
|
|
position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
|
|
overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
|
|
}
|
|
:focus-visible { outline: 2px solid var(--sys); outline-offset: 2px; }
|
|
|
|
.top { border-bottom: 1px solid var(--rule); padding: clamp(2.5rem,6vw,4.5rem) 0 2rem; }
|
|
.eyebrow {
|
|
font: 500 var(--step--1)/1 var(--mono); letter-spacing: .22em;
|
|
text-transform: uppercase; color: var(--ink-low); margin: 0 0 1.1rem;
|
|
}
|
|
h1 {
|
|
font: 700 var(--step-3)/1.02 var(--mono); letter-spacing: -.02em;
|
|
text-transform: uppercase; text-wrap: balance; margin: 0 0 1rem;
|
|
}
|
|
h1 em { font-style: normal; color: var(--sys); }
|
|
.lede { max-width: 62ch; color: var(--ink-mid); margin: 0 0 1.4rem; font-size: var(--step-1); }
|
|
.lede strong { color: var(--ink); font-weight: 600; }
|
|
|
|
.bar {
|
|
position: sticky; top: 0; z-index: 5; background: var(--ground);
|
|
background: color-mix(in srgb, var(--ground) 92%, transparent);
|
|
-webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
|
|
border-bottom: 1px solid var(--rule); padding: .75rem 0;
|
|
}
|
|
.bar__in { display: flex; flex-wrap: wrap; gap: .75rem 1.25rem; align-items: center; }
|
|
.seg { display: inline-flex; border: 1px solid var(--rule); }
|
|
.seg button {
|
|
font: 500 var(--step--1)/1 var(--mono); letter-spacing: .12em;
|
|
text-transform: uppercase; background: none; border: 0; color: var(--ink-mid);
|
|
padding: .55rem .9rem; cursor: pointer;
|
|
}
|
|
.seg button[aria-pressed="true"] { background: var(--sys); color: var(--on-accent); }
|
|
.search {
|
|
flex: 1 1 12rem; min-width: 9rem; font: 400 var(--step--1) var(--mono);
|
|
background: var(--panel); color: var(--ink);
|
|
border: 1px solid var(--rule); padding: .55rem .7rem;
|
|
}
|
|
.search::placeholder { color: var(--ink-low); }
|
|
.count { font: 500 var(--step--1) var(--mono); color: var(--ink-low); letter-spacing: .1em; }
|
|
|
|
.grid {
|
|
display: grid; gap: 1px; background: var(--rule);
|
|
border: 1px solid var(--rule); margin: 1.75rem 0 4rem;
|
|
grid-template-columns: repeat(auto-fill, minmax(19rem, 1fr));
|
|
}
|
|
.trk { background: var(--panel); padding: 1.1rem 1.25rem 1.25rem; }
|
|
.trk[hidden] { display: none; }
|
|
|
|
.plan { margin: 0 0 1rem; display: flex; justify-content: center; }
|
|
.plan__img {
|
|
display: block; width: 100%; max-width: 15rem; aspect-ratio: var(--ar);
|
|
background-color: var(--ink-mid);
|
|
-webkit-mask-image: var(--art); mask-image: var(--art);
|
|
-webkit-mask-size: contain; mask-size: contain;
|
|
-webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
|
|
-webkit-mask-position: center; mask-position: center;
|
|
}
|
|
.trk h3 {
|
|
font: 700 var(--step-2)/1.1 var(--mono); margin: 0 0 .2rem; color: var(--ink);
|
|
text-wrap: balance;
|
|
}
|
|
.trk__key {
|
|
font: 500 var(--step--1)/1 var(--mono); letter-spacing: .12em;
|
|
color: var(--ink-low); margin: 0 0 .7rem;
|
|
}
|
|
.trk__chips { display: flex; flex-wrap: wrap; gap: .3rem; margin: 0 0 .8rem; }
|
|
.chip {
|
|
font: 500 var(--step--1)/1 var(--mono); letter-spacing: .08em;
|
|
padding: .3rem .45rem; border: 1px solid currentColor;
|
|
}
|
|
.chip--arcade { color: var(--ink-mid); }
|
|
.chip--r411 { color: var(--ink-low); }
|
|
.chip--later { color: var(--ink-low); }
|
|
.chip--race { color: var(--sys); }
|
|
.chip--ball { color: var(--pilot); }
|
|
.chip--none { color: var(--wep); }
|
|
|
|
.stat { margin: 0; display: grid; grid-template-columns: 1fr auto; gap: .15rem .8rem; }
|
|
.stat div { display: contents; }
|
|
.stat dt {
|
|
font: 500 var(--step--1) var(--mono); letter-spacing: .1em;
|
|
text-transform: uppercase; color: var(--ink-low);
|
|
}
|
|
.stat dd {
|
|
margin: 0; text-align: right; font: 500 var(--step--1) var(--mono);
|
|
color: var(--ink); font-variant-numeric: tabular-nums;
|
|
}
|
|
.twin {
|
|
margin: .8rem 0 0; font: 400 var(--step--1)/1.45 var(--mono); color: var(--ink-low);
|
|
}
|
|
.twin.warn { color: var(--wep); }
|
|
|
|
.key { display: flex; flex-wrap: wrap; gap: .4rem .9rem; padding: 1.25rem 0 0; }
|
|
.key span {
|
|
display: inline-flex; align-items: center; gap: .4rem;
|
|
font: 500 var(--step--1) var(--mono); letter-spacing: .08em; color: var(--ink-low);
|
|
}
|
|
.key i { width: .7rem; height: .7rem; display: inline-block; }
|
|
|
|
.foot {
|
|
border-top: 1px solid var(--rule); padding: 1.5rem 0 4rem;
|
|
color: var(--ink-low); font-size: var(--step--1); max-width: 78ch;
|
|
}
|
|
.foot code { font-family: var(--mono); color: var(--ink-mid); }
|
|
.empty-state {
|
|
padding: 2rem; background: var(--panel); color: var(--ink-low);
|
|
font: 400 var(--step-0) var(--mono);
|
|
}
|
|
@media (prefers-reduced-motion: reduce) { * { animation: none !important; transition: none !important; } }
|