CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Project

Jekyll static site for Tech Design Concept (Azure/cloud consulting). Deployed via GitHub Pages from main; custom domain techdesignconcept.com (see CNAME).

Commands

bundle install                 # install Ruby gem dependencies
bundle exec jekyll serve       # local dev server with live reload
bundle exec jekyll build       # build to _site/
bundle exec jekyll serve --drafts  # include posts in _drafts/

No test suite, linter, or JS build step — this is plain HTML/CSS/JS served through Jekyll.

Architecture

Standard Jekyll layout; a few site-specific conventions worth knowing:

/* ─────────────────────────────────────────────────────────────

  1. Fonts ───────────────────────────────────────────────────────────── */ @font-face { font-family: ‘Geist’; src: url(‘/assets/fonts/GeistVF.woff2’) format(‘woff2-variations’); font-weight: 100 900; font-style: normal; font-display: swap; }

@font-face { font-family: ‘Geist Mono’; src: url(‘/assets/fonts/GeistMonoVF.woff2’) format(‘woff2-variations’); font-weight: 100 900; font-style: normal; font-display: swap; }

/* ─────────────────────────────────────────────────────────────

  1. Tokens ───────────────────────────────────────────────────────────── / :root { / Color — surfaces */ –bg-0: #0A0A0A; –bg-1: #111113; –bg-2: #17171A;
/* Color — borders */
--border: #232327;
--border-strong: #2E2E33;

/* Color — text */
--text-0: #F5F5F7;
--text-1: #A1A1AA;
--text-2: #71717A;

/* Color — brand accent */
--accent: #0078D4;
--accent-hover: #3392DD;
--accent-glow: rgba(0, 120, 212, 0.35);
--accent-glow-soft: rgba(0, 120, 212, 0.08);

/* Color — semantic */
--success: #22C55E;
--danger: #EF4444;

/* Typography */
--font-sans: 'Geist', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
--font-mono: 'Geist Mono', ui-monospace, 'SF Mono', Menlo, Consolas, monospace;

/* Spacing — 4px base */
--space-1: 4px;
--space-2: 8px;
--space-3: 12px;
--space-4: 16px;
--space-5: 24px;
--space-6: 32px;
--space-7: 48px;
--space-8: 64px;
--space-9: 96px;
--space-10: 128px;
--space-11: 160px;

/* Radii */
--radius-sm: 6px;
--radius-md: 10px;
--radius-lg: 16px;
--radius-pill: 999px;

/* Motion */
--ease: cubic-bezier(0.4, 0, 0.2, 1);
--dur-fast: 150ms;
--dur-base: 200ms;
--dur-slow: 400ms;

/* Z-index scale */
--z-nav: 100;
--z-overlay: 200; }

/* ─────────────────────────────────────────────────────────────

  1. Reset + base ───────────────────────────────────────────────────────────── */ *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

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

body { font-family: var(–font-sans); font-size: 16px; line-height: 1.65; color: var(–text-0); background-color: var(–bg-0); padding-top: 64px; /* header offset */ overflow-x: hidden; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; }

/* Site-wide atmospheric gradient + noise */ body::before { content: ‘’; position: fixed; inset: 0; background: radial-gradient(ellipse at 50% -20%, var(–accent-glow-soft), transparent 60%); pointer-events: none; z-index: 0; } body::after { content: ‘’; position: fixed; inset: 0; background-image: url(“data:image/svg+xml;utf8,”); pointer-events: none; z-index: 0; opacity: 0.6; } main, header, footer { position: relative; z-index: 1; }

/* Typography */ h1, h2, h3, h4, h5, h6 { font-family: var(–font-sans); font-weight: 600; line-height: 1.1; letter-spacing: -0.02em; color: var(–text-0); }

h1 { font-size: clamp(2.5rem, 6vw, 4.5rem); letter-spacing: -0.03em; line-height: 1.05; } h2 { font-size: clamp(2rem, 4vw, 3rem); } h3 { font-size: 1.5rem; } h4 { font-size: 1.25rem; }

