:root {
  --bg: #fbfaf8; --text: #2f2a2b; --muted: #6b6360; --card: #f3f3f3; --border: #e6e2dc;
  --link: #0f4c5c; --link-hover: #0f5e72; --green: #257953; --sandstone: #a88565; --meta: #5f7585;
  --meta-strong: var(--meta);
  --seg: color-mix(in srgb, var(--green) 75%, var(--bg));
  --seg-code: color-mix(in srgb, var(--sandstone) 75%, var(--bg));
  --font-head: "Open Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  --font-body: Lato, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
}
@media (prefers-color-scheme: dark) {
  :root {
    --bg: #1e1b1c; --text: #e8dfd0; --muted: #a89a8f; --card: #2f2a2b; --border: #3a3436;
    --link: #5aaec0; --link-hover: #2db8dd; --green: #46ac7d; --sandstone: #c8a585; --meta: #93a7b5;
    --meta-strong: #bcd0da;
    --seg: color-mix(in srgb, var(--green) 65%, var(--bg));
    --seg-code: color-mix(in srgb, var(--sandstone) 65%, var(--bg));
  }
}
* { box-sizing: border-box; }
body {
  margin: 0; background: var(--bg); color: var(--text);
  font-family: var(--font-body); font-size: 17px; line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}
.wrap { max-width: 720px; margin: 0 auto; padding: 7vh 24px 12vh; }
h1, h2, h3 { font-family: var(--font-head); font-weight: 700; line-height: 1.2; }
h1 { font-size: clamp(2rem, 6vw, 2.9rem); margin: 0 0 .3rem; letter-spacing: -.01em; }
.tagline { font-family: var(--font-head); font-weight: 600; font-size: clamp(1.05rem, 3.4vw, 1.3rem);
  color: var(--text); margin: 0 0 .6rem; }
a { color: var(--link); text-decoration: none; border-bottom: 1px solid transparent; transition: color .15s, border-color .15s; }
a:hover { color: var(--link-hover); border-bottom-color: currentColor; }
.contacts { display: flex; flex-wrap: wrap; gap: 1.1rem; margin-bottom: 2.6rem; font-family: var(--font-head); font-weight: 600; }
.lede { font-size: 1.08rem; margin: 0 0 2.8rem; max-width: 62ch; }
footer { margin-top: 3.5rem; padding-top: 1.4rem; border-top: 1px solid var(--border); color: var(--muted); font-size: .9rem; }
@media (max-width: 480px) { .contacts { gap: .8rem 1rem; } }
.ext-mark { font-size: .75em; }

/* /work: h1 becomes a link back home — keep it looking like a plain heading */
header h1 a { color: inherit; text-decoration: none; border-bottom: none; }
header h1 a:hover { opacity: .78; }

/* --- /work: twin-rail timeline ---
   Two 2px rails run down the middle track (1fr <track> 1fr grid), 12px apart — widened from
   an earlier 6px-apart prototype because at 6px the two 2026 dots (11px diameter) overlap;
   at 12px they land ~3px apart. Rails sit flush with the outer edges of the track (justify-self
   start/end), so every card-edge -> rail-center distance below (49/51/54.5px) holds regardless
   of the track's own width — only the visible gap *between* the two rails changes. */
@media (min-width: 900px) {
  .wrap { max-width: 1100px; }
}

.timeline-grid {
  display: grid;
  grid-template-columns: 1fr 16px 1fr;
  column-gap: 3rem;
  align-items: stretch;
  margin-top: 1rem;
}
.timeline-rail-left, .timeline-rail-right {
  grid-column: 2; grid-row: 1; background: var(--border); width: 2px;
}
.timeline-rail-left { justify-self: start; }
.timeline-rail-right { justify-self: end; }
.col-left, .col-right { display: flex; flex-direction: column; min-width: 0; grid-row: 1; }
.col-left { grid-column: 1; }
.col-right { grid-column: 3; }

