# Scott Steinhardt — HTML Project Design System

> The canonical reference for all personal HTML projects. Every page built for or by Scott Steinhardt should follow this document.

---

## 1. Identity & Metadata

Use this block (filled in per-project) on every HTML page:

```html
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="author" content="Scott Steinhardt">
<meta name="copyright" content="Scott Steinhardt">
<meta name="robots" content="index, follow">

<!-- Per-page: fill these in -->
<title>{{Page Title}} | Scott Steinhardt</title>
<meta name="description" content="{{Page description, 150–160 chars}}">
<link rel="canonical" href="https://www.scottfromny.com/{{path}}">

<!-- Open Graph -->
<meta property="og:type" content="website">
<meta property="og:site_name" content="Scott Steinhardt">
<meta property="og:title" content="{{Page Title}}">
<meta property="og:description" content="{{Page description}}">
<meta property="og:url" content="https://www.scottfromny.com/{{path}}">
<meta property="og:image" content="{{Absolute URL to preview image}}">
<meta property="og:locale" content="en_US">

<!-- Twitter Card -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="{{Page Title}}">
<meta name="twitter:description" content="{{Page description}}">
<meta name="twitter:image" content="{{Absolute URL to preview image}}">

<!-- Person structured data -->
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Person",
  "name": "Scott Steinhardt",
  "url": "https://www.scottfromny.com",
  "email": "hi@scottsteinhardt.com",
  "sameAs": [
    "https://www.linkedin.com/in/scottbsteinhardt/",
    "https://github.com/scottsteinhardt",
    "https://bsky.app/profile/scottfromny.com"
  ],
  "address": {
    "@type": "PostalAddress",
    "addressLocality": "Brooklyn",
    "addressRegion": "NY",
    "addressCountry": "US"
  }
}
</script>
```

### Personal Facts (for bios, footers, about sections)

