Skip to content
S
  • Home
  • Work
  • About
  • Writings
  • Contact
Hire me

Menu

Home→Work→About→Writings→Contact→
Hire me
Sarib · Lead UE5 DeveloperLahore, Pakistan · PKT (UTC+5)contact@msarib.dev
SSARIB Lead UE5 Developer
LAHORE · --:--:-- PKT

Pages

  • Home
  • Work
  • About
  • Writings
  • Contact

Connect

  • LinkedIn (opens in new tab)
  • YouTube (opens in new tab)
  • contact@msarib.dev

Tools

  • RSS
  • Resume (PDF)
  • Resilience
  • Design System
© 2026 Muhammad Sarib. All rights reserved.Lahore, Pakistan

On this page

  • Introduction
  • Brand identity
  • Colors
  • Typography
  • Spacing and radii
  • Shadows, blurs, filters
  • Motion and animation
  • Layout and grids
  • Components
  • Cards and forms
  • Effects
  • Iconography
  • Media patterns
  • Correct vs incorrect

01

Introduction

System documentation for msarib.dev.

This page inventories every token, component, and pattern the site uses. It is written against code truth, not memory: where the spec and the code disagree, the code wins and the spec is corrected. It is built with the same system it documents, so it doubles as a working proof of that system.

02

Brand identity

The S-logo mark, its sizes, text-label variants, color tokens, hover behavior, the favicon set, and the rules for using it. The mark is defined once in CSS (the singleton rule) and rendered through one component.

2.1 The mark

120px diameterborder-radius: 50%display font, weight 900font-size: calc(size * 0.56)S

A white circle (border-radius 50%) with the letter S in the display face at weight 900, font-size calc(size * 0.56). The S sits slightly above the optical center (0.05em bottom padding) and is tightened to -0.04em tracking. Nothing else.

2.2 Size variants

S24px
S32px
S36px
S44px
S48px
S96px

Size is one variable, , set inline by the component per instance. Two class shorthands exist: maps to 36px and to 44px; the base is 32px.

2.3 Text label variants

S

Bare mark (nav).

SSARIB

Mark + label.

SSARIB Lead UE5 Developer

Mark + label + sub (footer).

In the footer, sets the wrapper to align-items: flex-start and turns the sub line into a block, stacking it under the label.

2.4 Colors and CSS variables

VariableValueSource
:root default
var(--color-text-primary)
var(--color-bg)
var(--color-accent)
literal
literal
same as --ease-out

2.5 Hover interaction

S

Hover the mark. handleMarkEnter fires on the mark's onMouseEnter and adds ; onAnimationEnd removes it, so the 720 deg spin always completes even if the cursor leaves mid-rotation. Under reduced motion the global base-layer collapse zeroes animation-duration, so the spin resolves instantly.

2.6 Usage in the wild

S

Nav: bare mark, aria-label "Sarib, go to home".

SSARIB Lead UE5 Developer

Footer: mark + text in the brand column.

Those are the only two placements. It is not used in the hero: the hero is text-only. Full nav and footer specs are in the Components section.

2.7 Favicons

16x16PNG · Browser tab
32x32PNG · Browser tab (retina)
16 + 32ICO · Legacy browser tab
180x180PNG · iOS home screen
192x192PNG · PWA / Android (any)
512x512PNG · PWA / Android (maskable)

Six wired icons under /public/icons/, plus :

{
  "name": "msarib.dev",
  "short_name": "Sarib",
  "description": "Lead Unreal Engine 5 developer. Muhammad Sarib.",
  "start_url": "/",
  "display": "browser",
  "background_color": "#101014",
  "theme_color": "#101014",
  "icons": [
    { "src": "/icons/icon-192.png", "sizes": "192x192", "type": "image/png", "purpose": "any" },
    { "src": "/icons/icon-512.png", "sizes": "512x512", "type": "image/png", "purpose": "any maskable" }
  ]
}

2.8 Export formats

This mark is CSS-only. No SVG or PNG logo export files exist. The favicons are the only raster exports. For a fixed-size asset, screenshot the CSS mark.

2.9 Correct usage

S
Do

On the base background (--color-bg).

S
Do

On an elevated surface (--color-bg-low).

S
Do

On the highest surface (--color-bg-high).

S
Do

At a documented size (44px, .s-logo-xl).

SSARIB Lead UE5 Developer
Do

Mark with the text label lockup.

S
Do

As the home link. Keyboard focus rings the circle in accent.

2.10 Incorrect usage

S
Don't

Stretch it. The mark is a circle, never an ellipse.

S
Don't

Recolor the background off-token.

S
Don't

Drop the S below legible contrast.

S
Don't

Place it on a busy photographic background.

S
Don't

Render below ~24px. The S becomes unreadable.

S
Don't

Loop the spin. It distracts and fights reduced motion (static here if you prefer reduced motion).

SSS
Don't

Repeat the mark. One focal point per view.

03

Colors

Every token: surfaces, text, accent and its states, borders, overlays, the eight per-card tints, the three gradient pairs, and the single error color. Post the Phase 29.3 refactor, every value derives from a base token via color-mix; nothing is hardcoded.

3.1 Overview

A dark, single-scheme system. Four background surfaces, three text weights, one teal accent with three states, four border tiers, two overlay whites, eight card tints, three gradient pairs, and one error color. Every non-neutral value is built from a base token with , which is byte-identical to the rgba it replaced. See the derivation model at the end of this section.

3.2 Backgrounds

Base page background
Elevated (cards)
Higher (nested / hover targets)
Hover surface

3.3 Text colors

The three weights rendered as real text on each surface, with the WCAG 2.1 SC 1.4.3 contrast ratio for that pairing. text-secondary and text-muted are white at 65% / 55% alpha.

--color-bg

primary18.98:1

secondary8.28:1

muted6.19:1

--color-bg-low

primary17.70:1

secondary7.99:1

muted6.07:1

--color-bg-high

primary16.24:1

secondary7.58:1

muted5.85:1

--color-bg-hover

primary14.68:1

secondaryn/a

muted5.49:1

TokenValueRole
Body + headings
Subdued copy
Meta / eyebrows

3.4 Accent teal family

Base interactive (links, CTAs, focus)
Hover
Active / press
Foreground ON accent (9.30:1)
Foreground on gradient badges

The accent is the only chromatic UI color. Hover lightens to accent-hover, press darkens to accent-press; label text on a filled accent uses accent-fg (9.30:1, AAA). Live:

3.5 Borders

Four white-alpha border tiers by prominence. Post-refactor each is .

High-emphasis containers
Cards, inputs
Dividers
Ambient outlines

3.6 Overlay whites

Two translucent white fills for depth and hover layering, shown on each surface. was deleted in the T3 sweep (unused; border-subtle covers 15%).

5% whiteSubtle depth on cards
10% whiteHover-state overlays, glass layering

3.7 Semantic state

Form validation, error banners (5.59:1 on bg)

is the only tokenized semantic state. Success and warning states are component-local styles, not tokens: the contact success card composes + accent, and uses light-005 + a border, neither introduces a new color. This is deliberate: only error had enough site-wide reuse to justify a token.

3.8 Per-card tints

Eight tints (lilac was deleted in T3). They are never raw fills. Each is applied as over a grayscale card image, so the tint gives hue and saturation while the image keeps its luminance. The swatch below each card is the raw token; the card is the blended result at the shipped at-rest strength (opacity 0.375).

Each card class sets two runtime variables: (the blend color) and (the hover box-shadow). Post-refactor both derive from the tint tokens. The consuming rule:

.exp-tint {
  background: linear-gradient(165deg,
    var(--card-tint) 0%, var(--card-tint) 35%, transparent 100%);
  mix-blend-mode: color;
  opacity: 0.375;
}
.exp-card.c1 {
  --card-tint: var(--color-tint-teal);
  --card-glow: color-mix(in srgb, var(--color-tint-teal) 35%, transparent);
}

3.9 3D pill-badge gradient pairs

