9.2 KiB
dzanan.net — "Dark & technical" redesign
Date: 2026-09-06 · Status: approved by Amar (direction C of three mockups)
Goal
Replace the current warm/editorial design of dzanan.net with the "Dark & technical" direction: near-black surfaces with a faint grid, monospace labels, a terminal-style profile panel, and a single glowing green accent. The site serves both employers and consulting clients equally. The CV becomes a PDF that Amar provides; the site links to it.
Non-goals: new content for the case studies (text stays), a light theme, a CMS, new routes.
Scope
Kept: Angular 22 app structure, SSR + prerendering, SeoService, PageShellComponent
(restyled), landing page, four /work/* case-study pages, SystemDiagramComponent
(recoloured), not-found page, Tailwind v4 install, Docker deploy.
Removed: CvPageComponent + its spec, ThemeService, ThemeToggleComponent, the theme
bootstrap script in src/index.html, the cv client route, the cv prerender route.
Added: public/cv.pdf (placeholder until Amar supplies the file), a 301 from /cv to
/cv.pdf in src/server.ts, self-hosted fonts.
Visual system
Defined as CSS custom properties on :root in src/styles.scss; no .dark variant.
| token | value | use |
|---|---|---|
--bg |
#0D1015 |
page background |
--panel |
#12161D |
cards, list panel, code panel |
--panel-2 |
#0F1318 |
panel headers / inset |
--line |
#232A33 |
borders, dividers |
--line-strong |
#2A323D |
tag borders, button outline |
--text |
#E6EAF0 |
primary text |
--muted |
#8B95A5 |
secondary text |
--dim |
#5C6672 |
tertiary text, comments |
--accent |
#8BE04A |
labels, links, primary button, status dot |
--accent-glow |
rgba(139,224,74,.22) |
button and dot glow |
--code-key / --code-str / --code-num |
#7AA2F7 / #C3E88D / #F78C6C |
profile.json panel |
Grid: linear-gradient lines at 2.8% white, 64px cell, fixed to the page background.
Type: JetBrains Mono (labels, nav, meta, code, buttons) and IBM Plex Sans (headings and
body), self-hosted via @fontsource-variable/jetbrains-mono and @fontsource/ibm-plex-sans
(weights 400/500/600) imported in styles.scss. Fallbacks: Consolas/Menlo/monospace and
"Segoe UI"/system-ui/sans-serif. Base body 16px; headline scale clamp(2.4rem, 5vw, 3.9rem)
for h1, clamp(1.75rem, 3vw, 2.1rem) for h2, letter-spacing -0.03em/-0.025em, weight 600.
Labels (.label): mono, 12px, uppercase, 0.08em tracking, accent colour, prefixed with
// in markup (e.g. // selected work). Tags (.tag): mono 12px, 24px tall, 1px
--line-strong border, 4px radius. Panels (.panel): --panel fill, 1px --line
border, 10px radius. Buttons: 46px tall, 6px radius, mono 14px; .btn-accent accent fill
with dark text and glow, .btn-line outlined.
Container: .shell = min(1160px, 100% - 40px) centred. Section spacing 96px desktop,
64px below 720px.
Pages
Shell (header, footer, mobile menu)
Header: sticky, --bg at 92% with blur, bottom border. Left: mono wordmark ~/ (accent)
dzanan.net(600). Right (desktop): mono navwork · experience · contact · cv.pdf, then a divider and the status● available(accent dot with glow).cv.pdfis an<a href="/cv.pdf">with a download icon, opens in a new tab. Below 720px the nav collapses to the existing signal-driven menu button; the status stays visible.
Navigation config: [{work,'/',#work},{experience,'/',#experience},{contact,'/',#contact}]
plus the CV link rendered separately as a plain anchor (not a SectionNavItem).
Footer: mono 12px, Amar Džanan · Sarajevo, Bosnia and Herzegovina left; email and
LinkedIn right.
Landing (/)
- Hero — two columns (1.05fr / .95fr, 64px gap), stacks below 1024px.
Left: label
Senior full-stack engineer — .NET · Angular · MCP; h1 "Complex systems, understood before changed."; lead paragraph "I modernize enterprise software and connect it to AI through narrow, validated, verified interfaces — the kind you can run in production and sleep at night."; buttonsamar@dzanan.net(accent, mailto) andcv.pdf(outline, download). Right:profile.jsonterminal panel — title bar with three dots and file name, then a$ whoami --jsonline and a JSON object: name, role, stack[".NET","Angular", "TypeScript"], focus["modernization","safe AI integration"], since2018, location"Sarajevo · CET", open_to["senior roles","consulting"], closing prompt with a blinking cursor. Rendered from a small typed data structure in the component so it can change without touching markup. // selected work(#work) — heading "Production systems, anonymized." and a right-aligned mono count4 case studies. One.panelcontaining four rows (data-testid="project-row",routerLinkto/work/<slug>): index (accent on the featured first row), title + one-line summary (a new shorttaglinefield onPortfolioProject, ~60 chars), up to four stack tags (first four ofstack), arrow. Hover: row background--panel-2, arrow turns accent. Below 720px: grid collapses to index+title, tagline, tags stacked.// experience(#experience) — grid 340px / 1fr. Left: 96px square grayscale portrait (NgOptimizedImage, 8px radius, 1px border), label, h2 "Eight years, one product at a time.", about paragraph, LinkedIn link. Right: four role rows (period mono2025 — now, title + company, focus sentence), 1px dividers.// capabilities— three equal.panelcards:01 System modernization,02 Full-stack product delivery,03 Safe AI integration, each with the existing detail text. Single column below 720px.- Contact (
#contact) — a.panelwith a 1px accent-tinted border and inner glow: label// contact, h2 "Need a senior engineer who can understand the system before changing it?",.btn-accentmailto button, monoSarajevo · CET / CEST.
Structured data (schema.org Person) unchanged.
Case study (/work/:slug)
Breadcrumb as a path: ~/work/ (dim) + slug (text), mono. Header: label
<category> · <period>, h1 title, lead summary, then a meta strip in a .panel: role,
period, stack tags. Sections keep content; labels become // 01 context, // 02 delivery,
// 03 architecture, // 04 result; contributions as a numbered list with mono indices;
decisions as a 2×2 .panel grid (single column < 720px); technology as a tag row.
SystemDiagramComponent stays, recoloured: node fill --panel, stroke --line-strong,
accent node stroke/text --accent, lines --line-strong, notes --dim, mono text.
Prev/next as two .panel links. Contact block reused. The "View full CV" link points to
/cv.pdf.
Not found
Terminal panel: $ open <path> then command not found: <path> in --code-num, a short
sentence, and a .btn-line back to /. Server still returns 404.
Behaviour
- Motion: hero children fade-up (opacity 0→1, translateY 12px→0, 480ms, 80ms stagger) once
on load; cursor blink 1s step; row hover transitions 150ms. All wrapped in
@media (prefers-reduced-motion: no-preference). - Smooth anchor scrolling with
scroll-padding-topfor the sticky header (kept). - Focus rings: 2px accent outline, 3px offset.
<meta name="theme-color">→#0D1015;color-scheme: dark.
Server
src/server.ts: before the Angular handler, app.get('/cv', (_, res) => res.redirect(301, '/cv.pdf')). public/cv.pdf is served by the existing static middleware. Until Amar
supplies the file, a one-page placeholder PDF saying "CV coming soon — amar@dzanan.net" is
committed so the link never 404s. public/sitemap.xml drops /cv.
Files
Modified: styles.scss, index.html, server.ts, app.ts, app.routes.ts,
app.routes.server.ts, app.routes.spec.ts, page-shell.component.ts,
navigation.config.ts, landing-page.component.ts + spec, portfolio-page.component.ts
- spec,
system-diagram.component.ts,not-found-page.component.ts,portfolio-project.model.ts,portfolio-projects.data.ts,public/sitemap.xml,package.json/lock (fontsource packages).
Removed: features/cv/cv-page.component.ts, features/cv/cv-page.component.spec.ts,
core/services/theme.service.ts, shared/ui/theme-toggle/theme-toggle.component.ts.
Added: public/cv.pdf (placeholder), this spec, the implementation plan.
Testing
- Unit: route spec lists routes without
cv; landing spec asserts the new h1, four project rows,a[href="/cv.pdf"], mailto and LinkedIn links, the four role titles; portfolio spec unchanged in intent; new not-found assertion optional. Run with headless Chromium. - Build:
ng build(production, SSR, prerender of/and the four work pages) with zero errors and within budgets (component styles are inline SCSS; keep under 8kB each). - Visual: serve
distand screenshot/, one case study and/404at 1440px and 390px; fix wrapping, overflow and contrast issues found. - Smoke:
curl -I /cv→ 301 to/cv.pdf;/cv.pdf→ 200.
Delivery
Work happens in the cloud copy of the repo; changed and new files are written back to the
dzanan.net folder on Amar's machine, removed files are moved into _to_delete/. Amar runs
npm install locally afterwards (new font packages) and drops the real PDF over
public/cv.pdf.