/* Unique Painting KC

   The page is white. That is the whole starting point, and it is a change from the last version,
   which was navy-heavy and read as heavy. White and near-white fields carry the page, one hot color
   carries the energy, and navy only ever appears as a scrim laid over a photograph or in the footer.

   Depth comes from two things and not from decoration. Photographs run to the edge of the screen and
   are interrupted by solid panels laid on top of them, and anything that sits on top of something
   else casts a shadow that matches what it is: a sheet of paper on a surface gets a soft one, a
   painted panel gets none and relies on its own hard edge.

   Four things move. All four answer somebody's hand except the first, which runs once on load so a
   stranger learns the handle can be dragged, and then never again:

     1. the first wipe, one travel, once
     2. every wipe handle, dragged or arrowed
     3. the reel arrows, stepping between real jobs
     4. the tool tabs and the price tabs, swapping a panel

   No carousel that runs itself, no parallax, no video, no scroll-triggered fades, no framework. Two
   self-hosted faces and about seven kilobytes of script. */

/* fonts:start */
@font-face { font-family: "Barlow Condensed"; font-weight: 600; font-style: normal; font-display: swap; src: url("fonts/barlow-condensed-600.woff2") format("woff2"); }
@font-face { font-family: "Barlow Condensed"; font-weight: 700; font-style: normal; font-display: swap; src: url("fonts/barlow-condensed-700.woff2") format("woff2"); }
@font-face { font-family: "Source Sans 3"; font-weight: 400; font-style: normal; font-display: swap; src: url("fonts/source-sans-3-400.woff2") format("woff2"); }
@font-face { font-family: "Source Sans 3"; font-weight: 600; font-style: normal; font-display: swap; src: url("fonts/source-sans-3-600.woff2") format("woff2"); }
/* fonts:end */

:root {
  --paper: #FFFFFF;
  --mist: #F4F7FA;          /* the second light field. Cool and bright, never cream */
  --ink: #141C26;
  --slate: #5A6672;
  --rule: #DEE4EA;

  --navy: #102038;          /* brand. Scrims over photographs, and the footer */
  --navy-deep: #0A1527;
  --red: #EF3430;           /* brand. The one hot color on the page */
  --red-deep: #C32017;      /* the same red, dark enough to carry white words and to be read on white */
  --red-wash: #FFD9D6;      /* the palest red. The only accent that can be read on a red band */
  --on-navy: #C8D4E0;

  /* Where each face is allowed, October 29, 2026. MIT AgeLab, reported by NN/g: condensed costs
     11.2% more reading time than a regular width, and the recommendation is to avoid condensed
     where glanceability matters. So --display is for type set large enough that scale pays the
     penalty back: h1, h2, h3, and numbers or pull quotes at 28px and up. Everything a person reads
     once, small, in a hurry goes in --body: the phone number anywhere, button labels, nav and menu
     links, form labels, captions, small caps badges, footer links, table cells. That is the list of
     the things this site is here to get read. */
  --display: "Barlow Condensed", "Avenir Next Condensed", "Arial Narrow", "Roboto Condensed", sans-serif;
  --body: "Source Sans 3", "Segoe UI", system-ui, -apple-system, Arial, sans-serif;

  --page: 78rem;
  --measure: 36rem;
  --gutter: clamp(1.125rem, 4vw, 3rem);
  --lift: 0 1.25rem 2.75rem -1rem rgba(10, 21, 39, .28);   /* paper resting on a surface */
  --lift-high: 0 2.25rem 4.5rem -1.25rem rgba(10, 21, 39, .42);

  --r-sm: .45rem;           /* buttons, chips, small marks */
  --r-md: .85rem;           /* cards, photographs, panels */
  --r-lg: 1.4rem;           /* the big sheets a section is built around */

  color-scheme: light;
  scroll-padding-top: 7rem;
}

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

/* A form control does not inherit a face from its parent. Left alone they render in the browser's
   own Arial, which is a third family on the page and reads as a stylesheet that was never finished. */
button, input, select, textarea { font-family: inherit; }

/* the root element has no face of its own, so it reports as the browser default and shows up as a
   third family on every mechanical check */
html { font-family: var(--body); }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--body);
  font-size: 1.0625rem;
  line-height: 1.58;
  -webkit-text-size-adjust: 100%;
  overflow-x: hidden;
}
@media (min-width: 48rem) { body { font-size: 1.125rem; } }

h1, h2, h3 {
  margin: 0;
  font-family: var(--display);
  font-weight: 700;
  color: var(--ink);
  text-wrap: balance;
}
/* Condensed, set very large and very tight. The type is the graphic. */
h1 { font-size: clamp(3.1rem, 8.2vw, 6.75rem); line-height: .85; letter-spacing: -.014em; }
h2 { font-size: clamp(2.5rem, 7vw, 4.75rem); line-height: .88; letter-spacing: -.01em; }
h3 { font-weight: 600; font-size: 1.55rem; line-height: 1.1; }
.hot { color: var(--red-deep); }                 /* the second half of a two-tone headline */
.band .hot { color: var(--red); }
/* The closing band is a solid field of --red-deep. --red on it is 1.47:1, which is unreadable,
   and darker does not help either: a near-black red is 2.33:1 and large text needs 3:1.
   --red-wash is 4.56:1. No painting page puts an accent word in the closing band today, so this
   rule was never seen, but the remodeling site had the same mistake live on 12 pages. Fixing the
   one nobody can see too, so it cannot bite the day somebody adds one. */
.closing .hot { color: var(--red-wash); }
/* Not in the hero. The red on "Kansas City" was the brightest thing in the first screen and it is
   not clickable, so the eye landed on the one phrase that changes nothing and the button came
   second. Hierarchy condition 2 in the playbook. In the hero the headline carries one weight
   throughout and the only red in the viewport is the thing we want pressed. The span stays in the
   markup, which belongs to another agent; this just declines to accent it here. */
.hero .hot { color: inherit; }

p, ul, ol, dl, figure { margin: 0; }
img { max-width: 100%; }

a { color: var(--red-deep); text-decoration-thickness: 2px; text-underline-offset: 3px; }
a:hover { color: var(--ink); }
:focus-visible { outline: 3px solid var(--red-deep); outline-offset: 2px; }

.skip { position: absolute; left: -200vw; top: .5rem; z-index: 60; display: inline-flex; align-items: center; min-height: 3rem; padding: .5rem .8rem; background: var(--paper); border: 2px solid var(--navy); color: var(--navy); font-weight: 600; }
.skip:focus { left: var(--gutter); }

/* ---------- the frame */

.wrap { max-width: var(--page); margin-inline: auto; padding-inline: var(--gutter); }
.section { padding-block: clamp(4.75rem, 11vw, 9.5rem); }
.section--mist { background: var(--mist); }
.section--tight { padding-block: clamp(3.25rem, 7.5vw, 5.75rem); }

.prose { max-width: var(--measure); }
.wrap.prose { max-width: var(--page); }
/* Everything on a prose wrap is held to a reading measure except the things that are not prose.
   .reviews and .reviews-foot were missing from that list, so on reviews.html at 1440 the scroller
   ran in a 576px window inside a 1248px section: one card and a half of a second one cut off
   mid-word, with the right half of the page empty. That is the one page whose whole job is proof. */
.wrap.prose > :not(.drivers):not(.figures):not(.steps):not(.proof):not(.shots):not(.posts):not(.reviews):not(.reviews-foot) { max-width: var(--measure); }
.prose > * + * { margin-top: 1rem; }
.prose > h2 { margin-top: 3rem; font-size: clamp(1.9rem, 3.2vw, 2.7rem); }
.prose > h2:first-child { margin-top: 0; }
.prose > h3 { margin-top: 2.2rem; }
.lede { font-size: 1.2em; line-height: 1.45; color: var(--slate); }
.note, .hint { font-size: .93em; color: var(--slate); }
h1 + .lede, h2 + .lede, h2 + p, h2 + .note { margin-top: 1.25rem; }
:is(.proof, .shots, .cards, .picker, .figures, .drivers, .steps, .gate, .ticks, .price, .posts) + :is(p, .note, .hint) { margin-top: 1.8rem; }
:is(.proof, .shots, .cards, .picker) + .note { padding-top: 1.2rem; border-top: 1px solid var(--rule); max-width: 46rem; }

/* a heading that wants air above it inside a section */
.head { max-width: 46rem; }
.head + * { margin-top: 2.5rem; }

/* ---------- the promo bar and the header

   The live site carries a thin bar above the logo. Ours carries the two things a stranger wants in
   the first second: what we do and whether anyone is there. */

/* The header, October 27, 2026. Ben: "remove the header and have the logo in
   the upper left on top of the hero, model after that site. Headers are
   outdated now."

   What went: the navy promo strip, the white bar under it, the row of seven
   inline links, the Painting services dropdown, and the floating rail that
   carried a second menu button and a second call to action. Five pieces of
   furniture stacked across the top and down the right of every page. The promo
   strip said nothing the footer does not, and the rail duplicated what is now
   always in the header.

   What is left is the thing itself, laid over the picture: the mark, the
   number, the button, a menu.

   Two states. Over a hero it is transparent, white on the film. Anywhere else,
   and once anybody scrolls, it is solid navy. Solid is the DEFAULT on purpose:
   a browser without :has() then gets a readable header everywhere instead of
   white text on a white page. */
:root { --head: 4.1rem; }

.site-head {
  position: fixed; inset: 0 0 auto; z-index: 40;
  background: var(--navy);
  transition: background .25s ease, box-shadow .25s ease;
}
.site-head .wrap { display: flex; align-items: center; gap: .5rem; min-height: var(--head); }
/* the link gets a 48px box; the mark inside it keeps its own height */
.brand { display: inline-flex; align-items: center; min-height: 3rem; margin-right: auto; line-height: 0; }
.brand img { display: block; height: 2.6rem; width: auto; }

/* A page with a hero puts the film behind the header. A page without one needs
   the room back, or its first heading sits underneath. */
