v1.0 · November 2026
Bulletproof.to brand guide
One source of truth for the marketing site, client area and anything else we ship. Every component below is the real class used in production. Copy it as-is.
Brand
Mark. A geometric lowercase b on a rounded tile, its bowl holding a lime dot, a circle seen head-on. Use brand_mark(), never redraw it.
Name. Wordmark in lowercase, "bulletproof" with ".to" in lime (brand_wordmark()). In sentences write Bulletproof.to, capital B.
Clear space. Keep at least half the mark's height empty around it. The dot is always lime, the tile always the darkest or lightest color on the page.
Colors
Monochrome base, one signal color. Tokens are HSL channels in assets/src/app.css; Tailwind classes map to them (e.g. bg-accent, text-muted-foreground/60).
--background
Page background
light 0 0% 100% · dark 240 10% 4%
--foreground
Text, primary buttons, inverse cards
light 240 10% 4% · dark 0 0% 98%
--muted
Card fills, segmented controls
light 240 5% 96% · dark 240 6% 11%
--muted-foreground
Secondary text
light 240 4% 46% · dark 240 5% 64%
--border
Hairlines, outlines
light 240 6% 90% · dark 240 5% 17%
--accent
Signal lime, fills only, max one per view
light 78 92% 56% · dark 78 92% 56%
--accent-soft
Tinted backgrounds, soft badges
light 78 90% 94% · dark 78 40% 12%
--accent-ink
Accent as text on light backgrounds
light 84 80% 28% · dark 78 92% 60%
--success
Online, uptime, paid
light 152 70% 40% · dark 152 60% 48%
--warning
Degraded, expiring
light 38 92% 50% · dark 38 92% 55%
--danger
Destructive actions, errors
light 0 75% 55% · dark 0 80% 62%
Do
Use lime for one primary highlight per view, like a "Popular" badge, the active canary or a focus ring.
Don't
Put lime text on white (fails contrast, use text-accent-ink), or use lime for large backgrounds.
Typography
Space Grotesk for display, Inter for everything else, JetBrains Mono for machine data. All self-hosted from vendor/fonts.
Display XL
Space Grotesk 700 · 60/1.0 · −2%
No KYC, paid only in crypto
Display L
Space Grotesk 700 · 48/1.05
No KYC, paid only in crypto
Display M
Space Grotesk 700 · 30/1.2
No KYC, paid only in crypto
Title
Inter 600 · 18/1.5
No KYC, paid only in crypto
Body
Inter 400 · 16/1.6
No KYC, paid only in crypto
Small
Inter 400–500 · 14/1.5
No KYC, paid only in crypto
Eyebrow
Inter 600 · 12 · uppercase · +14%
No KYC, paid only in crypto
Mono
JetBrains Mono · 14
185.220.101.42 · 4821 7730 1956 0937
Two-tone headline
Offshore servers that don't ask
Our signature is the second half of a hero headline at 50% muted. Use once per page.
Radius & spacing
rounded-xl
Icon tiles · 12px
rounded-2xl
Inputs, menu items · 16px
rounded-3xl
Cards · 24px
rounded-full
Buttons, chips, badges
Spacing follows Tailwind's 4px scale. Card padding p-6–p-8, grid gaps gap-4, section spacing mt-24–mt-28, content width max-w-6xl. Shadows are rare, only on floating layers (menus, popovers, the "Popular" card).
Icons
Lucide (ISC license), 2px stroke, inlined server-side with <?= icon('server', 'size-5') ?>. 2,296 icons available in vendor/lucide.
Sizes: size-4 inline with text, size-5 default, size-6/7 in feature cards. Icon tiles: size-9–11 rounded-xl bg-muted.
Badges & status
Forms
Cards
.card
Default
Data, forms, tables.
.card-muted
Muted
Marketing tiles, plans.
.card-inverse
Inverse
One highlight per row.
App components
PHP helpers in includes/ui.php. The client area is assembled only from these plus the base classes above. Add a helper here before inventing a one-off.
€142.60
≈ 5 days of runway
19/24
3 stopped · 1 suspended
261.7 TB
Unlimited
ui_stat($label, $valueHtml, $sub = '', $icon = '', $spark = [], $tone = 'card' | 'inverse')
Status badges
ui_status($status)
Key/value + switch
ui_kv() · ui_switch()
Tag input
ui_tag_input($alpineArray, $suggestions). Enter or comma adds, Backspace removes
OS logos
os_icon($id), simple-icons (CC0), brand colour, self-hosted
Area chart
ui_area_chart($series, $labels, $unit), first series foreground, second accent
Empty state
ui_empty($icon, $title, $text, $actionHtml). Always offer a way out.
Globe
ui_globe($locations), cobe, self-hosted, labels via CSS anchors
Patterns
- Data tables. Status tabs with counts, search (/), filter selects, sortable headers, row → detail, floating bulk bar, pagination.
- Detail pages. Back button, title + status, primary actions right, underline tabs synced to the URL hash.
- Command palette. Ctrl/⌘ K searches pages, actions and every server by name or IP.
- Destructive actions are red, at the bottom, and require typing the resource name.
- Drawers for creating things (new ticket), toasts to confirm, never alerts.
- Needs attention strip on the dashboard, only when something actually needs action.
3D & motion
cobe globe
assets/globe.js · markers for our regions with an arc between them. Auto-rotates slowly, draggable, pauses off-screen, re-themes on dark mode.
three.js
assets/rack.js · the server rack on product banners. Loaded only on pages that use it (~2 MB), stops rendering off-screen.
Rules
One 3D element per page, never behind text. Durations 150–300 ms for UI, 600–800 ms for reveals. Everything respects prefers-reduced-motion.
Voice & tone
We sound
- Calm, precise, slightly dry.
- Concrete: "24 hours", not "a short time".
- Honest about limits, say what is still forbidden.
We avoid
- "Bulletproof", "untraceable", hacker clichés.
- Promises we can't prove ("100% anonymous").
- Exclamation marks and dark patterns.
Privacy rules for builders
These are part of the brand. A page that breaks them doesn't ship.
No third-party requests
Fonts, icons, scripts and images are self-hosted. The CSP header blocks anything else.
No analytics, no tracking cookies
Theme preference lives in localStorage. Sessions use a single first-party cookie only after login.
Works without JavaScript
Ordering and login must work in Tor Browser on "Safest". JS only enhances.
Collect less
Never add a form field we don't strictly need. Email is always optional.
No-referrer everywhere
Outbound links must not leak where the visitor came from.