ONE DESWIK v1.0.0

Design System Foundations

How our software applications look, behave and feel across the product suite — providing a unified, familiar experience for planning, production and reporting tools.

Principles

Our key UX principles we must abide by for our customers' benefit.

Clarity over complexity

Reveal only what is relevant, gradually displaying complexity progressively when required.

Consistency builds confidence

The same action, agnostic of application or service, must behave the same way.

Efficiency under pressure

Beyond minimising clicks — reduce friction and pain points wherever possible.

Safety by design

Always ensure users are clearly informed of destructive and irreversible actions.

Transparency in feedback

Always display visually what the system is doing. Never hide important information in the background.

Tone & Personality

At Deswik we strive for a professional and calm digital presence, reflective in our software and how it is designed and how it functions. Our users perform precise, data-driven actions and our solutions should aid them as best as possible.

Because our users work abroad, we avoid internal jargon and slang that is not industry-wide knowledge. We use clear and direct language when our systems communicate on our behalf.

Naming

The names we give CSS variables, design tokens, and components have to survive growth, redesigns, and new features. Four priorities drive every naming decision; a single structure pattern keeps tokens predictable; and a small list of preferences resolves the recurring "which word do we use" debates.

Priorities

Semantics

Names should explain what something does or represents, not just how it looks. Don't lock meaning to appearance — appearance changes; meaning shouldn't have to.

Consistency

The same concept gets the same name everywhere — across CSS, Figma tokens, component classes, and product code.

Growth

The naming system has to survive new features, redesigns, and new themes without forcing a global rename.

Searchable

Prefixes matter. A name should be findable by category, with theme expressed either in the name itself or in the grouping it sits in.

Structure

Token and class names follow a consistent left-to-right pattern, narrowing from broad to specific.

--{category}-{property}-{variant}-{state}-{size modifier}

Examples

--validation-toast-success-bright

--button-danger-hover-small

--field-number-focus

Categories

buttons color field text validation space size scale

Rules

  • All lower case.
  • Keep Figma design tokens and CSS names the same — one source of truth, two surfaces.
  • Prefer full words over abbreviations: background not bg; button not btn.

Preferences

When two reasonable words mean the same thing, we pick one and stick with it. The chosen term is in bold.

Concept Candidates Use
Spacing spacing · space · gap · padding · margin · size space (between objects) and size (of the object itself)
Colour hierarchy active · primary · accent brand, then primary / secondary / tertiary, then active
Corner radius radius · corner-radius · border-radius border-radius
Foreground colour color · fill color
Validation — bad error · danger danger
Validation — caution warning · caution warning
Validation — good success · positive success
Validation — neutral information · neutral info
Validation — partial — incomplete
Form control input · field field

Theme & Consistency

  • Always design in light theme first.
  • Allow users to switch between light, dark, or system preference.

Colors

Our target is WCAG 2.x AA contrast across the whole system — accessible, readable, and inclusive interfaces regardless of theme. The ratio you need depends on what the colour is doing.

4.5:1
Body text

The quick brown fox jumps over the lazy dog.

Paragraph copy, table cells, helper text — anything below 18 px.

3:1
Large text

Large text — 18 px+

18 px and above, or 14 px bold — headings, hero copy, callouts.

3:1
UI components & graphics
Approved

Icons, chips, borders, focus rings, status pills, and form-control outlines.

Product / accent colour

The product (or accent) colour changes per product. It carries the product's visual identity — brand chrome, hero accents, the product glyph — without touching any of the system's interactive states. Two examples shipping today:

NOVA#00AB61
MDM#7B2CBF
CAD#F38746
OPS#3D9BEA

Greyscale

Scales are generated from lightness values at 98, 96, 94, 90, 85, 80, 60, 40, 20 and 10. The active color can be used on backgrounds of --gray-1 and --gray-2. Backgrounds of --gray-3 and higher will fail contrast without shading the active color.

Background--background
Gray 1--gray-1
Gray 2--gray-2
Gray 3--gray-3
Gray 4--gray-4
Gray 5--gray-5
Gray 6--gray-6
Gray 7--gray-7
Gray 8--gray-8
Gray 9--gray-9
Gray 10--gray-10

Usage notes