main { padding-top: var(--head); }
body:has(.hero) main { padding-top: 0; }
body:has(.hero) .site-head { background: transparent; }
body:has(.hero) .site-head[data-stuck] {
  background: var(--navy);
  box-shadow: 0 .5rem 1.5rem -.5rem rgba(10, 21, 39, .45);
}

/* The number is the most glanceable thing on the site and the one the condensed study names
   outright, so it is set in the body face and given a 48px box of its own to be tapped in. */
.phone {
  display: inline-flex; align-items: center; min-height: 3rem; padding-inline: .2rem;
  font: 600 1.0625rem/1 var(--body); letter-spacing: .005em;
  color: var(--paper); text-decoration: none; white-space: nowrap;
}
.phone span { display: none; }
.phone:hover { color: #fff; }
.site-head .button { background: var(--red-deep); border-color: var(--red-deep); color: var(--paper); }
.site-head .button:hover { background: var(--paper); border-color: var(--paper); color: var(--ink); }

/* The short list of pages, wide screens only. Off below 72rem, where the logo, the number, the
   button and the menu already fill the row. The menu button stays at every width and still holds
   the whole site; this is the shortcut, not the index. */
.top-nav { display: none; }
@media (min-width: 72rem) {
  .top-nav { display: flex; align-items: center; gap: .35rem; margin-right: .5rem; }
  .top-nav a {
    display: inline-flex; align-items: center; min-height: 3rem; padding: 0 .7rem;
    border-radius: var(--r-sm);
    font: 600 1.0625rem/1 var(--body); color: var(--paper); text-decoration: none; white-space: nowrap;
  }
  .top-nav a:hover { background: rgba(255, 255, 255, .14); color: var(--paper); }
}

/* One menu button at every width. That is the part that reads as current,
   rather than as a nav bar that happens to collapse on a phone. */
.menu { position: relative; }
.menu > summary {
  display: grid; place-items: center; width: 2.9rem; height: 2.9rem;
  cursor: pointer; list-style: none; border-radius: var(--r-sm);
  border: 2px solid rgba(255, 255, 255, .45);
}
.menu > summary::-webkit-details-marker { display: none; }
.menu-bars, .menu-bars::before, .menu-bars::after {
  display: block; width: 1.15rem; height: 2px; background: var(--paper); border-radius: 2px;
}
.menu-bars { position: relative; }
.menu-bars::before, .menu-bars::after { content: ""; position: absolute; left: 0; }
.menu-bars::before { top: -.38rem; }
.menu-bars::after { top: .38rem; }
.menu[open] > summary { background: var(--paper); border-color: var(--paper); }
.menu[open] .menu-bars { background: transparent; }
.menu[open] .menu-bars::before { top: 0; background: var(--ink); transform: rotate(45deg); }
.menu[open] .menu-bars::after { top: 0; background: var(--ink); transform: rotate(-45deg); }
.menu-panel {
  position: absolute; right: 0; top: calc(100% + .6rem);
  width: min(20rem, calc(100vw - 2 * var(--gutter)));
  padding: .5rem 0; max-height: min(70vh, 34rem); overflow-y: auto;
  background: var(--paper); border-radius: var(--r-md); box-shadow: var(--lift-high);
}
/* Menu links are nav labels, so body face, and the box is 48px tall rather than the 45 it was. */
.menu-panel a {
  display: flex; align-items: center; min-height: 3rem; padding: .55rem 1.25rem;
  font: 600 1.0625rem/1.25 var(--body); color: var(--ink); text-decoration: none;
}
.menu-panel a:hover { background: var(--mist); color: var(--red-deep); }
.menu-panel a[aria-current="page"] { color: var(--red-deep); box-shadow: inset .22rem 0 0 var(--red); }

@media (min-width: 46rem) {
  :root { --head: 5.1rem; }
  .brand img { height: 3.7rem; }
  .phone span { display: inline; font-weight: 400; opacity: .75; margin-right: .3rem; }
  .site-head .wrap { gap: 1.1rem; }
  .phone { font-size: 1.15rem; }
}
@media (max-width: 30rem) {
  /* the thumb bar at the bottom of a phone already carries both of these */
  .site-head .button, .phone { display: none; }
}

/* ---------- buttons. Square, solid, the one hot color. */

.button {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 3rem; padding: .55rem 1.4rem; max-width: 100%; border-radius: var(--r-sm);
  border: 2px solid var(--red-deep); background: var(--red-deep); color: var(--paper);
  /* body face: a button label is read in one glance, which is the case the condensed study rules out */
  font: 600 1.0625rem/1 var(--body); letter-spacing: .005em;
  text-decoration: none; white-space: nowrap; cursor: pointer;
}
.button:hover { background: var(--ink); border-color: var(--ink); color: var(--paper); }
.button--paper { background: var(--paper); border-color: var(--paper); color: var(--ink); }
.button--paper:hover { background: var(--ink); border-color: var(--ink); color: var(--paper); }
.button--line { background: transparent; border-color: var(--ink); color: var(--ink); }
.button--line:hover { background: var(--ink); color: var(--paper); }
.button--big { min-height: 3.75rem; padding-inline: 1.9rem; font-size: 1.25rem; }
@media (max-width: 30rem) {
  .button { white-space: normal; text-align: center; }
  .button--big { font-size: 1.15rem; padding-inline: 1.25rem; }
}

/* The second action beside a button. It is deliberately a step down in weight from the button and
   it carries an underline, so it still reads as clickable without competing for the first glance. */
.actions { display: flex; flex-wrap: wrap; align-items: center; gap: .9rem 1.75rem; margin-top: 2.1rem; }
.actions a:not(.button) {
  display: inline-flex; align-items: center; min-height: 3rem;
  font: 600 1.0625rem/1 var(--body); text-decoration: none;
  border-bottom: 2px solid var(--red); padding-bottom: .22rem; color: inherit;
}
.actions a:not(.button):hover { color: var(--red-deep); }

/* ---------- the rail

   One call to action pinned to the edge of the screen at every scroll position, so the shortest road
   to a job is never more than a glance away. On a phone it becomes a bar across the bottom, because a
   thumb reaches the bottom of a phone and not the right edge of it. */

.to-top {
  position: fixed; right: 1.25rem; bottom: 1.25rem; z-index: 35;
  width: 3rem; height: 3rem; display: none; place-items: center;
  background: var(--paper); border: 2px solid var(--ink); border-radius: 50%; color: var(--ink);
  text-decoration: none; box-shadow: var(--lift);
}
.to-top::before { content: ""; width: .6rem; height: .6rem; margin-top: .22rem; border-top: 3px solid currentColor; border-right: 3px solid currentColor; transform: rotate(-45deg); }
.to-top:hover { background: var(--ink); color: var(--paper); }
.to-top[data-on] { display: grid; }
@media (min-width: 76rem) { .rail { display: block; } }

.thumb-bar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 35;
  display: grid; grid-template-columns: 1fr 1fr;
  border-top: 1px solid var(--rule); background: var(--paper);
  box-shadow: 0 -.75rem 1.5rem -.75rem rgba(10, 21, 39, .25);
  padding-bottom: env(safe-area-inset-bottom, 0px);
}
.thumb-bar a {
  display: flex; align-items: center; justify-content: center; min-height: 3.5rem;
  font: 600 1.0625rem/1.15 var(--body); text-align: center; text-decoration: none;
  background: var(--paper); color: var(--ink);
}
.thumb-bar a + a { background: var(--red-deep); color: var(--paper); }
@media (min-width: 76rem) { .thumb-bar { display: none; } }
@media (max-width: 75.99rem) { body { padding-bottom: 3.5rem; } .to-top { bottom: 4.75rem; } }

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

   A full width photograph of a real room of ours, in daylight, with the words on a white panel laid
   over its lower left so the panel and the picture overlap instead of sitting in two boxes. */

/* The hero, rebuilt October 27, 2026, after Ben sent a Loom of
   that1painter.com: "model after this!!!! This is what we want."

   The headline used to sit in a white card pulled up over the bottom of the
   film. Their pages, and our own remodeling site, put it straight on the
   picture, and that is the difference between a site that looks like it was
   built in 2019 and one that does not.

   So the film becomes a layer behind everything rather than a block above the
   words: absolutely positioned, z-index below, with the section carrying its
   own stacking context so nothing downstream can climb on top of it. The words
   sit in the lower left, held to a measure, so they are never read across the
   brightest part of a photograph. */
.hero { position: relative; isolation: isolate; background: var(--navy); }
.hero-shot { position: absolute; inset: 0; z-index: -2; }
.hero-shot img,
.hero-shot video {
  display: block; width: 100%; height: 100%;
  object-fit: cover; object-position: 50% 52%; background: var(--navy);
}
/* Two gradients doing two jobs. The one from the bottom carries the headline.
   The one from the top carries the header, which is transparent over this. */
.hero-shot::after {
  content: ""; position: absolute; inset: 0;
  background:
    linear-gradient(to top, rgba(10,21,39,.86) 0%, rgba(10,21,39,.55) 34%, rgba(10,21,39,.1) 68%),
    linear-gradient(to bottom, rgba(10,21,39,.6) 0, rgba(10,21,39,.2) 7rem, rgba(10,21,39,0) 12rem);
}
.hero-words {
  position: relative; z-index: 1;
  display: flex; flex-direction: column; justify-content: flex-end;
  min-height: clamp(27rem, 74vh, 44rem);
  padding-block: clamp(2.75rem, 7vw, 5rem);
}
.hero-words > div { max-width: 46rem; }
.hero-words h1 { color: var(--paper); text-wrap: pretty; }
.hero-words .lede { margin-top: 1.1rem; max-width: 34rem; color: var(--on-navy); }
/* The hero button, measured off the rendered page rather than guessed at. Sampled around the
   button at 1440: --red-deep sits at 2.48:1 against the median background and 1.77:1 against the
   brightest patches of the photograph, well under the 3:1 a control's edge has to clear. The
   brighter --red gets to 3.65:1 median but only 2.60:1 at the bright patches, and its white label
   drops to 4.04:1, which is under 4.5 at 20px semibold.
   So neither red solves it on its own, and the answer is not a fourth red. The fill stays
   --red-deep, where the white label measures 5.94:1 and passes at any size, and the button gets a
   white ring. The ring is what carries the edge against the photograph, at better than 13:1 on
   every patch of it, and it does not care how bright the picture behind it gets. */
