# Praskla Technology — Brand & Design Guidelines

**Version 1.0** · Last updated: October 2026
Living document. Maintained alongside [the website](https://prasklatechnology.com). Rendered as a web page at `/design-guidelines`.

---

Praskla Technology presents itself on a white, editorial canvas carried by a single deep plum accent, stadium-pill controls, and a disciplined two-font system — Suisse Intl for headlines, Inter for everything spoken aloud. The result reads precise, engineered, and quiet: a studio that lets its work speak in a consistent voice. These guidelines define that voice for every surface of the product, and every new page, section, or component must follow them. When a rule and existing code disagree, the rule wins and the code is scheduled for migration.

---

## 1. Brand Essence

Five principles govern every decision in this document.

1. **One brand color story.** All purple tones come from the registered token set. No new hex is ever invented inline.
2. **One neutral story.** A single gray family (slate) carries all UI neutrals. Other gray families are not introduced.
3. **Tokens before literals.** Any value that repeats twice becomes a token in `globals.css` and is referenced from there.
4. **Content is localized.** Every user-facing string passes through the English or German dictionary. Untranslated copy does not ship.
5. **Motion is intentional.** Standard durations and easings only; transform and opacity animate, layout properties never.

---

## 2. Logo

The primary mark is the official Praskla logo, used in two lockups.

| Asset | Path | Usage |
|---|---|---|
| Horizontal lockup | `/images/official-logo.webp` | Navbar, footer, documents |
| Symbol mark | `/assets/logos/official.webp` | Splash, hero moments, app icons |
| Favicon | `/favicon.webp` | Browser chrome only |

Both brand assets are offered for download on the guidelines page. Client logos (Agarwood, Selma, Tipy and others) are project assets, never brand assets, and must not appear in brand guidelines.

Rules: the mark always sits on white or on brand plum; it is never recolored, never rotated, never placed on photography without the standard plum overlay. Minimum clear space equals the height of the mark on all sides. In the navbar the mark is paired with the wordmark "Praskla Technology" set in Suisse Intl bold.

---

## 3. Color

All tokens are declared in `src/app/globals.css` (`@theme` and `:root`) and consumed as CSS variables or Tailwind theme utilities.

### 3.1 Brand — Plum

| Token | Value | Name | Role |
|---|---|---|---|
| `--color-primary` | `#301045` | Core Plum | CTAs, active navigation, emphasized headings |
| `--color-primary-light` | `#4a1c5e` | Lifted Plum | Hover state of primary elements |
| `--color-primary-dark` | `#1d0a2b` | Midnight Plum | Gradient endpoints, deepest surfaces |
| `--color-brand-plum` | `#1d0a2b` | Midnight Plum | Alias of primary-dark; overlays and footers |
| `--color-brand-lilac` | `#ddbce7` | Lilac | Accent text and details on dark surfaces |
| `--color-brand-lavender` | `#ebdcf2` | Lavender | Soft accent backgrounds |
| `--color-brand-tint` | `#f4ecf8` | Tint | Lightest section background |

### 3.2 Signature gradient

The only sanctioned multi-stop gradient is `.gradient-untitled` in `globals.css`:

`#FFFFFF → #B99BC1 → #81508F → #633178 → #48205F → #301045` (oklab, 180 degrees)

It is reserved for blend sections (services blend, updates blend) and must not be re-authored by hand elsewhere.

### 3.3 Neutrals

| Token | Role |
|---|---|
| `slate-900` | Primary body text on light backgrounds |
| `slate-700`, `slate-600` | Secondary body text |
| `slate-500`, `slate-400` | Muted and meta text |
| `slate-200`, `slate-100` | Hairlines and card borders |
| `slate-50`, `slate-100` | Subtle surfaces |
| `white` | Page background |

`gray-*`, `neutral-*`, `zinc-*` and one-off hexes are not part of the system. Where they still exist in code, they migrate to the slate scale whenever the file is touched.

### 3.4 Functional

Status semantics only, never decorative: `emerald-*` success, `red-*` error, `amber-*` warning, `blue-*` information.

### 3.5 Photographic treatment

Hero imagery always sits behind the brand overlay sandwich — a `--color-primary` wash at 80 percent opacity plus a midnight-plum gradient layer — so white type holds contrast on any photograph. The recipe is codified in `PageHero.tsx`.

---

## 4. Typography

A two-font system, self-hosted or Google-loaded and wired through CSS variables.

| Role | Typeface | Utility | Applied to |
|---|---|---|---|
| Primary | Suisse Intl | `font-primary`, `font-heading` | All headings h1–h6, hero display text, wordmark |
| Secondary | Inter | `font-secondary`, `font-sans` | Paragraphs, buttons, inputs, all UI chrome |

Headings inherit Suisse Intl automatically through the global `h1`–`h6` rule; explicit font utilities are only needed where markup deviates from semantics.

### 4.1 Scale

The Tailwind named scale is the type system: `text-xs` through `text-7xl`, always stacked responsively (`text-{base} sm:text-{…} lg:text-{…}`). Arbitrary pixel or rem sizes are outside the system; the one exception is the established display-type experiments in hero sections, which are reviewed case by case.

### 4.2 Fluid root

At 1024px and above the root font size scales fluidly with `clamp(12px, 1.1713vw, 40px)`; below it, the root is fixed at 16px. Every rem-based size inherits this behavior, so fixed pixel font sizes on layout text break the scaling model and are not used.

### 4.3 Weights

| Weight | Use |
|---|---|
| `font-medium` | UI labels, links |
| `font-semibold` | Sub-headings, buttons, eyebrows |
| `font-bold` | Headings and emphasis |
| `font-extrabold` | Hero display only |

### 4.4 Voice patterns

Eyebrow and label text: `text-xs font-semibold uppercase tracking-wide text-slate-500`. Hero headlines are tight: `tracking-tight` with line-height around 0.9–1.1. Body copy leads relaxed. German strings run longer than English; every layout carries with them, so overflow is tested in `/de` before shipping.

---

## 5. Layout & Spacing

### 5.1 Grid and containers

Three container recipes, no others:

| Container | Recipe | Used for |
|---|---|---|
| Showcase | `w-[99%] max-w-[1720px] mx-auto` | Home and hero surfaces |
| Standard | `max-w-7xl mx-auto px-4 sm:px-6 lg:px-8` | All regular sections |
| Reading | `max-w-3xl` / `max-w-4xl mx-auto` | Articles, legal, documents |

### 5.2 Vertical rhythm

One canonical section stack: `py-16 sm:py-20 lg:py-24`, with a compact variant `py-10 sm:py-14` for supporting sections. Bespoke padding stacks per section are not introduced; legacy values converge to these two whenever a section is edited.

### 5.3 Spacing scale

Tailwind's 4px scale only — `gap-4` for dense grids, `gap-6` for cards, `gap-8` between blocks. Arbitrary spacing values (`m-[14px]`) are outside the system.

### 5.4 Breakpoints

Mobile-first. `sm` for portrait refinement, `lg` for the desktop switch (navigation, multi-column), `xl` for wide-screen polish. The desktop navigation appears at `lg`; everything below uses the mobile shell.

---

## 6. Shape & Elevation

### 6.1 Radius vocabulary

Four values carry the entire product.

| Radius | Character | Application |
|---|---|---|
| `rounded-full` | Stadium pill | Primary CTAs, chips, icon buttons, pagination dots |
| `rounded-xl` | Soft panel | Cards, modals, the floating navbar shell |
| `rounded-lg` | Practical | Inputs, small buttons, image frames, logo plates |
| `rounded-md` | Precise | Badges, toggles, inline controls |

Bare `rounded`, `rounded-2xl`, `rounded-3xl` and the `rounded-4xl` shim are legacy; they migrate to the four values above.

### 6.2 Elevation

`shadow-sm` for hairline cards, `shadow-lg` for hoverable cards, `shadow-2xl` for floating calls to action. The signature shadow of the floating navbar is `0 10px 30px rgba(0,0,0,0.08)`. Elevation is paired with the standard transition: `transition-shadow duration-300`.

---

## 7. Motion

Four tools, each with a lane: GSAP with `@gsap/react` for scroll choreography and pinning, Framer Motion for component transitions, Lenis (wrapped in `SmoothScroll`) for global scroll, Three.js for hero visuals. A fifth animation approach is not added.

### 7.1 Timing

| Duration | Meaning |
|---|---|
| `duration-200` | Micro-interactions, hover feedback |
| `duration-300` | The standard; default for all transitions |
| `duration-500` | Entrances and reveals |
| 700–1000 | Cinematic hero moments only |

Easing follows physics: `ease-out` for entering, `ease-in` for exiting. `ease-linear` is reserved for loaders and ambient effects such as the sparkle keyframe.

### 7.2 Discipline

Only `transform` and `opacity` animate; layout properties do not. Transitions name their properties (`transition-transform`, `transition-colors`) rather than reaching for `transition-all`. Scroll reveals travel no more than 16–24 pixels with a fade. The global page transition is the `SliceRevealer` in brand plum (0.8s); the signature hover on primary CTAs is a gentle scale to 105 percent with a nudging arrow.

---

## 8. Z-Index Ladder

A fixed stacking contract. No values outside the ladder.

| Layer | Class |
|---|---|
| Decorative section background | `z-0` |
| Section content | `z-10` |
| Sticky in-section bars | `z-20` |
| Dropdowns and in-page overlays | `z-30` |
| Navbar, modals, global ripple | `z-50` |
| Page-transition slices | `z-[100]` (SliceRevealer only) |

---

## 9. Components

### 9.1 Buttons

Three variants, one anatomy: pill-shaped, bold Inter, an arrow glyph that nudges on hover.

- **Primary on dark:** `bg-white text-primary` with `shadow-2xl`, hover scales to 105 and tints toward lavender.
- **Primary on light:** `bg-primary text-white`, hover moves to `primary-light`.
- **Secondary on dark:** transparent pill, `border border-white/30 text-white`, hover fills `white/10`.

All CTAs end with the arrow glyph at 1em with `group-hover:translate-x-1`. The canonical recipe currently lives in `PageHero.tsx` and is being extracted into a shared `Button` primitive with a `variant` prop; until then, new buttons copy the recipe verbatim rather than improvising.

### 9.2 Cards

Surface: `bg-white rounded-xl border border-slate-200 shadow-sm`, on hover `shadow-lg` with `transition-shadow duration-300`. Tinted variants use `brand-tint` or `slate-50` — never a raw hex. Clickable cards open through the established modal pattern (`morphic-card-modal`).

### 9.3 Sections

Every section is a `relative` wrapper on the standard container with the canonical vertical rhythm. The section header pattern is an eyebrow in uppercase slate, an `h2` in Suisse Intl, and slate subcopy. Each page carries exactly one hero, built from `PageHero` or a dedicated hero component.

### 9.4 Navigation

The floating navbar is the only site header: fixed at 10px from the top, `z-50`, glass shell (`bg-white/95 backdrop-blur-md rounded-xl`). The active item is marked with brand-plum text and a 4px rounded underline. There is no separate header component.

### 9.5 Images

`next/image` throughout, with explicit dimensions or `fill`, descriptive alt text, and `.webp` assets from `/public/assets` or `/public/images`. Raw `<img>` is not introduced; `unoptimized` is allowed only for external or CDN sources. Photography behind text uses the overlay recipe from section 3.5.

### 9.6 Icons

`lucide-react` is the icon library for product and UI iconography. Brand-specific glyphs (arrow, chevrons) live in `shared/Icons.tsx` as inline SVG. `react-icons` is deprecated and removed as the last usage migrates. Icon sizing uses width and height utilities, not size props.

---

## 10. Architecture & Code Conventions

```
src/
  app/[locale]/          # routing only — pages compose components, hold metadata
  components/<domain>/   # about · careers · contact · home · projects · services · shared · ui · updates
    <SectionName>/<SectionName>.tsx   # PascalCase folder + PascalCase file, barrel index.ts where used
  context/               # LanguageContext, ContactContext
  locales/               # en.ts and de.ts dictionaries, mirrored key-for-key
  services/ constants/ types/ lib/
```

- Pages under `app/[locale]` stay thin: import sections, arrange them, pass data. Styling lives exclusively in components.
- `components/ui/` holds generic primitives; `components/shared/` holds cross-page brand furniture. Domain components never reach into a sibling domain — they go through shared or ui.
- Interactive or animated components are client components (`"use client"`) with a default export; typed props via exported `interface XxxProps`; strict TypeScript with no `any` added, and existing assertions removed opportunistically.
- Conditional class names merge through `cn()` from `lib/utils`.
- Links are localized: `Link` with `localizeHref()` or the `LocaleLink` wrapper; a bare unlocalized href is a defect on `/de`.
- No `console.*` in shipped code; dead boilerplate is deleted, not left dormant.

---

## 11. Internationalization

Two locales, `en` (default) and `de`, served from the `[locale]` segment with static params. Every visible string resolves through the dictionaries or the locale-keyed content pattern used by update articles. The two dictionaries stay mirrored key-for-key; drift is a bug. Because German runs roughly 20–30 percent longer than English, layouts are validated in `/de` for overflow, and the established sizing conventions for extended German text apply.

---

## 12. Accessibility

Each page has exactly one `h1` and heading levels never skip. Icon-only controls carry `aria-label`. Interaction uses native `button` and `a` elements. Contrast is verified against the palette: core plum on white and white or lilac on plum both clear WCAG AA; `slate-400` is for decorative or meta text only. Scrollbars are hidden globally, which makes visible `:focus-visible` rings mandatory on every control. All entrances and ambient motion degrade gracefully under `prefers-reduced-motion`.

---

## 13. Current State & Transition Guidance

The system as described above reflects where the product is heading; the built surface largely honors it. The dual-font typography, the App Router architecture, thin locale pages with domain component folders, `next/image` adoption, the photographic overlay, and the full i18n plumbing are all in place today.

Where the code still diverges, migration follows this order of impact:

1. **Color consolidation.** The brand hex is hardcoded across JSX in place of the token, three gray families compete with slate, and one-off hexes appear throughout. A mechanical sweep to `var(--color-*)` and slate resolves the largest share of inconsistency with low risk.
2. **A shared Button primitive.** The CTA recipe is duplicated across heroes; extracting it into `ui/Button.tsx` protects every future rebrand tweak.
3. **Section rhythm and containers.** A dozen padding stacks and several competing max-widths converge onto the two canonical recipes of section 5.
4. **Scale leaks.** Legacy radii, arbitrary spacing and font sizes, `transition-all`, and off-ladder z-index values migrate to the defined vocabularies.
5. **Dead code.** Dormant boilerplate components, the unused example hook, raw image tags, and the final `react-icons` import are removed as files are touched.
6. **Dictionary parity.** The en and de dictionaries are reconciled key-for-key and kept that way.

Every pull request that changes UI is checked against these guidelines; a section that fails the token rules or the i18n rule does not ship.

---

## 14. Quick Reference

| Practice | Follow | Avoid |
|---|---|---|
| Brand color | `text-[var(--color-primary)]` | Inline `#301045` or new purples |
| Neutrals | `text-slate-900` | `text-gray-900`, `text-[#18181b]` |
| Container | `max-w-7xl mx-auto px-4 sm:px-6 lg:px-8` | Ad-hoc widths |
| Section padding | `py-16 sm:py-20 lg:py-24` | Bespoke stacks |
| Radius | `rounded-full / xl / lg / md` | Bare `rounded`, `2xl`, `3xl` |
| Transition | `transition-transform duration-300 ease-out` | `transition-all duration-400` |
| Icons | `lucide-react` plus `shared/Icons` | New `react-icons` imports |
| Images | `next/image` with alt text | Raw `<img>` |
| Links | `localizeHref()` or `LocaleLink` | Raw href without locale |
| Copy | Dictionary or `t()` | Hardcoded English in JSX |
| Stacking | Ladder 0/10/20/30/50, 100 for slices | Any other z-index |
