Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions .github/workflows/brand-guard.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: Brand guard

on:
push:
branches: [main]
pull_request: # run on all PRs regardless of target branch, matching ci.yml

permissions:
contents: read

concurrency:
group: brand-guard-${{ github.ref }}
cancel-in-progress: true

jobs:
brand-guard:
name: Brand invariants
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- name: Check brand invariants
run: node scripts/brand-guard.mjs
74 changes: 74 additions & 0 deletions BRANDING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# BodyMaps branding — how to style this app

The visual identity comes from the BodyMaps brand pack (v1.0, July 2026). The
tokens live in `PanTS-Demo/src/styles/brand.css` and are available globally —
use them instead of hex literals for any app-chrome color or font.

CI runs `node scripts/brand-guard.mjs` (the **Brand guard** workflow) plus
`src/test/brand.test.ts` in the normal test suite. Both fail on regressions of
the rules below.

## Colors

| Token | Value | Use for |
|---|---|---|
| `--ink` / `--ink-2` / `--ink-3` | `#0F172A` / `#1B2436` / `#2A344A` | **The main color.** Headings, body text, primary button fills, active nav states, focus borders, toggles-on; `--ink-2/3` for hover/elevation on ink fills |
| `--paper` / `--paper-2` / `--paper-3` | `#FFFFFF` / `#F7F7F4` / `#ECEBE5` | Page ground, off-white bands, cards |
| `--rule` | `#E2E1DA` | Hairline dividers, card borders (instead of shadows) |
| `--accent` | `#E76F51` | Vivid orange: decorative bands/graphics, accents and CTA fills on **dark** surfaces (pair with ink text) |
| `--accent-deep` | `#C2532F` | Orange **text only** on light: links, eyebrow numbers, stat values. AA on `--paper` (#FFFFFF) **only** — on `paper-2`/`paper-3`/`#fafafa` use `--accent-deep-hover` instead. Not for button fills — primary fills are ink |
| `--accent-tint` | `#F08A6F` | Small orange text on **dark** (7.3:1 on ink) |
| `--muted` / `--muted-2` | `#5A6175` / `#6B7285` | Secondary / tertiary text on light |
| `--accent-deep-hover` | `#A8431F` | Hover state for accent-deep fills/links (app-local, not a pack token) |
| `--teal` | `#0B4F6C` | **Reserved — do not use** |

Ink is the main color; orange is strictly an accent and scarce by design: one
accent word per heading, one band per composition, small highlights only.
Never vivid `--accent` for normal-size text on white, and never orange as the
dominant fill color of a page.

Functional colors are **not** brand colors: segmentation palettes, organ mesh
colors, CT windowing grays, success/error states stay as they are.

## Typography

IBM Plex Sans 400/500/600 for everything; IBM Plex Mono 400/500 for labels,
eyebrows, and numeric metadata. Self-hosted from `PanTS-Demo/public/fonts/`
via `@font-face` in `brand.css` — never load fonts from an external host.
Use `var(--font-sans)` / `var(--font-mono)`. Weights above 600 are not shipped
(`font-synthesis: none` means they silently render as the nearest real weight,
so don't declare them). The viewer's `--vp-font` / `--vp-mono` alias these
tokens.

## Logo

`PanTS-Demo/public/bodymaps-logo.svg` is the adopted mark (two ink bars +
orange agreement band) and the only sanctioned mark. Never rotate, stretch,
recolor, round, clip, or add effects to it; minimum size 16px; keep roughly one
bar-height of clear space. Favicons (`favicon.svg`, PNG fallbacks,
`apple-touch-icon.png`) and the OG share image are the brand-pack exports —
replace them only with new pack exports.

## Naming

"BodyMaps" is the product/company; "PanTS" and "CancerVerse" name datasets and
case IDs only. Title format: `BodyMaps — <descriptor>` (em dash).

## Deferred surfaces (do not copy their style)

These files still carry pre-brand colors/fonts and are explicitly allowlisted
in `scripts/brand-guard.mjs` because they are under active development in
open PRs — they get migrated in a follow-up, not piecemeal:
`UploadPage.css/.tsx`, `VisualizationPage.css/.tsx`, `AnnotationToolbar.*`,
`FlyoutPrimitives.css`, the `segmentation/` components, `ToolWalkthrough.css`,
`MeasurementPanel.css`, `AISidebar.css`, `Preview.tsx`, and (pre-registered
for an in-flight branch) `SharePatientCard.tsx`. Their "Space Grotesk" /
"JetBrains Mono" declarations render as IBM Plex via an alias `@font-face`
shim in `brand.css` until migrated. Don't add files to an allowlist to
silence the guard — use the tokens.

The guard's scan scope is `PanTS-Demo/` only, by decision: repo-root apps
(`analytics/`) and `flask-server/` are out of scope for now. The Flask PDF
report (`flask-server/api/utils.py` header drawing plus its template) is a
known deferred brand surface *outside* the guard's reach — migrate it when
that file's in-flight PRs land.
18 changes: 13 additions & 5 deletions PanTS-Demo/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,21 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<!-- <link rel="icon" type="image/svg+xml" href="/vite.svg" /> -->
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32.png" />
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16.png" />
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
<meta name="theme-color" content="#0F172A" />
<meta name="description" content="Interactive CT segmentation platform by BodyMaps: upload scans, run organ and lesion segmentation, and explore results in 2D and 3D. Built around the PanTS dataset." />
<meta property="og:title" content="BodyMaps — CT Segmentation Platform" />
<meta property="og:description" content="Interactive CT segmentation platform by BodyMaps: upload scans, run organ and lesion segmentation, and explore results in 2D and 3D." />
<meta property="og:type" content="website" />
<meta property="og:image" content="/og-image-1200x630.png" />
<meta name="twitter:card" content="summary_large_image" />
<link href="/src/index.css" rel="stylesheet">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&family=Space+Grotesk:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap" media="print" onload="this.media='all'">
<noscript><link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&family=Space+Grotesk:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap"></noscript>
<link rel="preload" href="/fonts/ibm-plex-sans-v23-latin-normal-400.woff2" as="font" type="font/woff2" crossorigin />
<link rel="preload" href="/fonts/ibm-plex-sans-v23-latin-normal-600.woff2" as="font" type="font/woff2" crossorigin />
<title>BodyMaps — CT Segmentation Platform</title>
</head>
<body>
Expand Down
Binary file added PanTS-Demo/public/apple-touch-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 4 additions & 12 deletions PanTS-Demo/public/bodymaps-logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added PanTS-Demo/public/favicon-16.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added PanTS-Demo/public/favicon-32.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions PanTS-Demo/public/favicon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file removed PanTS-Demo/public/jhu_logo.jpg
Binary file not shown.
Binary file added PanTS-Demo/public/og-image-1200x630.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 0 additions & 1 deletion PanTS-Demo/public/vite.svg

This file was deleted.

Binary file not shown.
Binary file not shown.
1 change: 0 additions & 1 deletion PanTS-Demo/src/assets/react.svg

This file was deleted.

26 changes: 13 additions & 13 deletions PanTS-Demo/src/components/AuthButton.module.css
Original file line number Diff line number Diff line change
@@ -1,31 +1,31 @@
/* Account control for both nav bars. Monochrome to match the BodyMaps header;
the JHU Heritage Blue (#002D72) is reused for the primary "Sign in" action to
match the landing page's active tab / primary button. */
/* Account control for both nav bars. Ink primary per BRANDING.md;
ink fill on the primary "Sign in" action to match the landing
page's active tab / primary button. */

.signInBtn {
padding: 8px 20px;
border-radius: 22px;
font-family: 'Space Grotesk', sans-serif;
font-family: "IBM Plex Sans", system-ui, sans-serif;
font-size: 12px;
font-weight: 600;
letter-spacing: 0.06em;
cursor: pointer;
background: #002d72;
background: var(--ink);
color: #ffffff;
border: 1px solid #002d72;
border: 1px solid var(--ink);
transition: background 0.2s ease, transform 0.2s ease;
white-space: nowrap;
}
.signInBtn:hover {
background: #00399a;
border-color: #00399a;
background: var(--ink-2);
border-color: var(--ink-2);
transform: translateY(-1px);
}

/* ── Signed-in trigger ── */
.accountRoot {
position: relative;
font-family: 'Space Grotesk', sans-serif;
font-family: "IBM Plex Sans", system-ui, sans-serif;
}

.accountTrigger {
Expand All @@ -50,13 +50,13 @@
height: 26px;
flex-shrink: 0;
border-radius: 50%;
background: #002d72;
background: var(--ink);
color: #ffffff;
display: flex;
align-items: center;
justify-content: center;
font-size: 12px;
font-weight: 700;
font-weight: 600;
}

.accountEmail {
Expand Down Expand Up @@ -98,7 +98,7 @@
color: #111111;
}
.menuEmail {
font-family: 'JetBrains Mono', monospace;
font-family: "IBM Plex Mono", ui-monospace, monospace;
font-size: 11px;
color: #8f8f8f;
margin-top: 2px;
Expand All @@ -115,7 +115,7 @@
border: none;
background: transparent;
border-radius: 8px;
font-family: 'Space Grotesk', sans-serif;
font-family: "IBM Plex Sans", system-ui, sans-serif;
font-size: 13px;
color: #111111;
cursor: pointer;
Expand Down
40 changes: 19 additions & 21 deletions PanTS-Demo/src/components/AuthModal.css
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
/* Global auth popup. Light / monochrome to match the app, World Labs layout. */
/* Global auth popup. Light surface, ink primary per BRANDING.md. */

@import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500;700&display=swap');

.authm-backdrop {
position: fixed;
Expand All @@ -12,7 +11,7 @@
justify-content: center;
padding: 5vh 5vw;
animation: authm-fade 0.15s ease;
font-family: 'Space Grotesk', sans-serif;
font-family: "IBM Plex Sans", system-ui, sans-serif;
}

@keyframes authm-fade {
Expand Down Expand Up @@ -59,13 +58,12 @@
.authm-logo {
width: 40px;
height: 40px;
border-radius: 11px;
margin-bottom: 12px;
}

.authm-title {
font-size: 22px;
font-weight: 700;
font-weight: 600;
color: #111111;
margin: 0 0 22px;
}
Expand All @@ -83,7 +81,7 @@
background: #ffffff;
border: 1px solid rgba(0, 0, 0, 0.14);
color: #111111;
font-family: 'Space Grotesk', sans-serif;
font-family: "IBM Plex Sans", system-ui, sans-serif;
font-size: 14px;
font-weight: 500;
cursor: pointer;
Expand All @@ -104,7 +102,7 @@
width: 100%;
margin: 14px 0;
color: #b0b0b0;
font-family: 'JetBrains Mono', monospace;
font-family: "IBM Plex Mono", ui-monospace, monospace;
font-size: 11px;
}
.authm-divider::before,
Expand All @@ -122,17 +120,17 @@
width: 100%;
padding: 12px 16px;
border-radius: 10px;
background: #002d72;
background: var(--ink);
color: #ffffff;
border: 1px solid #002d72;
font-family: 'Space Grotesk', sans-serif;
border: 1px solid var(--ink);
font-family: "IBM Plex Sans", system-ui, sans-serif;
font-size: 14px;
font-weight: 600;
cursor: pointer;
transition: background 0.15s;
}
.authm-email-btn:hover {
background: #00399a;
background: var(--ink-2);
}

/* Email form */
Expand All @@ -157,35 +155,35 @@
border-radius: 10px;
border: 1px solid rgba(0, 0, 0, 0.12);
background: #fafafa;
font-family: 'Space Grotesk', sans-serif;
font-family: "IBM Plex Sans", system-ui, sans-serif;
font-size: 14px;
color: #111111;
transition: border-color 0.15s, background 0.15s;
}
.authm-input:focus {
outline: none;
border-color: #002d72;
border-color: var(--ink);
background: #ffffff;
}
.authm-error {
font-family: 'JetBrains Mono', monospace;
font-family: "IBM Plex Mono", ui-monospace, monospace;
font-size: 12px;
color: #ef4444;
}
.authm-submit {
padding: 12px 16px;
border-radius: 10px;
background: #002d72;
background: var(--ink);
color: #ffffff;
border: 1px solid #002d72;
font-family: 'Space Grotesk', sans-serif;
border: 1px solid var(--ink);
font-family: "IBM Plex Sans", system-ui, sans-serif;
font-size: 14px;
font-weight: 600;
cursor: pointer;
transition: background 0.2s;
}
.authm-submit:hover:not(:disabled) {
background: #00399a;
background: var(--ink-2);
}
.authm-submit:disabled {
opacity: 0.6;
Expand All @@ -195,7 +193,7 @@
background: none;
border: none;
padding: 2px;
font-family: 'Space Grotesk', sans-serif;
font-family: "IBM Plex Sans", system-ui, sans-serif;
font-size: 12px;
color: #6a6a6a;
cursor: pointer;
Expand All @@ -219,7 +217,7 @@
text-decoration: underline;
}
.authm-fineprint a:hover {
color: #002d72;
color: var(--accent-deep);
}

.authm-toggle {
Expand All @@ -237,7 +235,7 @@
padding: 0;
font: inherit;
font-weight: 600;
color: #002d72;
color: var(--accent-deep);
cursor: pointer;
text-decoration: underline;
}
Loading
Loading