| /* ============================================================ | |
| BASE — Brad Did Something | |
| Element defaults so any consumer page reads as the game by | |
| default: warm paper canvas, dark-ink headings, warm body text, | |
| clean (no scanlines). | |
| ============================================================ */ | |
| *, *::before, *::after { box-sizing: border-box; } | |
| html { -webkit-text-size-adjust: 100%; } | |
| body { | |
| margin: 0; | |
| background: var(--bg-app); | |
| color: var(--text-body); | |
| font-family: var(--font-body); | |
| font-size: var(--fs-body); | |
| line-height: var(--lh-body); | |
| letter-spacing: var(--ls-normal); | |
| -webkit-font-smoothing: none; /* keep pixels crunchy */ | |
| font-smooth: never; | |
| text-rendering: optimizeSpeed; | |
| } | |
| h1, h2, h3, h4, h5, h6 { | |
| font-family: var(--font-display); | |
| color: var(--text-heading); | |
| line-height: var(--lh-tight); | |
| margin: 0 0 var(--space-4); | |
| font-weight: 400; | |
| } | |
| h1 { font-size: var(--fs-h1); } | |
| h2 { font-size: var(--fs-h2); } | |
| h3 { font-size: var(--fs-h3); } | |
| p { margin: 0 0 var(--space-4); text-wrap: pretty; } | |
| a { | |
| color: var(--link); | |
| text-decoration: none; | |
| border-bottom: 2px solid currentColor; | |
| } | |
| a:hover { text-shadow: var(--text-glow-cyan); } | |
| :focus-visible { | |
| outline: none; | |
| box-shadow: var(--focus-shadow); | |
| } | |
| code, kbd, samp { font-family: var(--font-mono); } | |
| img[data-pixel-img], .pixel-art { image-rendering: pixelated; } | |
| /* ---------- Utility: arcade marquee text ---------- */ | |
| .bds-marquee { | |
| color: var(--text-heading); | |
| text-shadow: var(--text-glow-magenta); | |
| } | |
| .bds-terminal { color: var(--text-body); } | |
| .bds-money { color: var(--text-money); text-shadow: var(--text-glow-lime); } | |
| /* ---------- Utility: full-screen daylight shell ---------- | |
| Wrap a page in <div class="bds-screen"> to get the warm paper | |
| canvas + soft top-light automatically. (CRT is retired.) */ | |
| .bds-screen { | |
| position: relative; | |
| min-height: 100vh; | |
| background: | |
| radial-gradient(ellipse at 50% -10%, var(--bds-purple-900) 0%, var(--bg-app) 60%); | |
| overflow: clip; | |
| } | |
| /* ============================================================ | |
| COLORS — Brad Did Something · DAYLIGHT 3/4 re-skin | |
| Warm, sunlit office: tiled warm-grey floors, cream paper | |
| panels, dark warm INK for outlines + text, the five | |
| character colors muted to read in daylight. No CRT, no neon | |
| void. (--bds-void stays dark = it is the INK; --bds-white | |
| stays light = highlights / player / light fills.) | |
| ============================================================ */ | |
| :root { | |
| /* ---- INK (dark, warm) — outlines, borders, hard edges, text ---- */ | |
| --bds-void: #241f17; /* the ink line behind everything */ | |
| --bds-ink: #2b2519; /* near-ink */ | |
| --bds-ink-2: #4b4534; /* body text */ | |
| --bds-ink-3: #7c755f; /* muted label */ | |
| --bds-ink-4: #a79f88; /* disabled / ghost */ | |
| /* ---- PAPER ramp (warm light) — was the navy/purple ramp. | |
| darkest = desktop behind panels · lightest = hover ---- */ | |
| --bds-navy-900: #b7b1a0; /* app background (warm grey carpet) */ | |
| --bds-navy-800: #a59e8b; /* recessed wells */ | |
| --bds-purple-900: #ccc6b5; /* alt background band */ | |
| --bds-purple-800: #d7d1c0; /* raised surface */ | |
| --bds-purple-700: #e9e4d3; /* card surface (cream) */ | |
| --bds-purple-600: #f4f0e2; /* hover surface */ | |
| /* ---- Light ink: highlights, player, light fills ---- */ | |
| --bds-white: #faf7ee; /* warm white */ | |
| --bds-phosphor: #3f5a44; /* terminal/log text (dark sage, reads on paper) */ | |
| --bds-phosphor-dim:#6a7d62; /* muted terminal text */ | |
| --bds-amber: #b9852a; /* warning / scrutiny gold (reads on paper) */ | |
| --bds-grey: #7c755f; /* low-emphasis label */ | |
| --bds-grey-dim: #a79f88; /* disabled / ghost ink */ | |
| /* ---- The five underlings — muted for daylight ---- */ | |
| --bds-brad: #d2593a; /* warm orange-red — the problem */ | |
| --bds-stacey: #1f9c8e; /* teal — the competent one */ | |
| --bds-kevin: #cf9a2a; /* gold — the pie chart guy */ | |
| --bds-janet: #9a52c4; /* purple — the wildcard */ | |
| --bds-derek: #4f93c4; /* blue — barely present */ | |
| /* character tints — light wash behind portraits */ | |
| --bds-brad-soft: #f0d8cd; | |
| --bds-stacey-soft: #d2e9e4; | |
| --bds-kevin-soft: #efe4c4; | |
| --bds-janet-soft: #e7dcf0; | |
| --bds-derek-soft: #d6e6f2; | |
| /* ---- System accents — daylight-legible ---- */ | |
| --bds-neon-magenta:#c0398f; /* primary accent / CTA (raspberry) */ | |
| --bds-neon-cyan: #1f7fae; /* links, focus, selection (sea blue) */ | |
| --bds-neon-lime: #3f9a3f; /* success / money (forest green) */ | |
| /* ---- Semantic status ---- */ | |
| --bds-success: #3f9a3f; /* revenue went up (rare) */ | |
| --bds-warning: #cf9a2a; /* a Brad is forming */ | |
| --bds-danger: #d2593a; /* a Brad has formed */ | |
| --bds-info: #4f93c4; | |
| /* ============================================================ | |
| SEMANTIC ALIASES — design against these, not the raw scale | |
| ============================================================ */ | |
| --bg-app: var(--bds-navy-900); | |
| --bg-band: var(--bds-purple-900); | |
| --bg-well: var(--bds-navy-800); | |
| --surface-raised: var(--bds-purple-800); | |
| --surface-card: var(--bds-purple-700); | |
| --surface-hover: var(--bds-purple-600); | |
| --text-heading: var(--bds-ink); | |
| --text-body: var(--bds-ink-2); | |
| --text-muted: var(--bds-ink-3); | |
| --text-disabled: var(--bds-ink-4); | |
| --text-money: var(--bds-success); | |
| --accent: var(--bds-neon-magenta); | |
| --accent-2: var(--bds-neon-cyan); | |
| --link: var(--bds-neon-cyan); | |
| --focus-ring: var(--bds-neon-cyan); | |
| --selection: var(--bds-neon-magenta); | |
| --border: #b3ab95; /* soft divider / inset edge */ | |
| --border-bright: #3a3326; /* the dark pixel frame */ | |
| --border-neon: var(--bds-neon-magenta); | |
| } | |
| ::selection { | |
| background: var(--selection); | |
| color: var(--bds-white); | |
| } | |
| /* ============================================================ | |
| FONTS — Brad Did Something | |
| One typeface to rule them all: Press Start 2P. | |
| A bitmap arcade font (Namco, 1980s). Looks best at multiples | |
| of 8px. We ship the latin woff2 locally so consumers are | |
| offline-safe. | |
| ============================================================ */ | |
| @font-face { | |
| font-family: "Press Start 2P"; | |
| font-style: normal; | |
| font-weight: 400; | |
| font-display: swap; | |
| src: url("../fonts/PressStart2P-Regular.woff2") format("woff2"); | |
| } | |
| /* ============================================================ | |
| TYPOGRAPHY — Brad Did Something | |
| Everything is Press Start 2P. Headlines = arcade marquee. | |
| Body = crashed terminal. Sizes are multiples of 8 because | |
| the font is a bitmap and renders crisp on the grid. | |
| ============================================================ */ | |
| :root { | |
| --font-pixel: "Press Start 2P", "Courier New", monospace; | |
| --font-display: var(--font-pixel); | |
| --font-body: var(--font-pixel); | |
| --font-mono: var(--font-pixel); | |
| /* ---- Type scale (px, multiples of 8 where possible) ---- | |
| Press Start 2P runs LARGE and WIDE per glyph, so the body | |
| sizes are small numerically but read big. Never go below | |
| 8px; UI body lives at 10–12px, prose at 12px. */ | |
| --fs-display: 40px; /* hero / title screen */ | |
| --fs-h1: 28px; /* screen titles, arcade marquee */ | |
| --fs-h2: 20px; /* section headers */ | |
| --fs-h3: 16px; /* sub-headers */ | |
| --fs-body: 12px; /* default body / dialogue */ | |
| --fs-ui: 10px; /* buttons, labels, HUD readouts */ | |
| --fs-fine: 8px; /* legal-ish memo footer, terminal logs */ | |
| /* ---- Line height ---- | |
| Pixel fonts need air. 1.8–2.0 keeps the scanline rhythm. */ | |
| /* line-height — pixel fonts need air; 1.8–2.0 keeps scanline rhythm */ | |
| --lh-tight: 1.4; /* @kind other */ | |
| --lh-body: 1.9; /* @kind other */ | |
| --lh-loose: 2.2; /* @kind other */ | |
| /* ---- Letter spacing ---- | |
| The glyphs are already monospaced & square; only nudge. */ | |
| --ls-tight: -0.5px; | |
| --ls-normal: 0px; | |
| --ls-wide: 2px; /* HUD labels, all-caps tags */ | |
| /* ---- Semantic roles ---- */ | |
| --text-display-size: var(--fs-display); | |
| --text-h1-size: var(--fs-h1); | |
| --text-body-size: var(--fs-body); | |
| --text-ui-size: var(--fs-ui); | |
| } | |
| /* Pixel fonts must NOT be anti-aliased into mush. Keep edges | |
| crisp; let the CRT overlay do the softening. */ | |
| :root { | |
| --pixel-render: pixelated; /* @kind other */ | |
| } | |
| /* ============================================================ | |
| SPACING — Brad Did Something | |
| 8px grid. The font lives on it; so does everything else. | |
| No fractional spacing. Pixels are sacred. | |
| ============================================================ */ | |
| :root { | |
| --space-0: 0px; | |
| --space-1: 4px; /* hairline gap (half-step, use sparingly) */ | |
| --space-2: 8px; /* base unit */ | |
| --space-3: 12px; | |
| --space-4: 16px; | |
| --space-5: 24px; | |
| --space-6: 32px; | |
| --space-7: 48px; | |
| --space-8: 64px; | |
| --space-9: 96px; | |
| /* ---- Radius ---- | |
| Pixel UI = mostly hard corners. We allow a single 4px | |
| "chunky pixel" rounding for soft chips; never smooth. */ | |
| --radius-0: 0px; /* default — everything is square */ | |
| --radius-chunk:4px; /* chips, avatars, soft cards */ | |
| --radius-pill: 0px; /* there are no pills here */ | |
| /* ---- Border widths (the pixel frame) ---- */ | |
| --bw-1: 2px; /* default UI border */ | |
| --bw-2: 4px; /* emphasized frame / dialogue boxes */ | |
| --bw-3: 6px; /* HUD chrome, window bezels */ | |
| /* ---- Containers ---- */ | |
| --container-screen: 1280px; | |
| --container-narrow: 720px; | |
| --hud-bar-height: 64px; | |
| } | |
| /* ============================================================ | |
| EFFECTS — Brad Did Something | |
| CRT scanlines, neon glow, hard pixel shadows, glitch. | |
| Shadows are HARD-OFFSET (no blur) to read as 8-bit. Glow | |
| is the ONLY place blur is allowed. | |
| ============================================================ */ | |
| :root { | |
| /* ---- Hard pixel shadows (offset, zero blur) — warm, on paper ---- */ | |
| --shadow-pixel: 4px 4px 0 0 rgba(36,31,23,0.28); | |
| --shadow-pixel-lg: 8px 8px 0 0 rgba(36,31,23,0.26); | |
| --shadow-pixel-sm: 2px 2px 0 0 rgba(36,31,23,0.30); | |
| /* ---- Accent glow — kept SUBTLE in daylight (small, low-alpha) ---- */ | |
| --glow-magenta: 0 0 7px rgba(192,57,143,0.35); | |
| --glow-cyan: 0 0 7px rgba(31,127,174,0.35); | |
| --glow-lime: 0 0 7px rgba(63,154,63,0.35); | |
| --glow-soft: 0 0 6px rgba(120,100,70,0.25); | |
| /* text glow for arcade marquee headings — now a soft warm halo */ | |
| --text-glow-magenta: 0 0 5px rgba(192,57,143,0.28); | |
| --text-glow-cyan: 0 0 5px rgba(31,127,174,0.28); | |
| --text-glow-lime: 0 0 5px rgba(63,154,63,0.28); | |
| /* ---- Focus ---- */ | |
| --focus-shadow: 0 0 0 2px var(--bds-white), 0 0 0 4px var(--focus-ring), 0 0 6px rgba(31,127,174,0.4); | |
| /* ---- CRT scanline overlay ---- | |
| Apply as a fixed/absolute ::after layer. Two-layer: | |
| horizontal scanlines + a faint vignette. pointer-events:none. */ | |
| /* DAYLIGHT re-skin: CRT is retired. These are neutralized to | |
| transparent so any leftover .crt-overlay / [data-crt] renders | |
| nothing (kept as vars so old markup doesn't error). */ | |
| --crt-scanline-size: 3px; /* line period */ | |
| --crt-scanline: linear-gradient(rgba(0,0,0,0), rgba(0,0,0,0)); /* @kind other */ | |
| --crt-tint: linear-gradient(rgba(0,0,0,0), rgba(0,0,0,0)); | |
| /* ---- Motion ---- */ | |
| --ease-step: steps(4, end); /* @kind other */ | |
| --ease-pop: cubic-bezier(0.2,1.4,0.4,1); /* @kind other */ | |
| --dur-fast: 90ms; /* @kind other */ | |
| --dur: 160ms; /* @kind other */ | |
| --dur-slow: 320ms; /* @kind other */ | |
| } | |
| /* ---------- Reusable CRT overlay ---------- | |
| Put <div class="crt-overlay"></div> as a fixed child of a | |
| relatively/fixed positioned root, OR add data-crt to a box. */ | |
| .crt-overlay, | |
| [data-crt]::after { | |
| content: ""; | |
| position: absolute; | |
| inset: 0; | |
| pointer-events: none; | |
| z-index: 9999; | |
| background: var(--crt-scanline), var(--crt-tint); | |
| mix-blend-mode: multiply; | |
| } | |
| [data-crt] { position: relative; } | |
| /* faint flicker — disabled under reduced motion */ | |
| @media (prefers-reduced-motion: no-preference) { | |
| @keyframes bds-flicker { | |
| 0%, 97%, 100% { opacity: 1; } | |
| 98% { opacity: 0.82; } | |
| 99% { opacity: 0.94; } | |
| } | |
| .crt-overlay { animation: bds-flicker 6s steps(1,end) infinite; } | |
| } | |
| /* ---------- Pixel-perfect rendering helper ---------- */ | |
| [data-pixel-img] { | |
| image-rendering: pixelated; | |
| image-rendering: crisp-edges; | |
| } | |