p { color: var(–text-1); font-size: 1rem; line-height: 1.65; }

p.lede { font-size: 1.125rem; color: var(–text-0); max-width: 60ch; }

a { color: var(–accent); text-decoration: none; transition: color var(–dur-base) var(–ease); } a:hover { color: var(–accent-hover); }

strong { color: var(–text-0); font-weight: 600; }

code, pre { font-family: var(–font-mono); font-size: 0.9em; }

code { background: var(–bg-1); padding: 2px 6px; border-radius: var(–radius-sm); color: var(–text-0); }

pre { background: var(–bg-1); border: 1px solid var(–border); border-radius: var(–radius-md); padding: var(–space-5); overflow-x: auto; margin: var(–space-5) 0; }

pre code { background: transparent; padding: 0; }

ul, ol { color: var(–text-1); padding-left: 1.5rem; margin-bottom: var(–space-5); } li { margin-bottom: var(–space-2); } li strong { color: var(–text-0); }

blockquote { border-left: 2px solid var(–accent); padding-left: var(–space-5); margin: var(–space-6) 0; color: var(–text-1); font-style: italic; }

img { max-width: 100%; height: auto; display: block; }

*:focus-visible { outline: 2px solid var(–accent); outline-offset: 2px; border-radius: var(–radius-sm); }

/* Screen-reader only */ .sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0; }

/* Skip link */ .skip-link { position: absolute; top: -100px; left: 0; background: var(–accent); color: white; padding: var(–space-3) var(–space-5); z-index: var(–z-overlay); text-decoration: none; } .skip-link:focus { top: 0; color: white; }

/* ─────────────────────────────────────────────────────────────

  1. Layout primitives ───────────────────────────────────────────────────────────── */ .container { width: 100%; max-width: 1200px; margin: 0 auto; padding: 0 var(–space-5); }

.container-wide { width: 100%; max-width: 1440px; margin: 0 auto; padding: 0 var(–space-5); }

.section { padding: var(–space-9) 0; } @media (max-width: 768px) { .section { padding: var(–space-8) 0; } }

.section-divider { border: 0; border-top: 1px solid var(–border); margin: 0; }

.grid-2 { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(–space-6); } .grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(–space-6); } .grid-4 { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(–space-5); }

@media (max-width: 1024px) { .grid-4 { grid-template-columns: repeat(2, 1fr); } } @media (max-width: 768px) { .grid-2, .grid-3, .grid-4 { grid-template-columns: 1fr; gap: var(–space-5); } }

.stack { display: flex; flex-direction: column; gap: var(–space-5); } .cluster { display: flex; flex-wrap: wrap; gap: var(–space-3); align-items: center; }

main { min-height: calc(100vh - 200px); }