Three two-stop gradients drive the 3D pill badge. The visible badge is a blend: the diagonal gradient, a white top-sheen gradient, a six-layer box-shadow (white insets + black drops), and a white text-shadow. Label text is (#1a1a1f).

grad-1
badge-fg on midpoint: 9.91:1 (AAA)
grad-2
badge-fg on midpoint: 7.42:1 (AAA)
grad-3
badge-fg on midpoint: 7.98:1 (AAA)

Top to bottom: the two raw stops, the flat gradient, then the full 3D badge (the blend). Keep each pair together; do not mix a stop from one pair with a stop from another (see 3.13).

3.10 Dormant and removed tokens

Honest accounting. These are defined but not broadly consumed. They are documentation of intent, not active surface; the design system does not pretend they are wired.

Dormant tokenWhy
Breakpoint tokens; media queries are hardcoded (DEC-083).
Aspect-ratio tokens; usage varies.
Recipe type scale; partially consumed.

Removed in the Phase 29.3-T3 sweep:

Removed tokenWhy
Never used. #c7c8fe still lives as --color-grad-1-a (distinct).
Redundant with --color-border-subtle at the same 15% white.
Frosted-glass tints, never referenced.

3.11 Contrast reference matrix

ForegroundBackgroundRatioRating
bg18.98:1AAA
bg-low17.70:1AAA
bg-high16.24:1AAA
bg-hover14.68:1AAA
bg8.28:1AAA
bg-low7.99:1AAA
bg-high7.58:1AAA
bg6.19:1AA
bg-low6.07:1AA
bg-high5.85:1AA
bg-hover5.49:1AA
bg10.60:1AAA
bg-low9.88:1AAA
bg-high9.06:1AAA
bg5.59:1AA
bg-low5.22:1AA
bg-high4.78:1AA
accent9.30:1AAA
grad-1 (mid)9.91:1AAA
grad-2 (mid)7.42:1AAA
grad-3 (mid)7.98:1AAA

Contrast ratios computed per WCAG 2.1 Success Criterion 1.4.3 (Contrast Minimum) and 1.4.6 (Contrast Enhanced). Values in decimal to two places. Semi-transparent foregrounds composited over the surface before computation. Every shipped pairing passes AA; none fail.

3.12 Correct usage

Body text uses text-primary on bg (18.98:1, AAA).

Do

Subdued copy uses text-secondary on bg-low (7.99:1, AAA).

Do

Accent for interactive elements: pill CTA, label in accent-fg (9.30:1).

Do
Enter a valid email.

--color-error for genuine error states (5.59:1, AA).

Do

Borders by prominence: default for emphasis, faint for ambient.

Do

Overlay whites for subtle depth on card surfaces.

Do

3.13 Incorrect usage

Overlay white as text is nearly invisible (~1.15:1, fails 1.4.3).

Don't

Overlay whites are for surfaces and borders, never text.

A whole paragraph set in accent teal. It passes contrast but reads as one giant link.

Don't

Accent is for interactive elements, not body copy.

New feature shipped!
Don't

--color-error for non-error UI. Semantic drift; error means error.

Button
Don't

Tint as a raw fill. Tints are mix-blend card compositors, not button backgrounds.

Don't

Mix gradient pairs (grad-1-a with grad-2-b). Keep each pair intact.

Body text set in a border token.

Don't

Border tokens are for edges. Text is a separate concern; use text tokens.

Don't

Two adjacent cards on the same tint. Break the rhythm; each card gets a distinct tint.

3.14 The color-mix derivation model

After the Phase 29.3 refactor, every color in the stylesheet derives from a base token. A translucent value is , which is byte-identical to the rgba(base, N/100) it replaced; a fully opaque value is a direct var(). No rule holds a raw color literal. Change a base token once and every value derived from it moves with it.

The base tokens (the single edit surface):

Two deliberate carve-outs stay literal: the fallback block (literal rgba is its entire purpose, for Chrome <111 / Safari <16.4 / Firefox <113), applied selectively to the most visible surface rather than exhaustively; and the two teaching anti-patterns, whose hardcoded off-brand and low-contrast hex are the point of the demo. Tailwind v4 also auto-generates an @supports hex fallback for the re-expressed @theme tokens, so they keep a legacy path too.

04

Typography

A single-family system: PP Right Grotesk for display, PP Right Grotesk Text for body, JetBrains Mono for technical text. Post the Phase 29.4 refactor, every size, weight, line-height and letter-spacing derives from a token; nothing is hardcoded.

4.1 Type families

Three families, three roles. Display and body are the two cuts of one superfamily (Pangram Pangram's PP Right Grotesk); mono is JetBrains Mono. There is no A/B alternate and no font switcher.

Display

I build gameplay systems.

PP Right Grotesk
Body

Seven years of C++, Blueprints, GAS, AI, and multiplayer.

PP Right Grotesk Text
Mono

SHOWREEL · 2026 · 07 UE4 to UE5

JetBrains Mono

4.2 Cuts and weights in use

Five real PP cuts plus JetBrains. Each specimen renders at its actual weight.

Ag
Wide Black · 900Hero + heading display
Ag
Spatial Black · 800Sub-headings
Ag
Medium · 500UI labels, nav
Ag
Text Regular · 400Body copy
Ag
Text Compact Medium · 500Compact UI
Ag
JetBrains Mono · 400 / 500 / 700Timestamps, technical labels

Finding, not fixed: weights 600 and 700 have no matching PP cut (display cuts are 900 / 800 / 500, body 400 / 500), so on those families they render as synthetic bold. They are tokenized as and at their exact current render, flagged for a separate decision. JetBrains Mono does ship a real 700.

4.3 Type scale

Every size token, rendered live at its size. Fluid tokens use and resize with the viewport; the value shows the min and max.

Headings (fluid)

Ag
Ag
Ag
Ag
Ag

Headings (fixed)

Ag

Display (bespoke fluid)

Ag
Ag
Ag
Ag
Ag

Titles (fixed)

Ag
Ag
Ag
Ag

Body

Ag
Ag
Ag
Ag
Ag

UI

Ag
Ag
Ag

Eyebrow

Ag
Ag
Ag
Ag

Special

Ag
Ag

4.4 Line-height, letter-spacing, weight

Three canonical scales. Every value lives here once; the recipe tokens (, ) alias into them.

Line-heightValue
1
1.05
1.1
1.15
1.2
1.3
1.4
1.5
1.55
1.6
1.65
1.7
1.75
Letter-spacingValue
-0.04em
-0.03em
-0.025em
-0.02em
-0.015em
-0.01em
-0.005em
0em
0.02em
0.04em
0.06em
0.08em
0.1em
0.12em
WeightValueCut
400Text Regular
500Medium / Compact Medium
600no cut (synthetic)
700no cut (synthetic; JetBrains has 700)
800Spatial Black
900Wide Black

4.9 Font loading strategy

The five PP cuts load from /public/fonts via in globals.css. The two above-the-fold cuts (Wide Black 900 hero, Text Regular 400 body) use and are the only preloaded fonts, emitted once each by React 19's from react-dom in layout.tsx (not manual link tags). The other three cuts use : they take the file only if it arrives within ~100ms, else the metric-matched fallback holds for the page, avoiding swap-induced shift.

CutWeightfont-displayPreload
Wide Black900swapyes
Spatial Black800optionalno
Medium500optionalno
Text Regular400swapyes
Text Compact Medium500optionalno
JetBrains Mono400 / 500 / 700swapno

Two metric-matched fallbacks ( and ) size local Arial to Right Grotesk's line box (size-adjust 105% / 102%, ascent 90% / 92%, descent 22% / 23%) so layout stays stable while the web font loads. JetBrains Mono loads via with and weights 400 / 500 / 700, self-hosted from the Vercel CDN (no Google runtime call, no woff2 in the repo).

4.5 Composed heading styles

The recipe classes compose a family, weight, size and tracking token into one heading style. They are live below (real classes from ). Most of the site uses bespoke per-component heads that compose the same tokens; the two heaviest are specified after.

Ships fully loaded
Ships fully loaded
Ships fully loaded
Ships fully loaded
Ships fully loaded
Ships fully loaded
Composed styleSelectorTokens
Hero headlinedisplay / 900 / heading-lg / leading 1.05 / tracking -0.025em
Case study h2display / 900 / display-case-h2 / leading 1.1 / tracking -0.02em
Case study h3display / 800 / title-sm / tracking -0.01em
Case study bodybase / 400 / prose (17px) / leading 1.65 / max-width 780px

4.6 Body and prose

Long-form reading uses (17px) at capped at a 780px measure (about 70 characters), the comfortable line length for sustained reading. The paragraph recipe steps:

The work nobody sees.
base 400, paragraph-lg, leading 1.65
The work nobody sees.
base 400, paragraph-md, leading 1.65
The work nobody sees.
base 400, paragraph-sm, leading 1.6
The work nobody sees.
base 400, paragraph-xs, leading 1.55

I write the Blueprint coding standards. I set the per-device draw call budgets. I run the hiring rubrics and the code reviews. The work I do is the work nobody sees until it ships, which is the work that makes everything else possible.

17px / leading 1.65 / max-width 780px measure

4.7 Mono usage

SHIPPED PROJECTS · 10 · Five studios · 21:24:30 PKT

JetBrains Mono () carries anything technical or tabular, where fixed advance width reads as precision. Used for:

  • Eyebrows and section labels
  • The Lahore clock
  • Metadata rows and chips
  • Code blocks and inline code
  • Keyboard-shortcut keys
  • This design-system page (tokens, tables)

4.8 Fluid type

Headings scale with the viewport via : no breakpoint jumps, one continuous curve. For example is : 36px on a phone, 64px past ~1422px, fluid between. Resize the window and the heading below tracks it live.

Fluid

4.10 Correct usage

Heading

Display family for headings.

Do
Body copy

Text family for body, at a token size.

Do
v5.3 · 150 draw calls

Mono for technical or tabular data.

Do

4.11 Incorrect usage

A whole paragraph set in the display black cut is exhausting to read.
Don't

Set body copy in the display family. Use the text family.

Monospace makes long prose slow and uneven to read across a full measure.
Don't

Set long prose in mono. Reserve it for technical or tabular text.

Body text below the readable floor
Don't

Set body text at an eyebrow size (10 to 11px). Those are for labels.

4.12 The type derivation model

After Phase 29.4, every rule-level font-size, line-height, letter-spacing and weight is a to a token; nothing is hardcoded. The recipe classes and the bespoke component heads both compose the same tokens, so /resilience and the rest of the site draw from one scale. Change a token once and every consumer moves. The base tokens:

Three deliberate exemptions stay literal: the five weight descriptors (descriptors cannot reference custom properties), the OG image route (Satori has no CSS-variable resolution), and a `font-size: inherit`. One flagged finding: weights 600 and 700 have no matching PP cut, so on the display and body families they render as synthetic bold; they are tokenized at that exact render and left for a separate decision.

05

Spacing and radii

One 8px-based spacing rhythm, a responsive section gutter, value-preserving content-measure caps, a control/icon size axis kept separate from spacing, and the radius ramp. Post the Phase 29.5 refactor every spatial value derives from a token; nothing is hardcoded.

5.1 Overview

The spatial layer is four token families. The rhythm drives every padding, margin, gap, inset and positioning offset. Content width is capped by the readability tokens. Fixed control and icon geometry lives on a separate axis (, ) so resizing the rhythm never resizes a button. Corners come from the ramp. Before 29.5 the scale was defined but dormant (spacing was inline); the T1 to T4 sweep wired 540-plus spacing references, 26 measure caps and 53 control/icon dimensions to tokens.

5.2 Spacing scale

An 8px base with a 2px infill for the rhythm the site actually uses. Each bar is drawn live at its token width.

Core rhythm

Off-scale one-offs (value-preserving, 29.5-T4)

5.3 Section gutter, layout roles, measure caps

The is the single inline-padding source, stepping down responsively so content left-edges align down every page:

Viewport--section-gutter
default (> 1280px)64px
≤ 1280px40px
≤ 1024px32px
≤ 768px16px

Recurring layout amounts are named by role (the semantic half of the hybrid scale, DEC-102):

TokenValueRole
132pxHero top padding: clears the fixed nav
90pxscroll-margin-top for hash-target headings
200pxNegative-inset bleed for full-bleed washes
140pxTOC max-height viewport inset

Content width is capped for readability by : one token per distinct value, all value-preserving. The 780px is the ~70-character prose measure.

TokenValueSurface
380pxMobile menu drawer width
400pxContact success body
460pxKeyboard-shortcuts modal
480pxSmall caps: CTAs, empties, errors
540pxHero intro copy
560pxFeature text, featured cards
620pxCase summary
640pxLede paragraphs
700pxExpertise head copy
720pxWriting card, prev/next nav
760pxWhat-I-bring head
780pxLong-form prose (~70 characters)
880pxWide heads, post hero
1100pxCase title
1400pxGallery fullscreen content

Control and icon geometry sits on a deliberately separate axis: a edit must never resize a button. WCAG 2.5.5 minimum targets use (44px).

TokenValueUse
44pxWCAG 2.5.5 minimum target
32pxSmall control (compact pill)
40pxIcon buttons, gallery controls
48pxLarge control (fullscreen chevron)
64pxPlay-button overlays
160pxContact textarea min-height
11pxFooter external-link glyph
16pxInline icons (case links, info)
26pxCopy-email glyph
32pxInstagram embed glyph
5pxClock dot
6pxCursor, reel label, list bullets
1.5pxNav-link active/hover underline
104pxGallery filmstrip thumbnail width
64pxGallery filmstrip thumbnail height

5.4 Radius ramp

Seven corner steps plus two specials: (50%, a true circle on any aspect) and (9999px pill geometry). Each swatch is drawn live at its token radius.

1px
4px
8px
12px
16px
20px
24px
50%
9999px

5.5 Correct usage

Padded with tokens

Pad with a scale step (16 / 24).

Do
Prose capped at a measure token stays a comfortable line length.

Cap width with a --measure-* token.

Do

Size a control with the control axis, not --space.

Do

5.6 Incorrect usage

Off-scale padding
Don't

Hardcode an off-scale 17px / 23px / 7px. Use a token step.

Uncapped body copy runs the full container width and the eye loses the next line on a long viewport.
Don't

Leave prose uncapped. Apply a --measure-* limit.

Don't

Size a control off the spacing scale. A --space edit would then resize it.

5.7 The spatial derivation model

After Phase 29.5 every spatial and dimensional value is a to a token; change one token and every consumer moves. Deliberate remaining literals (documented, not oversights): grid-template-columns fixed tracks (a separate layout-grid concern), the internal demo dimensions on this page, skeleton loading placeholders, and one 5.5px hamburger-cross transform. The base tokens:

06

Shadows, blurs, filters

Named component shadow recipes (box and text), backdrop-filter blur tokens with their pointer:coarse caps, and the Phase 28 lesson that forced runtime glows onto pre-blurred Cloudinary derivatives. Post the Phase 29.5-T1/T2 refactor every shadow and blur is a token; nothing is hardcoded.

6.1 Overview

Depth is two token families. Shadows are component-named recipes, not an elevation scale (DEC-101): the site has ~18 shadows, each specific to one surface, so a forced 3-tier scale would either change values or just rename recipes. Blurs are semantic tokens with explicit caps (a Phase 28 mobile-GPU lesson). Shadow colours were already over the base palette from Phase 29.3; 29.5-T2 moved the composite offset/blur/spread recipes into named tokens.

6.2 Box-shadow tokens

Each recipe rendered live on a card surface. Inset tints (spoiler) and focus rings (skip) read differently from drop shadows by design.

Pill button resting depth
Pill button accent glow (hover / focus)
3D pill-badge, six-layer inset recipe
Work / case card hover elevation
wib / t-card 1px inset edge
The same edge, brightened on hover
Clock + reel status-dot glow
Larger reel glow
NSFW spoiler interactive tint (inset)
Spoiler tint, cleared on reveal
Skip-link focus pulse ring
Pulse ring at rest (zero spread)

6.2 Text-shadow tokens

Multi-layer drops that keep overlay text legible on bright video frames. Shown over a gradient to expose the drop.

Showreel
Pill-badge label emboss
Showreel
Reel label over bright video
Showreel
Credits over showreel (3-layer drop)
Showreel
Credits title, heavier drop
Showreel
Media caption legibility

6.3 Blur tokens

Each token as a live over the same image, so the radius difference is visible.

50px
Heavy frosted: nav, reel label, feature credit
24px
pointer:coarse cap of --blur-glass
20px
Card glass: work-card tag, wib / t cards
12px
pointer:coarse cap of --blur-surface
16px
Back-to-top button backdrop
19px
Showreel glow canvas (Phase 28: 19px x 4.2)
8px
Modal / fullscreen overlay backdrops
4px
Mobile-menu backdrop, spoiler reveal

6.4 The pointer:coarse caps

costs area times radius per backdrop change, and mobile GPUs rasterize blurs in tiles that seam at large radii (Phase 28, DEC-094). So always-on coarse- pointer surfaces halve their radius: 50px caps to 24px, and 20px caps to 12px, under . Transient overlays (modals, the mobile menu) are exempt because they are not always painting.

Always-on surfaceFine pointerCoarse cap
Nav, reel label, feature credit50px (--blur-glass)24px (--blur-glass-coarse)
Work-card tag, wib / t cards20px (--blur-surface)12px (--blur-surface-coarse)

The showreel glow does not use a runtime blur at all: Phase 28 found WebKit rasterizes large filter blurs into seaming tiles on real macOS / iOS Safari (invisible in headless Chromium). The atmosphere is now radial gradients and the feature / portrait glows are pre-blurred Cloudinary derivatives. The one surviving runtime blur token, (19px), feeds a low-res canvas scaled up, calibrated by pixel diff.

6.5 Correct usage

The named recipe for that surface (card hover).

Do
Glass tag

A --blur-* token on a card backdrop, capped on coarse.

Do
Legible

A multi-layer text-shadow token over bright media.

Do

6.6 Incorrect usage

Don't

Drop a dramatic hardcoded shadow on a flat surface. Use a recipe token.

Uncapped 50px
Don't

Leave a 50px blur uncapped on an always-on coarse-pointer surface.

No shadow
Don't

Set overlay text on bright media with no text-shadow token.

6.7 The depth derivation model

After Phase 29.5-T1/T2 every box-shadow, text-shadow and blur is a to a token; colours resolve through the Phase 29.3 palette. The one deliberate exemption is the feature query, which cannot reference a custom property. The base tokens:

07

Motion and animation

Duration and easing tokens, the keyframe set, and how the site honors prefers-reduced-motion.

7.1 Overview

Motion is CSS: transitions and keyframes, plus a few requestAnimationFrame loops for the cursor, the showreel glow, and the reading progress bar. There is no animation library. It is built from two token families, a duration scale and three easing curves, and every decorative animation collapses under . Hover the demos below to feel each value.

7.2 Duration scale

A value-preserving numeric scale, one token per millisecond value in real use, grouped by perceptual tier. Anything under roughly 150ms reads as a micro-interaction; 200 to 320ms is the standard band; 400ms and up is emphasized; 700ms and up is cinematic. Seconds-scale durations (the atmosphere drift, loading pulses) stay bespoke literals off this scale.

Micro Button press, small hovers.

80ms
120ms
150ms
160ms

Standard Cards, nav, most hover transitions.

200ms
240ms
250ms
280ms
300ms
320ms

Emphasized Menu slide, glows, filter fades.

400ms
450ms
500ms
600ms

Cinematic Card image scale.

700ms
800ms

Two role tokens name the durations that carry meaning: (360ms, the latent route-fade) and (, the locked S-logo spin).

7.3 Easing curves

Three curves cover every need. Each demo below runs the same 600ms travel so the shape is what differs. Standard CSS keywords stay in use where they are the right tool: linear for continuous rotation (the atmosphere orbits) and ease-in-out for loops.

Symmetric ease-in-out. Standard hovers, nav background, cursor.

Strong ease-out. Entrances, reveals, page transitions, the S-logo spin.

Overshoot past the target and settle. Deliberate spring on micro-interactions.

7.4 Reduced motion

The defensive pattern has two halves. A universal collapse nullifies every transition and animation under prefers-reduced-motion: reduce, so nothing decorative moves. Then decorative animations that should not exist at all under reduce (the hero reveals, the route skeleton shine, the atmosphere drift) are defined only inside @media (prefers-reduced-motion: no-preference), so reduced-motion users never get their from-frame stuck on screen.

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

The requestAnimationFrame loops guard themselves in JavaScript: the cursor and its homepage gradient hide, the showreel serves a poster with no video, and the reading progress bar snaps to position instead of lerping. Feedback motion is preserved: the skip-link focus pulse still fires, because it collapses to an instant state change rather than being removed. This pattern is the same one documented as a defensive pattern on the resilience page.

  • Collapsed under reduce: all transitions and keyframes (universal rule).
  • Never rendered under reduce: hero line and block reveals, skeleton shine, atmosphere orbits and breathe.
  • Hidden under reduce: cursor dot, homepage cursor gradient, showreel video (poster only).
  • Preserved under reduce: focus rings and the skip-link pulse (instant, not removed).

7.5 Keyframe animations

Eleven keyframes, all animating transform or opacity (the GPU compositor path), none animating layout. Hover a cell to play its motion; the demo timing is shortened and looped, the real production timing is listed below each. The S-logo spin is locked and shown here, not modified.

rotate() 0 to 720deg

700ms, --ease-out (locked)

Reduced motion: Collapses to instant; the spin still completes on animationend.

rotate() 360, transform only

23.5s to 29.5s, linear, infinite

Reduced motion: Not rendered (defined only under no-preference).

rotate() -360

36.5s / 42s, linear, infinite

Reduced motion: Not rendered (no-preference only).

scale() 1 to 1.12

15s / 20s, ease-in-out, infinite

Reduced motion: Not rendered (no-preference only).

opacity 1 to 0.35

2s, ease-in-out, infinite

Reduced motion: Collapses to a static element.

box-shadow ring fade

1s, --ease-base (feedback)

Reduced motion: Collapses to instant; feedback preserved, not removed.

opacity 0 to 1

fullscreen open fade

Reduced motion: Collapses to instant.

opacity + translateY

--ease-out, staggered

Reduced motion: Not rendered (no-preference only).

opacity + translateY

--ease-out

Reduced motion: Not rendered (no-preference only).

translateX sweep

1.8s, ease-in-out, infinite

Reduced motion: Not rendered (no-preference only).

opacity 0 to 1

modal open fade

Reduced motion: Collapses to instant.

7.6 Motion approach

The site uses no animation library. There are zero imports from motion/react, and motion is not in package.json. Everything is CSS transitions and keyframes plus four requestAnimationFrame loops: the cursor and its homepage gradient, the showreel glow canvas, the reading progress bar, and the atmosphere (SVG plus CSS keyframes). This adds zero JavaScript runtime for animation and keeps every transition on the token system.

A library would be warranted only for motion CSS cannot express: physics-based springs, drag gestures, or shared-element transitions with interruption and velocity. None of those exist here yet. If one is ever added, it is motion/react, never framer-motion. This supersedes the earlier "Motion v12" stack note, which was aspirational and never adopted (DEC-105).

7.7 Correct usage

  • Consume --duration-* and --ease-* tokens; never hardcode ms or a raw cubic-bezier.
  • Match the tier to the interaction: micro for a button press, standard for cards and nav, cinematic for a hero image scale.
  • Use --ease-out for entrances, --ease-base for symmetric hovers, --ease-spring for deliberate overshoot.
  • Keep linear for continuous rotation and ease-in-out for loops; these standard keywords are the right tool there.
  • Animate transform and opacity only; name keyframes semantically.
  • Let decorative motion collapse under reduce; define anything that should not exist under reduce inside no-preference.

7.8 Incorrect usage

  • Hardcoded ms or a raw cubic-bezier() in a declaration, off the scale.
  • ease-in on an entrance: it reads as laggy, the motion arrives late.
  • transition: all: it animates unrelated properties and triggers layout work.
  • Animating width, height, or margin instead of transform.
  • A generic keyframe name (anim1, keyframes-a) with no meaning.
  • Motion left unhandled under reduce, or a framer-motion import.
  • Over 500ms on a micro-interaction, or under 50ms where it reads as a glitch.

08

Layout and grids

The section-container standard and section gutter, the hero, work, and expertise grids, breakpoint behavior, and the full-bleed rule.

8.1 Overview

Layout is five systems: a width container, the section gutter, the breakpoints, the component grids, and the full-bleed rule. The house style is asymmetric editorial grids, not symmetric centered ones, so weightings like the hero's 0.85fr 1.4fr are intentional. The spatial values these consume (spacing, radii, measures) are tokenized in Section 5; this section documents the layout that arranges them.

8.2 Container system

Three width tiers, shown here to scale against the 1440px cap. --container-max caps the whole site; the two article widths cap reading measures.

1440px
site width cap
1200px
wide prose / TOC body
824px
reading measure

is the single source of section padding: it applies the width cap, centers, and reads the section gutter. Modifiers (adds nav clearance) and (zero top, for a section under a hero) cover the two exceptions. The dormant --container-article-lg was deleted in 29.7-T1 (it duplicated --container-max at 1440px and had no consumers).

8.3 Section rhythm

One token, , owns the inline padding of every section, so content left-edges align down each page and one edit moves them all (15 consumers). It steps down with the viewport:

base (>1280px)
<= 1280px
<= 1024px
<= 768px

8.4 Breakpoint behavior

Breakpoints are hardcoded, not tokenized, and layered into three families. Hardcoding is deliberate (DEC-083): fixed reflow points give predictable layout across the site, which fluid everything does not.

FamilyBreakpointsWhat changes
Component reflow1200 / 900 / 600nav to hamburger, hero to single column, mobile card grids
Gutter and container1280 / 1024 / 768the --section-gutter ladder and the two-column TOC layout
Edges360 / 700 / 2200 / 3000minimum width, showreel tier, ultrawide container ladder

The --breakpoint-sm/md/lg/xl/xs tokens in @theme are dormant (zero consumers): the media queries hardcode their values, and the tokens are kept only for future Tailwind utility variants (DEC-083). Resize the window to see the active tier and gutter:

Viewport...
mobiletabletlaptopdesktop
Section gutter: ...

8.5 Grid patterns

Every real-component grid reads a named --grid-*token (Phase 29.7-T1), so one edit moves it. The diagrams below show each grid's column proportions to scale. Flex handles one-dimensional rows; grid handles two-dimensional layouts.

Hero

· reflows to single column at 900px. Text left, showreel right. Asymmetric, locked.

Hero (major)

· reflows to single column mobile. Work index and About page heroes.

Nav

· reflows to auto auto at 1200px. Centered brand between two equal rails.

Footer

· reflows to 2-col then 1-col. Brand column plus four link columns.

Expertise / skills

· reflows to 2-col at 900, 1-col at 600. Eight cards, four columns.

WIB / three-card

· reflows to single column mobile. Three cards over the animated gradient.

Work / press grid

· reflows to single column mobile. Work cards and the ImageGrid (Tresemme press coverage).

Media split

· reflows to single column mobile. Text and a slightly larger visual.

Case hero

· reflows to single column mobile. Title left, fixed specs sidebar right.

About experience

· reflows to 200px 1fr then 1-col. Date, body, media. Fixed rails, fluid middle.

TOC layout

· reflows to single column below 1280. Sticky sidebar plus body. Shared by four routes.

Gaps use the --space-* tokens from Section 5. The trivial single-column mobile collapses (grid-template-columns: 1fr) stay inline; they are structural, not a value.

8.6 Full-bleed

Some elements break out of the container to span the viewport: the hero showreel, the atmospheric gradients, banded backgrounds. One mechanism is used everywhere, a viewport-width box pulled back by half the viewport:

.full-bleed {
  width: 100vw;
  margin-left: -50vw;
  left: 50%;            /* within a positioned context */
}
/* atmosphere uses 104vw / -52vw for a 2vw overshoot */

body and main both set overflow-x: clip (DEC-096), which bounds the bleed so it never produces a horizontal scrollbar. The atmosphere wash uses a slightly wider 104vw / -52vw for a 2vw overshoot past the edges (DEC-083 Phase 20.4). Reach for full-bleed only for decorative, edge-to-edge visuals, never for reading content.

8.7 Correct usage

  • Use --container-max for the site width cap and --container-article-sm/md for reading measures; wrap sections in .section-container.
  • Read --section-gutter for inline padding so the 64/40/32/16 ladder applies everywhere.
  • Align a new media query to an existing family (component 1200/900/600 or gutter 1280/1024/768).
  • Consume the named --grid-* token for a component grid; keep asymmetric editorial ratios where the weighting is intentional.
  • Full-bleed with the one 100vw plus negative-half-margin mechanism, bounded by overflow-x: clip.

8.8 Incorrect usage

  • A hardcoded max-width that duplicates a container role, or a bespoke container that re-implements .section-container.
  • Hardcoding a section's inline padding, which breaks the shared gutter ladder.
  • An arbitrary breakpoint (say 820px) that adds an inconsistent reflow point.
  • A @container query for site-wide layout (component-local behavior only).
  • A raw grid-template-columns literal on a component that has a --grid-* token.
  • A symmetric 1fr 1fr grid where an editorial weighting was intended.
  • A second full-bleed mechanism, or a breakout with no decorative reason.

09

Components

The shared UI components: the nav, the footer, the pill button, the 3D pill badge, and the links suite. Each carries its variants, states, prop API, and accessibility notes. Cards and forms are in Section 10; media patterns in Section 13. These components already consume the color, type, spatial, motion, and layout tokens from Sections 3 to 8.

9.1 Nav

A three-column grid, (minmax(0,1fr) auto minmax(0,1fr)), so the brand mark stays optically centered regardless of the link and action widths. The S-logo brand mark is documented in Section 2. Left: the S-logo home link. Center: the primary links. Right: the "Hire me" pill and the burger. At the links and pill hide, the burger appears, and the grid switches to (DEC-083). The bar gains a background and shadow once the page scrolls past 30px ().

S
HomeWorkAboutWritingsContact
Element / stateTreatment
Link, defaulttext-secondary, no underline
Link, hover wash, underline grows to
Link, active route + aria-current="page", persistent underline
Link, focus-visibleglobal 2px accent ring
Burger, openthree spans morph to an X (bespoke 5.5px transform, DEC-102)
Reduced motionall transitions off

Accessibility: <nav aria-label="Main navigation">, the active link carries aria-current="page", and the burger exposes aria-label / aria-expanded / aria-controls. The skip-link is a separate component () that targets main[tabindex="-1"], not part of the nav.

9.2 Footer

A five-column grid, (repeat(5,1fr)), reflowing to repeat(2,1fr) then a single column at the mobile breakpoints. The brand column spans two tracks and holds the S-logo lockup (Section 2) plus the live Lahore clock, which is lazy-loaded () with a --:--:-- fallback.

ColumnContents
Brand (span 2)S-logo + label + (live PKT)
PagesHome, Work, About, Writings, Contact
ConnectLinkedIn, YouTube (external),
ToolsRSS, Resume PDF, Resilience, Design System, Shortcuts (touch-hidden)

Links fade to on hover. External links carry a screen-reader "(opens in new tab)"; the name is wrapped in <span translate="no">. Touch targets meet the 44px minimum under pointer: coarse (25.7.e).

9.3 Pill button

The site's one button. Polymorphic: renders a native <button>, a Next.js <Link>, or a plain <a download> for static files (which sidesteps the RSC-prefetch 404 on the resume PDF). Two variants, three sizes.

Primary

Secondary

With icon, as link, and disabled

As link (home)
StatePrimarySecondary
Defaultaccent bg, light-005, hairline border
Hoveraccent-hover + (glow, no movement)light-010, border-default
Activescale(0.98) at same
Disabledopacity: .5, not-allowed (button only)same (button only)
Focus-visibleglobal 2px accent ringsame
Forced colorshairline ButtonText border (25.6.b)same

Sizes map to the control-height axis: sm , md , lg (md and lg clear the 44px touch floor). Hover is a glow only, never a positional move; the locked interaction is a multi-layer . There is no ghost variant and no loading state.

variant?: 'primary' | 'secondary'   // default 'primary'
size?:    'sm' | 'md' | 'lg'        // default 'md'
icon?:    ReactNode
children: ReactNode
// as button: type?, onClick?, disabled?
// as link:   href, prefetch?, download?

9.4 Pill badge

A non-interactive <span> label with a 3D composition: a base gradient, a top sheen, a multi-layer shadow, and an embossed text-shadow. Three gradient tones. No states.

Technical depthEngineering leadershipShipped products
base: linear-gradient(225deg, grad-a, grad-b)sheen: 18% white top gradientdepth: --shadow-badge (6 layers)text: --shadow-text-embossAnatomy

The gradient pairs and are documented in Section 3; all three tones clear AAA contrast on their gradient midpoints. Prop API: (default grad-1), plus children and className.

9.5 Links suite

Three small link components. All use the class prefix (SpoilerLink was retrofitted in Phase 29.8a).

SpoilerLink: blurred at rest, un-blurs on hover or tap (placeholder URL shown).

Gated demo link (design-system placeholder)View placeholder link

CopyEmail: mailto link plus a one-tap copy button with a copied confirmation.

contact@msarib.dev

HeadingAnchorCopy: a delegated listener (no visual of its own). On the prose heading anchors it copies the section URL, updates the address bar without a scroll jump, and passes modified clicks through.

Link pills consume platform icons through and the external-link fallback. The icon system (brand marks, the inline-SVG convention) is catalogued in Section 11 Iconography.

9.6 Correct and incorrect usage

  • Pill button: <PillButton variant size href?>; disable via the attribute; use download for static files (RSC-prefetch 404 avoidance); glow on hover with no positional movement.
  • Pill badge: one of the three gradient tones for a short, non-interactive label.
  • Nav / footer: a single S-logo instance; aria-current="page" on the active link; the --grid-nav / --grid-footer tokens; external links flagged "(opens in new tab)".
  • Links: msarib- prefixed classes; a fail-silent clipboard with a visible fallback; modified-click passthrough on copy anchors.
  • A bespoke rounded <a> that reimplements .pill-btn; a translate move on hover; styling disabled without the attribute; a ghost or loading variant (neither exists).
  • A clickable pill badge, a fourth tone from a raw gradient, or a badge where a button belongs.
  • A second .s-logo definition (the singleton rule); a raw grid-template-columns literal on the nav or footer; an unlabeled external link.
  • An unprefixed public class (the former .spoiler-* gap, closed in 29.8a); a copy action with no role="status" feedback.

10

Cards and forms

The content-surface cards (work, expertise, what-I-bring, writing, skills, and the case-study list) and the contact form suite. Each carries its variants, state matrix, prop API, token consumption, and accessibility. The previews below use the real card CSS classes, so hover and tint states are genuine.

10.1 Overview

Cards carry the majority of the site's content: every project, expertise pillar, what-I-bring bullet, writing entry, and skill group. They are all server components with no client state; hover behavior is pure CSS. They consume the color, type, spatial, motion, and layout tokens from Sections 3 to 8, and the tokens from Section 8 drive their reflow.

10.2.1 WorkCard family

(server). A Next <Link> to /work/{slug}. Four tint tones, teal, purple, pink, cyan (a color-mix over --color-tint-* into --card-tint). FeaturedWork is a section wrapper, not a distinct card: it renders WorkCards in (--grid-even) plus a "View all" pill. WorkIndex is the /work page (hero --grid-hero-major+ the same grid).

Performance
Q2 2024 · Studio

Anime-Stylized Action

Combat systems and tooling for a stylized action title.

Multiplayer
Q4 2023 · Studio

Metaverse Platform

Networked world with geospatial streaming.

AI
Q1 2023 · NVIDIA

AI Assistant

In-engine assistant with a tool-calling loop.

UEFN
Q3 2024 · Epic

UEFN Portfolio

Six published Fortnite islands.

StateTreatment
Defaultimage saturate(0.85), tint 0.4, title primary
Hoverlift (−4px), image scale(1.06), title → , tint 0.4→0.25 (LOCKED)
Focus-visibleglobal 2px accent ring

Reflow: (1fr 1fr) → 1fr at 900px. a11y: the <Link> wraps the <h3> + summary (title is the accessible name), image alt, overlay aria-hidden.

project: ProjectItem      // { slug, title, summary, thumbnail, tags, client, date, tintClass }
priority?: boolean        // first two cards set fetchPriority="high"

10.2.2 FeatureShowcase

(server, static, no hover). A two-column (1fr 1.2fr) with text + pill on the left and, on the right, a pre-blurred Cloudinary glow (, a plain<img> with a baked e_blur derivative, DEC-097) behind a framed<Image> and a credit badge. Reflows at 1200 (gap) / 900 (single column). a11y:aria-labelledby, glow alt=""/aria-hidden, creditaria-hidden. The glow recipe is documented in Section 13.7.

10.2.3 ExpertiseCard family

(server, non-interactive,cursor: default). Eight cards in , one per tone.c1 to .c8 (teal / blue / cyan / purple / indigo / orange / pink / magenta), each setting --card-tint + --card-glow.

Locked (no hover lift): on hover the card changes only border-color and box-shadow ( = 0 24px 48px black-30% + 0 0 80px var(--card-glow)). The card stays in place; the scale(1.06) is on the image only. Current state: the image is a full-colour still (grayscale(0) brightness(1)), tint 0.375 fading to 0 on hover. The earlier BW-to-colour hover-video was removed in Phase 20.2 (the video/poster fields were stripped from expertise.ts); the still is the current shipped behavior.

Pillar 1

Pillar 2

Pillar 3

Pillar 4

Pillar 5

Pillar 6

Pillar 7

Pillar 8

StateTreatment
Defaultfull-colour image, tint 0.375
Hovertint → 0, border brightens, , image scale(1.06), NO card lift
Reduced motionrest state pinned

Reflow: --grid-4col → 3col (1200) → 2col (900) → --grid-even (600). Non-interactive, so no keyboard focus target. Prop API: ({ bwImage, bwImageAlt, title, tintClass }).

10.2.4 WhatIBringCard

(server <article>): a PillBadge + headline + body + detail list, three per row (--grid-3col → 1fr at 900). The card hairline is a deliberate inset box-shadow (), NOT a border, to dodge WebKit bug 158807 on a backdrop-filter element.

Technical depth

Systems that ship

Gameplay, tooling, and pipelines other engineers build on.

  • Combat and ability systems
  • Editor tooling

Backdrop (holds): via --blur-surface; card hover lifts −4px. Atmosphere (current state): the animated background is , five SVG <radialGradient> blobs in orbit groups with the diffusion baked into the gradient stop alphas (no filter: blur, no canvas), animated by CSS keyframes (orbit 29.5-42s + breathe 15-25s). It moved from a blurred-canvas approach to SVG in Phase 28.A (DEC-094) as a WebKit blur-tiling resilience fix. The container edge mask is a dual linear-gradient composite on .atm-wrapper, not a radial ellipse (Phase 20.4). See /resilience Section 6.

10.2.5 WritingCard

(server <Link>). It exists and renders on /writings; only the Keystatic content is pending. Two variants: the default card, and (full-width, accent radial-gradient background, larger title) for the lead post. Hover shifts the background/border and the title to accent, with no lift.

2026 · 03 · 018 min readFeatured

The featured post variant

Full-width, accent radial background, larger title. One per index.

2026 · 02 · 015 min readEngineering

A standard writing card

Default surface, hover shifts background and title to accent.

slug, title, summary, published: string
readingTimeMinutes: number
tags: readonly string[]
featured?: boolean        // adds .is-featured

10.2.6 SkillCategory

(server, static, no hover). Class is (not .skill-category). A heading + list, four per row (--grid-4col → --grid-2col at 1200).

Engines

  • Unreal Engine 5
  • UEFN
  • Unity

Languages

  • C++
  • Blueprints
  • TypeScript

10.2.7 Case list item

Not a component: rendered by the Markdoc case-study body, styled as (--grid-case-list, 80px 1fr) with a leading-zero ::beforecounter in accent. Static; used for "What I built" (<ol>) and "Credits" (<ul>).

  1. Built the combat system

    Abilities, hit reactions, and the tooling around them.

  2. Shipped the multiplayer layer

    Replication, prediction, and server authority.

10.3.1 ContactForm

('use client'), schema, action . Server Action, not an API route: the action file opens with 'use server', is wired through useActionState, and passed to <form action={formAction}>. Four fields (name, email, company optional, message) plus the Turnstile token. Validation is mirrored on the client for instant feedback and enforced on the server by a zod schema (the source of truth); Turnstile is verified server-side against Cloudflare siteverify.

Enter a valid email address.

Field stateTreatment
Default --color-border-subdued border
Focusborder → , bg → --color-bg-low
Focus-visible2px accent outline (tokenized in Phase 29.10)
Invalid.is-error → border + aria-invalid + .field-error
Form stateRendering
Idlethe form, ready
SubmittingisPending → "Sending…", submit disabled
Successreturns <ContactSuccess> in place of the form
Error.form-error-banner role="alert" + per-field aria-describedby

a11y: each field has a <label htmlFor>, invalid fields set aria-invalid+ aria-describedby to a role="alert" message, and on submit error focus moves to the first invalid field. Extra states: a 30s timeout warning, a turnstileBlocked safety net for privacy extensions, and an offline guard.

10.3.2 TurnstileWidget

('use client'), a forwardRef wrapper over . Invisible / managed (interaction-only, no visible checkbox), theme: 'dark', refreshExpired: 'auto'. The site key comes from; the server secret verifies the token in the action. No live widget is shown here (it would call Cloudflare); its state (unverified / verified / expired / error / blocked) lives in ContactForm.

siteKey: string
onSuccess?: (token: string) => void
onError?:   () => void
onExpire?:  () => void

10.3.3 ContactInfo, ContactSuccess, ContactCTA

All three are server components. ContactInfo is an <aside> of external profile links (LinkedIn, YouTube, Upwork, Fiverr) plus the email row (contact@msarib.dev, translate="no" + a copy button) and a response-time line. ContactCTAis the cross-page "Ready to talk?" panel (section-container + Contact and resume pills). ContactSuccess replaces the form on a successful submit; it now carries + aria-live="polite" so the confirmation is announced to assistive tech (the Phase 29.9b a11y fix). Live:

Sent

Message received.

Thanks, Ada. I'll reply within two working days.

Back to home

10.4 Correct and incorrect usage

  • Cards: WorkCard for project cards (consume --grid-even); ExpertiseCard only in the expertise grid, non-interactive, no lift; WhatIBringCard only in the WIB section; WritingCard is-featured for the lead post; an inset box-shadow hairline on backdrop-filter cards.
  • Forms: Server Actions + useActionState; server-side zod + Turnstile siteverify; aria-invalid + aria-describedby; invisible Turnstile; role="status" on the success state.
  • A hover lift or link on ExpertiseCard (locked no-lift, non-interactive); reintroducing the removed hover-video; a bespoke card that reimplements WorkCard; a raw grid-template-columns literal instead of a --grid-* token; a real border on a backdrop-filter card (WebKit 158807).
  • An /api route for form submission; client-only validation; an always-visible Turnstile; a success state with no live announcement; a missing aria-invalid on a failed field.

11

Effects

The site-wide effect vocabulary: focus rings, the custom cursor, the route-loading skeleton, and the S-logo spin, plus the reduced-motion policy and a cross-reference index of the effects that component sections own.

11.1 Overview

Effects are CSS-first, with a requestAnimationFrame loop only where the CSS layer runs out (the cursor, the showreel glow, the reading progress bar). Every animation respects prefers-reduced-motion through a site-wide universal collapse (11.6). Most effects live in their component sections; this section owns the ones that apply site-wide, plus the reduced-motion policy and a catalog (11.7) that links the rest.

11.2 Focus rings

The focus indicator is an accent outline, gated on :focus-visible (so a mouse click does not paint it, only keyboard focus does). Three tokens (Phase 29.10a): (2px), (3px default), and (2px, for dense form fields where 3px would crowd the input border). The colour is site-wide. Tab into the demo to see it:

A link (default ring)
SiteWidthOffset
Global :focus-visible (3px)
S-logo mark (3px)
.field-input (2px)

Not every focus treatment is an outline ring: linked .image-grid images use an accent border + scale(1.02), the heading-anchor uses opacity, and the gallery thumbnail's 2px border is an active-item indicator (not a focus ring). The tokens exist so the ring can be tuned for craft, never removed (that would be an a11y regression).

11.3 Cursor

('use client', mounted only on the home route). Two aria-hidden layers: a 600px radial that follows --cursor-x/--cursor-y, and a 6px that grows to 12px over a, button, [role="button"]. The rAF is self-limiting (Phase 27.1): it lerps toward the pointer, snaps within 0.1px, and stops when settled, re-arming on the next mousemove (not a forever-60fps loop), and pauses on a hidden tab. CSS-var writes are coalesced to one per frame for INP. It bails unless (hover: hover) and (pointer: fine) and reads reduced-motion via the shared hook (Phase 29.10a); a CSS @media (hover: none), (pointer: coarse), (prefers-reduced-motion: reduce) hides both layers as a belt-and-suspenders. The hover/pointer query stays a direct matchMediabecause the hook is motion-only.

11.4 Route transitions

is the transition: an App-Router streaming fallback that renders a skeleton of the shared page anatomy ( + .msarib-skel--eyebrow/--title/--line, role="status") at the standard section gutter, so the swap to real content lands roughly in place (Phase 28 UX v2). Prefetch makes it near-invisible on warm navigation; it mostly covers cold clicks on slow networks. The skeleton shine animates only under prefers-reduced-motion: no-preference, so it is static under reduced motion. The view-transitions API is not adopted (the App Router navigates instantly by default; the API is opt-in and not a fit for this stack tier yet).

11.5 S-logo spin

The brand mark spins 720deg on hover: (rotate(0deg) to rotate(720deg)) over (var(--duration-700), 700ms) with (var(--ease-out)). SLogo.tsx adds .spinning on mouseenter (guarded so a re-enter mid-spin does not restart it) and removes it on animationend, so the spin always completes even if the cursor leaves mid-rotation. Under reduced motion the universal collapse (11.6) zeros the duration, so the mark resolves instantly. The mark itself is documented in Section 2. Hover the demo:

S

11.6 Reduced-motion policy

Three layers. The reduced state is the STATIC state, not a shortened animation.

LayerWhat it does
Universal collapse@media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation-duration: 0.01ms; transition-duration: 0.01ms } } neutralizes every animation/transition
Per-element reducewhere a state must be absent not just instant: cursor hidden, atmosphere blobs stopped, gallery fade off, showreel poster-only
Opt-in no-preferencedelayed/staggered animations (hero reveal, skeleton shine) are DEFINED only here, because the collapse zeros duration but not animation-delay