| Field        | Value                                                        |
|--------------|--------------------------------------------------------------|
| Name         | Scott Steinhardt                                             |
| Location     | Brooklyn, NY                                                 |
| Email        | hi@scottsteinhardt.com                                       |
| Main site    | https://www.scottfromny.com                                  |
| Blog         | https://scottfromny.com/blog/                                |
| Blog tagline | Scott Steinhardt Talks Fine Arts                             |
| Blog content | Essays, personal reflections, fiction, family stories        |
| Title        | Head of Communications and PR, [Apollo Research](https://www.apolloresearch.ai) |
| LinkedIn     | https://www.linkedin.com/in/scottbsteinhardt/                |
| GitHub       | https://github.com/scottsteinhardt                           |
| Bluesky      | https://bsky.app/profile/scottfromny.com                     |

### Bio

Scott Steinhardt has spent more than 15 years translating complicated, hard-to-explain companies into stories that stick. Today, he works at the intersection of communications and one of technology's most urgent problems: the erosion of truth.

Scott is Head of Communications and PR at [Apollo Research](https://www.apolloresearch.ai), an AI safety organization that evaluates frontier AI systems for dangerous behaviors like deception. Before that, as Head of Communications at Reality Defender, a Y Combinator-backed deepfake detection company, he spent nearly four years shaping how the world understands generative AI and synthetic media. Treating journalists as partners rather than targets, he drove over 300 placements in publications including *The New York Times*, *The Washington Post*, *Bloomberg*, and *Wired*.

His path to the AI trust-and-safety space wasn't born in a boardroom, but through a personal crisis. In 2020, he watched disinformation pull people he loved into the QAnon rabbit hole. Realizing he wanted to do more than just tell stories, he redirected his skills toward fighting the tools used to deceive people at scale.

Based in Brooklyn, Scott reads the news with the intensity of someone who takes the Fourth Estate seriously. When he's not working, he can usually be found at home with his wife, or playing guitar, bass, drums, and piano.

---

## 2. Color Palette

All projects use a **dark-first** scheme. Light mode is not required unless specified.

```css
:root {
  /* Backgrounds */
  --color-bg:         #0f0f0f;  /* page background */
  --color-surface:    #1a1a1a;  /* cards, panels, modals */
  --color-surface-2:  #242424;  /* elevated surfaces, hover states */

  /* Borders */
  --color-border:     #2e2e2e;
  --color-border-subtle: #1e1e1e;

  /* Text */
  --color-text:       #e8e4de;  /* primary — warm off-white */
  --color-text-muted: #8a8480;  /* secondary, captions, meta */
  --color-text-faint: #4a4644;  /* placeholder, disabled */

  /* Accent — warm gold, referencing fine arts / print */
  --color-accent:     #c8a96e;
  --color-accent-hover: #dfc08a;
  --color-accent-dim: rgba(200, 169, 110, 0.15);

  /* Utility */
  --color-error:      #e05c5c;
  --color-success:    #5ca87e;
  --color-link:       #c8a96e;
  --color-link-hover: #dfc08a;
}
```

### Usage Rules
- Never use pure `#000000` or `#ffffff` — always the palette values
- Accent (`--color-accent`) is for links, active states, highlights, and decorative elements only — not body text
- Text on `--color-surface` should always be `--color-text` (contrast ≥ 4.5:1)

---

## 3. Typography

```css
@import url('https://fonts.googleapis.com/css2?family=Lora:ital,wght@0,400;0,600;1,400&family=Inter:wght@400;500;600&family=JetBrains+Mono:wght@400&display=swap');

:root {
  /* Families */
  --font-serif:  'Lora', Georgia, 'Times New Roman', serif;
  --font-sans:   'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --font-mono:   'JetBrains Mono', 'Courier New', monospace;

  /* Scale */
  --text-xs:     0.75rem;   /* 12px */
  --text-sm:     0.875rem;  /* 14px */
  --text-base:   1rem;      /* 16px */
  --text-lg:     1.125rem;  /* 18px */
  --text-xl:     1.25rem;   /* 20px */
  --text-2xl:    1.5rem;    /* 24px */
  --text-3xl:    1.875rem;  /* 30px */
  --text-4xl:    2.25rem;   /* 36px */
  --text-5xl:    3rem;      /* 48px */

  /* Leading */
  --leading-tight:  1.25;
  --leading-normal: 1.6;
  --leading-loose:  1.8;

  /* Weight */
  --weight-normal:  400;
  --weight-medium:  500;
  --weight-semibold: 600;
}

body {
  font-family: var(--font-sans);
  font-size: var(--text-base);
  line-height: var(--leading-normal);
  color: var(--color-text);
  background-color: var(--color-bg);
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4, h5, h6 {
  font-family: var(--font-serif);
  font-weight: var(--weight-semibold);
  line-height: var(--leading-tight);
  color: var(--color-text);
}

h1 { font-size: var(--text-4xl); }
h2 { font-size: var(--text-3xl); }
h3 { font-size: var(--text-2xl); }
h4 { font-size: var(--text-xl); }
h5 { font-size: var(--text-lg); }
h6 { font-size: var(--text-base); }

p { margin-bottom: 1.25em; }

a {
  color: var(--color-link);
  text-decoration: underline;
  text-underline-offset: 3px;
  transition: color 0.15s ease;
}
a:hover { color: var(--color-link-hover); }

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

### Rules
- Headings → serif (`Lora`), body/UI → sans (`Inter`)
- Long-form prose body text: `var(--text-lg)` at `var(--leading-loose)` for readability
- Never go smaller than `var(--text-sm)` for visible content

---

## 4. Spacing System

Based on a 4px base unit. Always use these values — no arbitrary pixel values.

```css
:root {
  --space-1:   0.25rem;  /*  4px */
  --space-2:   0.5rem;   /*  8px */
  --space-3:   0.75rem;  /* 12px */
  --space-4:   1rem;     /* 16px */
  --space-5:   1.25rem;  /* 20px */
  --space-6:   1.5rem;   /* 24px */
  --space-8:   2rem;     /* 32px */
  --space-10:  2.5rem;   /* 40px */
  --space-12:  3rem;     /* 48px */
  --space-16:  4rem;     /* 64px */
  --space-20:  5rem;     /* 80px */
  --space-24:  6rem;     /* 96px */
}
```

---

## 5. Layout

```css
:root {
  --container-sm:   640px;
  --container-md:   768px;
  --container-lg:   1024px;
  --container-xl:   1280px;
  --container-prose: 680px;  /* max-width for body text / articles */

  --border-radius-sm:  4px;
  --border-radius:     8px;
  --border-radius-lg:  12px;
  --border-radius-xl:  16px;
  --border-radius-full: 9999px;
}

.container {
  width: 100%;
  max-width: var(--container-lg);
  margin-inline: auto;
  padding-inline: var(--space-6);
}

@media (max-width: 768px) {
  .container { padding-inline: var(--space-4); }
}

.prose {
  max-width: var(--container-prose);
  margin-inline: auto;
}
```

---

## 6. Components

### Buttons

```css
/* Base */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-6);
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  letter-spacing: 0.02em;
  border-radius: var(--border-radius);
  border: 1px solid transparent;
  cursor: pointer;
  text-decoration: none;
  transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
  white-space: nowrap;
  user-select: none;
}

