Set up in three steps
- Load the three fonts, then
tokens.css, thengridline-ui.css. Both stylesheets are plain CSS with no build step. - Put
class="gl"on the app root. Dark is the default. Adddata-theme="light"to the root, or to any wrapper, for the light theme. Leave it off and the app follows the operating system. - Build with the semantic tokens and the
gl-classes. When you need something that is not here, make it from the same parts: hairlines, square corners, caps labels, mono figures.
<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=Archivo:wght@500;600;700&family=IBM+Plex+Mono:wght@400;500&family=IBM+Plex+Sans:wght@400;500;600&display=swap"> <link rel="stylesheet" href="tokens.css"> <link rel="stylesheet" href="gridline-ui.css"> <body class="gl"> <!-- dark, or the system setting --> <body class="gl" data-theme="light"> <!-- light -->
Prefer to self-host? The same font files are in the brand package under fonts/ as WOFF2. Using Tailwind? Load tokens.css, then add tailwind.preset.js to your config: every color in it points at a CSS variable, so the theme switch keeps working.
// theme switch: "dark", "light", or null to follow the system
function setTheme(t) {
const root = document.documentElement
if (t) root.dataset.theme = t
else delete root.dataset.theme
}Five rules
The brand should read like infrastructure capital: credible, precise, quietly confident. When a choice is unclear, pick what an infrastructure fund would do, not what a software company would do. In product UI that comes down to five rules.
- Near-black and paperDark is primary: a
navy-950ground withnavy-900panels. Light is paper with white panels. Blue is a cast in the black, never a panel color. - One amber markAmber means "here": the site on a map, the current stage, the selected record. One per view. The logo and the focus ring do not count. Never an amber button.
- Square, flat, hairlineNo rounded corners, no shadows, no gradients. Depth is one step of surface and a 1px line. The node is the only round thing.
- Figures are measuredEvery number, unit, coordinate, ID and timestamp is IBM Plex Mono with tabular numerals, right-aligned in tables.
- Plain wordsLabels say what the thing is. Buttons say what happens. Claim only what is secured.
Color
Build with the semantic tokens. They switch with the theme, so one layout works in both. Reach for a primitive only when a map or chart has to name an exact color.
Semantic tokens
| Token | Dark | Light | Use |
|---|---|---|---|
| ground | navy-950 | paper | App and page background. |
| ground-deep | navy-950 | paper-deep | Alternate band, sidebar on light, table zebra if ever needed. |
| surface | navy-900 | white | Panels, cards, inputs, table bodies. |
| surface-raised | navy-800 | white | Menus, dialogs, toasts, tooltips. Always with a rule-strong border.App |
| ink | white | navy-900 | Text, icons, solid buttons. |
| ink-muted | steel-300 | slate-600 | Labels, captions, secondary text, inactive nav. |
| ink-disabled | steel-500 | fog-400 | Disabled text and placeholder hints. Exempt from contrast rules, so never use it for anything that matters.App |
| ink-inverse | navy-950 | white | Text on a solid ink fill (primary button, checked box).App |
| ink-hover | fog-200 | navy-800 | Hover fill of solid ink controls.App |
| hairline | navy-700 | fog-200 | Dividers, panel borders, table rules. Decorative only. |
| rule-strong | steel-500 | fog-400 | Control borders and any border that carries meaning (3:1). |
| node | amber-500 | amber-500 | The node: the one amber mark in a view. Selected row, current stage, the site on a map. |
| accent-text | amber-500 | amber-700 | The one amber word or figure in a view. |
| focus | amber-500 | amber-700 | Focus ring: 2px solid, 2px offset, every interactive element.App |
| danger | red-400 | red-700 | Errors, destructive actions, at-risk flags.App |
| positive | parcel-green | parcel-green-deep | Confirmations and completed states. Shares the parcel green.App |
| info | line-blue | line-blue-deep | Neutral notices and links inside running text. Shares the line blue.App |
| line | line-blue | line-blue-deep | Transmission lines on maps and diagrams. |
| parcel | parcel-green | parcel-green-deep | Controlled parcels on maps and diagrams. |
| fill-hover | rgba(255,255,255,.05) | rgba(13,27,46,.05) | Hover wash on rows, nav items, ghost buttons.App |
| fill-selected | rgba(255,255,255,.08) | rgba(13,27,46,.07) | Selected row or item.App |
| scrim | rgba(6,17,32,.72) | rgba(6,17,32,.56) | Behind dialogs.App |
Primitives
Eighteen brand colors and two reds added for product UI. The brand has no red, and an app needs one for errors: these two are muted to sit with navy and are not for marketing.
The amber budget
- Amber means "here". The site on a map, the current stage on a timeline, the selected record in a list. One per view.
- If a map is in view, the map gets it. Lists beside it fall back to the quiet selection: a 2px
inkrule. That is whatgl-table--quietis for. - What does not count. The logo node and the keyboard focus ring.
- What is never amber. Buttons, links, headings, icons, badges in bulk, backgrounds, charts as a series color.
- On light grounds amber text uses
accent-text, which switches toamber-700.amber-500on paper is a mark, never text.
Status color
- Stage is shown by form, not color. The five-step meter and a mono label carry it. A table of twenty sites stays monochrome.
- Color is for exceptions.
dangerfor errors and at-risk flags,positivefor a confirmation that just happened. Both always come with a word. infoandpositiveshare the map colors. Blue is transmission, green is controlled land. Keep them rare in chrome so they keep that meaning.
Contrast, measured
WCAG 2.1 ratios, computed from the hex values. Text needs 4.5:1, large text and meaningful borders need 3:1.
| Pair | Ratio | Good for |
|---|---|---|
| ink on ground | Dark · 18.9:1 | All text, AAA |
| ink on surface | Dark · 17.3:1 | All text, AAA |
| ink-muted on ground | Dark · 8.5:1 | All text, AAA |
| ink-muted on surface | Dark · 7.8:1 | All text, AAA |
| ink-muted on surface-raised | Dark · 6.9:1 | All text |
| ink-inverse on ink | Dark · 18.9:1 | All text, AAA |
| accent-text, focus on ground | Dark · 10.2:1 | All text, AAA |
| danger on ground | Dark · 7.3:1 | All text, AAA |
| danger on surface | Dark · 6.7:1 | All text |
| positive on ground | Dark · 7.2:1 | All text, AAA |
| info on ground | Dark · 7.5:1 | All text, AAA |
| rule-strong on ground | Dark · 3.7:1 | Large text, borders, icons. Not body text. |
| rule-strong on surface | Dark · 3.4:1 | Large text, borders, icons. Not body text. |
| hairline on ground | Dark · 1.9:1 | Decoration only. Never text or a meaningful border. |
| ink on ground | Light · 15.5:1 | All text, AAA |
| ink on surface | Light · 17.3:1 | All text, AAA |
| ink-muted on ground | Light · 6.5:1 | All text |
| ink-muted on ground-deep | Light · 5.9:1 | All text |
| ink-inverse on ink | Light · 17.3:1 | All text, AAA |
| accent-text, focus on ground | Light · 5.3:1 | All text |
| danger on ground | Light · 5.9:1 | All text |
| danger on surface | Light · 6.6:1 | All text |
| positive on ground | Light · 5.5:1 | All text |
| info on ground | Light · 4.8:1 | All text |
| info on ground-deep | Light · 4.3:1 | Large text, borders, icons. Not body text. |
| rule-strong on ground | Light · 3.3:1 | Large text, borders, icons. Not body text. |
| rule-strong on surface | Light · 3.7:1 | Large text, borders, icons. Not body text. |
| hairline on ground | Light · 1.4:1 | Decoration only. Never text or a meaningful border. |
Type
Three families, three jobs. Archivo labels and titles, always uppercase. IBM Plex Sans is everything people read. IBM Plex Mono is every figure. The marketing scale in the brand book is too large for product UI, so the app has its own, tighter scale.
| Style | Spec | Sample | Use |
|---|---|---|---|
| page-title | Archivo 700 28 / 32 · -0.005em · caps | Site pipeline | One per screen. |
| section-title | Archivo 700 20 / 24 · caps | Interconnection | Groups of panels, dialog titles. |
| panel-title | Archivo 600 13 / 20 · 0.06em · caps | Queue position | Panel and card headers. |
| label | Archivo 500 11 / 16 · 0.16em · caps | Acres under control | Field labels, table headers, stat labels. |
| button | Archivo 600 12 / 16 · 0.16em · caps | Save site | Buttons, tabs, text CTAs. |
| stat | Archivo 600 32 / 36 · -0.01em | 1,850 MW | KPI figures. Units in the same style, smaller. |
| body | IBM Plex Sans 400 16 / 26 | We begin at the substation and work outward. | Reading text: notes, descriptions, help pages. 64 characters a line. |
| ui | IBM Plex Sans 400 14 / 20 | Interconnection study under way | Controls, table cells, navigation. The app default. |
| ui-strong | IBM Plex Sans 600 14 / 20 | Site 01 | Row titles and inline emphasis. |
| small | IBM Plex Sans 400 12 / 18 | Figures as of September 2026. | Help text, captions. The smallest size for sentences. |
| data | IBM Plex Mono 400 13 / 20 · 0.04em | 33.7490° N 84.3880° W | Figures in tables, coordinates, IDs. Tabular numerals. |
| data-sm | IBM Plex Mono 400 11 / 16 · 0.08em · caps | 230 kV · 0.8 mi to POI | Map labels, chips, timestamps, meta. |
- Archivo is always uppercase in the app, except inside
statfigures. If a title needs lowercase, it is body copy. - Wide tracking is for 13px and below. Never letterspace body copy, lowercase, or a page title. Never stack two letterspaced lines.
- 12px is the floor for sentences. 11px is for mono labels and caps labels only.
- Tabular numerals everywhere.
.glsetsfont-variant-numeric: tabular-numsso columns of figures line up. - Line length. Reading text stops at about 64 characters. Tables and forms can run wider.
- Fallbacks. Arial Narrow for Archivo, Segoe UI for Plex Sans, Consolas for Plex Mono. They are in the font stacks already.
Layout
Spacing
A 4px base. Tokens are named by pixel value, --sp-16, so nobody has to look one up. The brand names from the design system map onto the same values.
The shell
240
64 collapsed
24 gutter · 16 on phones
24 between panels
| Size | Value | Use |
|---|---|---|
| --control-sm | 32px | Dense toolbars, table actions. |
| --control-md | 40px | Default buttons, inputs, selects. |
| --control-lg | 48px | Primary action on a form; touch. |
| --row | 44px | Table row. 36px in compact tables. |
| --topbar | 56px | App header. |
| --sidebar | 240px | Navigation. 64px collapsed. |
| --content-max | 1280px | Widest content column. |
- Breakpoints: 640, 960 and 1280. Below 960 the sidebar collapses to a menu and side panels stack under the table.
- Left-aligned. Titles, forms and tables hang from the left edge of the content column. Nothing is centered except an empty state inside a panel and a dialog on its scrim.
- One primary action per screen, top right of the page header. Everything else is secondary or a text CTA.
- Touch. On phones and tablets, controls are at least 44px tall: use
gl-btn--lgand 48px inputs.
Surfaces, borders, depth
- Three levels, no shadows.
groundis the page.surfaceis a panel, an input, a table.surface-raisedis anything floating: menu, dialog, toast, tooltip. - Hairlines separate.
hairlinebetween things that belong together,rule-strongaround anything you can type in or click, and under a table header. - Floating things get a
rule-strongborder. Dialogs also get thescrim. That is all the depth there is. - The decorative grid is 48px, in
hairline, and only ever a fragment: a corner of an empty state, a login screen, a report cover. Never behind a table or form.
Buttons
Four kinds, in order of weight. A screen has one primary button. Labels are a verb and an object in Archivo caps: "Add site", "File request", "Export table".
- Busy is a packet, not a spinner. Set
aria-busy="true", change the label to the present participle, and current runs along the bottom edge. - The text CTA is the brand's link style: caps label, a short rule, a node. Use it for "go somewhere", and a button for "do something".
- Never: amber fills, rounded corners, icons without a label in primary actions, two primary buttons side by side.
<button class="gl-btn gl-btn--primary">Add site</button> <button class="gl-btn gl-btn--secondary gl-btn--sm">Filter</button> <button class="gl-btn gl-btn--primary" aria-busy="true">Saving</button> <a class="gl-cta" href="/sites/01">Open site</a>
Forms
Labels sit above the field in caps and are always visible: a placeholder is a hint, never the label. Fields are 40px tall with a rule-strong border. Figures get a mono input and their unit in a fixed box, so nobody types "MW".
- Errors say what is wrong and how to fix it, under the field, with
aria-invalidon the input andaria-describedbypointing at the message. The square glyph means color is never the only signal. - Validate on blur, not on every keystroke. Never clear what the person typed.
- One column. Forms read top to bottom. Two columns only for short, related pairs such as load and voltage.
- Two to four options that fit on a line: use a segmented control instead of radios.
- Buttons go bottom left, primary first, under the last field.
<div class="gl-field">
<label class="gl-label" for="mw">Requested load</label>
<div class="gl-unitfield">
<input class="gl-input gl-input--mono" id="mw" inputmode="decimal">
<span class="gl-unit">MW</span>
</div>
<span class="gl-help">Peak load in the interconnection request.</span>
</div>
<label class="gl-check"><input type="checkbox"><span class="gl-box"></span><span>Rezoning approved</span></label>Status
A site moves through five stages, in the order the work is done. The meter shows how far along it is without any color, so a long table stays calm. Flags are the exception and get a color and a word.
| Stage | Meter | Means |
|---|---|---|
| Utility | 1 of 5 | Capacity screened and the serving utility engaged. No land committed. |
| Under control | 2 of 5 | Options or purchase agreements executed around the point of interconnection. |
| In queue | 3 of 5 | Interconnection request filed and a queue position held. Studies under way. |
| Entitled | 4 of 5 | Zoning, permits and county agreements in place. |
| Powered | 5 of 5 | Delivered to the user, ready to build. |
The brand's voice rule applies to data too: "under control", "in queue", "executed" and "entitled" each mean something specific. The app should never let a record claim a stage it has not reached.
Tables
Most of the app is tables. Text columns are left-aligned in Plex Sans. Figures are right-aligned in Plex Mono with the unit in the header, not in every cell. Rows are 44px, or 36px with gl-table--compact.
| Market | Stage | kV | POI mi | Updated | |||
|---|---|---|---|---|---|---|---|
| Site 01 | Georgia | In queue | 1,240 | 300 | 230 | 0.8 | Sep 12 |
| Site 02 | Georgia | Under control | 860 | 250 | 230 | 1.4 | Sep 09 |
| Site 03 | Alabama | Entitled | 2,100 | 600 | 500 | 0.6 | Sep 15 |
| Site 04 | Texas | Utility | 1,450 | 400 | 345 | 2.1 | Aug 28 |
| Site 05 | Texas | At risk | 750 | 300 | 138 | 1.9 | Sep 02 |
| Market | Stage | kV | POI mi | Updated | |||
|---|---|---|---|---|---|---|---|
| Site 01 | Georgia | In queue | 1,240 | 300 | 230 | 0.8 | Sep 12 |
| Site 02 | Georgia | Under control | 860 | 250 | 230 | 1.4 | Sep 09 |
| Site 03 | Alabama | Entitled | 2,100 | 600 | 500 | 0.6 | Sep 15 |
| Site 04 | Texas | Utility | 1,450 | 400 | 345 | 2.1 | Aug 28 |
| Site 05 | Texas | At risk | 750 | 300 | 138 | 1.9 | Sep 02 |
- No zebra stripes, no vertical rules. One hairline under each row, a
rule-strongline under the header. - Units live in the header. "MW", "kV", "POI mi". Cells hold the figure only, formatted the same way down the column.
- Seven rows by six columns is comfortable. Beyond that, let the table scroll inside its own wrapper and keep the first column visible.
- Empty cell: a single hyphen in
ink-muted. Never "N/A", never zero unless it is zero. - Row actions appear on hover as ghost buttons at the right edge, and are always reachable by keyboard.
Panels and stats
Interconnection
Updated Sep 12- Utility
- Placeholder Power
- Request
- 300 MW at 230 kV
- Queue position
- 14
- Study
- System impact, in progress
Interconnection
Updated Sep 12- Utility
- Placeholder Power
- Request
- 300 MW at 230 kV
- Queue position
- 14
- Study
- System impact, in progress
- Not everything is a panel. A page title, a paragraph and a form sit on the ground. Panels are for things with their own subject and edge: a table, a map, a record.
- Four stats at most, and only figures someone would quote. The unit is smaller, in the same style, never a separate color.
- Dividers inside a page use
gl-rule: a hairline with a small muted node at its left end.
Feedback
Drop Site 05?
The site leaves the pipeline and its two options are marked for release. The record and its documents are kept.
Nothing filed yet
Surveys, title work and utility letters for this site will appear here.
Drop Site 05?
The site leaves the pipeline and its two options are marked for release. The record and its documents are kept.
Nothing filed yet
Surveys, title work and utility letters for this site will appear here.
- Toasts confirm, alerts explain. A toast is one short sentence, bottom right, gone in five seconds, never for errors. Anything the person must read or act on is an inline alert next to the thing it is about.
- Loading. Under one second, show nothing. After that, a hairline with current running along it at the top of the region that is loading. Keep the old content visible until the new content is ready. No spinners, no shimmer.
- Dialogs are for confirming something destructive or collecting one small thing. Anything bigger is a page.
- Empty states say what will appear and offer the one action that fills them. This is the one place the 48px grid fragment shows up in the app.
Writing data
The app's credibility is in its figures. Format them one way everywhere.
| Quantity | Write | Not | Note |
|---|---|---|---|
| Acreage | 1,240 ac | 1240 Acres | Thousands separator always. Whole acres unless a survey says otherwise. |
| Power | 300 MW | 300mw, 0.3 GW | Stay in MW below 10,000. A space before the unit. |
| Voltage | 230 kV | 230KV | Lowercase k, capital V. |
| Distance | 0.8 mi | .8 miles | One decimal, leading zero. |
| Coordinates | 33.7490° N 84.3880° W | 33.749, -84.388 | Four decimals, hemisphere letters, in the UI. Signed decimals in exports. |
| Date | Sep 12, 2026 | 9/12/26 | In the UI. ISO 2026-09-12 in exports, logs and file names. |
| Time | 14:32 ET | 2:32pm | 24 hour, with the zone when it matters. |
| Money | $12.4M | $12,400,000.00 | Three significant figures in summaries. Full figures in ledgers. |
| Range | 250 to 300 MW | 250-300MW | Spell out "to". The unit once, at the end. |
| Missing | - | N/A, 0, blank | A single hyphen in ink-muted. |
- Mono labels are uppercase:
230 KV · 0.8 MI TO POI. In sentences, units keep their normal case: "0.8 mi from the substation". - Never round up. 1,238 acres is "1,238", not "about 1,250". A figure that is an estimate says so in its label.
- Every figure has an as-of date somewhere on the screen, in
data-sm.
Maps
Maps are schematic: a flat ground, a hairline graticule, contour lines where the land matters, and a small fixed vocabulary of marks. Never a satellite basemap by default, never shaded relief, never the stock look of a web map.
| Layer | Style | Token |
|---|---|---|
| Ground | Flat fill. No basemap labels, roads in hairline only if needed. | ground-deep |
| Graticule | 1px. Quarter-mile lines at half strength, mile lines at full strength. | hairline |
| Contours | 1px at 20%, every fourth at 50%. Never filled. Flatten under the site so lines wrap around it. | ink-muted |
| Transmission | Solid. 3px at 500 kV, 2.5px at 345, 2px at 230, 1.25px below. Towers are 8px open squares. Voltage labelled. | line |
| Substation | 20px open square with a cross, 2px stroke. | ink |
| Controlled land | 1.5px outline, 14% fill, acreage labelled. | parcel |
| Tap or route | 1px dashed 4 4 from the site to the point of interconnection. | ink-muted |
| The site | 7px radius disc with a 6px knockout ring in the ground color. One per map. Other sites are 5px open squares in ink. | node |
| Labels | IBM Plex Mono 11px, uppercase, 1px tracking. Name in ink, measurement under it in ink-muted. | ink, ink-muted |
| Scale and north | Bottom right, mono: a one-mile bar and "N". | ink-muted |
Paint values for a MapLibre or Mapbox style, dark theme. For light, swap each hex for the light value of the same token.
{
"background": { "background-color": "#061120" },
"contour": { "line-color": "#9CB0C4", "line-opacity": 0.2, "line-width": 1 },
"contour-index": { "line-color": "#9CB0C4", "line-opacity": 0.5, "line-width": 1 },
"transmission": { "line-color": "#6FA8DC",
"line-width": ["match", ["get", "kv"], 500, 3, 345, 2.5, 230, 2, 1.25] },
"parcel-fill": { "fill-color": "#7FA98A", "fill-opacity": 0.14 },
"parcel-line": { "line-color": "#7FA98A", "line-width": 1.5 },
"site": { "circle-color": "#F8B135", "circle-radius": 7,
"circle-stroke-color": "#061120", "circle-stroke-width": 6 },
"label": { "text-color": "#FFFFFF", "text-halo-color": "#061120", "text-halo-width": 2 }
}- Hover thickens a line by 1px or raises a parcel fill to 24%. Selected moves the amber node to that site; the previous one becomes an open square.
- Color is never the only signal. Every line and parcel carries a mono label at the zoom where it matters.
- Satellite is a toggle, off by default. When on, desaturate it to about 40% and overlay
navy-950at 55%, so the marks still read.
Charts
- Series order:
ink,line,parcel,ink-muted. Four series is the ceiling; past that, use small multiples. - Amber is not a series. It marks one point that matters, the latest value or a threshold crossing, as a node with a knockout ring.
- Gridlines are
hairline, horizontal only. The baseline isrule-strong. No chart borders, no fills under lines, no gradients, no 3D. - Labels are mono, 10 to 11px, uppercase for axes. Label lines directly at their right end. Put the unit in the title, not on every tick.
- Points are open squares. Round is reserved for the node.
Motion
Motion tells one story: the grid is energized. Lines draw, current runs, the node switches on. In the app that means quick, quiet transitions and one signature: a packet of current running along a hairline.
| Token | Value | Use |
|---|---|---|
| --dur-fast | 120ms | Hover, press, focus. |
| --dur | 200ms | Menus, tabs, toggles, checkbox tick. |
| --dur-draw | 400ms | A line or tick drawing on. |
| --dur-slow | 600ms | Panels and rules drawing in on first load. |
| --ease-out | cubic-bezier(.2,.6,.2,1) | Default. Things arrive quickly and settle. |
| --ease-draw | cubic-bezier(.6,0,.2,1) | Lines that draw: slow start, firm finish. |
- Ease out. Nothing bounces, overshoots or springs. Nothing loops beside text except a loading line.
- Move 8px at most. Menus and toasts fade and rise 8px. Pages do not slide.
- Amber moves only at the node. A newly selected site may brighten once and send one ring outward over 600ms. Nothing else glows.
- The logo intro (grid draws, node flickers on, name lights) is for the sign-in screen or first load, once per session, skippable. Never on every navigation.
- Reduced motion:
tokens.csssets every duration to zero. Show the finished state.
Accessibility
- Contrast. Body text is 15:1 or better in both themes.
ink-mutedis the quietest text allowed.ink-disabled,hairlineandrule-strongare never text. - Focus. Every interactive element shows a 2px
focusring at 2px offset on keyboard focus. Never remove it, never restyle it per component. - Keyboard. Everything works without a mouse, in reading order. Dialogs trap focus and return it. Escape closes whatever floats.
- Targets. 32px minimum with a pointer, 44px on touch.
- Never color alone. Status has a word, errors have a glyph and a message, map layers have labels.
- Real controls. The kit styles native inputs, selects, checkboxes and radios, so labels, names and states come for free. Keep
label for,aria-invalid,aria-describedby,aria-selected,aria-currentandaria-busy: the CSS hangs off them. - Zoom. Layouts hold at 200% and reflow at 320px wide. Tables scroll inside their wrapper, the page never scrolls sideways.
Words in the UI
Write the way a development partner talks to an investment committee. Plain words, short sentences, the fact first.
| Where | Write | Not |
|---|---|---|
| Primary button | File request | Submit |
| Destructive | Drop site | Delete, Are you sure? |
| Success | Site 06 saved. | Success! Your site has been saved |
| Error | The request was not filed. The utility portal timed out. Try again, or file by email. | Oops, something went wrong |
| Empty state | Nothing filed yet | No data available |
| Field help | Peak load in the interconnection request. | Please enter your MW here |
| Loading | Loading sites | Hang tight, crunching the numbers |
- Sentence case for sentences, caps for labels. Buttons, tabs, table headers and field labels are Archivo caps. Everything else is sentence case.
- No exclamation marks, no "please", no "oops", no "unlock", "seamless", "powerful" or "solutions".
- Name the thing. "Drop Site 05?" beats "Are you sure?". "Option on parcel 07" beats "This item".
- Same word, same thing. A site is always a site. Pick "drop", "file", "execute" and keep them.
Logo in the app
- Header: the primary lockup,
gridline-a-refined, 22 to 24px tall, top left, linked to the home view. Use theon-darkfile on dark andon-lighton light, or inline the SVG and drive its three colors fromink,ink-mutedandnodeas this page does. - Small spaces: below 140px wide, switch to the monogram,
gridline-e-monogram. It holds down to 16px. - Favicon and app icon:
gridline-e-monogram-app-icon.svg, which includes its navy ground. Let the platform round the corners; never round them yourself. - Clear space is half the mark's height on every side. Nothing else sits in it.
- Never redraw it, set the name in live type, recolor the node, or animate it outside the intro.
Before a screen ships
What is in the kit
| File | What it is |
|---|---|
| tokens.css | Every token as a CSS variable: primitives, both themes, spacing, sizes, motion. Follows the system theme unless told otherwise. |
| gridline-ui.css | The reference styles for every component on this page. Plain CSS, gl- prefixed, no JavaScript needed. |
| tokens.json | The same tokens in the W3C design tokens format, for Style Dictionary, Figma plugins or native builds. |
| tailwind.preset.js | Colors, fonts, type scale, spacing and motion as a Tailwind preset. Radius and shadow are locked to none. |
| Gridline-App-Design-Guide.html | This page, self-contained. Opens offline. |
| ../logos, ../fonts | In the brand package: every logo as SVG and PNG, and the three families as WOFF2. |
Questions about the brand itself, the logo, photography or the deck: see the brand guidelines PDF in the same package. If something here and something there disagree about product UI, this guide wins. For anything else, the guidelines win.