The first six steps build surfaces, fills, hovers and borders — the architecture the page is constructed from. The last four steps carry text, stepping from quietest helper copy at --gray-7 to the highest-contrast headings at --gray-10.

Surfaces, fills & borders
  • --gray-1 — Card-1 backgrounds, banded table rows, code-block fills, properties-panel and primary-nav surfaces.
  • --gray-2 — Card-2 backgrounds, default and transparent button hover, accordion hover, disabled-row fill, version-tag chip.
  • --gray-3 — Default button background, table row hover, ribbon-active fill, low-emphasis status tags.
  • --gray-4 — Tertiary button hover state.
  • --gray-5 — Tertiary button focus, slider and toggle tracks, light dividers.
  • --gray-6 — Standard border colour for inputs, cards, dividers, the close-button icon at rest.
Text colours
  • --gray-7 — Muted / secondary text — captions, helper copy, placeholder text, chart axis labels, file-list metadata.
  • --gray-8 — Stronger muted text — toolbar icons, sidebar nav labels, scrollbar thumb, hover state on close-button icons.
  • --gray-9 — <h2> / <h3> headings, the link :hover colour, code-pill text, axis values.
  • --gray-10 — Highest-contrast text — <h1>, the weighted headings <h4>–<h6>, button hover text, site title.

Active

The active colour signals interactivity — buttons, links, form-control states (checkboxes, radios, focus rings). Because no single hue holds 4.5 : 1 against every possible background, the active colour is shaded for its specific role: one tone for the resting state, one for hover, one for focus, and a separate tone for active text shown on a selected background.

Active--active
Active Hover--active-hover
Active Focus--active-focus
Active on Selected--active-on-selected

Usage

  • --active — Buttons, links and form-control resting state. Light: #1676d6. Dark: #1676d6.
  • --active-hover — Button / link hover. Light: #1260ae. Dark: #1260ae.
  • --active-focus — Button / link focus. Light: #0f4f8f. Dark: #0f4f8f.
  • --active-on-selected — Active text rendered on a selected background. Light: #0f4f8f. Dark: #6ca9e5.

--active-primary remains as an alias for --active — it's the token to reach for when you specifically need the contrast-safe variant for white text on an active-coloured background (the Primary button).

Validation — three variants

Pick whichever suits your application best. You can use the validation classes for general text highlighting, but use .warning-text rather than .warning as the warning colour does not pass contrast on light backgrounds.

Validation text colors

You can use the validation classes for general text highlighting, but use .warning-text as opposed to .warning as the warning colour does not pass contrast rules on light backgrounds.

Incomplete — .incomplete-text

Info — .info-text

Success — .success-text

Warning — .warning-text

Danger — .danger-text

Colourful

Incomplete — fields awaiting input.
Info — supporting context.
Success — your changes were saved.
Warning — review before proceeding.
Danger — operation failed. Try again.

Plain

Incomplete — fields awaiting input.
Info — supporting context.
Success — your changes were saved.
Warning — review before proceeding.
Danger — operation failed. Try again.

Bright

Incomplete — fields awaiting input.
Info — supporting context.
Success — your changes were saved.
Warning — review before proceeding.
Danger — operation failed. Try again.

Typography

Headings are sized proportional to the base text size. Line heights are calculated at 1.25× the font size and may be rounded to the nearest pixel if fractional sizes are not supported.

Headings

Heading 1 — Display

Heading 2 — Section

Heading 3 — Subsection

Heading 4 — Group

Heading 5 — Label
Heading 6 — Micro

Font size modifiers

Font bigger — .font-bigger

Font big — .font-big

Default body text — base size.

Font small — .font-small

Font smaller — .font-smaller

Font weights

Light weight (200) — .font-light

Regular weight (400) — .font-regular

Semibold weight (600) — .font-semibold

Bold weight (700) — .font-bold

Inline text

Use strong or bold to highlight specific words. Use links for navigation. Use inline code or samples in monospace. Subscript H2O and superscript E = mc2.

Date & time formats

Unless specified otherwise, display dates and times in the local format. The standard user-facing format is MMM DD, YYYY, HH:MM AM/PM — identified as the fastest to scan visually.