/* ─────────────────────────────────────────────────────────────

  1. Components — Buttons ───────────────────────────────────────────────────────────── */ .btn { display: inline-flex; align-items: center; justify-content: center; gap: var(–space-2); padding: 0 var(–space-5); height: 44px; background: var(–accent); color: #fff; font-family: var(–font-sans); font-size: 0.9375rem; font-weight: 500; border: 1px solid var(–accent); border-radius: var(–radius-sm); text-decoration: none; cursor: pointer; transition: all var(–dur-base) var(–ease); white-space: nowrap; } .btn:hover { background: var(–accent-hover); border-color: var(–accent-hover); color: #fff; transform: translateY(-1px); box-shadow: 0 0 40px var(–accent-glow); } .btn:active { transform: translateY(0); }

.btn-secondary { background: transparent; color: var(–text-0); border: 1px solid var(–border-strong); } .btn-secondary:hover { background: var(–bg-2); border-color: var(–border-strong); color: var(–text-0); box-shadow: none; }

.btn-ghost { background: transparent; color: var(–text-0); border: 0; padding: 0 var(–space-2); height: auto; } .btn-ghost:hover { background: transparent; color: var(–accent); box-shadow: none; transform: none; } .btn-ghost .fa-arrow-right, .btn-ghost .fas.fa-arrow-right { transition: transform var(–dur-base) var(–ease); } .btn-ghost:hover .fa-arrow-right { transform: translateX(3px); }

.btn-sm { height: 36px; padding: 0 var(–space-4); font-size: 0.875rem; } .btn-lg { height: 52px; padding: 0 var(–space-6); font-size: 1rem; }

/* ─────────────────────────────────────────────────────────────

  1. Components — Cards, tags, eyebrows ───────────────────────────────────────────────────────────── */ .eyebrow { display: inline-block; font-family: var(–font-mono); font-size: 0.75rem; font-weight: 500; text-transform: uppercase; letter-spacing: 0.08em; color: var(–text-2); margin-bottom: var(–space-4); }

.tag { display: inline-flex; align-items: center; padding: 4px 10px; border-radius: var(–radius-pill); background: var(–bg-1); border: 1px solid var(–border); font-family: var(–font-mono); font-size: 0.75rem; color: var(–text-1); }

.card { position: relative; background: var(–bg-1); border: 1px solid var(–border); border-radius: var(–radius-md); padding: var(–space-6); transition: border-color var(–dur-base) var(–ease), transform var(–dur-base) var(–ease); display: flex; flex-direction: column; gap: var(–space-4); } .card:hover { border-color: var(–border-strong); transform: translateY(-2px); }

/* Service card — icon + title + body + link */ .card-service .icon-tile { width: 48px; height: 48px; display: inline-flex; align-items: center; justify-content: center; border: 1px solid var(–border); border-radius: var(–radius-md); color: var(–accent); font-size: 1.25rem; background: var(–bg-2); } .card-service h3 { margin: 0; } .card-service p { margin: 0; }

/* Team card — no photo */ .card-team h3 { margin-bottom: var(–space-1); } .card-team .role { font-family: var(–font-mono); font-size: 0.8125rem; color: var(–accent); text-transform: uppercase; letter-spacing: 0.06em; margin-bottom: var(–space-3); } .card-team .socials { display: flex; gap: var(–space-3); margin-top: var(–space-3); } .card-team .socials a { color: var(–text-2); font-size: 1.125rem; } .card-team .socials a:hover { color: var(–accent); }

/* Post card — CSS-rendered, no image */ .card-post { padding: 0; overflow: hidden; text-decoration: none; color: inherit; } .card-post .card-post-banner { position: relative; aspect-ratio: 16 / 9; background: linear-gradient(135deg, rgba(0,120,212,0.25), transparent 60%), radial-gradient(circle at 85% 15%, rgba(0,120,212,0.35), transparent 50%), var(–bg-2); display: flex; align-items: flex-end; padding: var(–space-5); border-bottom: 1px solid var(–border); } .card-post .card-post-banner h3 { font-size: 1.125rem; font-weight: 600; color: var(–text-0); line-height: 1.3; margin: 0; } .card-post .card-post-body { padding: var(–space-5); display: flex; flex-direction: column; gap: var(–space-3); } .card-post .meta { font-family: var(–font-mono); font-size: 0.75rem; color: var(–text-2); text-transform: uppercase; letter-spacing: 0.06em; }

/* Case study card — larger, with metrics */ .card-case-study { display: grid; grid-template-columns: 1.3fr 1fr; gap: var(–space-7); padding: var(–space-7); align-items: center; } @media (max-width: 768px) { .card-case-study { grid-template-columns: 1fr; gap: var(–space-5); padding: var(–space-6); } } .card-case-study .meta-row { display: flex; flex-wrap: wrap; gap: var(–space-3); margin-bottom: var(–space-4); } .card-case-study h3 { font-size: 1.75rem; margin-bottom: var(–space-4); }

/* Stat */ .stat { display: flex; flex-direction: column; gap: var(–space-1); padding: var(–space-4) 0; } .stat .stat-number { font-family: var(–font-sans); font-size: 2.25rem; font-weight: 600; color: var(–text-0); line-height: 1; letter-spacing: -0.02em; } .stat .stat-label { font-family: var(–font-mono); font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(–text-2); } .stat-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: var(–space-5); border-top: 1px solid var(–border); padding-top: var(–space-5); }

