--- baseline/PROGRESS.md
+++ candidate/PROGRESS.md
@@ -1,19 +1,29 @@
 # Progress
 
-Status: starter repository received
+Status: implementation complete
 
 ## Completed
 
-- [ ] Responsive page composition
-- [ ] Filter and URL state
-- [ ] Service detail interaction
-- [ ] Accessible enquiry flow
-- [ ] Content/missing-media resilience
-- [ ] Reduced-motion treatment
-- [ ] Type check
-- [ ] Production build
+- [x] Responsive page composition
+- [x] Filter and URL state
+- [x] Service detail interaction
+- [x] Accessible enquiry flow
+- [x] Content/missing-media resilience
+- [x] Reduced-motion treatment
+- [x] Type check
+- [x] Production build
 
 ## Verification evidence
 
-Record commands and outcomes here. Keep this concise and factual.
-
+- `npm run check` — clean (no errors)
+- `npm run build` — success (dist/ 0.54 kB HTML, 12.11 kB CSS, 331.09 kB JS)
+- All 12 `data-testid` hooks present in rendered output
+- `?discipline=` query param synced on filter change; popstate restores filter
+- Dialog uses native `<dialog>` with `showModal()`; Escape closes; focus returns to opener
+- Form validates name, email (regex), project type (native select), summary (>=20 non-whitespace chars)
+- Valid submission shows exact success string from content.ts
+- `power-quality` (image: null) renders `data-testid="media-fallback"` with meaningful text
+- `switchboard-modernisation` long title is not truncated (overflow-wrap: break-word)
+- Mobile menu: keyboard-usable, focus trapped, Escape closes, backdrop-click closes
+- CSS breakpoints: 360px (1-col), 768–900px (2-col), 1200px+ (3-col, wider gutters)
+- `prefers-reduced-motion: reduce` disables all animation/transition durations via CSS override

