/* ---------------------------------------------------------------
   donahue.us — the portfolio index.

   Layout is the Portfolio canvas from the Pointe Analytics design
   system, with its inline styles lifted into classes and its bindings
   resolved at author time. Colour is the site's own: Michigan maize
   and blue, in tokens/donahue-colors.css. The type scale is still
   Pointe's and is vendored as such.

   Only this page uses these tokens — every project page carries its
   own design and is untouched by changes here.
   --------------------------------------------------------------- */

@import "tokens/donahue-fonts.css";
@import "tokens/donahue-colors.css";
@import "tokens/pointe-typography.css";

*, *::before, *::after { box-sizing: border-box; }

html, body { margin: 0; padding: 0; }

body {
  min-height: 100vh;
  background: var(--surface-canvas);
  color: var(--text-primary);
  font-family: var(--font-ui);
  font-size: var(--text-md);
  transition: background 180ms cubic-bezier(0.2, 0, 0, 1);
}

a { color: var(--accent); text-decoration: none; }
a:hover { color: var(--accent-hover); }

:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }

.shell { max-width: 1020px; margin: 0 auto; padding: 0 32px; }

/* ---------- sticky header ---------- */

.topbar {
  position: sticky;
  top: 0;
  z-index: 10;
  height: 48px;
  background: var(--surface-canvas);
  border-bottom: 1px solid var(--border-hairline);
}

.topbar .shell {
  height: 48px;
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.brand {
  display: flex;
  align-items: baseline;
  gap: 7px;
  font-size: var(--text-base);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-tight);
}

/* The face is the mark; the name is set in the same sans as the rest of
   the bar. Circle, hairline and sunken ground match the hero avatar, so the
   two read as the same object at two sizes. */
.brand .face {
  width: 24px;
  height: 24px;
  border-radius: 999px;
  object-fit: cover;
  border: 1px solid var(--border-hairline);
  background: var(--surface-sunken);
  flex: none;
  align-self: center;
}
.brand .word { color: var(--accent); }

/* ---------- hero ---------- */

.hero {
  padding: 80px 0 56px;
  display: grid;
  grid-template-columns: auto 1fr;
  column-gap: 24px;
  align-items: center;
}

.avatar {
  grid-row: 1 / 4;
  width: 96px;
  height: 96px;
  border-radius: 999px;
  object-fit: cover;
  border: 1px solid var(--border-hairline);
  background: var(--surface-sunken);
}

/* stand-in until assets/headshot.png exists; same box, so layout is identical */
.avatar--fallback {
  display: grid;
  place-items: center;
  font-size: var(--text-2xl);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-tight);
  color: var(--text-muted);
  user-select: none;
}

.hero h1 {
  margin: 0 0 12px;
  font-size: var(--text-3xl);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-tight);
  line-height: var(--leading-tight);
}

.hero .bio {
  margin: 0 0 20px;
  max-width: 58ch;
  font-size: 15px;
  line-height: 1.62;
  color: var(--text-secondary);
}

.hero .meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 24px;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--text-secondary);
}

/* ---------- section heading ---------- */

.section-head {
  display: flex;
  align-items: baseline;
  gap: 10px;
  margin-bottom: 18px;
}

.section-head h2 {
  margin: 0;
  font-size: var(--text-2xs);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
  color: var(--text-secondary);
}

.section-head .count {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}

/* ---------- project grid ---------- */

/* ---------- sections ---------- */

.group + .group { margin-top: 52px; }

.group-note {
  margin: -8px 0 18px;
  max-width: var(--measure, 60ch);
  font-size: var(--text-base);
  line-height: var(--leading-normal);
  color: var(--text-secondary);
}

.projects {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(340px, 1fr));
  gap: 24px;
}

.project {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: var(--surface-card);
  border: 1px solid var(--border-hairline);
  border-radius: 10px;
  color: inherit;
  box-shadow: var(--shadow-card);
  transition: box-shadow 180ms cubic-bezier(0.2, 0, 0, 1),
              border-color 180ms cubic-bezier(0.2, 0, 0, 1);
}

.project:hover,
.project:focus-visible {
  box-shadow: var(--shadow-raised);
  border-color: var(--border-strong);
  color: inherit;
}

.project .preview {
  position: relative;
  aspect-ratio: 16 / 10;
  background: var(--surface-sunken);
  border-bottom: 1px solid var(--border-hairline);
  display: grid;
  place-items: center;
  overflow: hidden;
}

/* Taken out of flow on purpose. `place-items: center` leaves the grid row
   auto-sized, so an in-flow image resolves `height: 100%` against a row that
   is itself sized by the image — the browser breaks the loop with the
   intrinsic height and the slot outgrows its aspect-ratio. Harmless for a
   screenshot wider than 16/10, but a portrait-ish one pushes the whole card
   taller than its neighbours. Absolute positioning decouples the two, so
   aspect-ratio always wins and object-fit does the cropping. */
.project .preview img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.project .body {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 18px 20px 20px;
}

.project .row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
}

.project h3 {
  margin: 0;
  font-size: var(--text-lg);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-tight);
  line-height: var(--leading-tight);
}

.project .arrow {
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  color: var(--text-muted);
  flex-shrink: 0;
}

.project p {
  margin: 0;
  font-size: var(--text-base);
  line-height: var(--leading-normal);
  color: var(--text-secondary);
}

/* ---------- fixed footer + theme toggle ---------- */

.tail { height: 128px; }

.footbar {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  z-index: 10;
  height: 40px;
  background: var(--surface-canvas);
  border-top: 1px solid var(--border-hairline);
}

.footbar .shell {
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: flex-end;
}

.theme-toggle {
  height: 26px;
  padding: 0 10px;
  display: flex;
  align-items: center;
  gap: 6px;
  background: var(--surface-card);
  border: 1px solid var(--border-hairline);
  border-radius: 6px;
  color: var(--text-secondary);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  cursor: pointer;
  transition: background 120ms cubic-bezier(0.2, 0, 0, 1),
              border-color 120ms cubic-bezier(0.2, 0, 0, 1);
}

.theme-toggle:hover {
  background: var(--surface-sunken);
  border-color: var(--border-strong);
}

/* The canvas file references --shadow-card / --shadow-raised but the design
   system's token files don't define them; these match its elevation language. */
:root {
  --shadow-card: 0 1px 2px oklch(0.185 0.01 60 / 0.06);
  --shadow-raised: 0 4px 16px oklch(0.185 0.01 60 / 0.10);
}
[data-theme="dark"] {
  --shadow-card: 0 1px 2px oklch(0 0 0 / 0.30);
  --shadow-raised: 0 4px 16px oklch(0 0 0 / 0.45);
}

@media (max-width: 640px) {
  .shell { padding: 0 20px; }
  .hero { padding: 48px 0 40px; grid-template-columns: 1fr; row-gap: 16px; }
  .avatar { grid-row: auto; }
}