.hero .button:not(.button--paper):not(.button--line) { border-color: var(--paper); }
.hero .actions a:not(.button) { color: var(--paper); }
.hero .actions a:not(.button):hover { color: #fff; }
.hero :focus-visible { outline-color: var(--paper); }
@media (max-width: 30rem) {
  .hero-shot img,
  .hero-shot video { object-position: 42% 62%; }
}

/* the small head on an inside page: no photograph, just air and large type */
.page-head { background: var(--mist); padding-block: clamp(2.75rem, 7vw, 5.5rem); }
.page-head .lede { margin-top: 1.25rem; max-width: 38rem; }

/* ---------- the tool row

   Three panels on one sheet of white, lifted off the field behind it. The first one is the proof,
   which is the thing we have that nobody else in the metro puts on a page. */

.tools { background: var(--mist); padding-block: clamp(2.5rem, 6vw, 4.5rem) clamp(3.5rem, 9vw, 7rem); }
.tool-sheet {
  position: relative; z-index: 1; background: var(--paper);
  border-radius: var(--r-lg); box-shadow: var(--lift-high); overflow: hidden;
}
/* The tool row. It was three words on a hairline tab bar and Ben put a
   screenshot of it next to the site he sent: "this is not nearly as
   prominent". It was not. Three real tiles now, each with a mark and a line
   saying what it is, under a headline big enough to stop a thumb, with the
   wordmark ghosted behind the lot. */
.tools .wrap { position: relative; }
.ghost-mark {
  position: absolute; left: 50%; top: -2.5rem; transform: translateX(-50%);
  margin: 0; z-index: 0; pointer-events: none; user-select: none;
  width: min(44rem, 94%); aspect-ratio: 16 / 10;
  background: url("logo-ghost.svg") center / contain no-repeat;
  opacity: .06; font-size: 0; color: transparent;
}
.tools-head {
  position: relative; z-index: 1; text-align: center; margin: 0 auto 2rem;
  max-width: 24ch; font-size: clamp(2.3rem, 6.2vw, 4.4rem); line-height: .98;
}
/* Ben, October 25: "put spacing between these blocks... make it less bulky".
   The three were flush against each other behind hairline dividers, which
   made one heavy slab. They are separate blocks on a tinted head now, with
   air around and between them, and the dividers are gone because the gap does
   that job. The live one still has to reach the panel, so it keeps the
   panel's white and runs down over the seam while the other two stop short. */
.tool-tabs {
  display: grid; gap: .45rem; grid-template-columns: 1fr; margin: 0;
  padding: .45rem;
  background: #E6ECF3; border-bottom: 1px solid var(--rule);
}
@media (min-width: 46rem) { .tool-tabs { grid-template-columns: repeat(3, 1fr); padding-bottom: 0; } }
.tool-tabs a {
  position: relative; display: flex; align-items: flex-start; gap: .7rem; min-width: 0;
  padding: clamp(.7rem, 1.6vw, .95rem) clamp(.8rem, 1.8vw, 1.1rem);
  border-radius: var(--r-sm);
  background: var(--mist); border: 0;
  text-decoration: none; color: var(--slate); cursor: pointer;
}
.tool-tabs a:hover { background: rgba(255, 255, 255, .7); color: var(--ink); }
.tool-tabs a[aria-selected="true"] {
  background: var(--paper); color: var(--ink);
}
@media (min-width: 46rem) {
  .tool-tabs a { border-radius: var(--r-sm) var(--r-sm) 0 0; }
  .tool-tabs a[aria-selected="true"] { margin-bottom: -1px; padding-bottom: calc(clamp(.7rem, 1.6vw, .95rem) + 1px); }
}
.tool-tabs a[aria-selected="true"]::before {
  content: ""; position: absolute; left: 0; right: 0; top: 0; height: 3px;
  border-radius: var(--r-sm) var(--r-sm) 0 0; background: var(--red);
}
.tool-tabs a[aria-selected="true"] .tool-name { color: var(--red); }
.tool-tabs a[aria-selected="true"] .tool-sub { color: var(--slate); }
.tool-tabs a:focus-visible { outline-offset: 3px; }
.tool-ico { flex: 0 0 auto; width: clamp(1.45rem, 3vw, 1.8rem); color: var(--red); }
.tool-ico svg { display: block; width: 100%; height: auto; }
.tool-name { display: block; font: 600 clamp(1rem, 1.9vw, 1.0625rem)/1.3 var(--body); }
.tool-sub { display: block; margin-top: .15rem; font-size: .88rem; line-height: 1.3; color: var(--slate); }
.tool-text { display: block; min-width: 0; }
.tool-panel { padding: clamp(1.5rem, 3.4vw, 2.6rem); }
.tool-panel + .tool-panel { border-top: 1px solid var(--rule); }
.tool-head { margin-bottom: 1.4rem; max-width: 42rem; }
.tool-head h3 { font-size: clamp(1.6rem, 3.4vw, 2.1rem); }
.tool-head p { margin-top: .5rem; color: var(--slate); }

/* ---------- before and after

   Two photographs of one real job, stacked, with the BEFORE one clipped from the left edge to
   wherever the handle sits. So BEFORE is always the half on the left and dragging right reveals more
   of it. Getting that backwards puts the finished house under the word Before, which is the one
   mistake this widget can make, so it is written here and checked on the rendered page. */

.ba { margin: 0; }
.ba-stage {
  --pos: 50%;
  position: relative; aspect-ratio: 4 / 3; overflow: hidden;
  border-radius: var(--r-md);
  background: var(--navy-deep); touch-action: pan-y; cursor: ew-resize;
  user-select: none; -webkit-user-select: none;
}
@media (min-width: 46rem) {
  /* 32rem tall at 16/10 is 51.2rem wide. Capping the stage made the browser
     shrink its WIDTH to hold the ratio, so the picture pulled away from a box
     that stayed put while the arrows stayed with the box. Cap the column
     instead and the picture, its caption, the count and both arrows all sit
     on the same two edges. */
  .reel, .ba, .reel-count { max-width: 51.2rem; margin-inline: auto; }
  .ba-stage { aspect-ratio: 16 / 10; }
  [data-tools] .tool-head { max-width: 51.2rem; margin-inline: auto; }
  #tool-work > .note { max-width: 51.2rem; margin-inline: auto; }
}
.ba-stage img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; display: block; pointer-events: none; -webkit-user-drag: none;
}
.ba-before { position: absolute; inset: 0; clip-path: inset(0 calc(100% - var(--pos)) 0 0); }

.ba-line { position: absolute; top: 0; bottom: 0; left: var(--pos); width: 3px; margin-left: -1.5px; background: var(--paper); box-shadow: 0 0 0 1px rgba(10,21,39,.25); pointer-events: none; }
.ba-grip {
  position: absolute; top: 50%; left: 50%;
  width: 3.1rem; height: 3.1rem; margin: -1.55rem 0 0 -1.55rem;
  background: var(--red); border: 3px solid var(--paper); border-radius: 50%;
  box-shadow: 0 .4rem 1rem rgba(10,21,39,.35);
  transition: transform .14s ease;
}
.ba-stage:active .ba-grip { transform: scale(1.09); }
.ba-grip::before, .ba-grip::after {
  content: ""; position: absolute; top: 50%; width: .46rem; height: .46rem; margin-top: -.23rem;
  border-top: 2px solid var(--paper); border-right: 2px solid var(--paper);
}
.ba-grip::before { left: .74rem; transform: rotate(-135deg); }
.ba-grip::after { right: .74rem; transform: rotate(45deg); }

/* the pills, which are the only words allowed to sit on a photograph */
.pill {
  position: absolute; top: .85rem; padding: .36rem .95rem .32rem;
  border-radius: 2rem; font: 700 .8rem/1 var(--body); letter-spacing: .1em;
  text-transform: uppercase; pointer-events: none;
}
.pill--before { left: .85rem; background: rgba(10,21,39,.78); color: var(--paper); }
.pill--after { right: .85rem; background: var(--red-deep); color: var(--paper); }

.ba-handle { position: absolute; inset: 0; cursor: ew-resize; }
.ba-handle:focus-visible { outline: 3px solid var(--red); outline-offset: -3px; }

.ba figcaption { margin-top: .9rem; max-width: 38rem; font: 600 1.1rem/1.3 var(--body); color: var(--ink); }
.ba figcaption span { display: block; margin-top: .25rem; font: 400 .95rem/1.45 var(--body); color: var(--slate); }
.band .ba figcaption, .hero .ba figcaption { color: var(--paper); }
.band .ba figcaption span { color: var(--on-navy); }

/* ---------- the reel: real jobs, stepped through by hand

   Every pair is in the page. The arrows move between them. With no script they are all on the page
   one under the other, which is a gallery, so nothing is hidden behind JavaScript. */

.reel { position: relative; }
.reel-slide + .reel-slide { margin-top: 2rem; }
.reel-arrow {
  position: absolute; top: calc(50% - 3.2rem); z-index: 3;
  width: 3rem; height: 3rem; display: none; place-items: center;
  background: var(--paper); border: 0; border-radius: 50%; cursor: pointer;
  box-shadow: 0 .4rem 1.1rem rgba(10,21,39,.3);
}
.reel-arrow::before { content: ""; width: .58rem; height: .58rem; border-top: 3px solid var(--ink); border-right: 3px solid var(--ink); }
.reel-arrow--back { left: .6rem; }
.reel-arrow--back::before { transform: rotate(-135deg); margin-left: .18rem; }
.reel-arrow--next { right: .6rem; }
.reel-arrow--next::before { transform: rotate(45deg); margin-right: .18rem; }
.reel-arrow:hover { background: var(--red-deep); }
.reel-arrow:hover::before { border-color: var(--paper); }
.reel[data-on] .reel-arrow { display: grid; }

/* The review scroller's arrows sit in a row under the cards, so they borrow
   the look of the reel arrows and none of the positioning. .reel-arrow is
   position:absolute, which took them out of that row entirely. */