.btn:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

/* Primary — filled accent */
.btn-primary {
  background: var(--color-accent);
  color: #0f0f0f;
  border-color: var(--color-accent);
}
.btn-primary:hover:not(:disabled) {
  background: var(--color-accent-hover);
  border-color: var(--color-accent-hover);
  color: #0f0f0f;
}

/* Secondary — outlined */
.btn-secondary {
  background: transparent;
  color: var(--color-accent);
  border-color: var(--color-accent);
}
.btn-secondary:hover:not(:disabled) {
  background: var(--color-accent-dim);
}

/* Ghost — minimal */
.btn-ghost {
  background: transparent;
  color: var(--color-text-muted);
  border-color: var(--color-border);
}
.btn-ghost:hover:not(:disabled) {
  background: var(--color-surface-2);
  color: var(--color-text);
}

/* Sizes */
.btn-sm { padding: var(--space-2) var(--space-4); font-size: var(--text-xs); }
.btn-lg { padding: var(--space-4) var(--space-8); font-size: var(--text-base); }
```

### Cards

```css
.card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--border-radius-lg);
  padding: var(--space-6);
  transition: border-color 0.15s ease;
}
.card:hover { border-color: var(--color-accent); }
```

### Inputs & Forms

```css
.input,
input[type="text"],
input[type="email"],
textarea,
select {
  width: 100%;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--border-radius);
  padding: var(--space-3) var(--space-4);
  font-family: var(--font-sans);
  font-size: var(--text-base);
  color: var(--color-text);
  outline: none;
  transition: border-color 0.15s ease;
}
.input:focus,
input:focus,
textarea:focus,
select:focus {
  border-color: var(--color-accent);
  box-shadow: 0 0 0 3px var(--color-accent-dim);
}
::placeholder { color: var(--color-text-faint); }

label {
  display: block;
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  color: var(--color-text-muted);
  margin-bottom: var(--space-2);
}
```

### Navigation (Standard Header)

Matches the link set on scottfromny.com. On mobile, the links collapse into a hamburger menu.

```html
<header class="site-header">
  <nav class="container nav">
    <a href="https://www.scottfromny.com" class="nav-brand">Scott Steinhardt</a>

    <button class="nav-toggle" aria-label="Toggle menu" aria-expanded="false">
      <span></span><span></span><span></span>
    </button>

    <ul class="nav-links">
      <li><a href="https://scottfromny.com/blog/">Blog + Newsletter</a></li>
      <li><a href="https://scottfromny.com/about/">About</a></li>
      <li><a href="https://scottfromny.com/work/portfolio/">Portfolio</a></li>
      <li><a href="https://scottfromny.com/projects/">Projects</a></li>
      <li><a href="https://www.linkedin.com/in/scottbsteinhardt/" target="_blank" rel="noopener">LinkedIn</a></li>
      <li><a href="https://bsky.app/profile/scottfromny.com" target="_blank" rel="noopener">Bluesky</a></li>
      <li><a href="https://github.com/scottsteinhardt" target="_blank" rel="noopener">GitHub</a></li>
      <li><a href="mailto:hi@scottsteinhardt.com">Contact</a></li>
    </ul>
  </nav>
</header>

<script>
  const toggle = document.querySelector('.nav-toggle');
  const links  = document.querySelector('.nav-links');
  toggle.addEventListener('click', () => {
    const open = toggle.getAttribute('aria-expanded') === 'true';
    toggle.setAttribute('aria-expanded', String(!open));
    links.classList.toggle('is-open');
  });
</script>
```

```css
.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  background: rgba(15, 15, 15, 0.85);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--color-border-subtle);
}

.nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 60px;
  position: relative;
}

.nav-brand {
  font-family: var(--font-serif);
  font-size: var(--text-lg);
  color: var(--color-text);
  text-decoration: none;
  letter-spacing: 0.01em;
  flex-shrink: 0;
}

.nav-links {
  display: flex;
  gap: var(--space-5);
  list-style: none;
  margin: 0;
  padding: 0;
  flex-wrap: wrap;
  justify-content: flex-end;
}

.nav-links a {
  font-size: var(--text-xs);
  color: var(--color-text-muted);
  text-decoration: none;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  transition: color 0.15s ease;
  white-space: nowrap;
}
.nav-links a:hover { color: var(--color-text); }