For tables, lists, and anywhere dates appear stacked, the digits must line up by column even when the dates themselves vary. The cleanest way to do that without breaking out of the page font is font-variant-numeric: tabular-nums: it keeps Inter as the family but engages the font's tabular-figure OpenType feature, so every digit takes the same advance width. The result reads as ordinary body text yet every comma, colon, and AM/PM lands in the same horizontal column down the list.

Don't — proportional digits
Jan 01, 2023, 09:05 AM
Mar 17, 2023, 11:28 AM
Aug 08, 2024, 02:30 PM
Dec 31, 2024, 10:00 PM
Feb 04, 2025, 12:45 PM
Sep 22, 2025, 05:00 AM

Inter's proportional digits make 1 narrower than 0 — every comma, colon, and meridiem token drifts row to row.

Do — tabular-nums (still Inter)
Jan 01, 2023, 09:05 AM
Mar 17, 2023, 11:28 AM
Aug 08, 2024, 02:30 PM
Dec 31, 2024, 10:00 PM
Feb 04, 2025, 12:45 PM
Sep 22, 2025, 05:00 AM

Same Inter family as the rest of the page — only the digit width has changed. The time portion locks to a perfect column.

One caveat: the MMM month abbreviation is still proportional (Jan, Mar, and Sep have different widths in Inter), so the comma after the day number can shift a pixel or two between rows. For columns where perfect start-to-end alignment is non-negotiable — reconciliation tables, audit logs, batched timestamps — use a numeric format like YYYY-MM-DD HH:MM or MM/DD/YYYY HH:MM AM/PM with tabular-nums. Every character then comes from the digit set or fixed punctuation.

Implementation

Apply font-variant-numeric: tabular-nums on the cell, the column's td rule, or use the existing .tabular-nums utility from the product layer. The foundation already wires this on td.num and th.num in the Tables & Grids section, so the «Tonnes» and «Grade» columns there are already tabular without any per-cell styling.

Code

Code snippets and inline formulas use Fira Code — a monospace family with programming ligatures for the arrows, equality signs, and comparison glyphs that engineering input contains. The generic monospace keyword is the fallback, so terminals, embedded views, and offline contexts still render with a fixed-width family when Fira Code isn't available.

Example — formula

IF([AU-Grade] > 2.5 & [AU-TONNES] > 50000, ABS([RECOVERY] - 0.92) < 0.05 & [STRIP-RATIO] < 4)

Snippet — declaration

code, samp, kbd, pre {
  font-family: 'Fira Code', monospace;
}

Full typography stack — @font-face declarations

The four font families used across the system are loaded locally via @font-face so the visual identity stays consistent regardless of the user's network or device font availability. Inter is the variable body face, Fira Code carries monospace contexts, Noto Serif SC handles Simplified Chinese, and Sandvik Sans is reserved for Sandvik-branded surfaces.

@font-face {
  font-family: 'Inter';
  src: url('Inter-VariableFont_opsz,wght.ttf') format('truetype');
  font-weight: 100 900;
  font-stretch: 50% 100%;
  font-display: swap;
}
@font-face {
  font-family: 'Fira Code';
  src: url('FiraCode-Regular.ttf') format('truetype');
  font-weight: 400;
  font-display: swap;
}
@font-face {
  font-family: 'Noto Serif SC';
  src: url('NotoSerifSC-Regular.ttf') format('truetype');
  font-weight: 400;
  font-display: swap;
}
@font-face {
  font-family: 'Sandvik Sans';
  src: url('SandvikSans-Regular.ttf') format('truetype');
  font-weight: 400;
  font-display: swap;
}

Font-family utility classes

Each face is reachable as a utility class so non-default contexts (a code block in a marketing page, a Chinese-language heading inside an English page, a Sandvik co-branded panel) can opt in without rewiring the whole element tree.

body, .font-body {
  font-family: 'Inter', sans-serif;
}
code, samp, kbd, pre, .font-code {
  font-family: 'Fira Code', monospace;
}
.font-chinese {
  font-family: 'Noto Serif SC', serif;
}
.font-sandvik {
  font-family: 'Sandvik Sans', sans-serif;
}

Special cases

When typography needs to display content in a language whose characters aren't well-served by Inter, switch to a face designed for that script. The default body font handles Latin glyphs cleanly but can't represent ideographic or other non-Latin scripts authentically — using a face designed for the script keeps the strokes, proportions, and visual rhythm that native readers expect.