.col-head {
  font-family: var(--font-head); font-weight: 700; font-size: 1.5rem;
  margin: 0 0 2rem; padding-bottom: .4rem; border-bottom: 2px solid var(--green);
  display: inline-block;
}

/* Card. Featured tier gets a green left rule (the only card-level accent) and an ink title;
   regular tier (including what used to be a third "small" tier) is one consistent size/weight. */
.item {
  position: relative; margin-bottom: 2.2rem;
  background: var(--card); border: 1px solid var(--border); border-radius: 8px;
  padding: 16px 18px;
}
.item:last-child { margin-bottom: 0; }
.item--featured { border-left: 3px solid var(--green); }

.item h3 { margin: 0 0 .35rem; font-size: 1.05rem; font-weight: 600; }
.item h3 a { border-bottom: none; }
.item--featured h3 { font-size: 1.35rem; font-weight: 700; }
.item--featured h3, .item--featured h3 a { color: var(--text); }

.meta { display: flex; gap: .5rem; align-items: baseline; white-space: nowrap; margin-bottom: .45rem; }
.tag { color: var(--sandstone); font-family: var(--font-head); font-weight: 600; font-size: .72rem;
  letter-spacing: .06em; text-transform: uppercase; }
.era { color: var(--meta); font-family: var(--font-head); font-weight: 600; font-size: .78rem; }
/* Chip doubles as a legend label (mobile only, see .timeline-mobile below): margin-left: auto
   pushes it to the far end of the flex .meta row, away from the era·tag cluster, and its text
   color is keyed to the item's lane so chip + spine marker read as one micro-legend. */
.lane-chip { display: none; font-family: var(--font-head); font-weight: 600;
  font-size: .72rem; letter-spacing: .06em; text-transform: uppercase; margin-left: auto; }
.item.lane-shipped .lane-chip { color: var(--green); }
.item.lane-code .lane-chip { color: var(--sandstone); }

.item p { margin: 0; font-size: .98rem; color: var(--text); line-height: 1.55; }
.related { margin: .6rem 0 0; font-size: .92rem; display: flex; gap: .5rem; align-items: baseline; }

/* Marker: single-year eras are a dot on the rail; multi-year eras become a rounded vertical
   segment whose height is time-proportional (28px per year of era span, set inline per item
   as --seg-h — see layouts/work/list.html). min-height on the segment card guarantees the
   card is always at least tall enough to contain its segment with 8px breathing room top and
   bottom, which is the "capped at card height" rule applied from the other direction — CSS
   can't cap a child's height to an auto-height parent's box directly, so the card grows to
   fit the segment instead of the segment shrinking to fit the card. */
.item:not(.item--segment)::before {
  content: ""; position: absolute; top: 21px; width: 11px; height: 11px;
  border-radius: 50%; background: var(--green); box-shadow: 0 0 0 3px var(--bg); z-index: 3;
}
.item--segment {
  min-height: calc(var(--seg-h, 0px) + 16px);
}
.item--segment::before {
  content: ""; position: absolute; top: 50%; width: 6px; height: var(--seg-h, 40px);
  transform: translateY(-50%);
  border-radius: 3px; background: var(--seg); z-index: 3;
}

/* Code lane: dots and segments swap green for sandstone (--sandstone / --seg-code) so the two
   rails carry the lane axis themselves, not just column position — applies on both breakpoints,
   the mobile equivalents are just below in the mobile block. Selector specificity here only
   needs to beat the plain .item rules above (not the mobile ones, which are already more
   specific via their .timeline-mobile ancestor), so this block is unscoped by media query and
   still holds at >=900px where the mobile rules don't apply at all. */
.item.lane-code:not(.item--segment)::before { background: var(--sandstone); }
.item--segment.lane-code::before { background: var(--seg-code); }

/* Connector: bridges the marker to the card's near edge. Fixed distance regardless of
   viewport width >=900px: card edge -> rail center is 49px on both sides. */