.rev-arrow {
  position: static; width: 3rem; height: 3rem; display: grid; place-items: center;
  background: var(--paper); border: 1px solid var(--rule); border-radius: 50%;
  cursor: pointer; box-shadow: var(--lift);
}
.rev-arrow::before { content: ""; width: .58rem; height: .58rem; border-top: 3px solid var(--ink); border-right: 3px solid var(--ink); }
.rev-arrow--prev::before { transform: rotate(-135deg); margin-left: .18rem; }
.rev-arrow--next::before { transform: rotate(45deg); margin-right: .18rem; }
.rev-arrow:hover { background: var(--red-deep); border-color: var(--red-deep); }
.rev-arrow:hover::before { border-color: var(--paper); }
.rev-arrow[disabled] { opacity: .35; cursor: default; }
.rev-arrow[disabled]:hover { background: var(--paper); border-color: var(--rule); }
.rev-arrow[disabled]:hover::before { border-color: var(--ink); }
@media (max-width: 34rem) { .reel-arrow { top: calc(50% - 4rem); } }
.reel-count { margin-top: .9rem; font: 600 .95rem/1 var(--body); color: var(--slate); }
.reel-count[hidden] { display: none; }

/* ---------- the price

   Five buckets and no more. Every one is a real range out of Jobber with the number of jobs behind it
   printed beside it, so the control says how thin or thick the evidence is. Nothing is calculated. */

.picker { display: grid; gap: 1.75rem; }
@media (min-width: 58rem) { .picker { grid-template-columns: 17rem minmax(0, 1fr); gap: 2.75rem; align-items: start; } }

.picker-tabs { display: flex; overflow-x: auto; gap: 0; border-bottom: 1px solid var(--rule); scrollbar-width: none; }
.picker-tabs::-webkit-scrollbar { display: none; }
.picker-tabs a {
  flex: 0 0 auto; display: block; padding: .7rem 1rem .75rem; border-bottom: 3px solid transparent; margin-bottom: -1px;
  color: var(--slate); font: 400 .88rem/1.3 var(--body); text-decoration: none; white-space: nowrap; cursor: pointer;
}
.picker-tabs a b { display: block; font: 600 1.0625rem/1.25 var(--body); color: var(--ink); }
.picker-tabs a:first-child { padding-left: 0; }
.picker-tabs a[aria-selected="true"] { border-bottom-color: var(--red); }
.picker-tabs a[aria-selected="true"] b { color: var(--red-deep); }
@media (min-width: 58rem) {
  .picker-tabs { display: block; overflow: visible; border-bottom: 0; border-left: 1px solid var(--rule); }
  .picker-tabs a {
    display: flex; justify-content: space-between; align-items: baseline; gap: 1rem;
    padding: .85rem 1rem; border-bottom: 0; border-left: 4px solid transparent; margin: 0 0 0 -1px;
  }
  .picker-tabs a b { flex: 1 1 auto; }
  .picker-tabs a[aria-selected="true"] { border-left-color: var(--red); background: var(--mist); }
  .picker-tabs a:hover { background: var(--mist); }
}

.picker-panel { min-width: 0; }
.picker-panel + .picker-panel { margin-top: 2rem; padding-top: 2rem; border-top: 1px solid var(--rule); }
.picker-range {
  display: flex; align-items: baseline; flex-wrap: wrap; gap: 0 .5rem;
  font: 700 clamp(2.8rem, 10vw, 5.5rem)/.88 var(--display);
  color: var(--ink); letter-spacing: -.015em; font-variant-numeric: lining-nums tabular-nums;
}
.picker-range i { font: 400 .3em/1 var(--body); font-style: normal; color: var(--slate); letter-spacing: 0; }
.picker-said { margin-top: 1.3rem; max-width: 34rem; }
.picker-said b { color: var(--ink); }
.picker-more { margin-top: 1.2rem; font: 600 1.0625rem/1.4 var(--body); }

/* the spread, drawn. The bar runs low to high and the notch is the middle job. */
.picker-bar { margin-top: 1.5rem; max-width: 34rem; }
.picker-bar-track { position: relative; height: 1.1rem; border-radius: var(--r-sm); background: var(--mist); border: 1px solid var(--rule); }
.picker-bar-fill { position: absolute; top: -1px; bottom: -1px; background: var(--navy); transition: left .42s cubic-bezier(.2,.7,.3,1), width .42s cubic-bezier(.2,.7,.3,1); }
.picker-bar-mid { position: absolute; top: -.35rem; bottom: -.35rem; width: 3px; margin-left: -1.5px; background: var(--red); transition: left .42s cubic-bezier(.2,.7,.3,1); }
.picker-bar-ends { display: flex; justify-content: space-between; margin-top: .5rem; font-size: .85em; color: var(--slate); }
.section--mist .picker-bar-track { background: var(--paper); }

/* the single range on an inside page */
.price { margin-top: 2rem; max-width: 38rem; }
.price-range { font: 700 clamp(2.6rem, 9vw, 4.5rem)/.88 var(--display); color: var(--ink); letter-spacing: -.012em; font-variant-numeric: lining-nums tabular-nums; }
.price-from { margin-top: 1rem; padding-top: 1rem; border-top: 2px solid var(--red); font-size: .98em; }
.price-from b { color: var(--ink); }
.price-mid { margin-top: .45rem; font-size: .98em; color: var(--slate); }

/* ---------- services, as photographs rather than icons */

.offer { list-style: none; padding: 0; display: grid; gap: 1.5rem; }
.offer li { position: relative; background: var(--paper); border-radius: var(--r-md); overflow: hidden; box-shadow: var(--lift); }
.offer img { display: block; width: 100%; height: auto; aspect-ratio: 4 / 3; object-fit: cover; }
.offer .offer-words { padding: 1.1rem 1.25rem 1.4rem; }
.offer h3 a { color: var(--ink); text-decoration: none; }
.offer h3 a::after { content: ""; position: absolute; inset: 0; }
.offer li:hover h3 a, .offer h3 a:focus-visible { color: var(--red-deep); }
.offer p { margin-top: .4rem; color: var(--slate); font-size: .97em; }
/* two tiles in the grid carry no photograph, because we have none that honestly shows that work.
   They are solid instead, which makes the grid read as a decision rather than a gap. */
.offer li.offer--flat { background: var(--navy); color: var(--on-navy); display: grid; align-items: end; min-height: 15rem; }
.offer li.offer--flat .offer-words { padding: 2.25rem 1.5rem 1.9rem; }
.offer li.offer--flat h3 { font-size: 2.1rem; }
.offer li.offer--flat h3 a { color: var(--paper); }
.offer li.offer--flat:hover h3 a, .offer li.offer--flat h3 a:focus-visible { color: var(--red); }
.offer li.offer--flat p { color: var(--on-navy); }
.offer li.offer--flat :focus-visible { outline-color: var(--paper); }
@media (min-width: 40rem) { .offer { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1.75rem; } }
@media (min-width: 64rem) { .offer { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 2rem; } }

/* the ghosted wordmark behind a section. Type used as a surface, not as a label. */
.ghosted { position: relative; overflow: hidden; }
.ghosted > .wrap { position: relative; z-index: 1; }
.ghosted::before {
  content: "";
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  width: min(58rem, 115%); aspect-ratio: 16 / 10;
  background: url("logo-ghost.svg") center / contain no-repeat;
  opacity: .055;
  pointer-events: none;
}

/* Three pages on this site carry a <span class="watermark">UNIQUE</span> and this sheet had no
   rule for it at all, so on every one of them the word rendered as ordinary grey text at the left
   edge of the page, sitting above the heading with nothing around it. Every one of the three is
   inside a .ghosted section, which already draws the mark behind the words at the opacity it was
   tuned to. One decoration a section, so the span is taken out of the flow rather than given a
   second mark to draw. The markup is another agent's, so it stays where it is. */
.watermark { position: absolute; left: -200vw; width: 1px; height: 1px; overflow: hidden; }

/* ---------- a full width photograph with a scrim and words in the left third */