For Simplified Chinese, the system uses Noto Serif Simplified Chinese (Google Fonts: Noto Serif SC) — a serif designed specifically for the character forms of simplified Chinese. Its stroke contrast and proportions reflect the script's construction in ways a Latin-first family cannot. Mark up the affected content with lang="zh-Hans" and the foundation's :lang(zh-Hans) rule swaps the family in automatically.

Example — Simplified Chinese

矿山规划设计系统

使用 Noto Serif 简体中文呈现汉字时,笔画结构和字形比例能够更加清晰准确地表现出来,适合阅读密集的内容。

Snippet — declaration

:lang(zh-Hans) {
  font-family: 'Noto Serif SC', serif;
}

For Sandvik branding, use Sandvik Sans — Sandvik's own corporate sans-serif. Apply it to surfaces that carry the Sandvik visual identity (co-branded pages, partner widgets, equipment displays). The generic sans-serif keyword is the fallback, so machines or kiosks without the licensed font still render cleanly. Mark the affected element with data-brand="sandvik" and the foundation's [data-brand="sandvik"] rule swaps the family in automatically.

Example — Sandvik branding

Sandvik · Mine Planning Toolkit

Surfaces that carry Sandvik's visual identity render in Sandvik Sans. The fallback sans-serif keeps the type legible when the licensed font isn't available on the device.

Snippet — declaration

[data-brand="sandvik"] {
  font-family: 'Sandvik Sans', sans-serif;
}

Scale

Sizing and spacing are foundational layout primitives, but they describe different things: sizing is the dimensions of an element (icon size, font size, component height), while spacing is the gap between elements (gap, padding, margin). They share a numeric scale so the values feel consistent, and at the call site they appear under two parallel token names — --size-N for the dimension of a thing, --space-N for the breathing room between things.

When a product only ever needs three to five values per role, an optional set of t-shirt aliases (--gap-sm, --padding-md, --margin-lg, etc.) is documented under Add Ons → Spacing Variables.

The scale

--size-1px
—1 px
--size-2px
—2 px
--size-1
0.25rem4 px
--size-2
0.5rem8 px
--size-3
0.75rem12 px
--size-4
0.875rem14 px
--size-5
1rem16 px
--size-6
1.25rem20 px
--size-7
1.5rem24 px
--size-8
1.75rem28 px
--size-9
2rem32 px
--size-10
2.5rem40 px

Special case — borders. Borders use fixed pixel values (--size-1px, --size-2px) for visual precision. A rem-based 1 px border can blur or vanish at certain zoom levels; a pixel value renders the same hairline on every device.

Sizing — element dimensions

Reach for --size-N when the value describes the element itself — its font size, icon size, height, or border width.

Typography
  • --size-3 — <h6>; smaller default font size for model-space applications.
  • --size-4 — Base text size, <h5>.
  • --size-6 — <h4>.
  • --size-7 — <h3>.
  • --size-8 — <h2>.
  • --size-9 — <h1>.
Icons, components & borders
  • --size-1px — Standard border width (table cells, dividers, input borders).
  • --size-2px — Heavier border (table-header underline, focus rings).
  • --size-3 — .icon-sm.
  • --size-4 — Default icon size (.icon-md).
  • --size-7 — Sidebar / navigation icons (.icon-lg).
  • --size-10 — Feature-card icons.

Spacing — between elements

Reach for --space-N when the value is the gap, padding or margin around an element. Same numeric values as --size-N; the parallel name signals layout intent at the call site so a reviewer can tell a gap from a font-size at a glance.

Token rem px Typical use
--space-1px — 1 Fixed pixel space.
--space-2px — 2 Fixed pixel space.
--space-1 0.25 4 Data-grid padding.
--space-2 0.5 8 Input / button padding.
--space-3 0.75 12 Field and input gaps.
--space-4 0.875 14 Equivalent to text size.
--space-5 1 16 —
--space-6 1.25 20 —
--space-7 1.5 24 —
--space-8 1.75 28 —
--space-9 2 32 Body / large component padding.
--space-10 2.5 40 Feature-card padding.