/* Hamburger button — hidden on desktop */
.nav-toggle {
  display: none;
  flex-direction: column;
  gap: 5px;
  background: none;
  border: none;
  cursor: pointer;
  padding: var(--space-2);
}
.nav-toggle span {
  display: block;
  width: 22px;
  height: 2px;
  background: var(--color-text-muted);
  transition: background 0.15s ease;
}
.nav-toggle:hover span { background: var(--color-text); }

@media (max-width: 768px) {
  .nav-toggle { display: flex; }

  .nav-links {
    display: none;
    position: absolute;
    top: 60px;
    left: 0;
    right: 0;
    flex-direction: column;
    gap: 0;
    background: var(--color-surface);
    border-bottom: 1px solid var(--color-border);
    padding: var(--space-4) 0;
  }
  .nav-links.is-open { display: flex; }

  .nav-links li { width: 100%; }
  .nav-links a {
    display: block;
    padding: var(--space-3) var(--space-6);
    font-size: var(--text-sm);
  }
  .nav-links a:hover { background: var(--color-surface-2); }
}
```

### Footer

```html
<footer class="site-footer">
  <div class="container footer-inner">
    <p class="footer-copy">&copy; <span id="footer-year"></span> Scott Steinhardt. Brooklyn, NY.</p>
    <p class="footer-contact"><a href="mailto:hi@scottsteinhardt.com">hi@scottsteinhardt.com</a></p>
  </div>
</footer>
<script>document.getElementById('footer-year').textContent = new Date().getFullYear();</script>
```

```css
.site-footer {
  border-top: 1px solid var(--color-border-subtle);
  padding: var(--space-8) 0;
  margin-top: var(--space-24);
}

.footer-inner {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-4);
}

.footer-copy,
.footer-contact {
  font-size: var(--text-sm);
  color: var(--color-text-faint);
  margin: 0;
}

.footer-contact a {
  color: var(--color-text-faint);
}
.footer-contact a:hover { color: var(--color-accent); }
```

---

## 7. Full HTML Template

Copy this as the starting point for any new project.

```html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta name="author" content="Scott Steinhardt">
  <meta name="copyright" content="Scott Steinhardt">
  <meta name="robots" content="index, follow">

  <title>{{Page Title}} | Scott Steinhardt</title>
  <meta name="description" content="{{Description}}">
  <link rel="canonical" href="https://www.scottfromny.com/{{path}}">

  <meta property="og:type" content="website">
  <meta property="og:site_name" content="Scott Steinhardt">
  <meta property="og:title" content="{{Page Title}}">
  <meta property="og:description" content="{{Description}}">
  <meta property="og:url" content="https://www.scottfromny.com/{{path}}">
  <meta property="og:image" content="https://www.scottfromny.com/images/og-default.jpg">
  <meta property="og:locale" content="en_US">

  <meta name="twitter:card" content="summary_large_image">
  <meta name="twitter:title" content="{{Page Title}}">
  <meta name="twitter:description" content="{{Description}}">
  <meta name="twitter:image" content="https://www.scottfromny.com/images/og-default.jpg">

  <script type="application/ld+json">
  {
    "@context": "https://schema.org",
    "@type": "Person",
    "name": "Scott Steinhardt",
    "url": "https://www.scottfromny.com",
    "email": "hi@scottsteinhardt.com",
    "sameAs": [
      "https://www.linkedin.com/in/scottbsteinhardt/",
      "https://github.com/scottsteinhardt",
      "https://bsky.app/profile/scottfromny.com"
    ],
    "address": {
      "@type": "PostalAddress",
      "addressLocality": "Brooklyn",
      "addressRegion": "NY",
      "addressCountry": "US"
    }
  }
  </script>

  <link rel="preconnect" href="https://fonts.googleapis.com">
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
  <link href="https://fonts.googleapis.com/css2?family=Lora:ital,wght@0,400;0,600;1,400&family=Inter:wght@400;500;600&family=JetBrains+Mono:wght@400&display=swap" rel="stylesheet">

  <style>
    /* === PASTE FULL CSS SYSTEM HERE === */
  </style>