JS side: the shared hook (a useSyncExternalStore reactive boolean) is used by seven components (ReadingProgress, BackToTop, TableOfContents, GalleryThumbnails, MediaRenderer, and, as of 29.10a, Cursor and ShowreelGlow). A one-shot matchMediaread is kept only where the check happens once at a decision point (ContactForm's scroll behavior), not as a subscription. The CSS mechanics per token are in Section 7 (Motion).

11.7 Effects catalog

Effects that component sections own. Linked, not re-documented here.

EffectSection
WorkCard hover lift -4px / image scale(1.06) / tint 0.4-0.25 / title accent10.2.1
ExpertiseCard hover border + shadow, tint fade, NO lift10.2.3
WhatIBring 5 SVG radial-gradient orbits (DEC-094)10.2.4
PillButton hover glow-no-movement + active scale(0.98)9.3
PillBadge 3D composition (gradient + sheen + shadow + emboss)9.4
Nav link underline grow + burger to-X morph9.1
ShowreelGlow canvas mirror + CSS filter blur scale(4.2)13.6
Cloudinary e_blur portrait/feature glows (DEC-097)13.7
Gallery thumbnail active border + fullscreen fade13.2
Motion durations + easings catalog7
Named component shadows6
Color-mix tints3

11.8 Correct and incorrect usage

  • Focus rings: consume --focus-ring-width / --focus-ring-offset for outline rings, --focus-ring-offset-tight in dense form fields, and keep --color-accent as the ring color site-wide; gate on :focus-visible.
  • Cursor: hide on touch (pointer: coarse) and under reduced motion; a self-limiting rAF that stops when settled (Phase 27.1).
  • Reduced motion: every animation respects it; the reduced state is the STATIC state; delayed/staggered animations live under no-preference; use the shared usePrefersReducedMotion hook for reactive consumers, a one-shot matchMedia only at a decision point.
  • Glows / atmospheres: Cloudinary e_blur for static glows (DEC-097); a canvas mirror for a playing-video glow (Phase 28.A2); SVG radial gradients with baked diffusion for atmosphere (DEC-094); reduced motion falls back to static.
  • A hardcoded outline: 2px; removing the focus ring (a11y regression); a non-accent ring color; using :focus (paints the ring on a mouse click).
  • A forever-60fps cursor loop; a cursor visible on touch (a ghost cursor); no reduced-motion bail; a custom cursor that blocks pointer events on targets.
  • Autoplay or parallax ignoring reduce; only shortening a duration (still animating); a delayed element left stuck at its from-frame; reimplementing a matchMedia subscription where the shared hook fits.
  • A runtime filter: blur() on a large layer (WebKit tiling, DEC-094); a per-frame in-canvas Gaussian (flickers on real hardware); an atmosphere still drifting under reduce.

12

Iconography

The PlatformIcon brand-icon system, the inline-SVG convention, the platformIconForUrl helper, and the icon usage conventions. There is no icon library; every glyph is inlined path data.

12.1 Overview

Iconography is a two-tier system. Tier one is : 11 components that make up the shared brand and external-link vocabulary. Tier two is per-component inline SVG for local control glyphs (play triangles, chevrons, close, copy/check, expand) that live in their consuming components (Gallery, CopyEmail, YouTubeEmbed, BackToTop) rather than the shared catalog. There is no icon library; every glyph is inlined path data, so there is no runtime fetch and the icons are offline-safe and recolorable. Icons theme via currentColor and size via the tokens (Section 5). The S-logo mark and the favicons are in Section 2.

12.2 Brand glyphs

Nine marks, path data from Simple Icons (CC0 1.0; see ). Each is an <svg viewBox="0 0 24 24" fill="currentColor" aria-hidden focusable="false">with a single <path>. Rendered at :

Size variants ( 11 / 16 / 26 / 32):

12.3 Utility icons

Two stroke-based glyphs (fill="none" stroke="currentColor" strokeWidth=1.6, round caps), a lighter visual weight than the fill-based brand marks. is hand-authored (Simple Icons ships brand marks only); is Heroicons "arrow-top-right-on-square" (MIT; see ), used for the footer external-link affordance and the platformIconForUrl fallback.

12.4 platformIconForUrl

maps an external URL to its brand mark by hostname (includes()), returning a JSX element with className="case-link-icon", and falls back to ExternalLinkIcon. Used by the case-study external-link pills. Upwork and Fiverr are not in the helper (they are used directly in ContactInfo). Live resolution:

https://www.linkedin.com/in/msarib/
https://x.com/msarib305
https://youtube.com/@msarib305
https://opensea.io/collection/samurai-saga
https://example.com/press-release

12.5 Conventions

  • Colour: currentColor (fill for brand marks, stroke for utility icons); the parent's color propagates. No hardcoded fill/stroke.
  • Size: the consumer's CSS class reads an --icon-* token (footer --icon-xs, case-link/info --icon-sm, grid --icon-lg). The one exception is the Gallery thumbnail media-type badge, a fixed 20px chip.
  • Accessibility: aria-hidden="true" + focusable="false" on the icon; the accessible name lives on the parent link/button (the footer's "(opens in new tab)").
  • Structure: viewBox="0 0 24 24" on every icon; inline path data (no fetch, no CDN, no icon-library dependency).
  • Two tiers: use PlatformIcon for brand/link marks; use a local inline SVG for a one-off control glyph. Do not cross them.

12.6 Favicons and attribution

The favicon set (favicon.ico, 16/32 PNG, apple-touch-icon, icon-192/512) is documented in Section 2 Brand identity; favicons are browser and PWA icons, a separate concern from the inline component icons here. Attribution for the icon path data (Simple Icons CC0, Heroicons MIT, the hand-authored Envelope) is in at the repo root.

12.7 Correct and incorrect usage

  • platformIconForUrl(url) when the URL determines the icon; a direct PlatformIcon component when it is known at author time (ContactInfo socials).
  • currentColor for colour and --icon-* tokens for size; aria-hidden on the icon with the accessible name on the parent.
  • Inline path data, one source per glyph in PlatformIcon.tsx; a local inline SVG only for a one-off control affordance.
  • Fetching an icon from an external URL or <img src> (no offline, a round-trip, cannot recolor); a hardcoded fill/stroke colour; a hardcoded width/height fighting the tokens.
  • An icon-only link/button with no aria-label on the parent; a missing viewBox; duplicating a brand glyph's path data instead of importing from PlatformIcon; adding a brand mark as a local inline SVG.

13

Media patterns

The Gallery carousel and its six media types, the static ImageGrid, the two YouTube and Instagram facades, the canvas-mirror ShowreelGlow, and the Cloudinary image wrapper with its zero-runtime e_blur glows. The demos below are live.

13.1 Overview

Media is the site's craft surface: galleries, embeds, and the showreel. The heavy interaction lives in (a 15-file client tree); embeds use hand-rolled facades that defer the third-party payload until a click; and the showreel and static glows encode the Phase 28 blur work (cross-referenced to /resilience).

Two structural ideas run through the section. First, the Gallery routes through a single MediaRenderer dispatch: six MediaItem types resolve to five sub-renderers (instagram-reel and instagram-post share one). Second, embeds are two-tier: a rich in-Gallery renderer plus a lighter standalone facade (YouTubeEmbed, InstagramEmbed) for prose contexts. Phase 29.12a converged the two YouTube tiers onto one thumbnail fallback chain.

13.2 Gallery

is a folder of 15 files (shell + reducer + provider, inline stage, filmstrip, a portal fullscreen modal, the six-type MediaRenderer, thumbnails, and four hooks). Props ; the MediaItem union covers image / video / gif / youtube / instagram-reel / instagram-post. State is a useReducer machine (currentIndex, isFullscreen, activatedEmbeds, igScriptStatus).

// props
items: MediaItem[]
ariaLabel?: string

// the discriminated union (src/components/Gallery/types.ts)
type MediaItem =
  | { type: 'image';          cloudinaryId: string; alt: string }
  | { type: 'gif';            cloudinaryId: string; alt: string }
  | { type: 'video';          cloudinaryId: string; accessibleName: string; autoplay?: boolean; loop?: boolean }
  | { type: 'youtube';        videoId: string; accessibleName: string; thumbnailUrl?: string }
  | { type: 'instagram-reel'; postUrl: string; accessibleName: string; thumbnailUrl?: string }
  | { type: 'instagram-post'; postUrl: string; accessibleName: string; thumbnailUrl?: string }

MediaRenderer dispatches the six types to five sub-renderers (both Instagram types share InstagramMedia):

typeSub-rendererDelivery
imageImageMediaCldImage, tier width by surface
gifGifMediaCloudinary video resource (MP4 loop), muted autoplay
videoVideoMediaCloudinary video with controls + poster
youtubeYouTubeMediathumbnail facade → click → youtube-nocookie iframe
instagram-reelInstagramMediaembed.js facade, scale-to-fit box
instagram-postInstagramMedia(same renderer, POST label)

The reducer actions are GO_TO / NEXT / PREV / FIRST / LAST (index clamps at the ends, no wrap), OPEN_FULLSCREEN / CLOSE_FULLSCREEN, ACTIVATE_EMBED (marks a YouTube/Instagram item live), and IG_SCRIPT (drives igScriptStatus). NeighborPrefetch preloads the two adjacent items once the strip is inView, keyed on currentIndex.

Element / stateTreatment
Thumbnail default / hoverhover lifts, aria-current on the active item → accent border
Fullscreenrole="dialog" aria-modal, focus trap + return-focus, Escape + backdrop close, scroll lock
Chevrondefault / hover / disabled at the ends (clamp, no wrap)
Counteraria-live="polite" "Item N of M" (the visible chip is aria-hidden)

Keyboard is scoped to the fullscreen modal only (the handler is on the fullscreen container, DEC-081), so arrow keys are inert on inline strips and multiple inline galleries never cross-fire. Coarse-pointer targets are 44px; reduced-motion drops the fade.

Live: one item per media type (video and gif reuse the homepage showreel asset).

Static Cloudinary image demo1 / 6

Image (Cloudinary static)

Item 1 of 6
#TypeConfig
1imagehttps://res.cloudinary.com/ddgwzcrim/image/upload/Lily_9_ce4kp1.jpg
2videoportfolio-showreel-new
3gifportfolio-showreel-new
4youtubevideoId: 16SzQjJ58Dc
5instagram-reelhttps://www.instagram.com/reel/C3tHZnFsSlt
6instagram-posthttps://www.instagram.com/reel/C6tQKTQuKUt

Multi-gallery regression surface (Phase 19.6.3): two galleries on one page, arrow keys inert on the inline strips, fullscreen one-at-a-time, state isolated per instance.

Gallery X

Gallery X item 11 / 2
Item 1 of 2

Gallery Y

Gallery Y item 11 / 2
Item 1 of 2

13.3 ImageGrid

(server). A static (repeat(2,1fr)) that stacks to one column below 600px; no carousel, no fullscreen. Items are ; an href makes the image a new-tab link with an accent border + scale(1.02)hover. coerces the Keystatic block shape into this prop. Live:

type ImageGridItem = { src: string; alt: string; caption?: string; href?: string }
items: ImageGridItem[]
ariaLabel?: string
Linked itemBorderScale
Defaultsubtle1
Hover--color-accent1.02
Focus-visible--color-accent ring1
  • Press coverage from BeautyMatter
    Captioned item (exercises figcaption)
  • Press coverage from Happi
  • Press coverage from ParlayMe
  • Press coverage from IGN Pakistan

13.4 YouTubeEmbed

A facade, not a raw iframe: the thumbnail loads first and the full youtube-nocookie iframe mounts only on click (deferring the ~1MB+ player). Two implementations exist. The standalone takes; the Gallery's YouTubeMediais the in-carousel renderer. Both idle controls are native <button>s (Phase 29.9c a11y fix, so Space and Enter both activate; the standalone was a div[role=button] with Enter-only handling).

Phase 29.12a consolidation: the standalone previously hard-coded maxresdefault.jpg with no fallback. It now shares the Gallery thumbnail chain, so both facades degrade the same way: maxresdefault → (onError) → hqdefault → (onError) → a static error tile. maxres is a 1280x720 frame that some videos never generate (they 404), so the fallback is load-bearing, not defensive.

// standalone facade
youtubeId: string
title:     string
priority?: boolean   // pass through to next/image for an above-the-fold embed

// thumbnail fallback (both facades)
const [thumbQuality, setThumbQuality] = useState<'maxres' | 'hq'>('maxres')
onError: maxres → hq → error tile

The URLs come from helpers, never hand-written:

HelperURL
youtubeEmbedUrl(id, { autoplay: true })youtube-nocookie.com/embed/{id}?autoplay=1
youtubeThumbnailUrl(id, 'maxres')img.youtube.com/vi/{id}/maxresdefault.jpg
youtubeThumbnailUrl(id, 'hq')img.youtube.com/vi/{id}/hqdefault.jpg
youtubeThumbnailUrl(id, 'mq')img.youtube.com/vi/{id}/mqdefault.jpg

The Gallery scroll strip uses mqdefault by design (Phase 28 image audit: maxres was 12.8x oversized in the 100px thumbnail slots). State matrix:

StateFacadeiframe
Idlethumbnail + play overlay (native button)not mounted
Playingreplacedmounted, autoplay=1

The Gallery demo above includes a live YouTube item.

13.5 InstagramEmbed

Two forms. The standalone is a link-card stub (an <a>with a brand tile, no script). The Gallery's InstagramMedia is the full embed: it lazy-loads on activation (reusing an existing tag if present), renders the official <blockquote class="instagram-media">, and wraps it in a ResizeObserver scale-to-fit box (Phase 28.E): it measures the scalebox's layout size against the fixed 16/9 stage and applies a uniform transform: scale(<=1), never upscaling. www.instagram.com is allowlisted in the enforced CSP (script-src / frame-src / connect-src, DEC-099).

The script lifecycle is tracked as igScriptStatus in the Gallery reducer (via the onIgScript callback):

igScriptStatusMeaning
idlenot yet activated (facade shown)
loadingembed.js fetch in progress
readyscript loaded, instgrm.Embeds.process() run
errorfetch failed → "View on Instagram" link fallback

13.6 ShowreelGlow

('use client'). A <canvas> mirrors the same <video> via a throttled rAF loop (INTERVAL_MS=66, ~15fps, 160px bitmap); the video src attaches only in the effect, so reduced-motion, lite mode, and no-JS pull zero video bytes (poster only), one network request total. srcMobile is picked at mount on matchMedia('(max-width: 700px)'), so phones stop pulling the 1280px encode (Phase 28.B1).

src:          string
srcMobile?:   string   // smaller tier attached on viewports <= 700px (Phase 28.B1)
poster:       string
reelLabel?:   string
creditsTitle?: string
creditsBody?: string
className?:   string

Single recipe (Phase 29.12a): the experimental ?glow=v2/v3 canvas-blur paths were removed. The one shipped recipe is the Phase 28.A2 small-scale-up: ctx.drawImage the video into the 160px bitmap, then let CSS blur the canvas element ( at 19px + scale(4.2) + opacity: 0.7). The blur runs on the small layout so the whole layer fits one WebKit GPU tile (no seam). The pure-canvas Gaussian was reverted on real hardware; see /resilience Sections 5 (failed approaches) and 6 (durable insights).

Hydration-safe byte gate (Phase 29.10a): the byte-critical bail cannot route purely through the usePrefersReducedMotion hook. useSyncExternalStore returns getServerSnapshot=false during hydration, so on a reduced-motion client the hook value is briefly false and a naive if (reduced) return lets the first effect run attach the video src (pulling bytes) before the hook settles. The fix: keep the hook in the deps (reactive re-run on a runtime motion toggle), but read matchMedia synchronously inside the effect for the actual bail. This generalizes to any hydration-sensitive resource attachment (a lazy iframe, a conditional media src, conditional font loading).

const reduced = usePrefersReducedMotion()   // in deps → reactive
useEffect(() => {
  // synchronous read is always correct at effect time
  const prefersReducedMotion =
    reduced || window.matchMedia('(prefers-reduced-motion: reduce)').matches
  if (prefersReducedMotion || liteMode) return   // ZERO video bytes
  video.src = isSmallViewport && srcMobile ? srcMobile : src
}, [src, srcMobile, reduced])

Live:

SHOWREEL · 2026
Selected highlightsSamurai Saga · NVIDIA · Valayt · TRESverse · Character Creator

13.7 CldImageClient and e_blur glows

is a thin client wrapper over's CldImage (it sets the client boundary and disables the ?_a= analytics ping). The cloud name is ddgwzcrim (env NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME, with that value as the hard fallback so server-side URL construction never breaks). holds the pure URL helpers, which callers use instead of hand-writing delivery URLs:

HelperReturns
cloudinaryPublicId(url)strips version / transform / extension → the public ID
buildCloudinaryUrl(id, { resource, tier, ext? })f_auto,q_auto,w_{width} for a video/gif source
cloudinaryVideoPoster(id, tier)f_jpg,so_0,q_auto,w_{width} first-frame JPG
youtubeEmbedUrl(id, opts)privacy-enhanced youtube-nocookie embed URL
youtubeThumbnailUrl(id, quality)maxres / hq / mq thumbnail URL

The three delivery tiers are : thumb feeds the scroll strip, main the inline stage, full the fullscreen modal (capped, not original, to bound payload). GIFs are delivered through the video resource (buildCloudinaryUrl(id, { resource: 'video' })) as an MP4 loop, never an animated GIF: smaller payload, real decode.

TransformUse
f_autoformat negotiation (webp / avif where supported)
q_auto / q_auto:ecoadaptive quality (eco tier in WorkCard)
w_{n}delivery width (from a tier)
f_jpg / so_0force JPG / start-offset-0 (video poster frame)
e_blur:Nblur effect, chained (one e_ per URL component)
e_saturation:Nsaturation, color-only (no spatial kernel)

The feature and portrait glows follow DEC-097: a plain <img> with a baked Cloudinary derivative (), zero-runtime filter, the CDN caches the blur. Cloudinary applies one e_ per URL component, so the blur is chained across two segments.

DPR / srcset: CldImage auto-generates srcSetfrom Next's default image sizes (next.config.ts sets only remotePatterns). srcset resolves in device pixels, not CSS pixels, so a transform width chosen by hand must be computed as CSS width x DPR (Phase 27.5.3). See /resilience Section 6 for the responsive-poster revert that established this; it is documented there, not re-derived here.

13.8 Aspect ratios and fallback strategies

Media frames commit to a fixed aspect so the layout never shifts as an asset loads:

ContextAspect
ShowreelGlow .showreel~16/10
FeatureShowcase .feature-visual-wrap16/11
WorkCard media / YouTube facade16/9
Gallery stage (inline + fullscreen)fixed 16/9 stage; media scaled to fit
ImageGridper-image intrinsic

Three fallback chains keep a broken asset from breaking the frame:

AssetChain
YouTube thumbnailmaxresdefault → hqdefault → static error tile
Instagram embedembed.js load fail → "View on Instagram" link
ShowreelGlowreduce / lite / no-JS → poster only, zero video bytes

13.9 Reduced motion (media)

The site-wide three-layer motion policy lives in Section 11.6; this is the media-specific slice. The tightest contract is ShowreelGlow: under prefers-reduced-motion: reduce it fetches zero video bytes from Cloudinary (verified by Network inspection in Phase 29.10a), guaranteed even through the hydration false-window by the sync-matchMedia bail (13.6).

ComponentUnder reduce
ShowreelGlowposter only, no canvas paint, zero video bytes
Galleryfullscreen fade dropped; coarse-pointer swipe preserved
Gallery gif / videono autoplay (poster holds); manual controls still work
YouTubeEmbedfacade shown; iframe only on explicit activation
ImageGridhover scale collapses to 1
InstagramEmbedscript loads on activation; the embed's own motion is Instagram's

13.10 Correct and incorrect usage

  • Gallery for a multi-item sequence, keyboard scoped to fullscreen (DEC-081); the native-button YouTube facade (Space and Enter both activate, 29.9c); CldImageClient for every Cloudinary image; the ShowreelGlow canvas mirror (one request, poster-only under reduced motion).
  • Every Cloudinary transform carries f_auto,q_auto (never a bare width); URLs come from the lib/cloudinary.ts helpers and the thumb/main/full tiers, never hand-written.
  • A GIF ships through the video resource (an MP4 loop); a static glow is a baked e_blur derivative (DEC-097), not a runtime filter.
  • Let CldImage generate srcSet; if a transform width is set by hand, compute CSS width x DPR first (Phase 27.5.3).
  • The YouTube thumbnail degrades maxres → hq → error tile; small slots (100px strip) use mqdefault by design.
  • A byte-critical bail reads matchMedia synchronously in the effect; the reduced-motion hook stays for reactivity only (the 29.10a hydration lesson).
  • A raw YouTube iframe in JSX (defeats the facade); a <div role="button"> play control (Space does not activate); Gallery for a single image; a page-level arrow-key handler (cross-fires every inline gallery).
  • A bare w_400 with no f_auto/q_auto (defeats format negotiation); a hand-written Cloudinary URL that bypasses the helpers and the tier contract; an animated-GIF <img> (larger than the MP4, no decode).
  • Hand-rolled DPR densities in srcSet (fights Next's default handling); maxresdefault in a 100px slot (12.8x oversized, Phase 28 image audit).
  • A runtime filter: blur() on a large media layer (WebKit tiling, DEC-094); a per-frame in-canvas Gaussian (flickered on real hardware, reverted Phase 28.I); a pure useSyncExternalStore gate on a byte-critical side effect (fires during the hydration false-window, the 29.10a regression).

14

Correct vs incorrect

The governing laws the whole system answers to, the platform anti-patterns they exist to avoid, and an index into every section's own correct and incorrect rules.

14.1 Overview

Every section above closes with its own correct and incorrect rules, scoped to that section's tokens and components. This section sits one level up. It states the laws the whole system answers to, names the platform anti-patterns those laws exist to avoid, and indexes the 103 per-section rules so any one of them is a click away. The laws are the entry point for a decision that spans sections; the index is the entry point for a specific component.

14.2 Governing laws

  1. Law 1

    The code is the spec. When this page and the code disagree, the code wins and the page gets fixed.

  2. Law 2

    Reach for the token, never the literal. If you are typing a raw value into a declaration, you are using the wrong token or you found a missing one.

  3. Law 3

    Reduced motion is a finished state, not a lesser one. The reduced version is the static design, fully designed, not an animation with its duration zeroed.

  4. Law 4

    The accessible name lives on the control, not the decoration. Icons are hidden from assistive tech; the label sits on the link or button around them.

  5. Law 5

    Define a thing once. A second copy is not a convenience, it is a future inconsistency.

  6. Law 6

    Use the component, do not rebuild it. A bespoke element that imitates one will drift from it the first time the original changes.

  7. Law 7

    Respect what the browser actually does. When a platform quirk is written down in /resilience, honor it instead of relearning it.

14.3 Anti-patterns behind the laws

Most of these laws were paid for. The failed approaches and durable insights on the resilience page carry the full narrative; the summary is below. Each one measured fine and broke somewhere real.

Chasing the blur radius on Safari

Tried
Shrinking a large filter: blur() radius to stop the atmospheric wash breaking into blocks on Safari.
Failed
WebKit rasterizes the blur in GPU tiles and clamps the kernel at each tile edge, so 100px, 60px and 40px all seamed. Radius was never the variable.
Replaced
SVG radial gradients with the diffusion baked in, no runtime blur on a large layer (DEC-094).

The glow that looked identical and re-seamed

Tried
A hand-matched blur recipe for the portrait and feature glows that read the same in a screenshot.
Failed
WebKit rasterizes composited layers at on-screen scale, so a small blur under a large scale still ran a wide kernel and re-seamed.
Replaced
Cloudinary e_blur derivatives baked at the CDN, plus a canvas mirror for the playing showreel (DEC-097, Phase 28.A2).

A blur that measured clean headless and flickered live

Tried
A per-frame in-canvas Gaussian for the showreel glow that passed every headless Playwright check.
Failed
On real hardware it rendered as a sharp, flickering copy; Chromium had moved the canvas from GPU to CPU after the unhinted pixel readback.
Replaced
The reference CSS blur on the canvas element, iterated on real hardware rather than in headless (Phase 28.I).

A canvas blur that renders unblurred on Safari

Tried
Blurring inside the canvas with ctx.filter = blur() as a portable one-liner.
Failed
Safari does not implement ctx.filter, so the draw landed completely unblurred with no error to catch it.
Replaced
Multi-pass drawImage resampling where an in-canvas blur is unavoidable, a CSS filter otherwise.

A real border on a backdrop-filter card

Tried
A one-pixel border on the frosted cards for a crisp edge.
Failed
WebKit bug 158807 tiles the backdrop under a real border, so the frost broke into rectangles on Safari.
Replaced
An inset box-shadow hairline that draws the same edge without a border box (Section 10).

A smaller mobile image that fetched the big one

Tried
A responsive poster that pointed phones at a smaller source to save bytes.
Failed
srcset resolves in device pixels, not CSS pixels, so a 3x phone still picked the large asset and the saving never happened.
Replaced
Compute CSS width x DPR first, then let CldImage generate the srcSet (Phase 27.5.3, durable insights).

A pure hook gate on a byte-critical resource

Tried
Gating the ShowreelGlow video source purely through the reduced-motion hook so it never loads under reduce.
Failed
useSyncExternalStore reports false during hydration, so the source attached in the hydration window and pulled video bytes on a reduced-motion client anyway.
Replaced
The hook for reactivity plus a synchronous matchMedia read for the byte-critical bail (DEC-113).

14.4 The per-section index

103 correct and incorrect rules across 12 sections (50 correct, 53 incorrect). Each stays in its home section; this is the pointer, not a copy.

SectionSubsectionCorrectIncorrect
02 Brand identity2.9 / 2.1067
03 Colors3.12 / 3.1367
04 Typography4.10 / 4.1133
05 Spacing and radii5.5 / 5.633
06 Shadows, blurs, filters6.5 / 6.633
07 Motion and animation7.7 / 7.857
08 Layout and grids8.7 / 8.857
09 Components9.644
10 Cards and forms10.422
11 Effects11.844
12 Iconography12.732
13 Media patterns13.1064
Total12 sections5053

14.5 How to read this system

For a specific component, jump to its section and read its rules directly. For a decision that spans the system, start from the seven laws. For the engineering history behind a call, the resilience page carries the narrative. Where any of them disagree with the code, the code is right and this page is what gets fixed.