When using these in Figma files, use pixels; in production code, prefer the relative rem values so the layout scales with the user's root font size.

Size modifiers

Size modifiers scale a whole component while preserving its proportions — the height, internal padding, font size and icon size all step together. Apply them to entire components (buttons, inputs, cards), not to individual properties.

  • Extra small (x-small) — dense surfaces (data grids, toolbars).
  • Small (small) — secondary actions, compact lists, side panels.
  • Medium (medium) — the default for almost everything; buttons in forms, page-level controls.
  • Large (large) — primary call-to-action on a hero or empty state.
  • Extra large (x-large) — feature cards, marketing surfaces, single-action splash screens.

Font size modifiers

Where the size modifiers above scale a whole component, font size modifiers scale a single piece of text relative to the element's own base size. They drive the same --font-size-scale variable that the foundation uses internally for headings, so a piece of text inside a heading still scales proportionally rather than jumping to a fixed pixel value.

.text-x-small — 0.75 × the element's base size.

.text-small — 0.875 × the element's base size.

Default body text — 1 × the element's base size.

.text-large — 1.25 × the element's base size.

.text-x-large — 1.5 × the element's base size.

  • .text-x-small — fine print, hint copy, captions in dense surfaces.
  • .text-small — secondary copy, helper text, table footnotes.
  • .text-large — emphasised body text, lead paragraphs in articles.
  • .text-x-large — pull quotes, hero subheads beneath an <h1>.

Reach for --font-size-scale directly only when none of the four modifier classes fits. Otherwise use the named class so the value stays anchored to the t-shirt scale shared with component size modifiers.

Tables and Data Grids

Table — used when space is available, visual display is more important and when data has a complex structure. Data grid — used when high density is needed, with inline editing as a key feature, where Excel would be a substitution.

Table (banded, with row states)

Block Material Tonnes (t) Grade (g/t) Dimensions Status
BX-01Ore 12,450.002.45 100 × 80 OK
BX-02Ore 9,820.503.10 100 × 80 Reviewing
BX-03Waste 21,300.000.15 120 × 90 Check
BX-04Waste 8,775.250.08 100 × 80 Failed
BX-05Ore 15,612.752.90 110 × 85 OK

Data grid (high density)

IDDescription Length (m)Width (m) Depth (m)Volume (m³) Status
D-001Drift heading north128.405.505.203,672.18OK
D-002Cross-cut east42.104.804.80970.30Warning
D-003Stope access88.655.505.202,536.95Danger
D-004Return airway204.003.503.502,499.00Info
D-005Service decline312.756.005.5010,320.75Incomplete

Alignment rules

  • Numerical data is right-aligned. Textual data is left-aligned. Headers align with their data.
  • Use center alignment for small controls — checkboxes, validation icons, numbered rows.
  • Multi-part values (e.g. 100 × 80) align by the separator; match decimal places.
  • Include the unit in the header so it isn't repeated in every cell.
  • Use font-variant-numeric: tabular-nums for clean number alignment.

Clickable cell text

When a cell value navigates to a record's own page, render the text in --text-color by default and only colour it on hover. A row of clickable cells in their default --active state competes with chips, status pills, and the row's own selection state for attention; pulling the colour back to body text keeps the table calm and reserves the active colour for the moment of intent.

Example

Schedule Owner Status
Pit West — Schedule v3 Jane Smith Approved
Pit East — Schedule v2 Marcus Khan In review
Combined — Schedule v1 Avani Barr Draft

Hover any name to see the link colour and underline appear; the cell stays neutral the rest of the time so the chips and selection state read first.

Snippet — declaration

table td a {
  color: var(--text-color);
  text-decoration: none;
}
table td a:hover {
  color: var(--active);
  text-decoration: underline;
}

Buttons

Button contents may include icons and text. As a general rule, contents should not wrap onto multiple lines. Each variant has states for: enabled (default), hover, focus and disabled.

Variants

With icons

Icon inherits the button's text colour, sized at --size-4, with a --size-2 gap from any text — all from the foundation button rule.

States

Default
Primary
Secondary
Danger

Usage

  • Primary — main call to action in forms and pages.
  • Secondary — Cancel and Close actions; should never require a disabled state.
  • Transparent — menus, tabs, table sorting, filtering — blends with page layout.
  • Danger / Error — destructive actions; usually placed last in a menu to avoid accidental clicks.

