/* Grand Rapids Snow Removal Pros - base stylesheet
   Single static stylesheet, no build step, no external font or JS dependency.

   Palette: deep spruce chrome with a copper signal color, and a warm tint of
   that copper for the second word of the wordmark. Chosen against every other
   stylesheet in the portfolio so no two sites share a family - the three other
   snow properties run slate/brick, indigo/red and blue/amber, so green/copper
   is unclaimed. Every pair below is computed, not eyeballed. This file is
   served publicly, so it carries the numbers and nothing else.

   Contrast (WCAG AA needs 4.5:1 for body text, 3:1 for large text):
     white on --glow-deep (#96481b) .... 6.48:1
     white on --alert-c (#b0541d) ......... 5.08:1
     white on --keel (#1e3a34) ........ 12.28:1
     white on --iron-c (#3f6157) .......... 6.87:1
     --iron-c on --backdrop ..................... 6.25:1
     --glow-deep on --backdrop ............... 5.90:1
     --fg on --backdrop ...................... 14.63:1
     --understated on --backdrop ..................... 5.15:1
     nav link (#dfe8e4) on --keel ...... 9.82:1
     wordmark tail (#eab892) on --keel . 6.88:1
     footer text (#a9b6b0) on #131a17 .... 8.42:1
*/

:root {
  --keel: #1e3a34;
  /* RGB channels of --keel, for the hero photo scrim. */
  --overlay: 30, 58, 52;
  --iron-c: #3f6157;
  --glow-deep: #96481b;
  --alert-c: #b0541d;
  --backdrop: #f6f4f1;
  --sheet: #ffffff;
  --fg: #1b2320;
  --understated: #5d6a64;
  --hairline: #dcd7d0;
  --fillet: 4px;
  --limit: 1120px;
  /* The fixed CTA bar's real height, not a round number: 7+10 padding top and
     bottom plus a 0.90rem line (23px), +2px slack. Above 768px the link grows to
     0.95rem and the bar to 60px. body's padding-bottom tracks both. */
  --shelf-h: 59px;
}

/* The bar is taller above the mobile breakpoint (larger type, roomier buttons). */
@media (min-width: 768px) { :root { --shelf-h: 60px; } }

* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  color: var(--fg);
  background: var(--backdrop);
  line-height: 1.55;
}
img { max-width: 100%; display: block; }
a { color: var(--iron-c); text-decoration: none; }
a:hover { text-decoration: underline; }
.column { max-width: var(--limit); margin: 0 auto; padding: 0 20px; }

/* Header */
header.headrail {
  background: var(--keel);
  color: var(--sheet);
  position: sticky;
  top: 0;
  z-index: 50;
}
header.headrail .gantry {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 20px;
  max-width: var(--limit);
  margin: 0 auto;
  flex-wrap: wrap;
  gap: 10px;
}
header.headrail .marque {
  font-weight: 700;
  font-size: 1.15rem;
  color: var(--sheet);
}
/* The brand mark sits on --keel. --glow-deep against --keel computes to 2.4:1,
   below the 3:1 large-text floor, so the mark uses a lighter tint of the
   same hue (6.43:1) rather than the accent variable. */