.band { position: relative; color: var(--paper); isolation: isolate; }
.band img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; z-index: -2; }
.band::before {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(100deg, rgba(10,21,39,.92) 0%, rgba(10,21,39,.86) 34%, rgba(10,21,39,.42) 64%, rgba(10,21,39,.3) 100%);
}
.band .wrap { padding-block: clamp(3.5rem, 9vw, 7rem); }
.band h2 { color: var(--paper); }
.band-words { max-width: 31rem; }
.band .lede, .band p { color: #DCE5EE; }
.band a:not(.button) { color: var(--paper); text-decoration-color: var(--red); }
.band :focus-visible { outline-color: var(--paper); }
.band-facts { margin-top: 2rem; display: grid; gap: 1.1rem; }
.band-facts > div { padding-left: 1.1rem; border-left: 2px solid var(--red); }
.band-facts dt { font: 600 .82rem/1.3 var(--body); letter-spacing: .1em; text-transform: uppercase; color: #9FB4CA; }
.band-facts dd { margin: .25rem 0 0; font: 600 1.25rem/1.25 var(--body); color: var(--paper); }
.band-facts dd a { text-decoration: none; }

/* ---------- the gallery: the same device, at a smaller size, staggered */

.proof { list-style: none; padding: 0; display: grid; gap: clamp(2rem, 4vw, 3rem); }
.proof figure { margin: 0; }
@media (min-width: 52rem) {
  .proof--two { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .proof--three { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .proof--stagger > li:nth-child(3n+2) { margin-top: 3.5rem; }
  .proof--stagger > li:nth-child(3n+3) { margin-top: 1.75rem; }
}

/* a pair shot from two different spots, so there is nothing for a handle to line up */
.pair { margin: 0; }
.pair-shots { display: grid; grid-template-columns: 1fr 1fr; gap: 3px; background: var(--rule); }
.pair-shots > div { position: relative; border-radius: var(--r-md); overflow: hidden; background: var(--mist); }
.pair-shots img { display: block; width: 100%; height: 100%; object-fit: cover; aspect-ratio: 3 / 2; }
.pair figcaption { margin-top: .9rem; max-width: 38rem; font: 600 1.1rem/1.3 var(--body); color: var(--ink); }
.pair figcaption span { display: block; margin-top: .25rem; font: 400 .95rem/1.45 var(--body); color: var(--slate); }

/* after-only shots */
.shots { list-style: none; padding: 0; columns: 1; column-gap: 1.5rem; }
.shots li { break-inside: avoid; margin-bottom: 1.5rem; }
.shots figure { margin: 0; }
.shots img { display: block; width: 100%; height: auto; border-radius: var(--r-md); background: var(--mist); box-shadow: var(--lift); }
.shots figcaption { margin-top: .6rem; font: 600 1.0625rem/1.35 var(--body); color: var(--ink); }
@media (min-width: 42rem) { .shots { columns: 2; } }
@media (min-width: 64rem) { .shots { columns: 3; } }

/* ---------- reviews */

.stars { display: inline-flex; gap: .18rem; vertical-align: -.1em; }
.stars i { width: .95rem; height: .95rem; background: #F5A623; font-style: normal; clip-path: polygon(50% 0%, 61% 35%, 98% 35%, 68% 57%, 79% 91%, 50% 70%, 21% 91%, 32% 57%, 2% 35%, 39% 35%); }
.rating-line { display: flex; align-items: center; gap: .75rem; flex-wrap: wrap; margin-top: 1.25rem; font: 600 1.0625rem/1.4 var(--body); }

/* ---------- a line somebody fills in before the site goes up */

.gate {
  padding: 1.15rem 1.3rem; border: 3px dashed var(--red); background: var(--paper);
  color: var(--ink); font-size: .98em; max-width: 42rem; box-shadow: var(--lift);
}
.gate b { color: var(--red-deep); }

/* ---------- lists of named things */

.drivers { border-bottom: 1px solid var(--rule); }
.drivers > div { display: grid; gap: .25rem 2rem; padding-block: 1.2rem; border-top: 1px solid var(--rule); }
.drivers dt { font: 600 1.5rem/1.12 var(--display); color: var(--ink); }
.drivers dd { margin: 0; max-width: 36rem; color: var(--slate); }
@media (min-width: 48rem) { .drivers > div { grid-template-columns: 15rem minmax(0, 1fr); align-items: baseline; } }

.figures { border-bottom: 1px solid var(--rule); max-width: 46rem; }
.figures > div { display: grid; gap: .1rem 1.5rem; padding-block: 1rem; border-top: 1px solid var(--rule); }
.figures dt { font: 600 1.0625rem/1.35 var(--body); color: var(--ink); }
.figures dd { margin: 0; color: var(--slate); }
@media (min-width: 42rem) { .figures > div { grid-template-columns: 13rem minmax(0, 1fr); align-items: baseline; } }

.ticks { list-style: none; padding: 0; display: grid; gap: .6rem; max-width: 38rem; }
.ticks li { position: relative; padding-left: 1.7rem; }
.ticks li::before { content: ""; position: absolute; left: 0; top: .72em; width: .95rem; height: 3px; background: var(--red); }

.steps { list-style: none; padding: 0; counter-reset: step; display: grid; gap: 0; border-bottom: 1px solid var(--rule); }
.steps li { counter-increment: step; display: grid; grid-template-columns: 3rem minmax(0, 1fr); column-gap: 1.1rem; padding-block: 1.3rem; border-top: 1px solid var(--rule); }
.steps li::before { content: counter(step); grid-row: 1 / span 2; font: 700 2.6rem/.85 var(--display); color: var(--red); }
.steps h3 { grid-column: 2; }
.steps p { grid-column: 2; margin-top: .35rem; color: var(--slate); }
/* side by side on a wide screen. The number moves above the heading, because a 3rem column of
   numeral beside a third of the page leaves a measure nobody can read. */
@media (min-width: 58rem) {
  .steps { grid-template-columns: repeat(3, minmax(0, 1fr)); column-gap: 3rem; border-bottom: 0; }
  .steps li { display: block; border-top: 2px solid var(--red); padding-block: 1.1rem 0; }
  .steps li::before { display: block; margin-bottom: .3rem; font-size: 2.2rem; }
  .steps h3, .steps p { grid-column: auto; }
}

/* ---------- lists of pages. Rules, not boxes. */

.cards { list-style: none; padding: 0; display: grid; gap: 0; border-bottom: 1px solid var(--rule); }
.cards li { position: relative; padding: 1.3rem 0 1.45rem; border-top: 1px solid var(--rule); }
.cards h3 { font-size: 1.6rem; }
.cards h3 a { color: var(--ink); text-decoration: none; }
.cards h3 a::after { content: ""; position: absolute; inset: 0; }
.cards li:hover h3 a, .cards h3 a:focus-visible { color: var(--red-deep); }
.cards p { margin-top: .45rem; color: var(--slate); max-width: 34rem; }
.cards .said { margin-top: .6rem; font: 700 2rem/1 var(--display); color: var(--ink); font-variant-numeric: lining-nums tabular-nums; }
.cards .said span { display: block; margin-top: .35rem; font: 400 .92rem/1.35 var(--body); color: var(--slate); }
@media (min-width: 46rem) {
  .cards { grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: 3rem; }
  .cards--three { grid-template-columns: repeat(3, minmax(0, 1fr)); column-gap: 2.25rem; }
}

/* the blog index */
.posts { list-style: none; padding: 0; display: grid; gap: 2rem; }
.posts li { position: relative; padding-top: 1.4rem; border-top: 2px solid var(--ink); }
.posts h3 { font-size: 1.75rem; }
.posts h3 a { color: var(--ink); text-decoration: none; }
.posts h3 a::after { content: ""; position: absolute; inset: 0; }
.posts li:hover h3 a, .posts h3 a:focus-visible { color: var(--red-deep); }
.posts > li > p:last-child { margin-top: .5rem; color: var(--slate); }
.posts .kind { margin-top: .55rem; font: 400 .92rem/1 var(--body); color: var(--slate); }
@media (min-width: 52rem) { .posts { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 2.5rem 3rem; } }

/* The reveal. Only ever active when site.js has put data-rise-on on <html>, so the content is
   visible to anybody whose script did not run, and the animation is an enhancement rather than the
   thing holding the page up. See the long note in site.js for why that matters. */
[data-rise-on] [data-rise] {
  opacity: 0; transform: translateY(12px);
  transition: opacity .55s cubic-bezier(.22,.61,.36,1), transform .55s cubic-bezier(.22,.61,.36,1);
  transition-delay: calc(var(--rise, 0) * 70ms);
}
[data-rise-on] [data-rise][data-risen] { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  [data-rise-on] [data-rise] { opacity: 1; transform: none; transition: none; }
}

/* What we paint, as expanding slats. Ben, November 4, 2026: "The what we paint is basic as shit...
   watch the video I sent. I want it to be as modern as the way they do it.... Recreate that". I had
   built a plain accordion off his written description without looking at the thing he pointed at.
   Opened it in his Chrome instead: six panels in a row, 500px tall, one open wide and the rest
   collapsed to narrow slivers with the title turned on its side, photo behind, dark scrim at the
   bottom so the type reads.

   Built on radio inputs and :has(), so it needs no javascript: the radio carries the state, the
   label is the click target, and arrow keys move between them because that is what a radio group
   already does. One open at a time comes free with a radio name.

   The same CSS does the phone layout by flipping the flex direction, because flex-basis is height
   in a column, so the slats open downward instead of sideways and no second set of rules is needed. */
.vh { position:absolute; width:1px; height:1px; margin:-1px; padding:0; overflow:hidden; clip-path:inset(50%); white-space:nowrap; border:0; }
.slats {
  display: flex; flex-direction: column; gap: .6rem;
  height: clamp(30rem, 78vw, 34rem); margin-top: 2rem;
}
.slat {
  position: relative; overflow: hidden; border-radius: 12px;
  flex: 0 1 4.25rem; min-height: 0; min-width: 0;
  background: var(--navy); box-shadow: 0 10px 30px rgb(16 32 56 / .18);
  transition: flex-grow .45s ease, flex-basis .45s ease;
}
.slat input { position: absolute; opacity: 0; width: 0; height: 0; }
.slat-hit { position: absolute; inset: 0; cursor: pointer; z-index: 1; }
.slat > img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; object-position: center;
}
.slat::after {
  content: ""; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: linear-gradient(180deg, rgb(16 32 56 / .12) 0%, rgb(16 32 56 / .62) 58%, rgb(16 32 56 / .92) 100%);
}
.slat-vert, .slat-face { position: absolute; z-index: 2; color: var(--paper); }
/* collapsed: the name, turned on its side, sitting at the bottom */
.slat-vert {
  inset: auto 0 1.1rem; text-align: center;
  font: 700 1.02rem/1 var(--display); letter-spacing: .01em; white-space: nowrap;
  opacity: 1; transition: opacity .25s ease;
}
/* open: the name, the line and the link */
.slat-face {
  inset: auto 0 0; padding: 1.4rem clamp(1.1rem, 2.4vw, 1.7rem) 1.5rem;
  opacity: 0; transform: translateY(.5rem); pointer-events: none;
  transition: opacity .3s ease .12s, transform .3s ease .12s;
}
.slat-face h3 { color: var(--paper); font-size: clamp(1.5rem, 3.1vw, 2.1rem); line-height: 1.05; }
.slat-face p { margin-top: .5rem; color: rgb(255 255 255 / .86); max-width: 34rem; font-size: .98rem; }
.slat-face a { display: inline-block; margin-top: .85rem; color: var(--paper);
  font-weight: 700; text-decoration-thickness: 2px; text-underline-offset: .28em; }
.slat:has(input:checked) { flex-grow: 1; flex-basis: 14rem; }
.slat:has(input:checked) .slat-vert { opacity: 0; }
.slat:has(input:checked) .slat-face { opacity: 1; transform: none; pointer-events: auto; }
.slat:has(input:focus-visible) { outline: 3px solid var(--red); outline-offset: 3px; }
@media (min-width: 52rem) {
  .slats { flex-direction: row; height: clamp(26rem, 42vw, 31rem); gap: .75rem; }
  .slat { flex-basis: 6.5rem; }
  .slat:has(input:checked) { flex-basis: 20rem; }
  .slat-vert {
    inset: auto 0 1.4rem; writing-mode: vertical-rl; transform: rotate(180deg);
    left: 50%; translate: -50% 0; font-size: 1.06rem;
  }
}
@media (prefers-reduced-motion: reduce) {
  .slat, .slat-vert, .slat-face { transition: none; }
}

/* The paint brands. Ben, November 4, 2026: "Just have an autoscroll bar of the paint brands we use".
   Two rails of the same list run end to end and the track slides exactly half its width, so the
   loop has no seam and no javascript. It pauses on hover and on keyboard focus, and under
   prefers-reduced-motion it stops moving entirely and wraps into a plain centered row, because a
   strip that scrolls on its own and cannot be stopped is the one piece of motion on this site that
   would be unreadable to somebody who needs it still. */
.brands { overflow: hidden; }
.brands .wrap { padding-block: clamp(2.5rem, 5vw, 3.75rem); }
.brands-head { text-align: center; max-width: none; margin-inline: auto; }
.brands-head > * { max-width: none; margin-inline: auto; }
.brands-rail { margin-top: 1.6rem; position: relative; overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 7rem, #000 calc(100% - 7rem), transparent);
          mask-image: linear-gradient(90deg, transparent, #000 7rem, #000 calc(100% - 7rem), transparent); }
.brands-track { display: flex; width: max-content; animation: brand-slide 34s linear infinite; }
.brands-rail:hover .brands-track, .brands-track:focus-within { animation-play-state: paused; }
.brands-track ul { list-style: none; margin: 0; padding: 0; display: flex; align-items: center; flex: 0 0 auto; }
.brands-track li { flex: 0 0 auto; padding-inline: clamp(1.75rem, 4vw, 3.5rem); }
.brands-track img { display: block; width: auto; }
/* Sized one at a time, by eye, not to a single height. Sherwin-Williams is a tall stacked
   lockup and Benjamin Moore is a wide one: give them the same pixel height and the first
   reads about half the size of the second. These three numbers are what makes the row look
   like one row instead of three logos of random importance. */
.brands-track img[alt="Sherwin-Williams"] { height: clamp(3rem, 6.2vw, 4rem); }
.brands-track img[alt="Benjamin Moore"]   { height: clamp(1.9rem, 3.9vw, 2.5rem); }
.brands-track img[alt="PPG"]              { height: clamp(2.2rem, 4.5vw, 2.9rem); }
/* Behr is the widest lockup of the four at about 4:1, so it gets the shortest height.
   Matched by eye to Benjamin Moore: give it the others height and it runs twice their width. */
.brands-track img[alt="Behr"]              { height: clamp(1.5rem, 3.1vw, 2rem); }
/* The typeset stand-in that runs until the real logo files land. */
.brands-track b { display: block; font: 700 clamp(1.3rem, 2.8vw, 1.9rem)/1 var(--display);
  letter-spacing: .01em; color: var(--ink); white-space: nowrap; opacity: .72; }
.brands-note { margin-top: 1.9rem; margin-bottom: 0; text-align: center; margin-inline: auto; max-width: 52rem; }
@keyframes brand-slide { from { transform: translate3d(0,0,0); } to { transform: translate3d(-50%,0,0); } }
@media (prefers-reduced-motion: reduce) {
  .brands-rail { -webkit-mask-image: none; mask-image: none; }
  .brands-track { animation: none; width: auto; flex-wrap: wrap; justify-content: center; }
  .brands-track ul { flex-wrap: wrap; justify-content: center; }
  .brands-track ul + ul { display: none; }
  .brands-track li { padding-block: .6rem; }
}

/* the two people a homeowner actually deals with */
.people { list-style: none; padding: 0; display: grid; gap: 2.75rem; }
.people img { width: 100%; height: auto; display: block; background: var(--mist); }
.people h3 { margin-top: 1.1rem; font-size: 1.75rem; }
.people .kind { margin-top: .25rem; font: 400 .92rem/1 var(--body); color: var(--slate); }
.people p + p { margin-top: .85rem; }
.people > li > p { max-width: 34rem; }
@media (min-width: 52rem) {
  .people { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 3rem; }
}

.statement { font: 700 clamp(1.75rem, 4.4vw, 2.6rem)/1.06 var(--display); color: var(--ink); max-width: 20em; text-wrap: balance; }
h2 + .statement { margin-top: 1.1rem; }
.statement + p { margin-top: 1.2rem; max-width: var(--measure); }
.band .statement, .closing .statement { color: var(--paper); }

.split { display: grid; gap: 2.5rem; }
.split > * { min-width: 0; }
@media (min-width: 60rem) {
  .split { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 4.5rem; align-items: start; }
  .split--wide { grid-template-columns: minmax(0, 1.15fr) minmax(0, .85fr); }
}

/* ---------- the close and the foot */

.closing { background: var(--red-deep); color: var(--paper); }
.closing h2 { color: var(--paper); }
.closing a:not(.button) { color: var(--paper); }
.closing .wrap { display: grid; gap: 1.75rem; padding-block: clamp(3rem, 7vw, 5rem); }
.closing p { margin-top: .8rem; max-width: 34rem; }
@media (min-width: 48rem) { .closing .wrap { grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 3rem; } }

.site-foot { background: var(--navy); color: var(--on-navy); font-size: .95em; }
.site-foot a { color: var(--paper); text-decoration-color: var(--red); }
.site-foot .wrap { display: grid; gap: 2rem; padding-block: 3rem; }
.foot-about { display: grid; gap: .75rem; max-width: 30rem; }
.foot-mark { margin: 0 0 .3rem; line-height: 0; }
.foot-mark img { display: block; width: auto; height: 4.5rem; }
.foot-call { margin: 0; }
.foot-call a { display: inline-flex; align-items: center; min-height: 3rem; font: 700 1.6rem/1 var(--body); text-decoration: none; white-space: nowrap; }
/* The gap is zero because the 48px box on each link is already the spacing. Both together made a
   14-row tower 800px tall beside a short column of text, which is the empty-space-above-content
   condition the false-bottom research names. Two columns from 54rem up for the same reason: this
   list is the whole site and it does not need a screen to itself. */
.foot-nav { list-style: none; padding: 0; display: grid; gap: 0; align-content: start; }
.foot-nav a { display: flex; align-items: center; min-height: 3rem; padding-right: 1rem; font: 600 1.0625rem/1.3 var(--body); text-decoration: none; }
.foot-nav a:hover { text-decoration: underline; }
.foot-fine { padding-bottom: 2.5rem; font-size: .88em; opacity: .7; }
/* the back-to-top disc rides above the thumb bar and was sitting on top of the last line of the
   page. A sticky control does not get to cover the words underneath it, so the line gets its own
   ground at the widths where the disc is there. */
@media (max-width: 75.99rem) { .foot-fine { padding-bottom: 5.75rem; } }
.foot-fine p { margin: 0; }
.foot-fine a + a { margin-left: .9rem; }
@media (min-width: 54rem) {
  .site-foot .wrap { grid-template-columns: minmax(0, 1fr) auto; gap: 4rem; align-items: start; }
  .foot-nav { grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: 2.5rem; }
}

@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; transition: none !important; }
}

/* ---------- Google reviews

   Ben, October 26, 2026: "copy all of them right now and then have a scroll
   bar of them on that section of the page. But also have the bottom corner
   popup of the reviews from people that show up periodically."

   One set of cards in the markup. The scroller is the cards; the corner popup
   reads the same cards out of the page, so there is only ever one copy of
   anybody's words and nothing can drift between the two. */

.reviews {
  list-style: none; margin: 2rem 0 0; padding: 0 0 1rem;
  display: flex; gap: 1rem;
  overflow-x: auto; overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory; scroll-padding-left: 0;
  scrollbar-color: var(--rule) transparent;
}
.reviews::-webkit-scrollbar { height: .5rem; }
.reviews::-webkit-scrollbar-track { background: transparent; }
.reviews::-webkit-scrollbar-thumb { background: var(--rule); border-radius: 999px; }
.review {
  scroll-snap-align: start; flex: 0 0 min(23rem, 82vw);
  display: flex; flex-direction: column; gap: .75rem;
  padding: 1.3rem 1.4rem 1.2rem;
  background: var(--paper); border-radius: var(--r-md); box-shadow: var(--lift);
}
.review blockquote { margin: 0; flex: 1 1 auto; }
.review blockquote p {
  margin: 0; font-size: 1.02rem; line-height: 1.5;
  /* one long review was making every card in the row as tall as it was.
     Clamped, so the row stays even. The whole of it is on Google. */
  display: -webkit-box; -webkit-line-clamp: 10; -webkit-box-orient: vertical; overflow: hidden;
}
.review-who { margin: 0; display: flex; flex-wrap: wrap; align-items: baseline; gap: .15rem .6rem; }
.review-who b { font: 700 1.0625rem/1.3 var(--body); }
.review-who span { font-size: .9rem; color: var(--slate); }
.reviews-foot { display: flex; align-items: center; gap: 1rem; margin-top: .5rem; flex-wrap: wrap; }
.reviews-nav { display: flex; gap: .5rem; }
.reviews-foot[hidden] { display: none; }
.reviews-count { font-size: .95rem; color: var(--slate); }

/* The corner popup. Bottom left, because the right side already carries the
   fixed rail on a wide screen and the call bar on a narrow one. It is off
   entirely below 46rem: a popup over a phone's bottom bar is just in the way. */
.review-pop {
  position: fixed; left: var(--gutter); bottom: 1.25rem; z-index: 40;
  width: min(23rem, calc(100vw - 2 * var(--gutter)));
  display: none; flex-direction: column; gap: .6rem;
  padding: 1.1rem 2.4rem 1.1rem 1.2rem;
  background: var(--paper); border-radius: var(--r-md); box-shadow: var(--lift-high);
  transform: translateY(.75rem); opacity: 0;
  transition: transform .4s ease, opacity .4s ease;
}
@media (min-width: 46rem) { .review-pop[data-on] { display: flex; } }
.review-pop[data-shown] { transform: none; opacity: 1; }
.review-pop blockquote { margin: 0; }
.review-pop blockquote p {
  margin: 0; font-size: .97rem; line-height: 1.45;
  display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical; overflow: hidden;
}
.review-pop .review-who b { font-size: 1rem; }
.review-pop-x {
  position: absolute; top: .55rem; right: .55rem;
  width: 1.75rem; height: 1.75rem; display: grid; place-items: center;
  background: none; border: 0; border-radius: 50%; color: var(--slate); cursor: pointer; font-size: 1.1rem;
}
.review-pop-x:hover { background: var(--mist); color: var(--ink); }
@media (prefers-reduced-motion: reduce) {
  .review-pop { transition: none; transform: none; }
}

/* The toolbox, directly under the hero.

   Ben, October 27, 2026, pointing at That 1 Painter's row of three tools and
   then sending a Loom of the whole site: "model after this!!!! This is what we
   want." Theirs is a virtual painter, a paint calculator and an instant
   estimate. Ours is the color tool we already had, a calculator built the same
   day, and the cost page, which is the honest version of "instant estimate"
   for a company that will not quote a house it has not seen.

   The QR lives in the first card. A QR on a phone is useless, because you
   cannot scan the screen you are holding, so it shows from 46rem up where
   somebody is at a laptop with a phone in their pocket. Below that the card is
   just a card and the button does the same job. */
.toolbox { background: var(--mist); border-bottom: 1px solid var(--rule); padding-block: clamp(2.5rem, 6vw, 4.5rem); }
.toolbox-head {
  margin: 0 0 1.5rem;
  font: 700 clamp(1.75rem, 1.2rem + 2vw, 2.6rem)/1.05 var(--display); color: var(--ink);
}
.tools-row { list-style: none; margin: 0; padding: 0; display: grid; gap: 1rem; }
.tool-card {
  display: flex; flex-direction: column; gap: .7rem;
  padding: 1.4rem 1.5rem 1.5rem;
  background: var(--paper); border-radius: var(--r-md); box-shadow: var(--lift);
}
.tool-card h3 { margin: 0; font: 700 1.5rem/1.1 var(--display); color: var(--ink); }
.tool-card h3 a { color: inherit; text-decoration: none; }
.tool-card h3 a:hover { color: var(--red-deep); }
.tool-card p { margin: 0; color: var(--slate); }
.tool-card .button { margin-top: auto; align-self: start; }
.tool-qr { display: none; }
@media (min-width: 52rem) {
  .tools-row { grid-template-columns: repeat(3, 1fr); }
  .tool-qr {
    display: flex; align-items: center; gap: .85rem;
    margin-top: .3rem !important; padding-top: .9rem; border-top: 1px solid var(--rule);
  }
  .tool-qr img {
    flex: 0 0 auto; width: 5.5rem; height: 5.5rem;
    padding: .3rem; background: var(--paper);
    border: 1px solid var(--rule); border-radius: var(--r-sm);
  }
  .tool-qr span { font-size: .9rem; color: var(--slate); }
}

/* The rates table, October 27, 2026. Ben sent a Loom of that1painter.com and
   said model after it. The thing their cost page does that ours did not is put
   the numbers in a table somebody can read in four seconds, instead of three
   paragraphs about the nature of a range.

   Ours is four rows where theirs is six, because only interior and exterior
   have enough finished jobs behind them to be a range. The other two say what
   they are instead of inventing a number, which is the whole difference
   between a guide and a guess. */
.rates { width: 100%; border-collapse: collapse; margin-top: 1.25rem; }
.rates caption {
  caption-side: top; text-align: left; padding-bottom: .9rem;
  font: 700 clamp(1.5rem, 1.1rem + 1.4vw, 2.1rem)/1.1 var(--display); color: var(--ink);
}
.rates th, .rates td { padding: .95rem 1rem; text-align: left; vertical-align: top; }
.rates thead th {
  font: 600 .88rem/1.2 var(--body); letter-spacing: .08em; text-transform: uppercase;
  color: var(--paper); background: var(--navy); white-space: nowrap;
}
.rates thead th:first-child { border-radius: var(--r-sm) 0 0 0; }
.rates thead th:last-child { border-radius: 0 var(--r-sm) 0 0; }
.rates tbody tr { border-bottom: 1px solid var(--rule); }
.rates tbody th { font: 600 1.0625rem/1.35 var(--body); color: var(--ink); white-space: nowrap; }
.rates tbody th a { color: var(--ink); text-decoration-color: var(--rule); }
.rates tbody th a:hover { color: var(--red-deep); }
.rates .rate { font: 700 1.0625rem/1.35 var(--body); color: var(--red-deep); white-space: nowrap; }
.rates td:last-child { color: var(--slate); }
@media (max-width: 46rem) {
  /* A three-column table on a phone is a three-column table nobody reads. Each
     row becomes its own block, with the column headings carried in as labels. */
  .rates thead { position: absolute; left: -200vw; }
  .rates tbody tr { display: block; padding-block: 1rem; }
  .rates tbody th, .rates tbody td { display: block; padding: 0; }
  .rates tbody th { font-size: 1.15rem; }
  .rates .rate { margin: .2rem 0 .45rem; font-size: 1.25rem; }
}

/* The eight questions. Numbered, because the order is the order you would ask
   them standing in a driveway, and because a numbered list reads as a thing to
   work through rather than a list of claims. */
.asks { margin: 1.5rem 0 1.25rem; padding: 0; list-style: none; counter-reset: ask; }
.asks li {
  counter-increment: ask; position: relative;
  margin: 0; padding: .7rem 0 .7rem 3rem;
  border-top: 1px solid var(--rule);
  font-size: 1.08rem;
}
.asks li:first-child { border-top: 0; }
.asks li::before {
  content: counter(ask); position: absolute; left: 0; top: .62rem;
  width: 2rem; height: 2rem; display: grid; place-items: center;
  background: var(--mist); border-radius: 50%;
  font: 700 .95rem/1 var(--body); color: var(--red-deep);
}

/* The paint calculator. Inputs on the left, the answer on the right, big
   enough to be the point of the page. */
.calc {
  display: grid; gap: 1.5rem; align-items: start;
  padding: clamp(1.25rem, 3vw, 2rem);
  background: var(--paper); border: 1px solid var(--rule);
  border-radius: var(--r-lg); box-shadow: var(--lift);
}
.calc-row { display: grid; gap: .9rem; grid-template-columns: repeat(3, 1fr); }
.calc label { display: block; font: 600 1.0625rem/1.35 var(--body); color: var(--ink); }
.calc label span { display: block; font: 400 .82rem/1.2 var(--body); color: var(--slate); margin-top: .1rem; }
.calc input[type="number"] {
  width: 100%; min-height: 3rem; margin-top: .4rem; padding: .62rem .7rem;
  font: 600 1.15rem/1.2 var(--body); color: var(--ink);
  background: var(--mist); border: 1px solid var(--rule); border-radius: var(--r-sm);
}
.calc input[type="number"]:focus-visible { outline: 3px solid var(--red); outline-offset: 1px; }
.calc-row + .calc-row { margin-top: .9rem; }
.calc-check { margin: 1rem 0 0; }
/* the box itself is small, so the row around it is the 48px target */
.calc-check label { display: flex; align-items: center; min-height: 3rem; gap: .55rem; font-size: 1.05rem; }
.calc-check input { width: 1.15rem; height: 1.15rem; accent-color: var(--red-deep); }
.calc-out {
  display: block; padding: 1.3rem 1.4rem;
  background: var(--navy); color: var(--on-navy); border-radius: var(--r-md);
}
.calc-big { margin: 0; display: flex; align-items: baseline; gap: .55rem; flex-wrap: wrap; }
.calc-big b { font: 700 clamp(2.6rem, 2rem + 3vw, 4rem)/1 var(--display); color: var(--paper); }
.calc-big span { font: 600 1.0625rem/1.35 var(--body); color: var(--on-navy); }
.calc-buy { margin: .5rem 0 0; font: 600 1.15rem/1.3 var(--body); color: var(--paper); }
.calc-ceil { margin: .5rem 0 0; font-size: 1rem; color: var(--paper); }
.calc-area { margin: .9rem 0 0; font-size: .93rem; color: #93A6BB; }
@media (min-width: 52rem) {
  .calc { grid-template-columns: 1.5fr 1fr; gap: 2rem; }
}
@media (max-width: 34rem) {
  .calc-row { grid-template-columns: 1fr 1fr; }
}

/* The "more from" grid at the foot of a service page. That 1 Painter runs a
   two-column list of twelve services at the bottom of every one of theirs, and
   it is the plainest, most useful thing on the page: somebody who did not find
   what they came for gets a second chance instead of the back button.

   Written once in parts/more-services.html and pulled in with {{part:...}},
   because eight hand-made copies is how a site ends up linking to a page that
   was renamed last spring. */
.more-grid {
  list-style: none; margin: 1.5rem 0 0; padding: 0;
  display: grid; gap: 0 2.5rem; grid-template-columns: 1fr;
}
.more-grid li { border-top: 1px solid var(--rule); }
.more-grid a {
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  padding: .85rem 0;
  min-height: 3rem; font: 600 1.0625rem/1.3 var(--body); color: var(--ink); text-decoration: none;
}
.more-grid a::after {
  content: ""; flex: 0 0 auto; width: .45rem; height: .45rem;
  border-right: 2px solid var(--red); border-top: 2px solid var(--red);
  transform: rotate(45deg);
}
.more-grid a:hover { color: var(--red-deep); }
@media (min-width: 46rem) { .more-grid { grid-template-columns: 1fr 1fr; } }
@media (min-width: 72rem) { .more-grid { grid-template-columns: repeat(3, 1fr); } }

/* The Jobber request form, embedded. The snippet injects an iframe that sizes itself after it
   loads, so reserve room first: an unreserved embed shoves the page down under the reader at
   the worst possible moment. Nothing here styles Jobber's own markup, which we do not control. */
.embed-form { min-height: 34rem; margin: 0 0 1.4rem; }
.embed-form iframe { width: 100%; border: 0; display: block; }

/* The hero headline rotates its last word. Ben, October 29, 2026, after watching the one on
   that1painter: "It was a rolling time setting that changed the words after Paint. It's super
   unique. Ours is bland." All four words are in the h1, so a screen reader reads the whole list
   and the sentence is true however it is read. The invisible .roll-set holds the column open at
   the width of the longest word, or the button under it would jump every two and a half seconds.
   It stops entirely for anyone whose device asks for less motion, which is why every word has to
   read correctly frozen on its own. */
.roll { display: inline-grid; vertical-align: bottom; }
/* Ben, November 4, 2026: "those should be in a different color. Maybe try Navy Blue letters with a
   subtle white outline". Navy on its own would not survive an aerial video that keeps changing
   brightness underneath it, so the white outline is not decoration here, it is the thing carrying
   the edge, the same job the white ring does on the hero button above. paint-order puts the stroke
   behind the fill so the stroke does not eat into the letterform of a condensed bold face. */
.roll > i, .roll-set {
  color: var(--navy);
  -webkit-text-stroke: .055em var(--paper);
  paint-order: stroke fill;
  /* Ben, November 4, 2026: "Have the white outline be offset also". So the outline is not a ring
     sitting evenly around the letter, it is thrown down and to the right, which is how a sign
     painter would do it and which gives the word depth against a moving background. */
  text-shadow: .045em .045em 0 var(--paper);
}
.roll > i { grid-area: 1 / 1; font-style: normal;
            opacity: 0; transform: translateY(.22em); animation: roll-cycle 10s infinite; }
.roll > i:nth-of-type(1) { animation-delay: 0s; }
.roll > i:nth-of-type(2) { animation-delay: 2.5s; }
.roll > i:nth-of-type(3) { animation-delay: 5s; }
.roll > i:nth-of-type(4) { animation-delay: 7.5s; }
.roll-set { grid-area: 1 / 1; visibility: hidden; }
@keyframes roll-cycle {
  0%   { opacity: 0; transform: translateY(.22em); }
  3%   { opacity: 1; transform: translateY(0); }
  23%  { opacity: 1; transform: translateY(0); }
  26%  { opacity: 0; transform: translateY(-.22em); }
  100% { opacity: 0; transform: translateY(-.22em); }
}
@media (prefers-reduced-motion: reduce) {
  .roll > i { animation: none; opacity: 0; transform: none; }
  .roll > i:first-of-type { opacity: 1; }
}

/* The Best of the Northland strip. Ben confirmed on October 31, 2026 that Unique has won it every
   year since 2018 and sent the artwork, so the badges are real images rather than type. He asked
   for the years to show: the ribbon on each badge carries them but is unreadable at this size, so
   each one gets its year underneath in the display face.
   Nine badges, nine years, no gaps. The 2024 file (34th anniversary) was missing from the first
   batch and Ben sent it ten minutes later. The gap was caught by counting the badges against the
   claim, not by the strip looking wrong, which is the only reason it got caught at all.
*/
.awards .kicker { color: var(--red-deep); }
.awards-lede { max-width: var(--measure); margin-top: .6rem; color: var(--slate); }
.awards-row {
  list-style: none; margin: 1.75rem 0 0; padding: 0;
  display: grid; gap: 1.25rem .75rem;
  grid-template-columns: repeat(auto-fit, minmax(6.5rem, 1fr));
}
.awards-row li { display: grid; justify-items: center; gap: .4rem; min-width: 0; }
.awards-row img {
  display: block; width: 100%; max-width: 8.5rem; height: auto;
  mix-blend-mode: multiply;   /* the files have white grounds; this sits them on the band */
}
.awards-row span {
  font-family: var(--display); font-weight: 700; font-size: 1.15rem;
  font-variant-numeric: tabular-nums; color: var(--slate); letter-spacing: .02em;
}

/* ---- the cost ranges, folded into the third tool card -------------------------------------
   Ben, November 4, 2026: "We have What does it cost on the first two blocks on the site...
   let's not have this on here twice." The standalone price section is gone and its two
   numbers live here, in the card that already pointed at them. */
.tool-prices { display: grid; gap: .9rem; margin: 1.1rem 0 1.4rem; }
.tool-prices div { display: grid; gap: .15rem; }
.tool-prices dt { font-size: .9rem; letter-spacing: .02em; color: var(--slate); }
.tool-prices dd { margin: 0; font: 700 clamp(1.35rem, 2.6vw, 1.7rem)/1.1 var(--display); color: var(--ink); }
.tool-prices dd span { display: block; margin-top: .3rem; font: 400 .85rem/1.45 var(--body); color: var(--slate); }

/* ---- where we work, beside the map --------------------------------------------------------
   The map is a Google map and the "Map Data" strip along its bottom edge is the attribution
   Google asks for, so nothing crops it off. Copy sits next to the map rather than on top of
   it: laid over this many pins neither one can be read. */
.area-split { display: grid; gap: 2rem; margin-top: 2rem; }
.area-side, .area-words { display: grid; gap: 1.6rem; align-content: start; }
.area-map { margin: 0; }
.area-map img { display: block; width: 100%; height: auto; border-radius: 12px;
  box-shadow: 0 1px 2px rgba(16,24,32,.09), 0 12px 28px -14px rgba(16,24,32,.3); }
.area-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 1.05rem; }
.area-list li { padding-left: 1rem; border-left: 3px solid var(--red); line-height: 1.55; }
.area-list b { display: block; font: 700 1.05rem/1.3 var(--display); color: var(--ink); margin-bottom: .15rem; }
.area-note { margin: 0; color: var(--slate); }
/* Its own facts list, not .band-facts. That one is built for white type on a photograph and
   this block sits on the light mist, where white on near-white is invisible. */
.area-facts { display: grid; gap: .85rem; margin: 0; }
.area-facts div { display: grid; gap: .1rem; padding-left: 1rem; border-left: 3px solid var(--rule); }
.area-facts dt { font-size: .78rem; letter-spacing: .08em; text-transform: uppercase; color: var(--slate); }
.area-facts dd { margin: 0; color: var(--ink); font-weight: 600; }
.area-facts dd a { color: var(--red-deep); }
.area-side .actions { margin: 0; }
@media (min-width: 56rem) {
  .area-split { grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr); gap: 3.25rem; align-items: start; }
}

/* ---- the closing block, on Kansas City ----------------------------------------------------
   The red stays underneath as the background color, so if the picture never loads the block
   is the solid red it always was and the white type still has its contrast. */
.closing--shot { position: relative; isolation: isolate; overflow: hidden; }
.closing-shot { position: absolute; inset: 0; z-index: -2; display: block; }
.closing-shot img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 58%; }
/* Heavy enough on the left to hold white type over a bright sunset, gone by the right hand
   side so the city is actually visible. Navy, not red: red over that sky goes muddy and the
   point of the picture is that it is Kansas City. */
.closing--shot::after { content: ""; position: absolute; inset: 0; z-index: -1;
  background:
    linear-gradient(90deg, rgba(14,22,36,.90) 0%, rgba(14,22,36,.80) 30%,
                           rgba(14,22,36,.42) 62%, rgba(14,22,36,.10) 88%, rgba(14,22,36,.04) 100%),
    linear-gradient(180deg, rgba(14,22,36,.22) 0%, rgba(14,22,36,0) 45%, rgba(14,22,36,.30) 100%); }
.closing--shot .wrap { padding-block: clamp(4rem, 9vw, 6.5rem); }
/* No room to fade sideways on a phone: the type runs the full width, so the cover is flat. */
@media (max-width: 48rem) {
  .closing--shot::after { background: rgba(14,22,36,.80); }
  .closing-shot img { object-position: 50% 50%; }
}

/* ---- the five year warranty seal ----------------------------------------------------------
   Ben sent the badge on November 4, 2026. It carries the promise better than the heading did,
   so the heading moves beside it rather than above it. The seal is the thing the eye lands on
   and the words are what it means. */
.warranty-split { display: grid; gap: 1.75rem; justify-items: center; text-align: center; }
.warranty-seal { display: block; line-height: 0; }
.warranty-seal img { width: clamp(9rem, 32vw, 11rem); height: auto; }
.warranty-words { display: grid; gap: .9rem; max-width: 40rem; }
.warranty-words h2 { margin: 0; }
.warranty-words .note { margin: 0; }
@media (min-width: 52rem) {
  .warranty-split { grid-template-columns: auto minmax(0, 1fr); gap: 3rem;
    justify-items: start; text-align: left; align-items: center; }
  .warranty-seal img { width: 15rem; }
}
/* The same seal at reading size, set into a narrow prose column rather than beside it. */
.seal-para { overflow: hidden; }
.seal-small { float: left; width: clamp(5rem, 14vw, 6.5rem); height: auto;
  margin: .15rem 1.1rem .4rem 0; }

/* ---- the before and after reel's controls -------------------------------------------------
   Ben, November 4, 2026: "there is a toggle at the bottom that allows you to go to the next
   before and after slider". They were .reel-arrow, which is position:absolute and sits on the
   photograph itself. These are the reviews row's static arrows instead, in a row under the
   slide with the count between them, so the picture is never covered and the control is where
   he asked for it. */
.reel-foot { display: flex; align-items: center; justify-content: center; gap: 1.1rem;
  margin-top: 1.4rem; }
.reel-foot .reel-count { margin: 0; min-width: 4.5rem; text-align: center; }
.reel[data-on] .reel-foot { display: flex; }
.reel:not([data-on]) .reel-foot { display: none; }
/* The panel heading was inheriting an auto side margin from the generic measure rule, so it
   sat 125px in from everything under it. Pinned to the panel's own left edge. */
.tool-panel .tool-head { margin-inline: 0; }
.tool-panel .tool-prices, .tool-panel .note, .tool-panel .actions { margin-inline: 0; }
/* The reel's controls are centred under the picture, so the gallery link goes under them
   rather than hanging off to the left on its own. */
#work .reel + .note { margin-top: 1.1rem; text-align: center; }