/* ─────────────────────────────────────────────────────────────

  1. Components — Header + Nav ───────────────────────────────────────────────────────────── */ .site-header { position: fixed; inset: 0 0 auto 0; height: 64px; background: rgba(10, 10, 10, 0.7); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); border-bottom: 1px solid var(–border); z-index: var(–z-nav); } .site-header .container { display: flex; align-items: center; justify-content: space-between; height: 100%; }

.logo-link { display: inline-flex; align-items: center; gap: var(–space-3); text-decoration: none; color: var(–text-0); font-weight: 600; letter-spacing: -0.01em; } .logo-link:hover { color: var(–text-0); } .logo-mark { width: 28px; height: 28px; flex-shrink: 0; color: var(–accent); display: block; } .logo-wordmark { font-size: 0.9375rem; }

.main-nav { display: flex; align-items: center; gap: var(–space-6); } .menu { display: flex; list-style: none; gap: var(–space-5); padding: 0; margin: 0; } .menu a { color: var(–text-1); text-decoration: none; font-size: 0.875rem; font-weight: 500; padding: var(–space-2) 0; position: relative; transition: color var(–dur-base) var(–ease); } .menu a:hover { color: var(–text-0); } .menu a.active { color: var(–text-0); } .menu a.active::after { content: ‘’; position: absolute; left: 0; right: 0; bottom: -2px; height: 1px; background: var(–accent); }

.menu-toggle { display: none; background: transparent; border: 0; color: var(–text-0); font-size: 1.25rem; cursor: pointer; padding: var(–space-2); }

@media (max-width: 768px) { .menu-toggle { display: inline-flex; } .menu { position: fixed; top: 64px; left: 0; right: 0; flex-direction: column; background: rgba(10,10,10,0.95); backdrop-filter: blur(12px); padding: var(–space-4) var(–space-5); border-bottom: 1px solid var(–border); transform: translateY(calc(-100% - 64px)); transition: transform var(–dur-base) var(–ease), visibility 0s linear var(–dur-base); visibility: hidden; gap: 0; } .menu.active { transform: translateY(0); visibility: visible; } .menu li { width: 100%; } .menu a { display: block; padding: var(–space-4) 0; border-bottom: 1px solid var(–border); } .menu a.active::after { display: none; } .header-cta { display: none; } }

/* ─────────────────────────────────────────────────────────────

  1. Components — Footer ───────────────────────────────────────────────────────────── */ .site-footer { border-top: 1px solid var(–border); padding: var(–space-8) 0 var(–space-5); margin-top: var(–space-9); background: transparent; } .footer-content { display: grid; grid-template-columns: 2fr 1fr 1fr; gap: var(–space-7); margin-bottom: var(–space-7); } @media (max-width: 768px) { .footer-content { grid-template-columns: 1fr; gap: var(–space-5); } } .footer-section h4 { font-family: var(–font-mono); font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.08em; color: var(–text-2); margin-bottom: var(–space-4); font-weight: 500; } .footer-section p, .footer-section li { color: var(–text-1); font-size: 0.9375rem; } .footer-menu { list-style: none; padding: 0; } .footer-menu li { margin-bottom: var(–space-2); } .footer-menu a { color: var(–text-1); text-decoration: none; } .footer-menu a:hover { color: var(–text-0); }

.footer-brand .logo-link { margin-bottom: var(–space-4); } .footer-brand p { max-width: 40ch; }

.footer-socials { display: flex; gap: var(–space-4); margin-top: var(–space-4); } .footer-socials a { color: var(–text-2); font-size: 1.125rem; transition: color var(–dur-base) var(–ease); } .footer-socials a:hover { color: var(–accent); }

.footer-bottom { display: flex; justify-content: space-between; padding-top: var(–space-5); border-top: 1px solid var(–border); color: var(–text-2); font-size: 0.8125rem; } @media (max-width: 768px) { .footer-bottom { flex-direction: column; gap: var(–space-2); text-align: center; } }