Form Inputs

Form inputs are minimally styled — browser defaults control the main appearance. Inputs and buttons share the same height for visual consistency. Inputs should be sized to the content they accept. Labels are inline with fields, right-justified, and linked via for/id.

Ore
Waste
Backfill
Overburden
Stockpile
Low-grade ore
Notifications
Risk level

Cards

Card containers group content. Use .card-1 or .card-2 for tinted backgrounds.

Default card

A simple container — no background tint.

Card 1

Tinted with --gray-1 for subtle separation.

Card 2

Tinted with --gray-2 for stronger separation.

Page Layouts

Two primary page layout variants for product UIs.

Top header & navigation layout

Provides navigation in the top header without a side navigation. Allows native display with labels, without taking up additional space. The header consists of the site title, switchable account/company control, and a menu of transparent buttons (collapsible to icons).

Side navigation layout

Familiar app-style side navigation in a collapsible menu. Click expand to show page titles — the state should persist across pages and sessions. Long company or user names should display outside the <nav> component.

Layout templates

App shell — 56px sidebar · 48px top · main · 280px right
Web shell — 48px top · main (flex) · 280px right (optional)

Icons

Icons are a visual representation of a function or message that helps reinforce it. They act as accelerators for advanced users who can recognise the symbol without reading the accompanying text.

Purpose and philosophy

  • Icons should support the meaning, not replace it.
  • Use icons to reinforce familiar, unambiguous actions or statuses where the symbol is widely understood and adds speed or clarity.
  • If an icon does not meaningfully improve recognition or scanability, do not include it — rely on text instead.
  • Do not use icons just because there is space, or to make a UI appear more interesting. Icons must serve a purpose.

Structure

Use <i> tags with Font Awesome classes. Always include .fa-fw so icons share a fixed width and align cleanly when listed, stacked, or paired with text.

<i class="fal fa-fw fa-house"></i>

Vue and React FA packages use the same icon names with a shorthand:

Vue
<FontAwesomeIcon :icon="byPrefixAndName.fal['house']" />
React
<FontAwesomeIcon icon={byPrefixAndName.fal['house']} />

Variants

Each product may use whichever variant or combination of variants it chooses — they need only be consistent within the product.

Sample Class When to use
.fal Lightweight icons — when regular feels too bold for the surface.
.far Regular weight — preferred for most contexts.
.fas Solid — suits icons used inside buttons or for alert statuses.
.fa-sharp Do not use. Reserved — kept here for reference only.

Stacked icons

Some icons (especially validation icons) contain a cutout that shows the surface colour through. Stack icons to place a solid white or black backplate behind the shape, making the symbol clearer against any background.

Apply .fa-stack to the parent element of the two icons, and add .fa-stack-1x or .fa-stack-2x to the icons themselves to size them within the stack.

Warning — black backplate
<span class="fa-stack">
  <i class="fa-solid fa-triangle fa-stack-2x black"></i>
  <i class="fa-solid fa-triangle-exclamation fa-stack-2x warning"></i>
</span>
Success — surface backplate
<span class="fa-stack">
  <i class="fa-solid fa-circle fa-stack-2x background"></i>
  <i class="fa-solid fa-circle-check fa-stack-2x success"></i>
</span>

States, behaviours, and interactions

Icons inherit states (hover, focus, active, disabled) and behaviours / interactions from their parent component. Don't re-style icons individually — let the button, link, chip, or row that hosts them drive their colour and feedback.

App and Model Space Considerations

General app considerations

  • Handling files generically: create new, open, see recent, save, save as, share, download, search, comment, see activity/details, export.
  • Generic header: consistent use of the main app icon, primary icons and other elements; show submenus, validation or functions directly from the menu.
  • In-flight validation: extending NOVA's framework — Incomplete / Info / Warning / Error / OK.

Modal space considerations

  • Icon library: CAD's extensive icon library reflects desktop heritage; a reduced palette or thematic colours may suit a modern cloud platform while reusing Suite content for familiarity.
  • Layer tree / object browser: common functions and layouts for hierarchical model objects — grouping, indenting, ghosting, visibility, row options.