.item::after {
  content: ""; position: absolute; top: 25.5px; height: 2px; background: var(--border); z-index: 1;
}
.col-left .item:not(.item--segment)::before { right: -54.5px; }
.col-left .item--segment::before { right: -52px; }
.col-left .item::after { right: -49px; width: 51px; }
.col-right .item:not(.item--segment)::before { left: -54.5px; }
.col-right .item--segment::before { left: -52px; }
.col-right .item::after { left: -49px; width: 51px; }

/* The broken rail: through the no-code decade, the right rail turns dotted instead of solid.
   .timeline-gap sits in col-right's normal flow at exactly the gap's vertical span, so the
   overlay lands over the gap regardless of viewport width or the height of cards above it.
   Left rail is untouched — solid the whole way down. Tune this height to keep the last item
   in each lane (Dredmor product / Dredmor core systems) roughly row-aligned. */
.timeline-gap { height: 20rem; display: flex; align-items: center; position: relative; }
.timeline-gap::before {
  content: ""; position: absolute; top: 0; bottom: 0; left: -47px; width: 4px; z-index: 2;
  background: repeating-linear-gradient(to bottom, var(--border) 0 6px, var(--bg) 6px 12px);
}
.gap-caption {
  margin: 0; max-width: 30ch;
  font-style: italic; font-size: .82rem; color: var(--meta-strong); line-height: 1.4;
}
/* Anchored caption (desktop only): a 16px leader tick runs from the dotted rail (x=-47, the
   same reference the overlay above uses) to the caption's own left edge (x=-31, achieved by
   pulling the caption 31px into the gutter with a negative margin). */
.timeline-gap .gap-caption {
  position: relative; margin-left: -31px; padding-left: 16px;
}
.timeline-gap .gap-caption::before {
  content: ""; position: absolute; left: -16px; top: 50%; width: 16px; height: 2px;
  background: var(--border); transform: translateY(-50%);
}

/* ---------- mobile: single column, one shared spine ---------- */
.timeline-mobile { display: none; }
@media (max-width: 900px) {
  .timeline-grid, .col-head { display: none; }
  .timeline-mobile {
    display: block; position: relative; padding-left: 26px; margin-top: 1rem;
  }
  .timeline-mobile::before {
    content: ""; position: absolute; left: 6px; top: 21px; bottom: .3rem; width: 2px; background: var(--border);
  }
  .timeline-mobile .item {
    margin-bottom: 2rem; text-align: left;
    background: var(--card); border: 1px solid var(--border); border-radius: 8px; padding: 16px 18px;
  }
  /* the border shorthand above resets border-left too (same specificity, two classes each);
     re-assert the featured green rule so it survives on mobile. */
  .timeline-mobile .item--featured { border-left: 3px solid var(--green); }
  .lane-chip { display: inline-block; }
  /* Segment marker is thinner (4px vs the 3px featured card border) and sits farther out from
     the card edge than the dot does, so it reads as a rail mark, not a mistaken featured rule. */
  .timeline-mobile .item:not(.item--segment)::before {
    content: ""; position: absolute; left: -24.5px; top: 21px;
    width: 11px; height: 11px; border-radius: 50%; background: var(--green); box-shadow: 0 0 0 3px var(--bg);
    z-index: 3;
  }
  .timeline-mobile .item--segment::before {
    content: ""; position: absolute; left: -25px; top: 50%; width: 4px; height: var(--seg-h, 30px);
    transform: translateY(-50%);
    border-radius: 2px; background: var(--seg); z-index: 3;
  }
  /* Same sandstone swap as desktop (see "Code lane" comment above) — repeated here at higher
     specificity (extra .lane-code class) so it wins over the two mobile rules just above,
     which are already more specific than the unscoped desktop override. */
  .timeline-mobile .item.lane-code:not(.item--segment)::before { background: var(--sandstone); }
  .timeline-mobile .item--segment.lane-code::before { background: var(--seg-code); }
  .timeline-mobile .item::after {
    content: ""; position: absolute; left: -19px; width: 21px; top: 25.5px; height: 2px;
    background: var(--border); z-index: 1;
  }
  .timeline-mobile .meta, .timeline-mobile .related { justify-content: flex-start; }
  .timeline-mobile .gap-caption-row { margin: 0 0 2rem; }
}