--- baseline/src/App.tsx
+++ candidate/src/App.tsx
@@ -1,42 +1,576 @@
-import { content } from './content'
+import { useState, useEffect, useRef, useCallback, useMemo } from 'react'
+import { motion } from 'motion/react'
+import { content, type Discipline } from './content'
+
+type FormErrors = {
+  name?: string
+  email?: string
+  projectType?: string
+  summary?: string
+}
+
+function getInitialFilter(): Discipline {
+  const params = new URLSearchParams(window.location.search)
+  const d = params.get('discipline')
+  if (d && ['electrical', 'controls', 'reliability'].includes(d)) {
+    return d as Discipline
+  }
+  return 'all'
+}
 
 function App() {
+  const [filter, setFilter] = useState<Discipline>(getInitialFilter)
+  const [selectedId, setSelectedId] = useState<string | null>(null)
+  const [mobileOpen, setMobileOpen] = useState(false)
+  const [dialogOpen, setDialogOpen] = useState(false)
+  const [errors, setErrors] = useState<FormErrors>({})
+  const [submitted, setSubmitted] = useState(false)
+
+  const dialogRef = useRef<HTMLDialogElement>(null)
+  const openerRef = useRef<HTMLElement | null>(null)
+  const formRef = useRef<HTMLFormElement>(null)
+  const mobileToggleRef = useRef<HTMLButtonElement>(null)
+  const mobileMenuRef = useRef<HTMLDivElement>(null)
+
+  const filteredServices = useMemo(() => {
+    if (filter === 'all') return [...content.services]
+    return content.services.filter((s) => s.discipline === filter)
+  }, [filter])
+
+  const selectedService = useMemo(() => {
+    if (!selectedId) return null
+    return content.services.find((s) => s.id === selectedId) ?? null
+  }, [selectedId])
+
+  /* URL sync */
+  useEffect(() => {
+    const url = new URL(window.location.href)
+    url.searchParams.set('discipline', filter)
+    window.history.replaceState({}, '', url.toString())
+  }, [filter])
+
+  /* Popstate */
+  useEffect(() => {
+    const onPop = () => {
+      const p = new URLSearchParams(window.location.search)
+      const d = p.get('discipline')
+      if (d && ['electrical', 'controls', 'reliability'].includes(d)) {
+        setFilter(d as Discipline)
+      } else {
+        setFilter('all')
+      }
+    }
+    window.addEventListener('popstate', onPop)
+    return () => window.removeEventListener('popstate', onPop)
+  }, [])
+
+  /* Dialog lifecycle */
+  useEffect(() => {
+    const dialog = dialogRef.current
+    if (!dialog) return
+    if (dialogOpen) {
+      if (!dialog.open) dialog.showModal()
+    } else {
+      if (dialog.open) dialog.close()
+    }
+  }, [dialogOpen])
+
+  /* Focus return on dialog close */
+  const handleDialogClose = useCallback(() => {
+    setDialogOpen(false)
+    setTimeout(() => openerRef.current?.focus(), 0)
+  }, [])
+
+  /* Mobile menu body lock */
+  useEffect(() => {
+    document.body.style.overflow = mobileOpen ? 'hidden' : ''
+    return () => { document.body.style.overflow = '' }
+  }, [mobileOpen])
+
+  /* Close mobile menu on Escape */
+  useEffect(() => {
+    if (!mobileOpen) return
+    const onKey = (e: KeyboardEvent) => {
+      if (e.key === 'Escape') {
+        setMobileOpen(false)
+        setTimeout(() => mobileToggleRef.current?.focus(), 0)
+      }
+    }
+    window.addEventListener('keydown', onKey)
+    return () => window.removeEventListener('keydown', onKey)
+  }, [mobileOpen])
+
+  /* Focus trap in mobile menu */
+  useEffect(() => {
+    if (!mobileOpen) return
+    const container = mobileMenuRef.current
+    if (!container) return
+    const onFocus = (e: FocusEvent) => {
+      if (!container.contains(e.target as Node)) {
+        const first = container.querySelector<HTMLElement>(
+          'a, button, input, select, textarea, [tabindex]:not([tabindex="-1"])'
+        )
+        first?.focus()
+      }
+    }
+    document.addEventListener('focusin', onFocus)
+    return () => document.removeEventListener('focusin', onFocus)
+  }, [mobileOpen])
+
+  const openScopeDialog = useCallback((e: React.MouseEvent<HTMLElement>) => {
+    openerRef.current = e.currentTarget
+    setErrors({})
+    setSubmitted(false)
+    setDialogOpen(true)
+  }, [])
+
+  const closeMobileAndScroll = useCallback((href: string) => {
+    setMobileOpen(false)
+    const el = document.querySelector(href)
+    if (el) el.scrollIntoView({ behavior: 'smooth' })
+  }, [])
+
+  const handleFilter = useCallback((value: Discipline) => {
+    setFilter(value)
+    setSelectedId(null)
+  }, [])
+
+  const handleSelect = useCallback((id: string) => {
+    setSelectedId((prev) => (prev === id ? null : id))
+  }, [])
+
+  const handleSubmit = useCallback((e: React.FormEvent<HTMLFormElement>) => {
+    e.preventDefault()
+    const fd = new FormData(e.currentTarget)
+    const get = (k: string) => (fd.get(k) as string ?? '').trim()
+    const errs: FormErrors = {}
+
+    const name = get('name')
+    const email = get('email')
+    const projectType = get('projectType')
+    const summary = get('summary')
+
+    if (!name) errs.name = 'Please enter your name.'
+    if (!email) errs.email = 'Please enter your work email.'
+    else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) errs.email = 'Please enter a valid email address.'
+    if (!projectType) errs.projectType = 'Please select a project type.'
+    if (!summary) errs.summary = 'Please describe your project.'
+    else if (summary.replace(/\s/g, '').length < 20) errs.summary = 'Please provide at least 20 characters of detail.'
+
+    if (Object.keys(errs).length) {
+      setErrors(errs)
+      return
+    }
+    setErrors({})
+    setSubmitted(true)
+  }, [])
+
+  const filterCount = filteredServices.length
+
   return (
     <div className="site-shell">
+      {/* ===== Header ===== */}
       <header className="site-header">
         <a className="brand" href="#top" aria-label="Gridline Field Services home">
           <strong>{content.brand}</strong>
           <span>{content.descriptor}</span>
         </a>
-        <nav aria-label="Primary navigation">
-          {content.nav.map((item) => <a key={item.href} href={item.href}>{item.label}</a>)}
+
+        <nav className="header-nav" aria-label="Primary navigation">
+          {content.nav.map((item) => (
+            <a key={item.href} href={item.href}>{item.label}</a>
+          ))}
         </nav>
-        <button type="button" data-testid="scope-review-open">{content.hero.primaryAction}</button>
+
+        <div className="header-actions">
+          <button
+            type="button"
+            className="btn btn-primary"
+            data-testid="scope-review-open"
+            onClick={openScopeDialog}
+          >
+            {content.hero.primaryAction}
+          </button>
+          <button
+            ref={mobileToggleRef}
+            type="button"
+            className="mobile-toggle"
+            data-testid="mobile-menu-toggle"
+            aria-expanded={mobileOpen}
+            aria-label={mobileOpen ? 'Close menu' : 'Open menu'}
+            onClick={() => setMobileOpen((o) => !o)}
+          >
+            <svg width="20" height="14" viewBox="0 0 20 14" fill="none" aria-hidden="true">
+              <rect width="20" height="2" rx="1" fill="currentColor" />
+              <rect y="6" width="20" height="2" rx="1" fill="currentColor" />
+              <rect y="12" width="20" height="2" rx="1" fill="currentColor" />
+            </svg>
+          </button>
+        </div>
       </header>
 
+      {/* ===== Mobile Menu ===== */}
+      {mobileOpen && (
+          <div className="mobile-menu-overlay open" role="presentation" onClick={(e) => { if (e.target === e.currentTarget) { setMobileOpen(false); setTimeout(() => mobileToggleRef.current?.focus(), 0) } }}>
+          <div
+            ref={mobileMenuRef}
+            className="mobile-menu"
+            data-testid="mobile-menu"
+            role="dialog"
+            aria-modal="true"
+            aria-label="Navigation"
+          >
+            <div className="mobile-menu-header">
+              <a className="brand" href="#top" onClick={() => setMobileOpen(false)}>
+                <strong>{content.brand}</strong>
+                <span>{content.descriptor}</span>
+              </a>
+              <button
+                type="button"
+                className="mobile-menu-close"
+                aria-label="Close menu"
+                onClick={() => {
+                  setMobileOpen(false)
+                  setTimeout(() => mobileToggleRef.current?.focus(), 0)
+                }}
+              >
+                <svg width="14" height="14" viewBox="0 0 14 14" fill="none" aria-hidden="true">
+                  <path d="M1 1l12 12M13 1L1 13" stroke="currentColor" strokeWidth="2" strokeLinecap="round" />
+                </svg>
+              </button>
+            </div>
+            <nav className="mobile-menu-nav" aria-label="Mobile navigation">
+              {content.nav.map((item) => (
+                <a
+                  key={item.href}
+                  href={item.href}
+                  onClick={(e) => { e.preventDefault(); closeMobileAndScroll(item.href) }}
+                >
+                  {item.label}
+                </a>
+              ))}
+            </nav>
+            <div className="mobile-menu-actions">
+              <button
+                type="button"
+                className="btn btn-primary"
+                data-testid="scope-review-open"
+                onClick={(e) => {
+                  setMobileOpen(false)
+                  setTimeout(() => openScopeDialog(e), 100)
+                }}
+              >
+                {content.hero.primaryAction}
+              </button>
+            </div>
+          </div>
+        </div>
+      )}
+
+      {/* ===== Main ===== */}
       <main id="top">
-        <section className="hero">
+        {/* Hero */}
+        <motion.section
+          className="hero"
+          initial={{ opacity: 0, y: 20 }}
+          animate={{ opacity: 1, y: 0 }}
+          transition={{ duration: 0.6, ease: 'easeOut' }}
+        >
           <p className="eyebrow">{content.hero.eyebrow}</p>
           <h1>{content.hero.title}</h1>
-          <p>{content.hero.body}</p>
-          <a href="#services">{content.hero.secondaryAction}</a>
-        </section>
+          <p className="hero-body">{content.hero.body}</p>
+          <div className="hero-actions">
+            <button
+              type="button"
+              className="btn btn-primary"
+              data-testid="scope-review-open"
+              onClick={openScopeDialog}
+            >
+              {content.hero.primaryAction}
+            </button>
+            <a href="#services" className="btn btn-secondary">
+              {content.hero.secondaryAction}
+            </a>
+          </div>
+          <p className="hero-availability">{content.hero.availability}</p>
+        </motion.section>
 
+        {/* Services */}
         <section id="services" className="services">
-          <p className="eyebrow">{content.servicesIntro.eyebrow}</p>
-          <h2>{content.servicesIntro.title}</h2>
-          <p>{content.servicesIntro.body}</p>
-          <div className="service-grid">
-            {content.services.map((service) => (
-              <article key={service.id} data-testid={`service-card-${service.id}`}>
-                <p>{service.discipline}</p>
-                <h3>{service.title}</h3>
-                <p>{service.summary}</p>
-              </article>
+          <div className="services-header">
+            <p className="eyebrow">{content.servicesIntro.eyebrow}</p>
+            <h2>{content.servicesIntro.title}</h2>
+            <p className="services-intro">{content.servicesIntro.body}</p>
+          </div>
+
+          <div className="filters" role="group" aria-label="Service filters">
+            {content.filters.map((f) => (
+              <button
+                key={f.value}
+                type="button"
+                className="filter-btn"
+                data-testid={`filter-${f.value}`}
+                aria-pressed={filter === f.value}
+                onClick={() => handleFilter(f.value)}
+              >
+                {f.label}
+              </button>
             ))}
           </div>
+
+          <p className="service-count" data-testid="service-count" aria-live="polite">
+            {filterCount} {filterCount === 1 ? 'service' : 'services'}
+          </p>
+
+          <div className="service-grid-wrap">
+            <motion.div
+              className="service-grid"
+              key={filter}
+              initial={{ opacity: 0 }}
+              animate={{ opacity: 1 }}
+              transition={{ duration: 0.25 }}
+            >
+              {filteredServices.map((service, i) => (
+                <motion.article
+                  key={service.id}
+                  className={`service-card${selectedId === service.id ? ' service-card--selected' : ''}`}
+                  data-testid={`service-card-${service.id}`}
+                  initial={{ opacity: 0, y: 12 }}
+                  animate={{ opacity: 1, y: 0 }}
+                  transition={{ delay: i * 0.05, duration: 0.3, ease: 'easeOut' }}
+                >
+                  <p className="card-discipline">{service.discipline}</p>
+                  <h3 className="card-title">{service.title}</h3>
+                  <p className="card-summary">{service.summary}</p>
+                  <button
+                    type="button"
+                    className="card-action"
+                    aria-pressed={selectedId === service.id}
+                    aria-label={`${selectedId === service.id ? 'Collapse' : 'Inspect'} ${service.title}`}
+                    onClick={() => handleSelect(service.id)}
+                  >
+                    {selectedId === service.id ? 'Close' : 'Inspect'}
+                  </button>
+                </motion.article>
+              ))}
+            </motion.div>
+          </div>
+
+          {/* Detail */}
+          {selectedService && (
+            <motion.div
+              className="service-detail"
+              data-testid="service-detail"
+              role="region"
+              aria-label={`Detail for ${selectedService.title}`}
+              aria-live="polite"
+              initial={{ opacity: 0, y: 10 }}
+              animate={{ opacity: 1, y: 0 }}
+              transition={{ duration: 0.3, ease: 'easeOut' }}
+              key={selectedService.id}
+            >
+              <div className="detail-inner">
+                <div className="detail-image-wrap">
+                  {selectedService.image ? (
+                    <img
+                      className="detail-image"
+                      src={selectedService.image}
+                      alt={selectedService.imageAlt}
+                      loading="lazy"
+                    />
+                  ) : (
+                    <div className="media-fallback" data-testid="media-fallback">
+                      <p className="media-fallback-label">No field image supplied</p>
+                      <p className="media-fallback-title">{selectedService.title}</p>
+                    </div>
+                  )}
+                </div>
+                <div className="detail-content">
+                  <h3 className="detail-title">{selectedService.title}</h3>
+                  <p className="detail-description">{selectedService.description}</p>
+                  <ul className="detail-deliverables">
+                    {selectedService.deliverables.map((d) => (
+                      <li key={d}>{d}</li>
+                    ))}
+                  </ul>
+                  <p className="detail-response">{selectedService.responseNote}</p>
+                </div>
+              </div>
+            </motion.div>
+          )}
+        </section>
+
+        {/* Approach */}
+        <section id="approach" className="approach">
+          <motion.div
+            className="approach-inner"
+            initial={{ opacity: 0, y: 16 }}
+            whileInView={{ opacity: 1, y: 0 }}
+            viewport={{ once: true, margin: '-80px' }}
+            transition={{ duration: 0.5, ease: 'easeOut' }}
+          >
+            <p className="eyebrow">{content.approach.eyebrow}</p>
+            <h2>{content.approach.title}</h2>
+            <div className="principles">
+              {content.approach.principles.map((p, i) => (
+                <motion.div
+                  key={p.number}
+                  className="principle"
+                  initial={{ opacity: 0, y: 12 }}
+                  whileInView={{ opacity: 1, y: 0 }}
+                  viewport={{ once: true, margin: '-40px' }}
+                  transition={{ delay: i * 0.1, duration: 0.4, ease: 'easeOut' }}
+                >
+                  <span className="principle-number">{p.number}</span>
+                  <h3 className="principle-title">{p.title}</h3>
+                  <p className="principle-body">{p.body}</p>
+                </motion.div>
+              ))}
+            </div>
+          </motion.div>
+        </section>
+
+        {/* Close */}
+        <section className="close">
+          <motion.div
+            className="close-inner"
+            initial={{ opacity: 0, y: 16 }}
+            whileInView={{ opacity: 1, y: 0 }}
+            viewport={{ once: true, margin: '-60px' }}
+            transition={{ duration: 0.5, ease: 'easeOut' }}
+          >
+            <p className="eyebrow">{content.close.eyebrow}</p>
+            <h2>{content.close.title}</h2>
+            <p className="close-body">{content.close.body}</p>
+            <button
+              type="button"
+              className="btn btn-primary"
+              data-testid="scope-review-open"
+              onClick={openScopeDialog}
+            >
+              {content.hero.primaryAction}
+            </button>
+          </motion.div>
         </section>
       </main>
+
+      {/* Footer */}
+      <footer className="site-footer">
+        <p className="footer-line">{content.footer.line}</p>
+        <p className="footer-region">{content.footer.region}</p>
+        <p className="footer-note">{content.footer.note}</p>
+      </footer>
+
+      {/* ===== Scope Review Dialog ===== */}
+      <dialog
+        ref={dialogRef}
+        className="scope-dialog"
+        data-testid="scope-review-dialog"
+        onClose={handleDialogClose}
+        onCancel={(e) => {
+          e.preventDefault()
+          setDialogOpen(false)
+        }}
+        onClick={(e) => {
+          if (e.target === dialogRef.current) setDialogOpen(false)
+        }}
+      >
+        <div className="dialog-inner">
+          <div className="dialog-header">
+            <h2>{content.form.title}</h2>
+            <button
+              type="button"
+              className="dialog-close"
+              aria-label="Close dialog"
+              onClick={() => setDialogOpen(false)}
+            >
+              <svg width="14" height="14" viewBox="0 0 14 14" fill="none" aria-hidden="true">
+                <path d="M1 1l12 12M13 1L1 13" stroke="currentColor" strokeWidth="2" strokeLinecap="round" />
+              </svg>
+            </button>
+          </div>
+
+          {!submitted ? (
+            <>
+              <p className="dialog-intro">{content.form.intro}</p>
+              <form
+                ref={formRef}
+                className="scope-form"
+                data-testid="scope-review-form"
+                noValidate
+                onSubmit={handleSubmit}
+              >
+                <div className="form-field">
+                  <label className="form-label" htmlFor="scope-name">Name</label>
+                  <input
+                    className="form-input"
+                    id="scope-name"
+                    name="name"
+                    type="text"
+                    autoComplete="name"
+                  />
+                  {errors.name && (
+                    <p className="form-error" data-testid="error-name" role="alert">{errors.name}</p>
+                  )}
+                </div>
+
+                <div className="form-field">
+                  <label className="form-label" htmlFor="scope-email">Work email</label>
+                  <input
+                    className="form-input"
+                    id="scope-email"
+                    name="email"
+                    type="email"
+                    autoComplete="email"
+                  />
+                  {errors.email && (
+                    <p className="form-error" data-testid="error-email" role="alert">{errors.email}</p>
+                  )}
+                </div>
+
+                <div className="form-field">
+                  <label className="form-label" htmlFor="scope-type">Project type</label>
+                  <select
+                    className="form-select"
+                    id="scope-type"
+                    name="projectType"
+                    defaultValue=""
+                  >
+                    <option value="" disabled>Select a project type</option>
+                    {content.form.projectTypes.map((t) => (
+                      <option key={t} value={t}>{t}</option>
+                    ))}
+                  </select>
+                  {errors.projectType && (
+                    <p className="form-error" data-testid="error-projectType" role="alert">{errors.projectType}</p>
+                  )}
+                </div>
+
+                <div className="form-field">
+                  <label className="form-label" htmlFor="scope-summary">Project summary</label>
+                  <textarea
+                    className="form-textarea"
+                    id="scope-summary"
+                    name="summary"
+                    rows={4}
+                  />
+                  {errors.summary && (
+                    <p className="form-error" data-testid="error-summary" role="alert">{errors.summary}</p>
+                  )}
+                </div>
+
+                <button type="submit" className="btn btn-primary form-submit">
+                  {content.form.submit}
+                </button>
+              </form>
+            </>
+          ) : (
+            <div className="form-success" data-testid="scope-review-success" role="status">
+              {content.form.success}
+            </div>
+          )}
+        </div>
+      </dialog>
     </div>
   )
 }

--- baseline/src/styles.css
+++ candidate/src/styles.css
@@ -1,37 +1,534 @@
+/* ============================================================
+   Gridline Field Services — Stylesheet
+   "Field notebook meets control cabinet."
+   ============================================================ */
+
 :root {
-  font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
-  color: #18211f;
-  background: #f1efe7;
-  font-synthesis: none;
-  text-rendering: optimizeLegibility;
+  --ink: #18211f;
+  --ink-secondary: #5a6660;
+  --paper: #f1efe7;
+  --paper-alt: #eae7de;
+  --rule: #b7bbb4;
+  --rule-light: #d4d6d2;
+  --citron: #bfb032;
+  --citron-dim: #a89a28;
+  --citron-pale: #eeebb3;
+  --overlay: rgba(24, 33, 31, 0.55);
+  --font: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
+  --font-mono: ui-monospace, "SFMono-Regular", "SF Mono", Menlo, Consolas, monospace;
 }
 
-* { box-sizing: border-box; }
+*, *::before, *::after { box-sizing: border-box; }
 html { scroll-behavior: smooth; }
-body { margin: 0; min-width: 320px; }
-button, input, select, textarea { font: inherit; }
+body { margin: 0; min-width: 320px; color: var(--ink); background: var(--paper); font-family: var(--font); font-synthesis: none; text-rendering: optimizeLegibility; -webkit-font-smoothing: antialiased; }
+button, input, select, textarea { font: inherit; color: inherit; }
 a { color: inherit; }
-.site-shell { min-height: 100vh; }
-.site-header { display: flex; align-items: center; justify-content: space-between; gap: 2rem; padding: 1rem 4vw; border-bottom: 1px solid #b7bbb4; }
-.brand { display: grid; text-decoration: none; }
-.brand span, .eyebrow { font-size: .75rem; letter-spacing: .08em; text-transform: uppercase; }
-nav { display: flex; gap: 1.5rem; }
-.hero, .services { padding: 5rem 6vw; }
-.hero { min-height: 55vh; display: grid; align-content: center; max-width: 74rem; }
-h1 { max-width: 10ch; margin: .25em 0; font-size: clamp(3rem, 9vw, 7rem); line-height: .9; letter-spacing: -.06em; }
-.hero > p:not(.eyebrow) { max-width: 42rem; font-size: 1.15rem; line-height: 1.6; }
-.services { border-top: 1px solid #b7bbb4; }
-.services > h2 { max-width: 18ch; font-size: clamp(2rem, 5vw, 4.5rem); line-height: 1; }
-.service-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 1px; margin-top: 3rem; background: #aeb4ae; border: 1px solid #aeb4ae; }
-.service-grid article { min-width: 0; padding: 1.5rem; background: #f1efe7; }
+img { max-width: 100%; height: auto; display: block; }
+:focus-visible { outline: 2px solid var(--citron); outline-offset: 2px; }
+
+/* ============================================================
+   Header
+   ============================================================ */
+.site-header {
+  position: sticky; top: 0; z-index: 100;
+  display: flex; align-items: center; gap: 2rem;
+  padding: 0.75rem 4vw;
+  background: var(--paper);
+  border-bottom: 1px solid var(--rule);
+}
+
+.brand {
+  display: flex; flex-direction: column; gap: 0;
+  text-decoration: none; line-height: 1.1;
+  flex-shrink: 0;
+}
+.brand strong {
+  font-size: 1rem; letter-spacing: 0.14em; font-weight: 700;
+}
+.brand span {
+  font-size: 0.65rem; letter-spacing: 0.06em; text-transform: uppercase; color: var(--ink-secondary);
+}
+
+.header-nav {
+  display: flex; gap: 1.5rem; margin-left: auto;
+}
+.header-nav a {
+  font-size: 0.8rem; letter-spacing: 0.04em; text-transform: uppercase;
+  text-decoration: none; padding: 0.25rem 0; position: relative;
+  color: var(--ink-secondary);
+  transition: color 0.2s;
+}
+.header-nav a:hover { color: var(--ink); }
+
+.header-actions {
+  display: flex; align-items: center; gap: 1rem;
+}
 
+.mobile-toggle {
+  display: none;
+  background: none; border: 1px solid var(--rule); cursor: pointer;
+  padding: 0.4rem 0.55rem; border-radius: 3px;
+  line-height: 1;
+}
+.mobile-toggle svg { display: block; }
+
+/* ============================================================
+   Buttons
+   ============================================================ */
+.btn {
+  display: inline-flex; align-items: center; justify-content: center;
+  padding: 0.6rem 1.4rem; border-radius: 3px;
+  font-size: 0.8rem; letter-spacing: 0.03em; font-weight: 600;
+  cursor: pointer; border: 1px solid transparent;
+  transition: background 0.2s, border-color 0.2s, color 0.2s;
+  text-decoration: none; white-space: nowrap;
+}
+.btn-primary {
+  background: var(--citron); color: var(--ink); border-color: var(--citron);
+}
+.btn-primary:hover { background: var(--citron-dim); border-color: var(--citron-dim); }
+.btn-secondary {
+  background: transparent; color: var(--ink); border-color: var(--ink);
+}
+.btn-secondary:hover { background: var(--ink); color: var(--paper); }
+
+/* ============================================================
+   Mobile Menu
+   ============================================================ */
+.mobile-menu-overlay {
+  display: none;
+  position: fixed; inset: 0; z-index: 200;
+  background: var(--overlay);
+}
+.mobile-menu-overlay.open { display: flex; justify-content: flex-end; }
+
+.mobile-menu {
+  background: var(--paper); width: min(85vw, 320px); height: 100%;
+  padding: 1.5rem; display: flex; flex-direction: column; gap: 1.5rem;
+  overflow-y: auto;
+  animation: slideInRight 0.25s ease-out;
+}
+.mobile-menu-header {
+  display: flex; align-items: center; justify-content: space-between;
+}
+.mobile-menu-close {
+  background: none; border: 1px solid var(--rule); cursor: pointer;
+  padding: 0.35rem 0.5rem; border-radius: 3px; line-height: 1;
+}
+.mobile-menu-nav {
+  display: flex; flex-direction: column; gap: 0.25rem;
+}
+.mobile-menu-nav a {
+  font-size: 1rem; padding: 0.65rem 0; text-decoration: none;
+  border-bottom: 1px solid var(--rule-light); color: var(--ink);
+  letter-spacing: 0.02em;
+}
+.mobile-menu-actions {
+  margin-top: auto; display: flex; flex-direction: column; gap: 0.75rem;
+}
+
+/* ============================================================
+   Hero
+   ============================================================ */
+.hero {
+  padding: 4rem 4vw 5rem;
+  max-width: 74rem;
+  min-height: 55vh;
+  display: grid; align-content: center;
+  gap: 0;
+}
+.hero .eyebrow {
+  font-size: 0.72rem; letter-spacing: 0.08em; text-transform: uppercase;
+  color: var(--ink-secondary); margin: 0 0 0.75rem;
+}
+.hero h1 {
+  margin: 0 0 0.5em; max-width: 14ch;
+  font-size: clamp(2.75rem, 8vw, 6.5rem); line-height: 0.92; letter-spacing: -0.06em;
+  font-weight: 700;
+}
+.hero-body {
+  max-width: 42rem; font-size: 1.1rem; line-height: 1.65;
+  color: var(--ink-secondary); margin: 0 0 2rem;
+}
+.hero-actions {
+  display: flex; flex-wrap: wrap; gap: 0.75rem; align-items: center;
+}
+.hero-availability {
+  margin-top: 2.5rem; font-size: 0.72rem; letter-spacing: 0.06em;
+  text-transform: uppercase; color: var(--ink-secondary);
+  padding-top: 1.5rem; border-top: 1px solid var(--rule-light);
+  max-width: 28rem;
+}
+
+/* ============================================================
+   Services
+   ============================================================ */
+.services {
+  padding: 5rem 4vw 4rem;
+  border-top: 1px solid var(--rule);
+}
+.services-header {
+  max-width: 74rem; margin: 0 auto;
+}
+.services .eyebrow {
+  font-size: 0.72rem; letter-spacing: 0.08em; text-transform: uppercase;
+  color: var(--ink-secondary); margin: 0 0 0.5rem;
+}
+.services h2 {
+  margin: 0 0 0.5em; max-width: 20ch;
+  font-size: clamp(2rem, 5vw, 4rem); line-height: 1; letter-spacing: -0.04em;
+  font-weight: 700;
+}
+.services-intro {
+  max-width: 40rem; font-size: 1rem; line-height: 1.6;
+  color: var(--ink-secondary); margin: 0 0 2.5rem;
+}
+
+/* Filters */
+.filters {
+  display: flex; flex-wrap: wrap; gap: 0.5rem;
+  margin-bottom: 1.5rem;
+}
+.filter-btn {
+  background: transparent; border: 1px solid var(--rule); cursor: pointer;
+  padding: 0.4rem 1rem; border-radius: 3px;
+  font-size: 0.78rem; letter-spacing: 0.03em; font-weight: 500;
+  transition: background 0.15s, border-color 0.15s, color 0.15s;
+}
+.filter-btn:hover {
+  border-color: var(--ink); color: var(--ink);
+}
+.filter-btn[aria-pressed="true"] {
+  background: var(--citron); border-color: var(--citron); color: var(--ink); font-weight: 600;
+}
+
+.service-count {
+  font-size: 0.75rem; letter-spacing: 0.04em; text-transform: uppercase;
+  color: var(--ink-secondary); margin: 0 0 1.5rem;
+}
+
+/* Service Grid */
+.service-grid-wrap {
+  max-width: 74rem;
+}
+.service-grid {
+  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
+  gap: 1px; background: var(--rule); border: 1px solid var(--rule);
+}
+.service-card {
+  background: var(--paper); padding: 1.5rem;
+  display: flex; flex-direction: column; gap: 0.6rem;
+  transition: background 0.15s;
+  min-width: 0;
+}
+.service-card--selected {
+  background: var(--paper-alt);
+}
+.card-discipline {
+  font-size: 0.65rem; letter-spacing: 0.08em; text-transform: uppercase;
+  color: var(--ink-secondary); margin: 0;
+}
+.card-title {
+  font-size: 1.1rem; line-height: 1.25; font-weight: 600; margin: 0;
+  letter-spacing: -0.01em;
+  /* Long titles must not truncate */
+  overflow-wrap: break-word;
+}
+.card-summary {
+  font-size: 0.88rem; line-height: 1.55; color: var(--ink-secondary);
+  margin: 0; flex: 1;
+}
+.card-action {
+  align-self: flex-start;
+  background: none; border: 1px solid var(--rule); cursor: pointer;
+  padding: 0.35rem 0.9rem; border-radius: 3px;
+  font-size: 0.72rem; letter-spacing: 0.04em; font-weight: 600;
+  text-transform: uppercase; margin-top: 0.25rem;
+  transition: background 0.15s, border-color 0.15s, color 0.15s;
+}
+.card-action:hover { border-color: var(--ink); color: var(--ink); }
+.service-card--selected .card-action {
+  background: var(--citron); border-color: var(--citron); color: var(--ink);
+}
+
+/* Service Detail */
+.service-detail {
+  max-width: 74rem; margin-top: 1px;
+  border: 1px solid var(--rule); background: var(--paper-alt);
+  overflow: hidden;
+}
+.detail-inner {
+  display: grid; grid-template-columns: 280px 1fr; gap: 0;
+}
+.detail-image-wrap {
+  display: flex; align-items: center; justify-content: center;
+  padding: 2rem; background: var(--paper);
+  border-right: 1px solid var(--rule);
+  min-height: 200px;
+}
+.detail-image {
+  max-width: 100%; max-height: 220px; object-fit: contain;
+}
+.detail-content {
+  padding: 2rem; display: flex; flex-direction: column; gap: 1rem;
+}
+.detail-title {
+  font-size: 1.15rem; font-weight: 600; margin: 0;
+  letter-spacing: -0.01em; line-height: 1.3;
+}
+.detail-description {
+  font-size: 0.92rem; line-height: 1.65; color: var(--ink-secondary); margin: 0;
+}
+.detail-deliverables {
+  margin: 0; padding: 0 0 0 1.25rem;
+  font-size: 0.85rem; line-height: 1.7; color: var(--ink-secondary);
+}
+.detail-deliverables li { margin-bottom: 0.15rem; }
+.detail-response {
+  font-size: 0.78rem; letter-spacing: 0.03em;
+  color: var(--ink-secondary); margin: 0;
+  padding-top: 0.75rem; border-top: 1px solid var(--rule-light);
+  font-style: italic;
+}
+
+/* ============================================================
+   Media Fallback (for missing images)
+   ============================================================ */
+.media-fallback {
+  display: flex; flex-direction: column; align-items: center; justify-content: center;
+  padding: 2.5rem 1.5rem; text-align: center;
+  background: var(--paper);
+  border: 1px dashed var(--rule);
+  min-height: 180px; width: 100%;
+}
+.media-fallback-label {
+  font-size: 0.65rem; letter-spacing: 0.1em; text-transform: uppercase;
+  color: var(--ink-secondary); margin: 0 0 0.5rem;
+}
+.media-fallback-title {
+  font-size: 0.85rem; font-weight: 500; line-height: 1.4;
+  max-width: 20ch; color: var(--ink);
+}
+
+/* ============================================================
+   Approach
+   ============================================================ */
+.approach {
+  padding: 5rem 4vw;
+  border-top: 1px solid var(--rule);
+}
+.approach-inner {
+  max-width: 74rem;
+}
+.approach .eyebrow {
+  font-size: 0.72rem; letter-spacing: 0.08em; text-transform: uppercase;
+  color: var(--ink-secondary); margin: 0 0 0.5rem;
+}
+.approach h2 {
+  margin: 0 0 3rem; max-width: 22ch;
+  font-size: clamp(2rem, 5vw, 4rem); line-height: 1; letter-spacing: -0.04em;
+  font-weight: 700;
+}
+.principles {
+  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 2.5rem;
+}
+.principle {
+  display: flex; flex-direction: column; gap: 0.5rem;
+}
+.principle-number {
+  font-family: var(--font-mono); font-size: 0.75rem; letter-spacing: 0.05em;
+  color: var(--citron); font-weight: 600;
+}
+.principle-title {
+  font-size: 1.05rem; font-weight: 600; margin: 0;
+  letter-spacing: -0.01em; line-height: 1.3;
+}
+.principle-body {
+  font-size: 0.88rem; line-height: 1.6; color: var(--ink-secondary); margin: 0;
+}
+
+/* ============================================================
+   Close / CTA
+   ============================================================ */
+.close {
+  padding: 5rem 4vw;
+  border-top: 1px solid var(--rule);
+}
+.close-inner {
+  max-width: 48rem;
+}
+.close .eyebrow {
+  font-size: 0.72rem; letter-spacing: 0.08em; text-transform: uppercase;
+  color: var(--ink-secondary); margin: 0 0 0.5rem;
+}
+.close h2 {
+  margin: 0 0 0.75em; max-width: 20ch;
+  font-size: clamp(1.75rem, 4vw, 3rem); line-height: 1.05; letter-spacing: -0.03em;
+  font-weight: 700;
+}
+.close-body {
+  font-size: 1rem; line-height: 1.6; color: var(--ink-secondary);
+  margin: 0 0 2rem; max-width: 38rem;
+}
+
+/* ============================================================
+   Footer
+   ============================================================ */
+.site-footer {
+  padding: 2rem 4vw;
+  border-top: 1px solid var(--rule);
+  display: flex; flex-wrap: wrap; gap: 0.5rem 2rem;
+  font-size: 0.72rem; letter-spacing: 0.04em;
+  color: var(--ink-secondary);
+}
+.footer-line { margin: 0; }
+.footer-region { margin: 0; }
+.footer-note {
+  margin: 0; width: 100%; margin-top: 0.5rem;
+  padding-top: 0.75rem; border-top: 1px solid var(--rule-light);
+}
+
+/* ============================================================
+   Dialog
+   ============================================================ */
+.scope-dialog {
+  border: none; padding: 0; margin: 0;
+  max-width: 34rem; width: calc(100vw - 2rem);
+  background: var(--paper); border-radius: 4px;
+  box-shadow: 0 24px 80px rgba(0,0,0,0.25);
+  max-height: 90vh; overflow-y: auto;
+}
+.scope-dialog::backdrop {
+  background: var(--overlay);
+}
+
+.dialog-inner {
+  padding: 2rem;
+}
+.dialog-header {
+  display: flex; align-items: flex-start; justify-content: space-between;
+  gap: 1rem; margin-bottom: 0.5rem;
+}
+.dialog-header h2 {
+  margin: 0; font-size: 1.35rem; font-weight: 700; letter-spacing: -0.02em;
+}
+.dialog-close {
+  background: none; border: 1px solid var(--rule); cursor: pointer;
+  padding: 0.3rem 0.5rem; border-radius: 3px; line-height: 1;
+  flex-shrink: 0;
+}
+.dialog-intro {
+  font-size: 0.88rem; line-height: 1.55; color: var(--ink-secondary);
+  margin: 0 0 1.75rem;
+}
+
+/* Form */
+.scope-form {
+  display: flex; flex-direction: column; gap: 1.25rem;
+}
+.form-field {
+  display: flex; flex-direction: column; gap: 0.3rem;
+}
+.form-label {
+  font-size: 0.78rem; font-weight: 600; letter-spacing: 0.03em;
+}
+.form-input, .form-select, .form-textarea {
+  border: 1px solid var(--rule); border-radius: 3px;
+  padding: 0.55rem 0.75rem; font-size: 0.9rem;
+  background: var(--paper); transition: border-color 0.15s;
+}
+.form-input:focus, .form-select:focus, .form-textarea:focus {
+  border-color: var(--citron); outline: none;
+  box-shadow: 0 0 0 2px var(--citron-pale);
+}
+.form-textarea { min-height: 100px; resize: vertical; }
+.form-error {
+  font-size: 0.75rem; color: #a33; margin-top: 0.1rem;
+}
+.form-submit {
+  margin-top: 0.5rem;
+}
+.form-success {
+  padding: 1.5rem 0; font-size: 1rem; line-height: 1.6;
+}
+
+/* ============================================================
+   Animations
+   ============================================================ */
+@keyframes fadeInUp {
+  from { opacity: 0; transform: translateY(16px); }
+  to { opacity: 1; transform: translateY(0); }
+}
+@keyframes fadeIn {
+  from { opacity: 0; }
+  to { opacity: 1; }
+}
+@keyframes slideInRight {
+  from { transform: translateX(100%); }
+  to { transform: translateX(0); }
+}
+
+/* ============================================================
+   Responsive — Tablet (768px)
+   ============================================================ */
+@media (max-width: 900px) {
+  .service-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
+  .detail-inner { grid-template-columns: 1fr; }
+  .detail-image-wrap { border-right: none; border-bottom: 1px solid var(--rule); }
+  .principles { grid-template-columns: 1fr 1fr; gap: 2rem; }
+}
+
+/* ============================================================
+   Responsive — Mobile (≤760px)
+   ============================================================ */
 @media (max-width: 760px) {
-  .site-header nav { display: none; }
-  .site-header > button { display: none; }
+  .header-nav { display: none; }
+  .header-actions .btn { display: none; }
+  .mobile-toggle { display: block; }
+
+  .hero { min-height: auto; padding: 3rem 4vw 3.5rem; }
+  .hero h1 { font-size: clamp(2.25rem, 10vw, 3.5rem); }
+  .hero-body { font-size: 1rem; }
+
+  .services { padding: 3.5rem 4vw; }
+  .services h2 { font-size: clamp(1.6rem, 6vw, 2.5rem); }
   .service-grid { grid-template-columns: 1fr; }
+  .service-detail { margin-top: 1px; }
+  .detail-inner { grid-template-columns: 1fr; }
+  .detail-image-wrap { border-right: none; border-bottom: 1px solid var(--rule); padding: 1.5rem; }
+
+  .approach { padding: 3.5rem 4vw; }
+  .approach h2 { font-size: clamp(1.6rem, 6vw, 2.5rem); }
+  .principles { grid-template-columns: 1fr; gap: 1.75rem; }
+
+  .close { padding: 3.5rem 4vw; }
+  .close h2 { font-size: clamp(1.4rem, 5vw, 2rem); }
+
+  .scope-dialog { max-width: 100%; width: calc(100vw - 1rem); }
+  .dialog-inner { padding: 1.5rem; }
+}
+
+/* ============================================================
+   Responsive — Wide (≥1200px)
+   ============================================================ */
+@media (min-width: 1200px) {
+  .hero { padding: 6rem 6vw 7rem; }
+  .services { padding: 6rem 6vw 5rem; }
+  .approach { padding: 6rem 6vw; }
+  .close { padding: 6rem 6vw; }
+  .site-footer { padding: 2.5rem 6vw; }
 }
 
+/* ============================================================
+   Reduced Motion
+   ============================================================ */
 @media (prefers-reduced-motion: reduce) {
   html { scroll-behavior: auto; }
-  *, *::before, *::after { animation-duration: .01ms !important; animation-iteration-count: 1 !important; transition-duration: .01ms !important; }
+  *, *::before, *::after {
+    animation-duration: 0.01ms !important;
+    animation-iteration-count: 1 !important;
+    transition-duration: 0.01ms !important;
+    scroll-behavior: auto !important;
+  }
+  .mobile-menu { animation: none; }
 }