header.headrail .marque span { color: #eab892; }
header.headrail nav { display: flex; gap: 16px; flex-wrap: wrap; }
header.headrail nav a { color: #dfe8e4; font-size: 0.95rem; }
header.headrail nav a:hover { color: var(--sheet); }
header.headrail .hail {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  white-space: nowrap;
  background: var(--glow-deep);
  color: var(--sheet);
  padding: 9px 16px;
  border-radius: var(--fillet);
  font-weight: 700;
}
header.headrail .hail:hover { background: #8d4419; text-decoration: none; }

/* Hero */
.prologue {
  background: linear-gradient(135deg, var(--keel), var(--iron-c));
  color: var(--sheet);
  padding: 56px 20px 48px;
}
.prologue .column { display: flex; flex-direction: column; gap: 18px; }
.prologue .prehead {
  display: inline-block;
  background: rgba(255,255,255,0.12);
  padding: 5px 12px;
  border-radius: 999px;
  font-size: 0.8rem;
  letter-spacing: 0.03em;
  width: fit-content;
}
.prologue h1 { font-size: 2.2rem; margin: 0; max-width: 760px; }
.prologue p.opening-line { font-size: 1.1rem; color: #e5e3df; max-width: 600px; margin: 0; }
.prologue .act-row { display: flex; gap: 12px; flex-wrap: wrap; margin-top: 6px; }
.engage {
  display: inline-block;
  padding: 13px 22px;
  border-radius: var(--fillet);
  font-weight: 700;
  font-size: 1rem;
}
.engage.chief { background: var(--glow-deep); color: var(--sheet); }
.engage.chief:hover { background: #8d4419; text-decoration: none; }
.engage.subdued { background: rgba(255,255,255,0.08); color: var(--sheet); border: 1px solid rgba(255,255,255,0.35); }
.engage.subdued:hover { background: rgba(255,255,255,0.16); text-decoration: none; }
.prologue .apostil { font-size: 0.9rem; color: #ccc8c1; max-width: 640px; }

/* The referral disclosure is a legal requirement (16 CFR 461.3 and the FTC's
   .com Disclosures prominence factors), not decoration, so it does not rely on
   the hero photo being dark behind it. Its own scrim keeps it conspicuous at
   every viewport width and against any part of the background image. */
.prologue .avowal {
  font-size: 0.9rem;
  color: #ffffff;
  max-width: 680px;
  background: rgba(var(--overlay), 0.82);
  border-left: 3px solid var(--glow-deep);
  padding: 12px 16px;
  border-radius: 6px;
  margin: 18px 0 10px;
}
.prologue .avowal strong { color: #ffffff; }

/* Hero with a full-bleed background photo (homepage only) — layers a
   left-to-right dark gradient over the image so the H1/lead text stays
   readable.

   Stops are darker than the default ramp. Measured at 1440px: the H1 runs
   to x=1100 and the lead to x=940 of 1440, i.e. 76% and 65% across — and this
   site's hero photo has a white van sitting right under that range. On the
   default 0.90/0.72/0.28/0.05 ramp the lead computed to about 2.5:1 against
   white text, well under WCAG AA. At 0.93/0.88/0.72/0.35 the lead lands near
   7:1 and the H1 near 5:1, and the right quarter of the frame is still open
   enough to read as a photograph. Check this again if the hero is ever
   replaced with a darker image — the ramp can go back. */
.prologue.pictorial {
  background-image:
    linear-gradient(90deg, rgba(var(--overlay), 0.93) 0%, rgba(var(--overlay), 0.88) 45%, rgba(var(--overlay), 0.72) 70%, rgba(var(--overlay), 0.35) 100%),
    url('/images/hero-ocsr-photo.jpg');
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  min-height: 540px;
  display: flex;
  align-items: center;
  padding: 56px 20px;
}
@media (max-width: 820px) {
  .prologue.pictorial {
    background-image:
      linear-gradient(180deg, rgba(var(--overlay), 0.88) 0%, rgba(var(--overlay), 0.8) 55%, rgba(var(--overlay), 0.65) 100%),
      url('/images/hero-ocsr-photo-mobile.jpg');
    min-height: 460px;
  }
}

/* Sections */
section { padding: 48px 20px; }
section.tinted { background: var(--sheet); border-top: 1px solid var(--hairline); border-bottom: 1px solid var(--hairline); }
.band-name {
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: 0.78rem;
  color: var(--glow-deep);
  font-weight: 700;
  margin-bottom: 6px;
}
h2 { font-size: 1.65rem; margin: 0 0 20px; color: var(--keel); }
h3 { font-size: 1.15rem; margin: 0 0 8px; color: var(--keel); }

/* Grid cards */
.panels { display: grid; gap: 18px; }
.panels.threefold { grid-template-columns: repeat(3, 1fr); }
.panels.twofold { grid-template-columns: repeat(2, 1fr); }
@media (max-width: 820px) {
  .panels.threefold, .panels.twofold { grid-template-columns: 1fr; }
  .prologue h1 { font-size: 1.7rem; }
  header.headrail .gantry { justify-content: center; text-align: center; }
}

/* 821-1060px: brand + a full nav + the phone number no longer fit on one line
   now that the call button shows real digits. Rather than shrink the number,
   give the nav its own centered row — brand left, phone right, nav beneath —
   instead of letting the call button orphan itself under the brand. */
@media (min-width: 821px) and (max-width: 1060px) {
  header.headrail nav {
    order: 3;
    flex: 1 0 100%;
    justify-content: center;
    margin-top: 2px;
  }
}
.plate {
  background: var(--sheet);
  border: 1px solid var(--hairline);
  border-radius: var(--fillet);
  padding: 20px;
}
.plate .pictogram { font-size: 1.6rem; margin-bottom: 8px; }
.plate p { color: var(--understated); margin: 6px 0 0; font-size: 0.95rem; }

/* The second card shape on this site. `.plate` is the plain bordered card;
   `.chip` is the one used where a grid is making a comparison rather than a list
   — the three ways a contract can treat a plow berm, the property types on the
   commercial hub. The left rule in the signal color is what separates them at a
   glance, and it is why the two are not the same class with a modifier. */
.chip {
  background: var(--sheet);
  border: 1px solid var(--hairline);
  border-left: 3px solid var(--alert-c);
  border-radius: 0 var(--fillet) var(--fillet) 0;
  padding: 18px 20px;
}
.chip h3 { margin: 0 0 7px; font-size: 1.06rem; }
.chip p { color: var(--understated); margin: 0 0 8px; font-size: 0.95rem; }
.chip p:last-child { margin-bottom: 0; }
.chip .apostil { display: block; margin-top: 8px; }

/* Trust strip */
.reassure {
  display: flex;
  flex-wrap: wrap;
  gap: 14px 28px;
  justify-content: center;
  padding: 18px 20px;
  background: var(--sheet);
  border-bottom: 1px solid var(--hairline);
  font-size: 0.92rem;
  color: var(--understated);
}
.reassure strong { color: var(--keel); }

/* FAQ — native <details>/<summary> accordion, no JS needed */
.query-block { border-bottom: 1px solid var(--hairline); padding: 14px 0; }
.query-block:first-child { padding-top: 0; }
.query-block summary {
  font-size: 1.15rem;
  font-weight: 600;
  color: var(--keel);
  cursor: pointer;
  list-style: none;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
}
.query-block summary::-webkit-details-marker { display: none; }
.query-block summary::after {
  content: "+";
  font-size: 1.4rem;
  font-weight: 400;
  color: var(--glow-deep);
  flex-shrink: 0;
}
.query-block[open] summary::after { content: "\2212"; }
.query-block p { margin: 10px 0 0; color: var(--understated); }

/* How It Works */
.process { display: grid; grid-template-columns: repeat(4, 1fr); gap: 20px; }
.phase-card { background: var(--sheet); border: 1px solid var(--hairline); border-radius: var(--fillet); padding: 20px; }
.phase-card .stage-no {
  width: 30px; height: 30px; border-radius: 50%;
  background: #eaefec; color: var(--glow-deep); font-weight: 700;
  display: flex; align-items: center; justify-content: center;
  margin-bottom: 10px;
}
.phase-card h3 { font-size: 1.02rem; }
.phase-card p { color: var(--understated); font-size: 0.92rem; margin: 0; }
@media (max-width: 820px) { .process { grid-template-columns: 1fr 1fr; } }
@media (max-width: 540px) { .process { grid-template-columns: 1fr; } }

/* Sticky CTA bar — visible at EVERY width (calls are the priority conversion) */
.clingbar {
  display: flex;
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 60;
  background: var(--keel);
  padding: 7px 14px calc(7px + env(safe-area-inset-bottom));
  box-shadow: 0 -2px 10px rgba(0,0,0,0.15);
  /* Fallback for chrome baked into blog pages before the .clingbar-inner
     wrapper existed: those have the two <a> as direct children. No-op once the
     wrapper is present (single child, already full width). */
  gap: 10px;
  justify-content: center;
}
/* Constrain to the site's content width rather than two full-bleed halves. */
.clingbar-inner {
  display: flex;
  gap: 10px;
  width: 100%;
  max-width: var(--limit);
  margin: 0 auto;
}
.clingbar a {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  white-space: nowrap;
  text-align: center;
  padding: 10px 10px;
  border-radius: 5px;
  font-weight: 700;
  font-size: 0.90rem;
}
.clingbar .handset-mark { flex: none; }
/* Mobile: keep both buttons, but weight the call button ~60/40 over the form. */
.hoverbar-call { flex: 3; background: var(--glow-deep); color: var(--sheet); }
.hoverbar-ask { flex: 2; background: rgba(255,255,255,0.1); color: var(--sheet); border: 1px solid rgba(255,255,255,0.35); }
.hoverbar-call:hover { background: #8d4419; text-decoration: none; }
.hoverbar-ask:hover { background: rgba(255,255,255,0.18); text-decoration: none; }
/* Narrow phones: the digits must survive, the qualifier is what gives way. */
.clingbar .trailer { display: none; }
@media (min-width: 520px) {
  .clingbar .trailer { display: inline; }
}
/* Above the mobile breakpoint: content-width buttons, centered. */
@media (min-width: 768px) {
  .clingbar-inner { justify-content: center; }
  .clingbar a { flex: 0 0 auto; padding: 10px 22px; font-size: 0.95rem; }
}
/* Keep content — including the footer's last row — clear of the fixed bar. */
body { padding-bottom: var(--shelf-h); }
/* Area links */
.adjacent-line { display: flex; flex-wrap: wrap; gap: 10px; }
.adjacent-line a {
  background: var(--sheet);
  border: 1px solid var(--hairline);
  padding: 9px 14px;
  border-radius: 999px;
  color: var(--keel);
  font-size: 0.92rem;
}
.adjacent-line a:hover { border-color: var(--glow-deep); text-decoration: none; }

/* CTA band */
.envoi {
  background: var(--keel);
  color: var(--sheet);
  text-align: center;
  padding: 44px 20px;
}
.envoi h2 { color: var(--sheet); }
.envoi p { color: #dfe8e4; margin-bottom: 18px; }

/* Contact form */
form.reach-form { display: grid; gap: 12px; max-width: 480px; }
form.reach-form label { font-size: 0.88rem; font-weight: 600; color: var(--keel); display: block; margin-bottom: 4px; }
form.reach-form input, form.reach-form select, form.reach-form textarea {
  width: 100%;
  padding: 11px 12px;
  border: 1px solid var(--hairline);
  border-radius: 5px;
  font-size: 0.95rem;
  font-family: inherit;
}
form.reach-form .advisory { font-size: 0.78rem; color: var(--understated); }
form.reach-form .spare-line { position: absolute; left: -9999px; top: -9999px; }
form.reach-form button[disabled] { opacity: 0.6; cursor: not-allowed; }
.return-note { margin-top: 12px; padding: 11px 14px; border-radius: 5px; font-size: 0.9rem; display: none; }
.return-note.visible { display: block; }
.return-note.success { background: #eaefec; color: #35453f; }
.return-note.error { background: #fbeae4; color: #9c3a15; }

/* Breadcrumb */
.path { font-size: 0.85rem; color: var(--understated); padding: 14px 20px 0; max-width: var(--limit); margin: 0 auto; }
.path a { color: var(--understated); }

/* Footer */
footer.headrail {
  background: #131a17;
  color: #a9b6b0;
  padding: 40px 20px 24px;
  font-size: 0.9rem;
}
footer.headrail .column { display: grid; grid-template-columns: 2fr 1fr 1fr 1fr; gap: 24px; }
footer.headrail h2 { color: var(--sheet); font-size: 0.95rem; margin: 0 0 10px; }
footer.headrail ul { list-style: none; padding: 0; margin: 0; }
footer.headrail li { margin-bottom: 6px; }
footer.headrail a { color: #a9b6b0; }
footer.headrail .floorline {
  max-width: var(--limit);
  margin: 24px auto 0;
  padding-top: 18px;
  border-top: 1px solid rgba(255,255,255,0.08);
  font-size: 0.8rem;
  display: flex;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 8px;
}
@media (max-width: 720px) {
  footer.headrail .column { grid-template-columns: 1fr 1fr; }
}
.not-yet {
  background: #fbf1d9;
  color: #6b571a;
  border: 1px dashed var(--alert-c);
  padding: 2px 6px;
  border-radius: 3px;
  font-size: 0.82em;
}

/* Brand logo (added 2026-08-11) */

header.headrail .marque {
  display: inline-flex;
  align-items: center;
  gap: 9px;
}
.crest {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  display: block;
  flex-shrink: 0;
}

/* --- Work photos ------------------------------------------------------ */
/* Inline documentary shots dropped between two content sections partway down a
   service page. Deliberately NOT a gallery grid and NOT a CSS background: one
   photo per page, off-rhythm, no captions.

   The base rule caps width so an unclassed figure can never render full-bleed
   across the page — that failure looks completely correct in the markup, so the
   block has to ship before any page references the class. No .portrait / .wide
   / .pair modifiers here: every master on this site is landscape 1200x800, and
   an unused modifier is how "add the class" becomes the easy fix for an image
   that should have been regenerated. */
.documentary {
  max-width: var(--limit);
  margin: 0 auto;
  padding: 34px 20px;
}
.documentary img {
  display: block;
  width: 100%;
  max-width: 800px;
  height: auto;
  margin: 0 auto;
  border-radius: var(--fillet);
  border: 1px solid var(--hairline);
}

/* --- Homepage work strip ---------------------------------------------- */
/* Eight images on this site, so the grid is 4 columns and the counts come out
   even at every breakpoint: 4x2 on desktop, 2x4 at 900px and 2x4 at 520px. The
   column count is tuned to the image count, not copied - a ragged trailing row
   is the visible tell that nobody redid the arithmetic. */
.gallery-band .tiles-xs {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 12px;
}
.gallery-band img {
  display: block;
  width: 100%;
  /* height:auto is required - the img height="320" attribute is a
     presentational hint that would otherwise make the box 320px tall and
     cause aspect-ratio to be ignored entirely. */
  height: auto;
  aspect-ratio: 3 / 2;
  object-fit: cover;
  border-radius: var(--fillet);
  border: 1px solid var(--hairline);
  background: var(--sheet);
}
@media (max-width: 900px) { .gallery-band .tiles-xs { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 520px) { .gallery-band .tiles-xs { grid-template-columns: repeat(2, 1fr); gap: 10px; } }

/* --- Wide tables ------------------------------------------------------- */
/* A table whose minimum content width exceeds
   the viewport slides the WHOLE document sideways at 375px unless it gets its
   own scroll context. The table's own overflow:hidden (used for radius
   clipping) does not create one. Only the permit-comparison page has a table,
   and it has five columns. */
.table-drag {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  border: 1px solid var(--hairline);
  border-radius: var(--fillet);
  background: var(--sheet);
}

/* --- Snow-trade blocks — specific to a seasonal-contract trade. ------------
   .numbers-row replaces the .reassure strip under the hero: four figures rather
   than four claims, because on a seasonal-contract page the numbers ARE the
   argument. .rates and .queries-list exist so this site does not repeat the
   .query-block <details> shape every other trade uses (§12 — vary structure,
   not only class names). */
.numbers-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 1px;
  background: var(--hairline);
  border-top: 1px solid var(--hairline);
  border-bottom: 1px solid var(--hairline);
}
.numbers-row > div {
  background: var(--sheet);
  padding: 18px 20px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.numbers-row .metric {
  font-size: 1.45rem;
  font-weight: 700;
  color: var(--keel);
  letter-spacing: -0.01em;
}
.numbers-row .metric-cap { font-size: 0.86rem; color: var(--understated); line-height: 1.4; }

.rates { width: 100%; border-collapse: collapse; margin: 6px 0 18px; font-size: 0.95rem; }
.rates caption {
  caption-side: top;
  text-align: left;
  font-size: 0.85rem;
  color: var(--understated);
  padding-bottom: 8px;
}
.rates th, .rates td {
  text-align: left;
  padding: 11px 14px;
  border-bottom: 1px solid var(--hairline);
  vertical-align: top;
}
.rates thead th {
  background: var(--keel);
  color: var(--sheet);
  font-size: 0.82rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.rates tbody tr:nth-child(even) td { background: rgba(0, 0, 0, 0.018); }
.rates td:last-child { white-space: nowrap; font-variant-numeric: tabular-nums; }

.thaw-steps { counter-reset: step; list-style: none; margin: 4px 0 16px; padding: 0; }
.thaw-steps li {
  counter-increment: step;
  position: relative;
  padding: 0 0 14px 44px;
  margin: 0;
}
.thaw-steps li::before {
  content: counter(step);
  position: absolute;
  left: 0;
  top: 1px;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: var(--alert-c);
  color: var(--keel);
  font-weight: 700;
  font-size: 0.9rem;
  display: flex;
  align-items: center;
  justify-content: center;
}

.queries-list { margin: 4px 0 0; }
.queries-list dt {
  font-weight: 650;
  color: var(--keel);
  margin: 18px 0 5px;
  font-size: 1.02rem;
}
.queries-list dt:first-child { margin-top: 0; }
.queries-list dd { margin: 0; padding: 0 0 4px 0; color: var(--fg); }

@media (max-width: 560px) {
  .numbers-row .metric { font-size: 1.25rem; }
  .rates th, .rates td { padding: 9px 10px; }
}

/* --- Reviews partial (inc/partials/reviews.php).
   Ships gated OFF via site.php show_reviews=false, but the partial ALSO renders
   when $IS_PREVIEW is true — so without these rules the block appears unstyled
   on the preview URL, and if the switch is ever flipped. Styled now so that
   flipping it is safe. */
.feedback-block {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 16px;
  margin-top: 8px;
}
.citation-card {
  background: var(--sheet);
  border: 1px solid var(--hairline);
  border-radius: var(--fillet);
  padding: 18px 20px;
}
.citation-card p { margin: 0 0 12px; font-size: 0.96rem; }
.grade-marks {
  color: var(--alert-c);
  font-size: 0.95rem;
  letter-spacing: 0.08em;
  margin-bottom: 8px;
}
.said-by {
  font-size: 0.86rem;
  font-weight: 600;
  color: var(--understated);
  font-style: normal;
}

/* --- Work photos ------------------------------------------------------ */
/* The base rule caps width so an unclassed figure can never render
   full-bleed. Copied from the reference implementation per
   job-photo-prompts.md 5.1, with the variable names translated to this
   stylesheet's own. The .portrait and .wide modifiers are DELIBERATELY NOT
   carried: every master on this site is 1200x800, and shipping the modifiers
   makes "add the class" the easy fix when an image comes back the wrong
   shape, when the correct fix is to regenerate it. No .pair either - this
   site has no before/after sequence. */
.worksite-shot {
  max-width: var(--limit);
  margin: 0 auto;
  padding: 34px 20px;
}
.worksite-shot img {
  display: block;
  width: 100%;
  max-width: 800px;
  height: auto;
  margin: 0 auto;
  border-radius: var(--fillet);
  border: 1px solid var(--hairline);
}

/* --- Homepage work strip ---------------------------------------------- */
/* Ten small proof-of-work thumbnails low on the homepage - one per service
   page and one per commercial page. Deliberately NOT links and NOT
   lightboxed; they are scroll-depth reassurance, not a gallery. Column
   counts are set for TEN images per 5.1b, so rows come out even at every
   breakpoint: 5/5 on desktop, five rows of 2 below 900px and below 520px.
   A ragged trailing row is the visible tell that nobody checked. */
.work-reel .vignettes {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 12px;
}
.work-reel img {
  display: block;
  width: 100%;
  /* height:auto is required - the img height="320" attribute is a
     presentational hint that would otherwise make the box 320px tall and
     cause aspect-ratio to be ignored entirely. */
  height: auto;
  aspect-ratio: 3 / 2;
  object-fit: cover;
  border-radius: 7px;
  border: 1px solid var(--hairline);
  background: var(--sheet);
}
@media (max-width: 900px) { .work-reel .vignettes { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 520px) { .work-reel .vignettes { grid-template-columns: repeat(2, 1fr); gap: 10px; } }