/* --- hero landing page --- */
.hero {
  position: relative;
  height: 100vh;
  height: 100svh;
  /* Floor: below this the fixed-size overlay stack would clip against overflow:hidden.
     Short viewports scroll the hero instead. Keep in step with the overlay's
     padding-top floor (half of this value) so the composition holds. */
  min-height: 720px;
  width: 100%;
  overflow: hidden;
  background: #1e1b1c;
}
.hero-photo {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 42%;
  display: block;
}
@media (max-width: 600px) {
  .hero-photo { object-position: 50% 60%; }
}
.hero::after {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(ellipse 60% 50% at 50% 55%, rgba(0, 0, 0, .22) 0%, rgba(0, 0, 0, .06) 45%, rgba(0, 0, 0, 0) 72%);
  pointer-events: none;
}
@media (prefers-color-scheme: dark) {
  .hero::after {
    background: radial-gradient(ellipse 60% 50% at 50% 55%, rgba(0, 0, 0, .34) 0%, rgba(0, 0, 0, .12) 45%, rgba(0, 0, 0, 0) 72%);
  }
}
.hero-overlay {
  position: relative;
  z-index: 1;
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  gap: 1.6rem;
  padding: max(50vh, 360px) 6vw 6vh;
  text-align: center;
  color: #fff;
}
.hero-line1, .hero-line2 {
  margin: 0;
  font-family: var(--font-head);
  font-weight: 300;
  color: #fff;
  letter-spacing: .01em;
  text-shadow: 0 1px 3px rgba(0, 0, 0, .35), 0 2px 16px rgba(0, 0, 0, .22);
}
.hero-line1 {
  font-size: clamp(1.9rem, 5.4vw, 3.6rem);
  line-height: 1.15;
}
.hero-line2 {
  font-size: clamp(1.15rem, 2.9vw, 1.7rem);
  line-height: 1.4;
  font-weight: 300;
}
.hero-icons {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 1rem;
  margin-top: .4rem;
}
.hero-icons a {
  width: 48px;
  height: 48px;
  border-radius: 12px;
  background: rgba(255, 255, 255, .94);
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 2px 10px rgba(0, 0, 0, .18);
  transition: transform .15s ease, background-color .15s ease;
  border-bottom: none;
}
.hero-icons a:hover { background: #fff; transform: translateY(-2px); }
.hero-icons a:focus-visible {
  outline: 3px solid #fff;
  outline-offset: 3px;
  box-shadow: 0 0 0 3px rgba(0, 0, 0, .55);
}
.hero-icons svg { width: 22px; height: 22px; fill: #22201f; }
.hero-more {
  font-family: var(--font-head);
  font-weight: 300;
  font-size: clamp(.95rem, 2vw, 1.05rem);
  color: #fff;
  text-shadow: 0 1px 3px rgba(0, 0, 0, .35);
  border-bottom: 1px solid transparent;
}
.hero-more:hover { color: #fff; border-bottom-color: rgba(255, 255, 255, .7); }
.hero-more:focus-visible { outline: 2px solid #fff; outline-offset: 4px; }
@media (max-width: 480px) {
  .hero-overlay { gap: 1.2rem; padding: max(50vh, 360px) 6vw 5vh; }
  .hero-icons { gap: .8rem; }
}

/* Dan's picks from the comparison gallery (2026-07-16) */
header h1 { font-weight: 300; }           /* /work masthead echoes the hero's light voice */
.hero-more { font-weight: 400; font-size: clamp(1.09rem, 2.3vw, 1.21rem);
  border-bottom: 1px solid rgba(255,255,255,.45); }
