Logo
docs/LOGO.md in the repository. Do not edit. Open the source file.The logo is a keyhole. This file is the contract for its shape, its colours and where the product uses it. Do not change the shape. One generator (brand/, fed by brand/tokens.json) makes every output from the same geometry (see “Files and generator”). The brand blue is Lapis #26619C since 2026-10-20 (docs/BRAND.md).
Geometry
Start with a pointy-top hexagon. Its side is s. Its centre is the origin, y is up. The top vertex is T = (0, s).
The keyhole is the union of two shapes:
- a circle with centre
Tand radiusr = s(√3 − 1); - a kite with the corners
T,(s√3/2, −s/2),(0, −s)and(−s√3/2, −s/2).
The rule: every straight edge of the outline is s long. The outline has four straight edges: two from the shoulder points to the side corners, and two from the side corners to the bottom point. The shoulder is the point where an edge of the kite leaves the circle. A kite edge from T is s√3 long. The circle covers r = s(√3 − 1) of it, and s is left.
Derived numbers:
| Item | Value |
|---|---|
Radius r | 0.732 s |
| Shoulder points | (±(√3 − 1)s/2, (√3 − 1)s/2), about (±0.366 s, 0.366 s) |
| Width | s√3 (1.732 s, the width of the kite) |
| Height | s(√3 + 1) (2.732 s) |
| Ratio height : width | 1.577 |
The DXF files docs/logo-shape.dxf and docs/logo-construction.dxf have the construction.
Master files
The files are in docs/logo/. They are generated (make brand). Each one has s = 10 and the view box -8.661 -17.321 17.321 27.321 (the glyph) or 0 0 100 100 (the tile). The path of the glyph (y down):
M3.660 -3.660 L8.660 5 L0 10 L-8.660 5 L-3.660 -3.660 A7.321 7.321 0 1 1 3.660 -3.660 ZThe tile transform is translate(50 50) scale(2.196) translate(0 3.6605) in a 100 x 100 box.
| File | Content |
|---|---|
glyph.svg | The bare glyph, accent (Lapis #26619C). |
glyph-dark-ui.svg | The bare glyph, dark-UI accent (Lapis #8CB8E6). |
mono-black.svg | The bare glyph, black. |
mono-white.svg | The bare glyph, white. |
tile-light.svg | The flat tile: white keyhole on the tile colour (the rendering at 32 px and smaller). |
tile-enamel.svg | The enamel tile (gradient, shadow). |
app-icon.svg | The cut icon (gradient, sheen, hole, inner shadow, rim). |
The framed tile is a rounded square (corner radius 22 % of the side). The keyhole is 60 % of the tile height. It is in the middle of its bounding box (not of its circle). The macOS app icon uses the standard grid: a 824 px squircle (|x|⁵ + |y|⁵ ≤ 1) in a 1024 px canvas, with the same 60 % keyhole. It has no drop shadow in the file (as before).
Two renderings: cut and enamel
Decision (2026-10-20). The same keyhole has two renderings. Both use the vertical tile gradient (top, mid, bottom). The numbers are in brand/tokens.json (render).
Cut (large: app icons, store icons, 64 px and larger). The keyhole is a hole in the tile.
- The tile has a vertical gradient (tile top, tile, tile bottom) and a soft white sheen at the top left (radial, 18 % opacity, fading to 0).
- The hole has an umber vertical gradient (hole top to hole bottom).
- An inner shadow at the top edge of the hole: black, 75 %, offset down 0.9 % of the tile, blur 0.6 glyph units (0.6 × 2.196 % of the tile).
- A light rim: the keyhole shape in the rim colour at 85 %, moved down 0.32 glyph units, drawn behind the hole. A thin light edge shows under the bottom edges.
Enamel (small and inline: favicon, extension toolbar and inline button, apple-touch-icon, in-app marks, the Android splash mark, the 64 px preview).
- The same gradient tile. The keyhole is white with a very light vertical gradient (white to key bottom) and a soft drop shadow (drop colour, 45 %, offset down 0.7 glyph units, blur 0.7).
- At 32 px and smaller the tile is flat (the tile mid colour) and the keyhole is white, with no shadow, rounded to whole pixels. This keeps small icons crisp.
Gradients and shadows are allowed only in these two icon renderings. The rest of the brand stays flat and quiet (docs/BRAND.md). The wordmark cursor is flat, and its keyhole is solid paper colour #F3F1EC, light and dark. It is not cut out.
Where a vector format has no blur (the Android launcher icon), the inner shadow is a darker first stop of the hole gradient.
Colours
The values are in brand/tokens.json. The active palette is Lapis. The alternative is Ultramarine. Both are in docs/BRAND.md.
| Name | Lapis (active) | Use |
|---|---|---|
| Accent | #26619C | Glyph and tile on light surfaces. |
| Accent, dark UI | #8CB8E6 | The bare glyph on dark surfaces only. The framed tile stays on the tile colour on every ground. |
| Ink | #15171B | Bare glyph in a one-colour place on a light surface (Firefox toolbar, light theme). |
| Light ink | #F3F4F6 | Bare glyph on a dark toolbar (Firefox). |
| White | #FFFFFF | The keyhole on the tile. Also the mono white file. |
| Paper | #F3F1EC | The keyhole in the wordmark cursor. |
| Black | #000000 | Mono black file. Template images (only the alpha counts). |
Decision (2026-10-17, renewed 2026-10-20): the framed tile is always white on the tile colour (Lapis: 6.42 : 1), in light and dark UIs. The dark-UI accent is too light for a white keyhole.
The layered icon (iOS 26)
apple/LasboltiOS/AppIcon.icon is an Icon Composer document. make brand writes it (icon.json, Assets/plate.svg, Assets/hole.svg). It has two groups. The first group is the front:
- Plate (
plate.svg): the 1024 px square with the keyhole cut out by an SVG mask. It is the glass layer (glass: true). The colour is a gradient fromtileToptotileBottom. Dark appearance:iconPlateDarkToptoiconPlateDarkBottom. The group has a neutral shadow andspecular: true. Translucency is off. - Hole (
hole.svg): the keyhole with the umber gradienticonHoleToptoiconHoleBottom, scaled byrender.glassIcon.holeScale(1.04) about the glyph centre, so it fills the cut. It is not glass and has no shadow. In the tinted appearance it is white.
The keyhole has the same place as in every other icon: translate(50 50) scale(2.196) translate(0 3.6605) in a 100 unit tile, times 10.24 on the 1024 px canvas. The path is GlyphPath(). No file has another copy.
Why the plate is the glass layer: a cut reads inward. The plate edge takes the light, and the plate shadow falls into the hole. If the keyhole is glass, it reads as embossed (it stands out of the plate). The preview has a plate without the edge light (icon-nospecular-*) to compare the edge ring. It is not shipped.
How to edit: change brand/tokens.json (iconPlateDark*, iconHole*, render.glassIcon), then run make brand. Do not edit the document by hand: the next make brand writes over it. You can open it in Icon Composer to look at it: the generator writes icon.json in the same format as Icon Composer (sorted keys, " : ", five decimals, no new line at the end), so opening and saving it gives no diff. A change that you make there must go into the tokens. The plate colours are the sRGB numbers of the tokens written as display-p3: on purpose: the glass material takes colour out of the plate, and the wider space gives it back (approved on an iPhone, 2026-10-20). The hole is in the SVG and keeps the exact token colours. Each dark plate colour is tileBottom mixed with black: 12 % (top) and 55 % (bottom). A test checks the rule for every palette.
Previews: with Xcode 26 on the machine, make brand renders the document with ictool for every palette into docs/brand/palettes/<name>/icon-<rendition>-<size>.png (Default, Dark, TintedLight, TintedDark, ClearLight, ClearDark at 180 px; Default and Dark also at 1024 px). make brand-check does not run ictool and does not compare these PNG files. It compares the three text files of the document. A render depends on the macOS version, and a check must run without Xcode.
Clear space and minimum sizes
- Clear space: keep free space of
s / 2on every side of the bare glyph. For a framed tile the tile edge is the edge of the logo, and the clear space iss / 2of the keyhole around the tile. - Minimum size of the bare glyph: 14 px high on a screen. The framed tile: 16 px.
- At 32 px and smaller the generator rounds the circle centre, the radius and the bottom point to whole pixels, so the icons are crisp. Larger sizes use the exact geometry.
- Do not rotate, stretch, outline or put text inside the keyhole. Add a shadow only in the enamel and cut renderings above.
Where the logo is used
“Framed” is the tile. “Bare” is the glyph alone. “Cut” and “enamel” are the renderings above. T is the tile colour (Lapis #26619C).
| Place | Variant | Colour | Why |
|---|---|---|---|
Web: tab icon (favicon.svg, favicon-32.png) | Framed, enamel (the 32 px PNG is flat) | Tile T in light and dark | A tab strip can be light or dark, and the tile is clear on both. |
Web: apple-touch-icon.png (180 px) | Framed, enamel, full-bleed square | White on tile gradient | iOS rounds the corners itself. A transparent corner would turn black. |
Web: top bar of the app (.wordmark) | The wordmark: lasbolt and the cursor (docs/BRAND.md), 21 px; on a phone the cursor alone, 36 px | Cursor block T, keyhole solid paper #F3F1EC, in light and dark | The name in the brand tone, small enough for the bar. |
| Web: login, register, approve, recover, reset pages | The wordmark, 30 px | As the top bar | The page has no other graphic; the wordmark is the brand moment. |
Extension: toolbar of Chrome and Safari (icon-N.png, 16 to 128 px) | Framed, enamel at 48 px and larger, flat at 32 px and smaller | White on T | One icon for light and dark toolbars. |
| Extension: store icon (128 px) | Framed, enamel | White on tile gradient | The store shows it on a light and a dark page. |
Extension: toolbar of Firefox (theme_icons) | Bare | Ink #15171B on a light theme, light ink #F3F4F6 on a dark theme | Firefox toolbars have the theme colour; the bare glyph follows it. |
| Extension: popup header | The wordmark (docs/BRAND.md), 20 px, Besley bundled (besley-latin.woff2) | Cursor block T, keyhole solid paper | The name in the brand tone, as the web top bar. |
| Extension: inline field button | Framed, enamel (CSS gradient, drop shadow), 28 px | White on tile gradient | It sits in a page of any colour; the tile has its own ground. |
macOS: AppIcon (16 to 1024 px) | Framed, squircle; cut at 64 px and larger, flat enamel at 16 and 32 px | Umber hole on the tile gradient | The system draws no frame, so the squircle is in the file. |
macOS: menu bar extra (MenuBarGlyph, 18 pt canvas, 16 pt glyph) | Bare, template image | Black alpha; the system colours it. MenuBarGlyphDim (alpha 0.45) shows locked or not ready | A menu bar icon is one colour and follows light, dark and the wallpaper. |
macOS: menu bar popover header (Wordmark, 19 pt) | The wordmark | Cursor block T, keyhole solid paper | The name in the brand tone. BrandMark (the enamel tile) stays for other places. |
Android: launcher icon (ic_launcher, adaptive) | Framed, cut: background is the tile gradient with the sheen; foreground is the hole (umber gradient and rim); a monochrome layer | The system colours the monochrome layer | The same tile as the macOS icon. The keyhole is 40 of 108 dp high, in the safe zone. |
Android: system splash screen (Android 12 and later, values-v31/themes.xml) | The launcher foreground on a T circle, and the wordmark as the branding image (splash_wordmark.xml) | The wordmark ink follows light and dark; the cursor keyhole is paper | The first frame of a cold start. The system masks the icon to a circle. |
Android: the “starting” screen (Wordmark, 40 sp, a thin progress bar) | The wordmark | As the start screen | It follows the splash while the agent starts, so the brand does not drop out. |
Android: start screen (Wordmark, 40 sp) | The wordmark | Cursor block T, keyhole solid paper | The brand moment of the app. |
Android: top bar of the vault list (Wordmark, 22 sp) | The wordmark | As the start screen | The name in the brand tone, as the web top bar. |
iOS: AppIcon (apple/LasboltiOS/AppIcon.icon, layered, iOS 26) | Framed, full-bleed square. Two layers: the plate (glass) with the keyhole cut out, and the hole behind it. See “The layered icon” below | Plate: tile gradient (dark: a darker pair). Hole: umber gradient (lighter than the macOS hole); tinted: white | iOS rounds the corners and draws the glass itself. The macOS app is on macOS 15, so it keeps the PNG icon above. |
iOS: launch screen (LaunchMark, 96 pt) and the privacy cover | The enamel tile on the paper colour; the cover has the wordmark | Paper #F3F1EC light, #14130F dark | The first frame, and what the app switcher shows when the scene is not active (DESIGN 14.4). |
iOS: start screen, “starting” screen (Wordmark, 40 and 44 pt in Views/Brand.swift) | The wordmark | Cursor block T, keyhole solid paper | The brand moment of the app. Besley is bundled (UIAppFonts). |
| Safari app extension | Framed | Same as the Chrome toolbar icon (icon-N.png, from the same build) | One source. The appex has no icon of its own. |
The semantic key icon (i-key: Keys page, approval dialog, “approval: each use” badge) is not the logo. Keep it.
Files and generator
- Source of truth:
brand/tokens.json(palettes, neutrals, geometry constants, rendering numbers). Do not edit a brand colour in another file. - Generator:
brand/cmd/lasbolt-brand(Go, standard library only). It has a supersampled anti-aliased rasteriser with gradients, alpha compositing and a Gaussian blur. The same code makes every output. make brandwrites the committed files.make brand-checkmakes them in memory and fails on any difference or failed contrast check.make logoandmake logo-checkare old names for them. A generated file has the header “Generated by make brand from brand/tokens.json. Do not edit.” A hand-written file has marked regions:/* brand:begin NAME */and/* brand:end NAME */. The generator replaces only the lines between them.- Generated, committed:
docs/logo/*.svg;apple/LasboltiOS/AppIcon.icon/(the layered iOS icon);site/favicon.svg;server/internal/web/static/favicon.svg,favicon-32.png,apple-touch-icon.png;server/internal/web/templates/logo.html; the regions inserver/internal/web/static/lasbolt.css,extension/popup.css,extension/content.jsandsite/index.html;apple/LasboltKit/Sources/LasboltKit/BrandColors.swift; on Androidvalues/brand_colors.xml,ui/BrandColors.kt,drawable/ic_launcher_background_gradient.xml,ic_launcher_foreground.xml,ic_launcher_monochrome.xmlandsplash_wordmark.xml; the previewsdocs/brand/preview.htmlanddocs/brand/palettes/<name>/for every palette (theicon-*.pngrenders there needictool). - Built, not committed: the PNG icons of the extension (
make extension, indist/), and the PNG and SVG files of the Apple asset catalogs (make apple-assets, whichmake apple-projectandmake ios-projectrun first). TheContents.jsonfiles of the catalogs are committed..gitignorehas the generated files. The popup and the inline button take the path from the marks@LOGO_PATH@and@LOGO_VIEWBOX@, which the extension build replaces. No file has a copy of the digits. - The splash wordmark has the letters as outlines (
brand/internal/brand/data/wordmark-text.path: Besley Bold 700, 2000 units per em, y down). They came from the font once. The cursor and the keyhole are made fromtokens.json. - A PNG in the check may differ by 1 in a color value (the floating point math can differ between CPUs).
- A change of the shape is a change of this file and of
brand/internal/brand/geometry.go. Then runmake brand.