# Bark style guide

## Brand architecture

Bark is a family brand. Products inherit the same base style and express their
purpose through a product suffix.

The detailed inheritance contract lives in `docs/INHERITANCE_RULES.md`. Use it
when deciding what a new product must inherit, may adapt, or must avoid.

| Product | Purpose | UI display | Subtitle |
| --- | --- | --- | --- |
| `barkone` | Personal cabinet | `barkone` | `Личный кабинет` |
| `barkmon` | Monitoring | `barkmon` | `Мониторинг` |
| `barkops` | Support operations | `barkops` | `Операции поддержки` |
| `barkadmin` | Internal admin tools | `barkadmin` | `Админка` |
| `barkhr` | People operations | `barkhr` | `Персонал` |
| `barkledger` | Financial reporting | `barkledger` | `Финансы проектов` |
| `barkstock` | Warehouse and inventory | `barkstock` | `Склад` |

Rules:

- `bark` is the stable family prefix.
- The product suffix (`one`, `mon`) is the accent part.
- UI lockups are lower-case and no-space.
- The product subtitle explains the context.

## Logo system

Core mark: a **monochrome `b`** (vertical stem + round bowl), white on the dark ink
tile. The accent (`#0d8f9c`) is carried by the **product suffix**, not by the mark —
the bowl counter is the background showing through, not a coloured dot.

Two renderings of the same `b`, chosen by size:

- **Family favicon / small mark** (`assets/favicon.svg`, `assets/mark.svg`): a geometric `b`
  (stem + ring), monochrome white — crisp down to 16px, needs no font.
- **Product favicon** (`products/bark-<m>/assets/favicon.svg`): the same geometric `b`, but the
  **bowl is filled with the product colour** so a strip of tabs is told apart — see below.
- **App icons & lockups** (`pwa-icon.svg`, `logo-lockup.svg`, apple-touch): the `b` is
  **typeset in Red Hat Display** (bold), with the module word in the product colour beneath.
  Rasterise to PNG with the font installed (the shipped icons are baked via headless Chrome).

Use:

- mark tile on dark ink background, mark in white
- `bark` in ink or white, directly followed by the suffix
- product suffix in the product colour (`one`, `mon`, …); for `barkone` that colour is the accent
- subtitle in muted/faint text

Avoid:

- all-caps brand names
- spaced UI wordmarks such as `bark one`
- dot separators such as `bark·one`
- colouring the whole `b`, or stretching/skewing it (the favicon bowl colour is the one
  intentional exception — see below)
- making the whole wordmark turquoise

### One geometry, one tile radius

The geometric `b` has a **single source**: `assets/mark.svg` (stem `rect x20 w7.6 h36.5 rx3.2` + bowl
ring path, 64 viewBox). Every other asset reuses that exact stem + bowl: `favicon.svg` + `mark.svg`
keep the white ring (counter = background); product favicons fill the bowl with a **solid
product-colour disc** (the 16px tab key); every `logo-lockup.svg` + the brand book reuse it too. The tile corner radius is **`round(0.22 × side)`** everywhere (favicon `rx14`, app icon `rx113`,
lockup tile `rx16`) — never a hand-picked value.

![bark logo: clear space + variants](assets/logo-rules.png)

### Clear space & minimum size

- **Clear space:** keep at least **0.5 × the tile height** clear on every side of the mark/lockup — no
  type, edge, or other element may enter it.
- **Minimum size:** the tile floor is **16px**. At or below 16px use a favicon (`favicon.svg` or the
  product favicon) only — **never** the text lockup — and never render the geometric bowl counter below ~14px.

### Variants

- **Default:** white `b` on the dark ink tile (gradient `#1d2733 → #14181f`).
- **Inverse:** ink `b` (`#14181f`) on a solid light tile — for dark backgrounds/documents.
- **Mono / 1-colour** (`assets/mark-mono.svg`): tile-free, `currentColor` — for print, embossing,
  watermark, single-colour media. Fill ink on light, white on dark; never the gradient, never an accent.