/* ─────────────────────────────────────────────────────────────

  1. Components — Forms ───────────────────────────────────────────────────────────── */ .form-field { display: flex; flex-direction: column; gap: var(–space-2); margin-bottom: var(–space-4); } .form-label { font-family: var(–font-mono); font-size: 0.75rem; font-weight: 500; text-transform: uppercase; letter-spacing: 0.08em; color: var(–text-2); } .form-control { width: 100%; padding: var(–space-3) var(–space-4); background: var(–bg-1); border: 1px solid var(–border-strong); border-radius: var(–radius-sm); color: var(–text-0); font-family: var(–font-sans); font-size: 0.9375rem; transition: border-color var(–dur-base) var(–ease), box-shadow var(–dur-base) var(–ease); } .form-control:focus { outline: 0; border-color: var(–accent); box-shadow: 0 0 0 3px rgba(0, 120, 212, 0.15); } .form-control::placeholder { color: var(–text-2); } textarea.form-control { min-height: 140px; resize: vertical; font-family: var(–font-sans); } select.form-control { appearance: none; background-image: url(“data:image/svg+xml;utf8,”); background-repeat: no-repeat; background-position: right var(–space-4) center; padding-right: var(–space-7); } .form-success { border: 1px solid var(–success); border-radius: var(–radius-md); padding: var(–space-5); background: rgba(34, 197, 94, 0.06); color: var(–text-0); } .form-error { color: var(–danger); font-size: 0.8125rem; margin-top: var(–space-1); }

