Design languageTypography

Design language Foundations

Typography

Two self-hosted typefaces set the text of this site: New Black for language and Geist Mono for what machines write. Sizes live in the components that use them, so this page copies each value from its source file and a test keeps the copy true.

Two typefaces, one job each.

#

New Black sets every word written for people: headlines, body text, buttons and navigation. Geist Mono has two jobs: it sets what a machine writes or reads back, such as hashes, paths, dates, versions and code, and it sets the small labels and notes that organise a page. No other typeface is downloaded.

Language

New Black

Headlines, body text, buttons and navigation.

Ç ç Ğ ğ İ ı Ö ö Ş ş Ü ü 0123456789

Weights
400, 500, 600, 700
Glyphs
311 in each weight
Files
10956 to 11048 bytes per weight, WOFF2
Figures
Proportional. At weight 400, on a 1000-unit em, a 1 is 291 units wide and a 0 is 640.
Licence
Commercial licence, from the foxtype foundry.
In the file
Copyright © 2024 by foxtype. All rights reserved.

Machine text

Geist Mono

Hashes, paths, dates, code, labels and eyebrows.

Ç ç Ğ ğ İ ı Ö ö Ş ş Ü ü 0123456789

Weights
400, 500
Glyphs
615 in each weight
Files
14224 to 14408 bytes per weight, WOFF2
Figures
Fixed. On a 1000-unit em, every digit and letter is 600 units wide.
Licence
SIL Open Font License 1.1, from Basement.studio and Vercel.
In the file
Copyright 2024 The Geist Project Authors (https://github.com/vercel/geist-font.git)

How they load.

  1. From this site, through Astro

    Both families are files in this repository, registered with the font API of Astro through its local provider. Nothing is fetched from a font service, and the content security policy accepts fonts from this site only.

    Font registration, as written
    const nb = (w) => ({ weight: w, style: 'normal', src: [`./src/assets/fonts/NewBlack-${w}.woff2`] });
    const gm = (w) => ({ weight: w, style: 'normal', src: [`./src/assets/fonts/GeistMono-${w}.woff2`] });
    
    fonts: [
      {
        provider: fontProviders.local(),
        name: 'New Black',
        cssVariable: '--font-newblack',
        options: { variants: [nb(400), nb(500), nb(600), nb(700)] },
      },
      {
        provider: fontProviders.local(),
        name: 'Geist Mono',
        cssVariable: '--font-geistmono',
        // Varsayilan yedek sans-serif: uretilen degisken Arial ve sans-serif
        // ile bitiyor, tokenin ui-monospace / monospace yedekleri hic
        // erisilmiyordu. Dosya gelmezse metin yine esit genislikli dizilir.
        fallbacks: ['ui-monospace', 'monospace'],
        // optional: ilk boyamaya yetismeyen dosya sonradan yerine konmaz, bu
        // yuzden Geist Mono duzeni hic kaydiramaz. Olcuye gore uretilen yedek
        // yuz Courier New'u local() ile ister; macOS ve Windows'ta var, Linux
        // ve Android'de yok. Orada ilk ekrani genel monospace yuz dizer, swap
        // ile Geist Mono gelince ana sayfa girisi kayardi: CI'daki mobil
        // Lighthouse denetimi bu kaymayi 0.23 olctu. Iki agirlik da head'de
        // onden yuklenir; dosya normalde ilk boyamaya yetisir.
        display: 'optional',
        options: { variants: [gm(400), gm(500)] },
      },
    ],
  2. One variable per family

    Astro exposes each family as a CSS variable and the design tokens wrap it, so components read the token, never the family name. Each variable Astro writes already ends in fallback faces sized to match and a generic family: sans-serif for New Black and, as its registration asks, ui-monospace and monospace for Geist Mono. If Geist Mono is not ready when the page is first drawn, or fails to load, machine text is still set in a face of fixed width. The names the tokens list after the variable are never reached.

    The two font tokens
    --font-sans: var(--font-newblack), system-ui, sans-serif;
    --font-mono: var(--font-geistmono), ui-monospace, SFMono-Regular, monospace;

    The whole token file is published as tokens.css.

  3. Preloaded by decision

    New Black 400 and 700 are preloaded: they set the body and the headline of the first screen. The 500 and 600 weights are on that screen too, in links and buttons, but holding them back by 1500 milliseconds changed layout shift by only 0.002, so they load when first used. Geist Mono 400 and 500 are preloaded too, so they are normally ready when the page is first drawn; the next step says why that matters.

    Font tags in the page head
    <Font cssVariable="--font-newblack" preload={[{ weight: 400 }, { weight: 700 }]} />
    <Font cssVariable="--font-geistmono" preload={[{ weight: 400 }, { weight: 500 }]} />
  4. Readable before the files arrive

    For every weight of both families Astro generates a fallback face from a local system font, scaled to the metrics of the real face, so text appears at once. New Black's @font-face rules declare font-display: swap: the real file replaces the fallback when it arrives, and the measurement in the previous step shows how little that moves. The fallback of Geist Mono asks for Courier New, which Linux and Android do not have. There the generic monospace face set the first screen, and with font-display: swap the arrival of Geist Mono caused a layout shift of 0.23 in the mobile Lighthouse audit of the home page. The rules of Geist Mono therefore declare font-display: optional: a file that is not ready when the page is first drawn is never swapped in, and that page keeps the fallback.

New Black 400 and 700 also exist as TTF files. They are read only while the site is built, to draw the share image of each page, and browsers never download them. The share cards are covered on the Logo and name page.

  • Fonts come from this site and nowhere else.

    WhyApart from the bot check on the contact form, the site loads nothing from other hosts, and a font served from elsewhere would add a request to every page. The test reads every built page and stylesheet: none links a font host, no @font-face points elsewhere and every content security policy accepts fonts from this site only.

    TestEnforced by a test on every change.

  • Every shipped font file is a real WOFF2 of a sensible size.

    WhyA truncated file, or one that was never cut down, fails quietly in the browser. The test checks the signature and the size of all 6 files.

    TestEnforced by a test on every change.

  • Only New Black 400 and 700 and Geist Mono 400 and 500 are preloaded.

    WhyThe New Black files cover the body and the headline. Its other weights swap in behind fallbacks sized to match, so preloading them would cost an early request and save almost no movement. Geist Mono declares font-display: optional, so a late file is not used at all on that page; preloading both of its weights makes them ready in time on a normal connection.

    TestEnforced by a test on every change.

  • Components name the token, never the family.

    WhyComponent styles read the two font tokens, so changing a face is one edit. The family names appear only where the fonts are registered and in the code that draws the share images. The test reads every font-family declaration, and every font shorthand, in the style blocks of the site.

    TestEnforced by a test on every change.

Weights in use

#

New Black ships in weights 400, 500, 600 and 700 and Geist Mono in 400 and 500. Each weight has a job on the site. The lines below are sentences from this site, set in the weight the site uses for them.

  • 700New Black

    From zero trust to one verdict.

    Headlines: page and section titles and large figures.

  • 600New Black

    Every signal, one verdict

    Subheads, card titles, terms in definition lists and buttons.

  • 500New Black

    Read the research

    Text links, among them the proof link under each rule on the home page.

  • 400New Black

    Zero Door weighs every binary, library and package on your servers against the original, and backs each verdict with evidence your auditor can check offline.

    Body text, leads and form fields.

  • 500Geist Mono

    Product · Solutions · Research · Services · Company · Trust · Legal

    Column headings in the footer and group headings in the site map.

  • 400Geist Mono

    No third-party trackers on this site.

    Labels, dates, document details, code and notes.

Each family is shown at one size so its weights compare; the scale below gives the sizes in use.
Font files as shipped
FamilyWeightBytesPreloaded
New Black40011016Yes
New Black50010984No
New Black60010956No
New Black70011048Yes
Geist Mono40014224Yes
Geist Mono50014408Yes

Emphasis

Neither family ships an italic. The site does not style strong text in long-form copy: the browser sets it one step bolder, which New Black draws at 700. Some imported research articles still contain italic, and with no italic file the browser slants New Black itself. That slant is accepted for now; no rule asks for it or against it.

The scale in use

#

Type sizes are not tokens. Each component declares its own size, line height and tracking in its scoped style block. These are the main roles in use, copied from those blocks; a unit test fails the moment a value here stops matching its file. Smaller labels, from badges to the text inside diagrams, sit below this scale and are not listed.

  1. Home headline

    Size
    clamp(40px, 5.6vw, 74px)
    Line height
    1
    Tracking
    -0.035em
    Weight
    700
    Measure
    12ch
    Wrap
    balance

    From zero trust to one verdict.

  2. Page headline

    Size
    clamp(36px, 4.6vw, 60px)
    Line height
    1.02
    Tracking
    -0.03em
    Weight
    700
    Measure
    16ch
    Wrap
    balance

    Where it sits, what it sends, who it talks to.

  3. Article headline

    Size
    clamp(32px, 4.2vw, 52px)
    Line height
    1.05
    Tracking
    -0.03em
    Weight
    700
    Measure
    26ch
    Wrap
    balance

    Attacking kiosk devices: red team research

  4. Statement headline

    Size
    clamp(30px, 3.6vw, 46px)
    Line height
    1.04
    Tracking
    -0.03em
    Weight
    700
    Wrap
    balance

    Prove it on your own servers.

  5. Section headline

    Size
    clamp(28px, 3.2vw, 40px)
    Line height
    1.05
    Tracking
    -0.03em
    Weight
    700
    Measure
    22ch
    Wrap
    balance

    One agent out, nothing in.

  6. Feature title

    Size
    clamp(24px, 2.4vw, 32px)
    Line height
    1.08
    Tracking
    -0.025em
    Weight
    700
    Wrap
    balance

    The first question: is it the original?

  7. Card title

    Size
    20px
    Line height
    1.15
    Tracking
    -0.02em
    Weight
    600

    Every signal, one verdict

  8. Page lead

    Size
    18px
    Line height
    1.55
    Tracking
    0, inherited
    Weight
    400, inherited
    Measure
    52ch

    The questions an architect asks before a pilot, answered on one page: the shape of a deployment, the data that leaves a host, the systems it plugs into, and the things it deliberately does not do.

  9. Section lead

    Size
    17px
    Line height
    1.55
    Tracking
    0, inherited
    Weight
    400, inherited
    Measure
    56ch

    The point of the product is evidence about files, not the files. What the agent sends is bounded and listed here.

  10. Long-form text

    Size
    16.5px
    Line height
    1.6
    Tracking
    0, inherited
    Weight
    400, inherited
    Measure
    68ch

    The first scan weighs every binary, library and package already on the host against the original. A baseline records what is there; it does not bless it.

  11. Body

    Size
    16px
    Line height
    1.5
    Tracking
    0, inherited
    Weight
    400, inherited

    Package updates, log rotation, temp files, a real implant: they all look like change.

  12. Card text

    Size
    15.5px
    Line height
    1.6
    Tracking
    0, inherited
    Weight
    400, inherited

    A small Rust agent runs as a service on each host.

  13. Button

    Size
    14px
    Line height
    1.5, inherited
    Tracking
    0, inherited
    Weight
    600

    Discover Zero Door

  14. Text link

    Size
    14px
    Line height
    1.5, inherited
    Tracking
    0, inherited
    Weight
    500

    Read the research

  15. Small text

    Size
    13.5px
    Line height
    1.5
    Tracking
    0, inherited
    Weight
    400, inherited

    One Windows servicing run touches thousands of files.

  16. Code block

    Size
    13px
    Line height
    1.55
    Tracking
    0, inherited
    Weight
    400, inherited

    --font-mono: var(--font-geistmono), ui-monospace, SFMono-Regular, monospace;

  17. Document details

    Size
    12px
    Line height
    1.5, inherited
    Tracking
    0, inherited
    Weight
    400, inherited

    Published 04/03/2026

  18. Eyebrow

    Size
    11px
    Line height
    1.5, inherited
    Tracking
    0.12em
    Weight
    400, inherited
    Case
    uppercase

    Design language · Foundations

  19. Step number

    Size
    11px
    Line height
    1.5, inherited
    Tracking
    0.12em
    Weight
    400, inherited

    01 02 03

  20. Trust strip

    Size
    11px
    Line height
    1.5, inherited
    Tracking
    0.06em
    Weight
    400, inherited
    Case
    uppercase

    PCI DSS · ISO 27001 · NIST 800-53 · SOC 2 · GDPR

Each sample is text the site sets in that role, styled with the declarations of its source rule at the width of your window. Fluid sizes show the size they take right now; values a rule does not declare are marked as inherited.

Fluid headlines

Headlines grow with the window through clamp(): a smallest size, a share of the viewport width and a largest size. The table gives the window width at which each one starts to grow and the width at which it stops.

On phones the home hero sets smaller sizes of its own. Where max-width: 600px matches, its headline is 36px, below the floor of its clamp(), and its lead 16px, so that the text fits the pinned first screen; where max-height: 700px matches as well, they are 32px and 15px.

Fluid sizes, computed from the declarations
RoleDeclarationGrows fromStops at
Home headlineclamp(40px, 5.6vw, 74px)715 px1322 px
Page headlineclamp(36px, 4.6vw, 60px)783 px1305 px
Article headlineclamp(32px, 4.2vw, 52px)762 px1239 px
Statement headlineclamp(30px, 3.6vw, 46px)834 px1278 px
Section headlineclamp(28px, 3.2vw, 40px)875 px1250 px
Feature titleclamp(24px, 2.4vw, 32px)1000 px1334 px

Size follows the outline.

Each page has one h1, at the top of its hero or layout. Sections open with an h2 and divide with h3. Visual size steps down with the level, and no level is skipped to get a smaller look.

  • Every value in this scale matches its source file.

    WhyThere is no type token to point at, so the scale points at the components. If a component changes, the test fails until this page changes with it.

    TestEnforced by a test on every change.

  • Heading levels never skip inside the main content.

    WhyA skipped level breaks the outline that screen reader users move through. The build fails on any page where, say, an h2 is followed by an h4.

    TestEnforced by a test on every change.

  • Headlines that make a statement are sentences, in sentence case.

    WhySuch a headline states something and ends with a full stop. Research articles and legal texts keep their own titles; item titles and labels carry no full stop.

    ReviewKept by review, not by a test.

Tracking and case

#

New Black is set tight, and tighter as it grows. Geist Mono is never tightened; when it is set in capitals it is opened up. On web pages, capitals and open tracking belong to Geist Mono alone.

New Black: closed as it grows

  • Nothing is trusted for having been there yesterday.

    -0.035em74px at its largestHome headline

  • Nothing is trusted for having been there yesterday.

    -0.03em60px at its largestPage headline

  • Nothing is trusted for having been there yesterday.

    -0.025em32px at its largestFeature title

  • Nothing is trusted for having been there yesterday.

    -0.02em20pxCard title

  • Nothing is trusted for having been there yesterday.

    016pxBody

Geist Mono: opened in capitals

  • Design language

    0.12em11pxEyebrow

  • On this page

    0.1em11pxContents title

  • Red team

    0.08em12pxArticle category

  • PCI DSS · ISO 27001 · NIST 800-53

    0.06em11pxTrust strip

Each sample takes the size, weight and tracking of its source rule; headlines take the size they have at the width of your window. Tracking is set in em, so it scales with the size.
Design language · FoundationsTypography
DoSet eyebrows with the kick utility: Geist Mono, 11px, capitals, tracked 0.12em.
Design language · FoundationsTypography
Do notDo not set New Black in capitals with open tracking. That treatment belongs to Geist Mono.
  • In the scale, tracking tightens as size grows.

    WhyLarge letters at their default spacing look loose, so the larger the size, the more spacing is taken back. The test reads every New Black role above and fails if a larger one is tracked looser than a smaller one.

    TestEnforced by a test on every change.

  • On web pages, capitals and open tracking appear only in Geist Mono.

    WhyLabels in capitals need open spacing to stay legible at 11px, and labels are set in Geist Mono. New Black stays in sentence case, at zero or negative tracking. The share images drawn at build time are the exception: they load only New Black, and their kicker is set in it, in capitals, tracked 0.08em.

    TestEnforced by a test on every change.

  • Capitals come from CSS, not from the text.

    WhyDictionaries hold labels in sentence case and text-transform raises them, so the browser applies the casing rules of the declared language.

    ReviewKept by review, not by a test.

Machine text

#

Geist Mono marks text that a machine wrote or will read back: a hash, a path, a date, a version, a line of code. Every character in it is the same width, so values line up in columns and a long string reads as one unit. It also sets the small labels and notes that organise a page.

This sentence is prose, so it is set in New Black. Its fingerprint, the address it is published at and the moment its text last changed are machine text.

sha256
5b30d3c28c8ddc6f91b3534ec4e33fa625f8d7f6d3e239e3d47b000691e5e42d
page
/design/typography
changed
The fingerprint is the SHA-256 of the sentence, computed when this page was built. The time comes from git: the last commit that changed the text of this page.
Where Geist Mono is used
KindExampleIn use on
Eyebrows and section labelsDesign languagePage heads and most section heads
Dates and document detailsPublished 04/03/2026The research list, articles and legal documents
Hashes and digests5b30d3c28c8ddc6f…Zero Door evidence diagrams and the integrity line on the trust page
Paths and code/.well-known/security.txtResearch articles and product diagrams
Compliance framework namesISO 27001The trust strip on the home page and the trust page
Step numbers01Feature rows, the company story and the solution pages
Notes and fine print© 2026 Zerone. All rights reserved.Form notes, pricing notes and the bottom row of the footer

Figures

New Black draws proportional figures: each digit is as wide as its shape needs, so digits in a column do not line up. Geist Mono gives every digit the same width. Where values must line up column by column, as in the number columns of the tables on this page and in the legal index, the site sets them in Geist Mono.

New Black

  • 3,411
  • 1
  • 13
  • 99.5
  • 48

Geist Mono

  • 3,411
  • 1
  • 13
  • 99.5
  • 48
Each box is as wide as the digit inside it at weight 400, read from the font files. Below, figures from the Zero Door and trust pages, aligned to the right in each face.
  • Inline machine strings may break anywhere; code blocks scroll.

    WhyA hash or a path has no spaces to wrap at, so inline code in long-form text sets overflow-wrap: anywhere. A code block keeps its lines whole and scrolls inside its own box.

    TestEnforced by a test on every change.

  • Mono carries values and labels, not emphasis.

    WhyGeist Mono sets machine text and the small labels and notes that organise a page. A sentence meant to carry weight is set in New Black; setting it in mono to look technical adds noise without adding a fact.

    ReviewKept by review, not by a test.

Measure and wrapping

#

Line length is set in ch, the width of the digit zero in the current font. Headlines are held short so they break into even lines; long-form text stops at 68ch.

Measures in use
ElementMeasureAt its largest, about
Home headline12ch572 px
Page headline16ch618 px
Section headline22ch567 px
Article headline26ch871 px
Legal document headline34ch1007 px
Feature paragraph44ch451 px
Home lead44ch507 px
Page lead52ch599 px
Section lead56ch609 px
Long-form text68ch718 px

In New Black the zero is wide: 0.64 em at weight 400 and 0.644 em at 700, against 0.6 em in Geist Mono and 0.546 em for an average lowercase letter. A New Black ch is therefore wider than a typical letter: a 68ch column of 16.5px text is about 718 pixels wide and holds about 80 average lowercase letters.

Balanced headlines

Headline rules set text-wrap: balance, so the browser evens out their lines instead of leaving a single word on the last one. Reading text keeps normal wrapping: balancing is meant for a few lines, not a paragraph.

Four rules, each with its proof.

DoHeadlines balance their lines: text-wrap: balance.

Four rules, each with its proof.

Do notDo not let a headline wrap greedily and end on a single word.
  • Long-form text stops at 68ch.

    WhyOn long lines the eye loses the start of the next one. A New Black ch is wider than its letters, so a 68ch line of 16.5px text holds about 80 average lowercase letters. Research articles and legal documents share the same column.

    TestEnforced by a test on every change.

  • Headlines balance their lines; card titles are the one exception.

    WhyAn even shape reads as one statement; a lone last word reads as an accident. The test lists every headline role in the scale and fails if one neither balances nor is named as an exception.

    TestEnforced by a test on every change.

  • When text must fit an exact box, size the box in pixels.

    WhyA New Black ch is a wide zero. A description box on the home page, once sized in ch, ran past the frame it sat in; it is now sized in pixels.

    ReviewKept by review, not by a test.

Two languages, one page.

#

The site is written by hand in English and Turkish, at the same addresses under /tr. Type has to hold in both: every page declares its language, and the English phrases the Turkish home page keeps are marked as English, so that the browser applies the right casing and a screen reader the right voice.

EN

From zero trust to one verdict.

TR

Sıfır güvenden tek karara.

The home headline in both languages, from the site dictionaries, each marked with its language.
Zero Trust, One Security
DoOn a Turkish page, mark English with lang="en". Its capitals then follow English rules.
Zero Trust, One Security
Do notWithout it, Turkish casing applies and the i of Security becomes a dotted capital İ.

Where the language is declared.

  • Every page declares its language on the html element.

    WhyEnglish pages are lang="en" at the root of the site; Turkish pages are lang="tr" at /tr and below it. The test reads every built page.

    TestEnforced by a test on every change.

  • On Turkish pages, the tagline and framework names that stay English carry lang="en".

    WhyThe tagline on the home page, the framework names in its trust strip and the framework names that keep their English form in the lists on the trust and solution pages stay in English. Marking them keeps their capitals and their pronunciation English. Framework names with a Turkish form are written in Turkish and carry no mark.

    TestEnforced by a test on every change.

  • Research articles stay in English, and the Turkish research list says so.

    WhyOn a Turkish route the page frame is Turkish and the article body sits in an article element with lang="en". The category, the date, the contents title and the links below the article stay in Turkish and carry lang="tr", so the category is capitalised by Turkish rules. Each entry in the Turkish list carries a badge that names the language.

    TestEnforced by a test on every change.

  • A Turkish document on an English route says it is Turkish.

    WhyUntil a legal text has an English version, the English route shows the Turkish body with lang="tr" and a note above it. The document details, the notes and the link back to the index stay in English and carry lang="en".

    TestEnforced by a test on every change.

Letters the fonts cover

The New Black files are cut down to a subset that includes every Turkish letter. A few symbols are left out; this page names them instead of drawing them, and where the site uses one, such as the arrow between two figures, the browser draws it from a system font. The table is read from the shipped files when the page is built.

Ç ç Ğ ğ İ ı Ö ö Ş ş Ü ü â î û

Ç ç Ğ ğ İ ı Ö ö Ş ş Ü ü â î û

Turkish letters and the circumflex vowels, in New Black 700 and 400. All 15 are present in every weight.
Symbols in the shipped files
CharacterCode pointNew BlackGeist Mono
En dashU+2013PresentPresent
Curly quotation markU+201CPresentPresent
EllipsisU+2026PresentPresent
BulletU+2022PresentPresent
Euro signU+20ACPresentPresent
Em dashU+2014AbsentPresent
Rightwards arrowU+2192AbsentPresent
Backtick (grave accent)U+0060AbsentPresent
Turkish lira signU+20BAAbsentAbsent
Check markU+2713AbsentAbsent
Ballot boxU+2610AbsentAbsent

The em dash is not used on the site in any case: a test rejects it in the site dictionaries and a build gate on every built page.

  • The New Black subset covers every Turkish letter.

    WhyTurkish text must never fall back to another face in the middle of a word. The test reads the character map of each shipped weight.

    TestEnforced by a test on every change.

Figures and dates

Figures in copy are written by hand in each dictionary, in the convention of that language. Research dates are formatted when the site is built, with the en-GB and tr-TR locales: day first in both, with slashes in English and dots in Turkish. Legal document versions and the Last changed line of these pages are written year first, as ISO 8601.

Figures and dates, in each language
ItemEnglishTurkish
A figure from the Zero Door page3,4113.411
The latest research publication date04/03/202604.03.2026
The last change to this page2026-11-052026-11-05

Type in Zero Door

#

The interface speaks in the calm register. Of the site's two typefaces it shares one, Geist Mono, for machine text. This is what its code shows.

The site and the product, side by side
AspectThis siteZero Door
Typeface for languageNew Black, 4 static weightsInter, one variable file
Machine textGeist Mono, 2 weightsGeist Mono, one variable file
Weights in use400 to 700400 to 600
Largest heading74 px, the home headline24 px, the page title
Body text16 px, line height 1.514 px, line height 20 px
LoadingSelf-hosted through AstroSelf-hosted through next/font/local

The typeface and the four roles are read from the source code of the product into a snapshot, published as product-tokens.json. The page title, the weights in use, the tabular figures and the contract test are checked by hand in the product code.