- **On a photo / colour surface:** never place the mark bare — set it on a solid `--ink` (`#14181f`)
  plate with ≥16px padding (the inverse white-tile variant only on solid light fills), so contrast holds.

### Product colour (tab differentiation)

![bark service favicons](assets/favicon-services.svg)

A browser strip full of `barkone` / `barkmon` / `barkpay` tabs must be readable at a glance, so
**each product owns one colour**. It fills the **favicon bowl** (the 16px tab key) and the
**module word** in app icons and lockups. The family mark, dark tile, and `bark` wordmark stay
identical — only the colour changes. The neutral family favicon (`assets/favicon.svg`) stays
monochrome: it represents the family, not a product.

| Product | Colour | · | Product | Colour |
| --- | --- | --- | --- | --- |
| `barkone` | `#0d8f9c` teal | · | `barkops` | `#7c4dd6` violet |
| `barkmon` | `#2f6fed` blue | · | `barkhr` | `#e0871f` amber |
| `barkpay` | `#1f9d63` green | · | `barkcrm` | `#d6457e` magenta |
| `barkadmin` | `#d6a100` yellow | · | `barkledger` | `#164a2f` forest green |
| `barkstock` | `#61762f` olive | · |  |  |

- `--accent` (`#0d8f9c`) stays the **active / hover / KPI** colour in EVERY product — never wire it
  to the product colour. The product colour is used ONLY for the favicon bowl and the module word.
- New products take the next free colour; **do not reuse a status colour** (`ok`/`warn`/`bad`).
- Keep each product colour as distinct as practical from every other product colour and from the
  dynamic-favicon status colours (`ok`/`warn`/`bad`) — **aim for ≥25° hue / ≥10 ΔE** so 16px tabs
  stay apart. Known, accepted closenesses: `barkpay` green meets `ok` green only in `barkmon`'s
  transient dynamic-favicon state (a momentary signal, not a fixed identity); `barkadmin` yellow sits
  in the same amber family as `warn` but reads apart as a tab. `info` (`#2a6fdb`) is a **non-tab
  secondary text blue**, not a favicon colour, so it is exempt from tab-distinctness even though it is
  close to `barkmon` `#2f6fed`.
- PWA `theme_color` = the product colour (so installed apps + the mobile status bar differ);
  `background_color` stays `#eef0f4`. The generator writes this into the product manifest.
- Source of truth: `tokens/brand.tokens.json` → `productColors` (+ `product.<m>` for the subtitle).
  Generate with `npm run make:product -- <module>` — colour and subtitle are looked up from tokens
  and the generator **errors** if they are missing (it never guesses). Pass `<subtitle> <#color>`
  only for a brand-new product not yet in tokens.
- **Wiring is part of the rule.** The app's `<head>` inlines the generated
  `products/bark-<m>/favicon.head.html` (or `templates/favicon.head.html` filled by hand) — SVG
  icon, PNG fallback, apple-touch, manifest, `theme-color`, in that order. Icons are never
  hand-drawn: `favicon.svg`/`manifest` come from the generator, PNGs are rasterised from
  `pwa-icon.svg`, and stale icons (old `favicon.ico`, framework defaults) are removed. A favicon
  is accepted only when all five acceptance points in the head template hold.

**Dynamic favicon.** A favicon may be *dynamic* — its bowl colour reflects live state instead of a
fixed product colour. `barkmon` is the example: green (`#15a06a`) when all systems are ok, red
(`#e23d52`) on an incident. Ship one SVG per state (`favicon.svg` = ok, `favicon-alert.svg` = alert)
and swap the `<link rel="icon">` at runtime — see `templates/dynamic-favicon.snippet.js`. The dark
tile and white stem stay identical; only the bowl changes. A product's brand colour (app icon,
lockup) is unaffected — barkmon stays blue there.

**No fitting colour? Ask.** When a new product has no suitable colour in the palette, **ask the
owner which colour to use for the favicon** — do not guess or silently grab a status colour.