</head>
<body>

  <header class="site-header">
    <nav class="container nav">
      <a href="https://www.scottfromny.com" class="nav-brand">Scott Steinhardt</a>
      <button class="nav-toggle" aria-label="Toggle menu" aria-expanded="false">
        <span></span><span></span><span></span>
      </button>
      <ul class="nav-links">
        <li><a href="https://scottfromny.com/blog/">Blog + Newsletter</a></li>
        <li><a href="https://scottfromny.com/about/">About</a></li>
        <li><a href="https://scottfromny.com/work/portfolio/">Portfolio</a></li>
        <li><a href="https://scottfromny.com/projects/">Projects</a></li>
        <li><a href="https://www.linkedin.com/in/scottbsteinhardt/" target="_blank" rel="noopener">LinkedIn</a></li>
        <li><a href="https://bsky.app/profile/scottfromny.com" target="_blank" rel="noopener">Bluesky</a></li>
        <li><a href="https://github.com/scottsteinhardt" target="_blank" rel="noopener">GitHub</a></li>
        <li><a href="mailto:hi@scottsteinhardt.com">Contact</a></li>
      </ul>
    </nav>
  </header>

  <main class="container" style="padding-top: var(--space-16); padding-bottom: var(--space-16);">
    <!-- Page content here -->
  </main>

  <footer class="site-footer">
    <div class="container footer-inner">
      <p class="footer-copy">&copy; <span id="footer-year"></span> Scott Steinhardt. Brooklyn, NY.</p>
      <p class="footer-contact"><a href="mailto:hi@scottsteinhardt.com">hi@scottsteinhardt.com</a></p>
    </div>
  </footer>

  <script>document.getElementById('footer-year').textContent = new Date().getFullYear();</script>
</body>
</html>
```

---

## 8. Responsive Design Rules

- **Mobile-first**: write base styles for mobile, then use `min-width` media queries to scale up
- **Breakpoints:**

| Name    | Width    | CSS                        |
|---------|----------|----------------------------|
| sm      | 640px+   | `@media (min-width: 640px)`  |
| md      | 768px+   | `@media (min-width: 768px)`  |
| lg      | 1024px+  | `@media (min-width: 1024px)` |
| xl      | 1280px+  | `@media (min-width: 1280px)` |

- Minimum touch target size: **44×44px**
- Never rely on hover-only interactions for mobile
- Font sizes never below `14px` (`var(--text-sm)`) on any screen
- Images always `max-width: 100%`, with `height: auto`
- Use `clamp()` for fluid type where needed: e.g. `font-size: clamp(1.5rem, 4vw, 2.25rem)`

---

## 9. Animation & Transitions

Keep motion subtle and fast. This isn't a flashy portfolio — it's a writer's space.

```css
:root {
  --transition-fast:   0.1s ease;
  --transition-base:   0.15s ease;
  --transition-slow:   0.25s ease;
}

/* Respect user preference */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}
```

- Transitions on interactive elements: color, background, border-color, opacity, transform
- No gratuitous animations — entrance animations only if they add clarity
- Page transitions: none by default

---

## 10. Accessibility Checklist

Every project must pass these before shipping:

- [ ] All images have descriptive `alt` text (or `alt=""` for decorative)
- [ ] Color contrast ≥ 4.5:1 for body text, ≥ 3:1 for large text and UI
- [ ] All interactive elements reachable and operable by keyboard
- [ ] Focus styles visible — never `outline: none` without a custom replacement
- [ ] `lang="en"` on `<html>`
- [ ] Landmark regions used: `<header>`, `<main>`, `<footer>`, `<nav>`
- [ ] No reliance on color alone to convey meaning
- [ ] Form inputs have associated `<label>` elements
- [ ] Skip-to-content link for keyboard users (optional but recommended)

---

## 11. File & Asset Conventions

```
project/
├── index.html
├── style.css          # or styles/ directory
├── script.js          # or scripts/ directory
└── images/
    ├── og-default.jpg # 1200×630, used as fallback OG image
    └── ...
```

- Images: prefer WebP with JPEG fallback; compress before shipping
- OG image dimensions: **1200×630px**
- Favicon: provide at minimum a 32×32 `.ico` and a 180×180 Apple Touch icon
- CSS: single file for small projects, organized with `/* === SECTION === */` comments for larger

---

## 12. Writing & Tone

When generating copy for Scott Steinhardt projects:

- Voice: first-person, warm, literary, self-aware without being self-indulgent
- Tagline register: "Scott Steinhardt Talks Fine Arts"
- Topics he writes about: personal essays, family, fiction, Brooklyn life, fine arts
- Avoid: corporate jargon, startup-speak, excessive exclamation points
- Default footer attribution: `Scott Steinhardt. Brooklyn, NY.`
- Default contact: `hi@scottsteinhardt.com`