/* ─────────────────────────────────────────────────────────────

  1. Components — Marquee ───────────────────────────────────────────────────────────── */ .marquee { position: relative; overflow: hidden; padding: var(–space-6) 0; mask-image: linear-gradient(90deg, transparent 0%, #000 10%, #000 90%, transparent 100%); -webkit-mask-image: linear-gradient(90deg, transparent 0%, #000 10%, #000 90%, transparent 100%); } .marquee-track { display: flex; gap: var(–space-9); width: max-content; animation: marquee 40s linear infinite; } .marquee:hover .marquee-track { animation-play-state: paused; } .marquee-item { flex: 0 0 auto; color: var(–text-2); font-family: var(–font-mono); font-size: 1rem; display: inline-flex; align-items: center; gap: var(–space-3); opacity: 0.7; transition: opacity var(–dur-base) var(–ease); } .marquee-item:hover { opacity: 1; } .marquee-item svg { width: 20px; height: 20px; } @keyframes marquee { from { transform: translateX(0); } to { transform: translateX(-50%); } }

/* ─────────────────────────────────────────────────────────────

  1. Components — Glow + Hero ───────────────────────────────────────────────────────────── */ .glow { position: absolute; pointer-events: none; width: 600px; height: 600px; background: radial-gradient(circle, var(–accent-glow) 0%, transparent 60%); filter: blur(60px); opacity: 0.6; z-index: 0; }

.hero { position: relative; min-height: 88vh; padding: var(–space-9) 0 var(–space-8); } .hero .container { display: grid; grid-template-columns: 1.4fr 1fr; align-items: center; gap: var(–space-7); min-height: inherit; } @media (max-width: 1024px) { .hero { min-height: auto; padding-top: var(–space-8); } .hero .container { grid-template-columns: 1fr; } } .hero-copy { position: relative; z-index: 2; max-width: 60ch; } .hero-copy h1 { margin-bottom: var(–space-5); } .hero-copy .lede { margin-bottom: var(–space-6); color: var(–text-1); } .hero-ctas { display: flex; flex-wrap: wrap; gap: var(–space-3); } .hero-visual { position: relative; aspect-ratio: 1 / 1; width: 100%; max-width: 480px; justify-self: end; transform: translateX(8%); } @media (max-width: 1280px) { .hero-visual { transform: translateX(0); max-width: 440px; } } @media (max-width: 1024px) { .hero-visual { justify-self: center; max-width: 400px; margin-top: var(–space-6); } } .hero-visual .glow { inset: -60px; width: auto; height: auto; opacity: 0.8; } .hero-visual img, .hero-visual svg { position: relative; z-index: 1; width: 100%; height: auto; } .hero-visual img { mix-blend-mode: screen; opacity: 0.95; -webkit-mask-image: radial-gradient(circle at center, #000 55%, transparent 92%); mask-image: radial-gradient(circle at center, #000 55%, transparent 92%); }

/* Page headers */ .page-header { padding: var(–space-9) 0 var(–space-7); text-align: left; } .page-header .lede { margin-top: var(–space-4); font-size: 1.25rem; max-width: 56ch; }

/* CTA band */ .cta-band { text-align: center; padding: var(–space-9) 0; border-top: 1px solid var(–border); border-bottom: 1px solid var(–border); margin: var(–space-9) 0 0; } .cta-band h2 { margin-bottom: var(–space-4); } .cta-band .lede { max-width: 60ch; margin: 0 auto var(–space-6); } .cta-band .cluster { justify-content: center; }

/* Numbered approach blocks */ .steps { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(–space-6); } @media (max-width: 1024px) { .steps { grid-template-columns: repeat(2, 1fr); } } @media (max-width: 640px) { .steps { grid-template-columns: 1fr; } } .step { border-top: 1px solid var(–border); padding-top: var(–space-4); } .step .step-num { font-family: var(–font-mono); color: var(–accent); font-size: 0.75rem; letter-spacing: 0.06em; } .step h3 { margin: var(–space-2) 0 var(–space-2); font-size: 1.125rem; } .step p { font-size: 0.9375rem; }

/* Utilities */ .text-center { text-align: center; } .mt-0 { margin-top: 0; } .mt-4 { margin-top: var(–space-4); } .mt-6 { margin-top: var(–space-6); } .mb-0 { margin-bottom: 0; } .mb-4 { margin-bottom: var(–space-4); } .mb-6 { margin-bottom: var(–space-6); }

/* Scroll-reveal */ .reveal { opacity: 0; transform: translateY(12px); transition: opacity 600ms var(–ease), transform 600ms var(–ease); } .reveal.is-revealed { opacity: 1; transform: none; } @media (prefers-reduced-motion: reduce) { .reveal { opacity: 1; transform: none; } } `.

Design system

Content conventions

Blog post front matter (required fields)

---
layout: post
title: "Post Title"
date: YYYY-MM-DD
author: "Name"
image: "/assets/imgs/featured.png"
excerpt: "Short summary"
tags: [tag1, tag2]
---

Filename must be YYYY-MM-DD-title-of-post.md for Jekyll to pick it up.

Case studies

_case_studies/ is a Jekyll collection served at /work/:slug/. Each markdown file needs this frontmatter:

---
title: "Engagement title"
client: "Client name or anonymised descriptor"
industry: "Industry label"
duration: "e.g. 8 weeks"
services: [Cloud Migration, Security]
summary: "Short card/hero summary."
featured: true   # optional; exactly one case study should be featured on the home page
metrics:
  - "200|+|VMs migrated"     # format: value|suffix|label
  - "32|%|cost reduction"
---

Body uses ## Challenge, ## Approach, ## Outcome sections by convention.

Security headers

_layouts/default.html sets a strict CSP via <meta http-equiv> tags. When adding external scripts, styles, fonts, or image sources, the CSP script-src / style-src / img-src / font-src / connect-src directives must be updated — otherwise the resource will be blocked silently in the browser. Currently allowed: self, cdnjs.cloudflare.com (styles/fonts), use.fontawesome.com (fonts), data: (images), formspree.io (form submit), googletagmanager.com + google-analytics.com (GA). GA (gtag.js) is loaded in default.html; init lives in assets/js/gtag-init.js.

Deployment

Pushing to main triggers GitHub Pages to build and deploy. _site/ is generated output — do not hand-edit or commit meaningful changes there.