## Color tokens

| Token | Hex | Use |
| --- | --- | --- |
| `accent` | `#0d8f9c` | active states, default `barkone` suffix, key highlights |
| `banner` | `#16386e` | deep-blue hero / banner gradient base |
| `ink` | `#14181f` | primary text, dark tile, dark surfaces |
| `ink-2` | `#3a4150` | secondary headings, icons |
| `muted` | `#6a7180` | helper text, subtitles |
| `faint` | `#98a0ae` | labels, meta text |
| `bg` | `#eef0f4` | app background |
| `surface` | `#ffffff` | panels and content areas |
| `surface-2` | `#f7f8fb` | raised/quiet surface |
| `field` | `#f5f6fa` | input / field fill |
| `chip` | `#f0f2f7` | chips, quiet pills |
| `sidebar-bg` | `#fafbfc` | sidebar background |
| `line` | `#e6e8ee` | borders and dividers |
| `line-2` | `#eef0f4` | subtle inner dividers |

Status colors (live cabinet names in brackets):

- success / `ok` `#15a06a`
- warning / `warn` `#cf850f`
- danger / `bad` `#e23d52`
- info `#2a6fdb` (optional secondary blue; the cabinet itself uses `banner` for hero blue)

Soft tints used for chips, active nav, and status pills are derived from the base via
`color-mix` — e.g. `--accent-soft`, `--ok-soft`, `--warn-soft`, `--bad-soft`. The KPI
highlight system (`--kpi`, `--kpi-soft`, `--kpi-banner`) defaults to the accent. Elevation
uses three shadow tokens: `--shadow-card`, `--shadow-pop`, `--shadow-up`. See `tokens/brand.css`.

## Typography

> **IBM Plex Mono — числа, Onest — интерфейс, Red Hat Display — логотип.**
> This role assignment is fixed and must be visible in onboarding and AI instructions.

- Logo only: Red Hat Display, weights 500-800. It typesets Bark wordmarks and
  branded lettering in app icons/lockups; never use it for interface headings.
- Interface: Onest, weights 400-700, including H1/H2 and all other headings.
- Data: IBM Plex Mono, weights 400-600.

Guidance:

- Keep dashboard headings compact.
- Use strong weight rather than oversized type inside tools.
- Use mono only for data-like values, not for general prose.

### Wordmark sizes (pin these)

The wordmark is **always Red Hat Display** — `bark` at weight 800, the module suffix at 600 in
the product colour, subtitle in Onest 700, uppercase, `letter-spacing 0.05em`, faint. The module
colour comes from `--logo-module` (CSS `.bark-logo__module`), which each product sets to its product
colour on the lockup (`style="--logo-module: <productColor>"`); it falls back to `--accent`, so
`barkone` (whose product colour is the accent) and any unconfigured lockup stay correct — `--accent`
itself is never rewired and stays the active/hover/KPI colour in every product. Do not pick
ad-hoc sizes — use one of these tiers (`tokens/brand.tokens.json` → `wordmark`; CSS
`.bark-logo` + `--xl`/`--md`/`--sm`, default = `lg`):

| Tier | Where | Tile | Wordmark | Subtitle |
| --- | --- | --- | --- | --- |
| `xl` | large in-page lockup / hero | 48px | 26px | 11px |
| `lg` | desktop sidebar (default) | 32px | 18px | 10px |
| `md` | mobile header | 28px | 15px | 9px |
| `sm` | compact / inline | 24px | 13px | — |

The exported `logo-lockup.svg` asset is bigger (tile 72 / word 36 / subtitle 11) — that is the
print/marketing lockup, **not an in-product size**.

> **The product sidebar lockup is `lg` (tile 32 / word 18 / subtitle 10)** — this matches the live
> `barkone` cabinet. Use the same `lg` for **every** product sidebar (barkmon, barkops, …). Do **not**
> use `xl` and do **not** drop the 72px export `logo-lockup.svg` straight into a sidebar — that makes a
> product lockup look oversized next to the rest. (The cabinet renders the lockup as one parameterised
> size where the «b» = 0.74 × tile; keep the whole lockup on one tier, don't mix sizes.)

## Interface style

The system should feel operational, calm, and clear.

- Backgrounds are light gray, not pure white everywhere.
- Panels use white or near-white surfaces with restrained borders.
- Active navigation uses a light accent tint and accent text.
- Metrics and monitoring views should be dense enough to scan — «dense» is not a
  mood, it is the pinned numbers in §Page shell & density below.
- Empty states should be useful and short (`.bark-empty` in §Page shell & density).
- Avoid decorative blobs, heavy gradients, oversized marketing heroes, and
  generic stock-like visuals.

## Page shell & density

Density is a **brand constant**, not a per-page choice — this is what makes two
Bark screens feel like one product. Spec: `tokens/brand.tokens.json` → `layout`,
`density`, `table`, `kpi`, `emptyState`; CSS `.bark-main`, `.bark-grid`,
`.bark-page-header*`, `.bark-panel__*`, `.bark-table`, `.bark-kpi`, `.bark-empty`.

The page skeleton of every product screen:

```text
.bark-sidebar | .bark-main
                ├── .bark-page-header   (title + meta left, tools + avatar right)
                ├── section …           (H2/H3 + .bark-panel / .bark-grid)
                └── section …
```

Pinned numbers — use these, never invent:

| Zone | Value |
| --- | --- |
| Page padding (`.bark-main`) | `24px 32px 40px` desktop, `16px` mobile |
| Gap between sections | 24px |
| Gap inside card grids (`.bark-grid`) | 16px |
| Panel header / footer | `16px 20px` / `12px 20px` |
| Panel body | 20px (dense: `12px 16px`) |
| KPI card padding | `16px 20px`; value = IBM Plex Mono 24/600 |
| Table rows | 44px (dense 36px), header 40px caption-style |
| List toolbar (`.bark-toolbar`) | `12px 20px`, controls 32px |
| Pagination row (`.bark-pagination`) | `10px 20px`, mono range counter |
| Reading pages (`.bark-main--reading`) | max-width 840px |

- **Two density modes only:** default and `--dense` (tables/monitoring). Nothing
  in between and nothing airier. A working screen never uses a gap or padding
  larger than 40px — air beyond that belongs only to empty states and auth
  screens.
- **Rule of thumb:** at 1440×900 the first screen of a dashboard shows the page
  header plus at least two rows of content. If it does not, the page is too airy —
  tighten to the table above, do not scale type up.
- Empty state (`.bark-empty`): icon 20px in a 40px `--chip` circle, title Onest
  14/600, hint 12px ≤360px wide, optional ghost `--sm` action. It fills its
  region, never the whole screen.

## Page header & identity

Every authenticated product page starts with `.bark-page-header`
(`templates/topbar.html`): the H1 (plus optional caption/meta line — values in
IBM Plex Mono with `·` separators) on the left, the utility cluster
`.bark-page-header__tools` on the right (36px ghost icon buttons, Lucide 20px).

**The identity contract (exactly one identity point per shell):**

- The employee identity lives in the **sidebar footer**: `.bark-sidebar__user` —
  40px circle avatar + name + email + icon-only logout (see §Sidebar). The page
  header carries **no avatar and no user name**.
- Photo src comes only from the current SSO session (`docs/SSO_AVATAR.md`);
  empty/error → initials from `initialsFromName()` — one formula for all
  products («Владимир Шурыгин» → «ВШ») on `--accent-soft`.
- The full name may additionally appear in the home-page greeting
  (`Добрый вечер, {имя}` + meta line) as page content — nowhere else in the
  shell.
- **`barkone` is the documented legacy exception**: the live cabinet keeps its
  top-right header avatar. New products do not copy it. If a legacy app already
  renders the Avatar elsewhere, keep that single existing placement; never two
  identity points at once.

## Motion

One motion language (`--motion-*`, `--ease-out`): hover/focus = 120ms; popover,
dropdown and modal enter = 200ms; region/page reveal = 300ms;
`cubic-bezier(0.2, 0, 0, 1)`. Transition only `color`, `background`,
`border-color`, `box-shadow`, `opacity`, `transform` — never every property at
once. `prefers-reduced-motion: reduce` disables decorative animation (loaders
already comply). Z-layers come from the pinned `--z-*` scale (sticky 20,
dropdown 600, drawer 800, modal 1000, popover 1100, toast 1200, loader 9999).

## Sidebar

The left sidebar is a **fixed brand element** — every Bark product uses the same structure, not a
bespoke nav. Spec: `tokens/brand.css` (`.bark-sidebar*`) + `templates/sidebar.html`
(`tokens/brand.tokens.json` → `sidebar`).

![bark sidebar](assets/sidebar.png)

- Width **244px**, height **100dvh**, `position: sticky; top: 0`, background
  `--sidebar-bg` (`#fafbfc`), right border `--line`, padding `20px 14px 14px`.
- **Top:** the logo lockup at `lg` size (tile + `bark`+module + subtitle).
- **Scroll:** only `.bark-sidebar__scroll` scrolls. It has `min-height: 0`,
  `overflow-y: auto`, and contains all nav groups. The logo and bottom zone never
  move and never overlap the navigation.
- **Groups:** an uppercase, faint group label (10.5px / 700 / `0.1em`) above each block of items.
- **Item:** icon (18px, `currentColor`) + label (Onest 14px, `--ink2`), padding `10px 12px`,
  radius 8px. Active = `--accent-soft` tint + accent text + weight 700; hover = `--chip`.
- **Bottom zone:** `.bark-sidebar__bottom` is fixed inside the sidebar. It contains
  a theme switch that spans the full available width, followed by the footer.
- **Footer:** the identity block first, then product + version and commit hash in
  mono. All of it remains pinned to the bottom. Author/developer attribution is
  optional and must never displace navigation or the identity block.
- **Identity block (`.bark-sidebar__user`)** — THE identity point of the shell:
  a 40px circle avatar (SSO photo; initials via `initialsFromName()` on
  `--accent-soft`), the employee name (Onest 13/600, one line, ellipsis), the
  email (Onest 11/500 `--muted`, one line, ellipsis), and the icon-only logout
  at the right end. Name and email come from the current SSO session — never
  from a local profile store.
- **Logout:** icon-only 40×40px button (Lucide `LogOut` 18px), radius 8px, at
  the right end of the identity block. `Выйти` stays as `aria-label` + `title`;
  busy state = 18px spinner + `aria-busy` (`Выходим…` as the busy aria-label).
  Default is neutral `--ink2`; hover/focus uses `--bad-soft` + `--bad`. Product
  colour never changes it. Mobile placement is the footer of the
  navigation/settings drawer, same block.

“Fixed footer” means pinned within the `100dvh` sidebar, not `position: fixed` over
the navigation. Do not make the whole sidebar scroll and do not allow the footer
or theme switch/logout to cover the last nav item.

Do not change the width, the group-label treatment, or the active-item tint per product — only the
nav contents and the product colour change.

The sidebar **owns the user identity**: the footer's `.bark-sidebar__user` block is the single
identity point of every authenticated product (see §Page header & identity). `barkone` is the
documented legacy exception with its header avatar.

## Theme — light / dark / system

Bark ships **three theme modes**, chosen with a pinned segmented switch (sun / moon / monitor):
**system** (the default — follows the OS `prefers-color-scheme`), **light**, and **dark**. Only the
neutral ramp and a slightly lifted accent change between light and dark — the mark, type, spacing
and layout stay identical.

![bark theme switch](assets/theme-switch.png)

- Dark applies by setting `data-theme="dark"` on `<html>`. Tokens swap automatically, so a component
  built on `--bg` / `--surface` / `--ink` / … needs no per-component dark CSS.
- Switch: `.bark-theme-switch` (`tokens/brand.css`); markup `templates/theme-switch.html`; behaviour
  `templates/theme.snippet.js` (persists the choice, reacts to OS changes while in system mode).
- Active segment = the raised pill (`--raised`) + accent icon. On desktop, mount
  the switch in `.bark-sidebar__bottom`; it is a three-column control and spans
  the full sidebar content width. On mobile, move the same control to the nav/settings
  sheet. Never keep two simultaneously visible or focusable copies.
- **No-flash:** inline `templates/theme.head.html` **verbatim** in `<head>` before any stylesheet —
  it sets the theme before first paint. Required, not optional.
- Dark values live in `tokens/brand.tokens.json` → `theme.dark` and are **tunable** — change the
  values, keep the structure.

## Layout primitives

- **Spacing.** Every gap and padding snaps to the 4px scale (`tokens.spacing` / `--space-*`:
  4 / 8 / 12 / 16 / 20 / 24 / 32 / 40). No in-between values.
- **Radius.** Content cards and panels use `--radius-panel` (12px); controls, chips, pills and nav
  items use `--radius-control` (8px); the logo tile uses `--radius-tile` (22%). Nothing else.
- **Headings.** `tokens.text` / `.bark-h1`–`.bark-caption`: h1 = Onest 28/700,
  h2 = Onest 20/700, h3 = Onest 15/700, body = Onest 14/400, caption = Onest
  12/500. Red Hat Display belongs only to the wordmark scale under `wordmark` —
  don't mix it into interface typography.
- **Icons.** One outline set: [Lucide](https://lucide.dev/), `stroke-width 1.7`,
  `currentColor`; **18px** in the sidebar, **20px** in content (KPI cards,
  buttons, table cells). Import icons from the official Lucide package for the
  framework in use. No filled icons, hand-drawn replacements, mixed packs, or
  mixed stroke widths.

## Components

- **Buttons** (`.bark-btn`): primary = solid `--accent` + white; `--ghost` = transparent + `--line`
  border + `--ink2`. Radius `--radius-control` (8px), font Onest 600, focus ring `--accent-soft`,
  hover = brightness +6% (ghost → `--chip`), active = scale 0.98, disabled = 0.45 opacity. **Pinned
  heights — pick one, never invent:**

  | Size | Height | Font | Padding | Use |
  | --- | --- | --- | --- | --- |
  | `--sm` | 32px | 13px | 0 12px | dense / table actions |
  | (md) | 40px | 14px | 0 16px | default |
  | `--lg` | 48px | 15px | 0 20px | forms / primary CTA |

  Buttons **hug their content** by default. `--block` = full width **only in a narrow container**
  (mobile, modal, ≤~420px) — on desktop (`≥640px`) it caps at ~360px and **never spans the screen**,
  so there's no edge-to-edge button bar. `--icon` = square icon-only (32/40/48); icon inside a button
  is 18px (20px in `--lg`).

  ![bark buttons](assets/buttons.png)
- **Status pills** (`.bark-pill--ok/warn/bad/info`): the matching `*-soft` tint + status text, radius
  999px, padding `4px 10px`.
- Active / hover / selected states reuse the sidebar + switch pattern: `--accent-soft` tint + accent
  text/icon. The base `--accent` is the same in every product (the product colour never drives states).

Loaders, charts, modals, and form controls are specified separately in
`docs/COMPONENT_RULES.md`. Those rules are part of the brand contract, not optional
examples.

## Product variant rules

When creating a new Bark product:

1. Choose a short lower-case module suffix.
2. Keep the base Bark tokens unless there is a strong product reason to add a
   secondary accent.
3. Generate product assets in `products/bark-<module>/assets/`.
4. Update app metadata and PWA manifest.
5. Keep the subtitle specific: `Мониторинг`, `Платежи`, `Операции`, etc.

Example:

```text
displayName: barkmon
module: mon
subtitle: Мониторинг
description: Monitoring and operational visibility
```
