/* Handoff base — the shared block from the five .dc.html files.
 *
 * BUILD.md: "Move the :root token block and the two @media blocks into
 * css/design-base.css once. Do not duplicate them per template." This is that
 * block, lifted verbatim from Home Page.dc.html. Service, trade, guides and
 * post link the same file as they land in steps 2-5.
 *
 * It is a separate file from design-base.css rather than an addition to it,
 * and that is deliberate. design-base.css sets `section{padding-block:64px}`,
 * `h1/h2/h3{max-width}` and `p{max-width:60ch}` at element level. Those are
 * invisible to an inline style attribute, so linking it would silently add
 * padding to all thirteen sections and cap every heading — the port would not
 * match the source and the difference would not show up in the markup. The
 * sixty pages not yet ported keep using design-base.css; when step 5 lands,
 * this file replaces it.
 *
 * Four @media blocks, not two: 1100px, 640px, 980px, 520px.
 * Do not convert anything here to classes. That is a later pass, one pattern
 * at a time, verified against the source after each.
 */

:root{
--surface-base:oklch(12% 0.018 280);--surface-raised:oklch(16% 0.022 280);--surface-panel:oklch(20% 0.026 280);
/* --text-tertiary is 61%, not the 56% the mockups shipped. At 56% it measured
   4.33 / 4.15 / 3.86 against base / raised / panel, and WCAG AA wants 4.5 for
   text under 18px. It carries the sub-bar, kickers, captions and the note next
   to the primary CTA. 61% is the smallest step that clears 4.5 on all three. */
--text-primary:oklch(96% 0.006 280);--text-secondary:oklch(73% 0.014 280);--text-tertiary:oklch(61% 0.020 280);
--accent-core:oklch(55% 0.250 278);--accent-text:oklch(76% 0.155 278);
--line-soft:oklch(100% 0 0 / 0.08);--line-strong:oklch(100% 0 0 / 0.16);--line-media:oklch(100% 0 0 / 0.10);
--fd:"Satoshi","Aeonik",system-ui,sans-serif;--fb:"Switzer","Suisse Intl",system-ui,sans-serif;
--gut:clamp(20px,5.2vw,80px);
}
body{margin:0;background:var(--surface-base);color:var(--text-secondary);font-family:var(--fb);-webkit-font-smoothing:antialiased}
a{color:var(--accent-text);text-decoration:none}
a:hover{color:var(--text-primary)}
img{display:block;width:100%;height:auto}
summary::-webkit-details-marker{display:none}

@media (max-width:1100px){
  /* minmax(0,1fr), not 1fr. A bare 1fr means minmax(AUTO,1fr), and the auto
   minimum resolves to the widest child's max-content. An in-body image at
   882px intrinsic width therefore forced the whole track to 882 inside a
   375px viewport, and the sticky Contents rail inherited it. Latent until
   the blog posts moved onto this template and brought their images. */
[data-r="hero"],[data-r="split"],[data-r="cols3"],[data-r="rail"]{grid-template-columns:minmax(0,1fr) !important;gap:32px !important}
  [data-r="ledger"]{grid-template-columns:1fr !important;gap:18px !important}
  [data-r="ledger"]>figure,[data-r="ledger"]>div[style*="aspect-ratio"]{order:3}
  [data-r="cols4"]{grid-template-columns:1fr 1fr !important}
  [data-r="rail"]>aside{position:static !important;top:auto !important}
  [data-r="postrow"]{grid-template-columns:1fr !important;gap:6px !important}
  [data-r="cols3"]>*,[data-r="cols4"]>*{border-right:0 !important}
  [data-r="cols3"]>*{border-bottom:1px solid var(--line-soft)}
  [data-r="cols3"]>*:last-child{border-bottom:0}
  [data-r="cols3"]>*,[data-r="cols4"]>*{padding-left:0 !important;padding-right:0 !important}
}
@media (max-width:640px){
  [data-r="cols4"],[data-r="cols2"]{grid-template-columns:1fr !important}
  [data-r="towns"]{grid-template-columns:1fr 1fr !important}
  [data-r="ledger"]>figure,[data-r="ledger"]>div[style*="aspect-ratio"]{max-width:100%}
}

@media (max-width:980px){
  [data-r="navrow"]{flex-wrap:wrap !important;row-gap:10px !important}
  [data-r="navrow"]>nav{order:3;width:100%;overflow-x:auto;white-space:nowrap !important;-webkit-overflow-scrolling:touch;padding-bottom:2px;scrollbar-width:none}
  [data-r="navrow"]>nav::-webkit-scrollbar{display:none}
  [data-r="navcta"]{margin-left:auto !important;flex-wrap:wrap !important;justify-content:flex-end}
}
@media (max-width:520px){
  [data-r="navcta"]>a:last-child{padding:10px 14px !important;font-size:12px !important}
  [data-r="navrow"]{gap:12px !important}
}

/* ---- Article body ----------------------------------------------------
   Blog Post.dc.html inline-styles every paragraph, heading and callout in
   its article. A real post's body comes from markdown, so there are no
   inline styles to carry across — these rules exist because that content
   would otherwise render unstyled.

   This is NOT the class-conversion pass BUILD.md defers. Nothing here is a
   conversion: every value is lifted from the corresponding inline style in
   the source file, and the selectors are element-level inside the article
   so authored markdown needs no classes to look right.
   -------------------------------------------------------------------- */
[data-post-body] > p { margin: 20px 0 0; font: 400 17px/1.7 var(--fb); }
[data-post-body] > p:first-child {
  margin: 0; font: 400 clamp(1.0625rem, 1.3vw, 1.1875rem)/1.7 var(--fb);
  color: var(--text-primary);
}
[data-post-body] > h2 {
  margin: 44px 0 0; font: 600 clamp(1.5rem, 3vw, 2.25rem)/1.12 var(--fd);
  letter-spacing: -.022em; color: var(--text-primary);
}
[data-post-body] > h2 + p { margin-top: 16px; }
[data-post-body] > h3 {
  margin: 32px 0 0; font: 600 20px/1.25 var(--fd); color: var(--text-primary);
}
[data-post-body] > blockquote {
  margin: 32px 0 0; padding-left: 32px; border-left: 2px solid var(--accent-core);
}
[data-post-body] > blockquote > p {
  margin: 0; font: 500 clamp(1.25rem, 2.4vw, 1.625rem)/1.4 var(--fd);
  letter-spacing: -.018em; color: var(--text-primary);
}
/* Numbered list, hanging indent, never a coloured dot (§2). */
[data-post-body] > ol, [data-post-body] > ul { margin: 20px 0 0; padding-left: 22px; }
[data-post-body] > ul { list-style: none; padding-left: 0; }
[data-post-body] > ul > li {
  padding-left: 22px; text-indent: -22px; margin-top: 10px;
  font: 400 17px/1.7 var(--fb);
}
[data-post-body] > ol > li { margin-top: 10px; font: 400 17px/1.7 var(--fb); }
[data-post-body] img { border-radius: 14px; border: 1px solid var(--line-media); margin-top: 32px; }

/* ---- Site navigation -------------------------------------------------
   The five .dc.html mockups were single-page designs, so every nav link in
   them was an on-page jump (#work, #pricing). Ported verbatim that left the
   whole site with no navigation at all: 33 pages and no route between any
   two of them but the logo back to home.

   This restores the menu the legacy base.njk carried, rewritten against the
   handoff tokens. The legacy rules in css/parts/30-home.css use --radius,
   --space-xs, --z-menu and --type-body-s, none of which exist in this sheet,
   so they could not simply be linked.

   No JavaScript: the desktop panels open on :hover and :focus-within, and
   the mobile panel is a <details>, which is also what makes it latch.
   -------------------------------------------------------------------- */

.sitenav{display:flex;align-items:center;gap:clamp(14px,1.7vw,24px);min-width:0}
.sitenav a,.sitenav button{font:500 14px/1 var(--fb);color:var(--text-secondary);white-space:nowrap}
.sitenav a:hover,.sitenav button:hover{color:var(--text-primary)}

.navdrop{position:relative}
.navdrop>button{display:inline-flex;align-items:center;gap:6px;background:none;border:0;padding:0;cursor:pointer;font-family:var(--fb)}
.navdrop>button::after{content:"";width:5px;height:5px;margin-top:-3px;flex:none;border-right:1px solid currentColor;border-bottom:1px solid currentColor;transform:rotate(45deg);opacity:.55;transition:transform .18s ease}
.navdrop:hover>button::after,.navdrop:focus-within>button::after{transform:rotate(-135deg)}

.navdrop__panel{position:absolute;top:100%;left:-14px;z-index:60;min-width:238px;display:grid;gap:2px;margin-top:12px;padding:8px;border-radius:14px;background:var(--surface-panel);border:1px solid var(--line-strong);box-shadow:0 18px 48px oklch(0% 0 0 / .5);opacity:0;visibility:hidden;transform:translateY(-4px);transition:opacity .18s ease,transform .18s ease,visibility 0s .18s}
/* Bridges the 12px gap so the pointer can travel into the panel. */
.navdrop__panel::before{content:"";position:absolute;left:0;right:0;top:-12px;height:12px}
.navdrop:hover>.navdrop__panel,.navdrop:focus-within>.navdrop__panel{opacity:1;visibility:visible;transform:none;transition-delay:0s}
.navdrop__panel a{padding:9px 12px;border-radius:8px;font:400 14px/1.3 var(--fb);color:var(--text-secondary)}
.navdrop__panel a:hover{background:var(--surface-raised);color:var(--text-primary)}
.navdrop__panel a.navdrop__all{margin-top:4px;padding-top:11px;border-top:1px solid var(--line-soft);border-radius:0 0 8px 8px;color:var(--accent-text)}

/* Mobile. Hidden on desktop; swaps with .sitenav at 980px, which is also
   where the header row starts wrapping. */
/* position:static so the panel measures against the sticky header, not the
   Menu button, which sits just right of the logo and would push a
   right-anchored panel off screen. */
.navmob{display:none;position:static}
.navmob>summary{list-style:none;cursor:pointer;font:500 14px/1 var(--fb);color:var(--text-primary)}
.navmob>summary::marker,.navmob>summary::-webkit-details-marker{content:"";display:none}
.navmob__panel{position:absolute;top:100%;left:var(--gut);right:var(--gut);z-index:60;display:grid;gap:2px;margin-top:14px;padding:12px;max-height:72vh;overflow-y:auto;border-radius:14px;background:var(--surface-panel);border:1px solid var(--line-strong);box-shadow:0 18px 48px oklch(0% 0 0 / .5)}
.navmob__panel a{padding:12px 8px;font:400 15px/1.3 var(--fb);color:var(--text-secondary);border-bottom:1px solid var(--line-soft)}
.navmob__panel a:last-child{border-bottom:0}
.navmob__panel span{padding:14px 8px 6px;font:500 12px/1 var(--fd);letter-spacing:.06em;text-transform:uppercase;color:var(--text-tertiary)}

@media (max-width:980px){
  .sitenav{display:none}
  .navmob{display:block}
}

/* ---- Site footer -----------------------------------------------------
   The mockups' footer held one link, "Back to top". These columns are how
   the 33 pages are reachable from anywhere, and how they get crawled.
   -------------------------------------------------------------------- */
.sitefoot{display:grid;grid-template-columns:repeat(4,1fr);gap:32px;padding:56px var(--gut) 0}
.sitefoot h2{margin:0 0 14px;font:500 12px/1 var(--fd);letter-spacing:.06em;text-transform:uppercase;color:var(--text-tertiary)}
.sitefoot a{display:block;padding:7px 0;font:400 14px/1.45 var(--fb);color:var(--text-secondary)}
.sitefoot a:hover{color:var(--text-primary)}
@media (max-width:820px){.sitefoot{grid-template-columns:1fr 1fr;gap:28px}
  .sitefoot a{padding:12px 0}}
@media (max-width:480px){.sitefoot{grid-template-columns:1fr}}

/* ---- Section sub-bar -------------------------------------------------
   The on-page jump links the mockups had in the header. They were dropped
   when the site menu went in (getting between 33 pages beats getting
   between 5 sections) and this puts them back on their own row.

   It sits INSIDE <header>, which is already position:sticky. A separate
   sticky element would need to know the header's height, and that height
   changes with the viewport.
   -------------------------------------------------------------------- */
.subbar{display:flex;gap:clamp(16px,2vw,28px);align-items:center;padding:0 var(--gut);border-top:1px solid var(--line-soft);overflow-x:auto;white-space:nowrap;scrollbar-width:none;-webkit-overflow-scrolling:touch}
.subbar::-webkit-scrollbar{display:none}
.subbar a{padding:13px 0;font:500 13px/1.4 var(--fb);color:var(--text-tertiary);border-bottom:2px solid transparent;flex:none}
.subbar a:hover{color:var(--text-primary);border-bottom-color:var(--line-strong)}
@media (max-width:520px){.subbar a{font-size:12px}}

/* ---- As seen on ------------------------------------------------------
   The marks ship colour-on-white and two of the three have a frame baked
   into the PNG. Inverting the plate to sit them on the dark surface turned
   those frames into bright rectangles, so each mark gets a light chip
   instead and is shown as its owner drew it.

   The chip is a fixed box with object-fit:contain rather than a max-height,
   because the three files carry very different amounts of internal
   whitespace: matching their heights left USA Today reading at half the
   weight of the other two.
   -------------------------------------------------------------------- */
.seenon{display:flex;flex-wrap:wrap;align-items:center;gap:clamp(18px,2.4vw,32px);padding:26px var(--gut);border-top:1px solid var(--line-soft);border-bottom:1px solid var(--line-soft)}
.seenon>span{font:500 12px/1 var(--fd);letter-spacing:.08em;text-transform:uppercase;color:var(--text-tertiary);flex:none}
.seenon img{flex:none;width:132px;height:44px;object-fit:contain;padding:7px 12px;box-sizing:border-box;border-radius:8px;background:oklch(95% 0.004 280);opacity:.82;transition:opacity .18s ease}
.seenon img:hover{opacity:1}
@media (max-width:640px){.seenon{gap:14px}.seenon img{width:104px;height:36px;padding:6px 9px}}

/* The sticky header is ~111px with the sub-bar under it, so an anchor jump
   would drop its target behind the bar. scroll-margin-top keeps the heading
   visible; the extra 16px is breathing room rather than a flush edge. */
html{scroll-behavior:smooth}
[id]{scroll-margin-top:127px}
@media (max-width:980px){[id]{scroll-margin-top:150px}}
@media (prefers-reduced-motion:reduce){html{scroll-behavior:auto}}

/* ---- Centred composition ---------------------------------------------
   The .dc.html mockups inline `margin:24px 0 0` alongside `max-width:56ch`
   on nearly every paragraph. That pair is the lock: max-width without an
   auto side margin pins the measure hard left, and because it is an inline
   style no class can move it. Overriding needs !important, which is why it
   is here rather than in a tidier rule.

   What gets centred: headings, short intros, eyebrows, stat rows, CTA rows.
   What does not: running body copy at a 60ch measure, where centring costs
   real readability because every line starts in a different place.
   -------------------------------------------------------------------- */
.ctr{text-align:center}
.ctr > h1,.ctr > h2,.ctr > h3,.ctr > p,.ctr > span,.ctr > div{margin-left:auto !important;margin-right:auto !important}
.ctr [data-r="split"],.ctr .row{justify-content:center}
.ctr > div[style*="display:flex"]{justify-content:center}

/* ---- Trust band -------------------------------------------------------
   Three claims, boxed and centred. Replaces the four-cell strip that led
   with "Parker, CO", which is a location rather than a reason to trust.
   -------------------------------------------------------------------- */
.trustband{display:grid;grid-template-columns:repeat(3,1fr);gap:0;margin:0 var(--gut);border:1px solid var(--line-strong);border-radius:16px;overflow:hidden;background:var(--surface-raised)}
.trustband > div{padding:26px 24px;text-align:center;border-right:1px solid var(--line-soft);display:flex;flex-direction:column;justify-content:center;gap:8px}
.trustband > div:last-child{border-right:0}
.trustband b{font:600 clamp(1rem,1.5vw,1.1875rem)/1.3 var(--fd);color:var(--text-primary);letter-spacing:-.012em}
.trustband span{font:400 14px/1.5 var(--fb);color:var(--text-tertiary)}
@media (max-width:820px){
  .trustband{grid-template-columns:1fr}
  .trustband > div{border-right:0;border-bottom:1px solid var(--line-soft)}
  .trustband > div:last-child{border-bottom:0}
}

/* ---- Contact form -----------------------------------------------------
   Netlify Forms: no backend, and the POST is handled at the edge. The
   honeypot is a real field hidden from people; bots fill it and get dropped.
   -------------------------------------------------------------------- */
.cform{display:grid;grid-template-columns:1fr 1fr;gap:18px;margin-top:34px}
.cform label{display:grid;gap:8px;font:500 13px/1 var(--fd);color:var(--text-tertiary)}
.cform label.wide{grid-column:1 / -1}
.cform input,.cform textarea,.cform select{
  width:100%;box-sizing:border-box;padding:13px 15px;border-radius:10px;
  border:1px solid var(--line-strong);background:var(--surface-base);
  color:var(--text-primary);font:400 15px/1.45 var(--fb);
}
.cform textarea{min-height:118px;resize:vertical}
.cform input::placeholder,.cform textarea::placeholder{color:var(--text-tertiary)}
.cform input:focus,.cform textarea:focus,.cform select:focus{outline:2px solid var(--accent-core);outline-offset:1px;border-color:transparent}
.cform fieldset{grid-column:1 / -1;margin:0;padding:0;border:0}
.cform legend{padding:0 0 12px;font:500 13px/1 var(--fd);color:var(--text-tertiary)}
.cform .checks{display:flex;flex-wrap:wrap;gap:10px}
/* display:flex, not the grid inherited from .cform label. flex-direction has
   no effect on a grid container, which stacked the box above its wording. */
.cform .checks label{
  display:flex;flex-direction:row;align-items:center;gap:10px;cursor:pointer;
  padding:12px 16px;border-radius:999px;border:1px solid var(--line-strong);
  font:500 14px/1 var(--fb);color:var(--text-secondary);
}
.cform .checks label:hover{border-color:var(--text-tertiary);color:var(--text-primary)}
.cform .checks input{width:16px;height:16px;padding:0;accent-color:var(--accent-core)}
.cform .hp{position:absolute;left:-9999px}
.cform .send{grid-column:1 / -1;display:flex;flex-wrap:wrap;align-items:center;gap:16px}
.cform button{
  padding:15px 26px;border:0;border-radius:999px;cursor:pointer;
  background:var(--text-primary);color:oklch(14% 0.020 280);font:600 14px/1 var(--fd);
}
.cform button:hover{opacity:.9}
.cform .send span{font:400 13px/1.5 var(--fb);color:var(--text-tertiary)}
@media (max-width:640px){.cform{grid-template-columns:1fr}}

/* Centred press row. Same markup, centred where the owner asked for it. */
.seenon--ctr{justify-content:center}

/* A centred block of running copy. text-align stays left because a 60ch
   measure with ragged left edges is measurably harder to read; only the box
   is centred. This is the compromise the owner's "centre the sections" ask
   and readability can both live with. */
.midcol{max-width:76ch;margin-left:auto;margin-right:auto}
.midcol > *{margin-left:auto !important;margin-right:auto !important}

/* A ledger row whose media cell is empty. In production the "Photo needed"
   panels do not render (src/_data/build.js), which would otherwise leave the
   340px image column as a gap. Collapse the row to two columns instead. */
[data-r="ledger"]:not(:has(figure)):not(:has(div[style*="aspect-ratio"])){grid-template-columns:44px 1fr}

/* ---- Landing (the 3D scroll page) ------------------------------------
   A different buyer from the rest of the site: a developer or a fund
   deciding on a $10k+ presentation piece, not a contractor deciding on a
   website. So the page leads with motion and gives each claim room, while
   staying inside the same palette and type scale as everything else.
   -------------------------------------------------------------------- */
.lreel{margin:0;border:1px solid var(--line-media);border-radius:18px;overflow:hidden;background:var(--surface-panel);position:relative}
.lreel video,.lreel img{display:block;width:100%;height:auto}
.lreel figcaption{padding:14px 16px;font:400 13px/1.5 var(--fb);color:var(--text-tertiary);border-top:1px solid var(--line-soft)}

/* Alternating walkthrough: copy one side, a portrait clip the other. */
.lstep{display:grid;grid-template-columns:1fr 380px;gap:clamp(32px,5vw,72px);align-items:center;padding:clamp(44px,6vw,72px) var(--gut);border-bottom:1px solid var(--line-soft)}
.lstep--flip{grid-template-columns:380px 1fr}
.lstep--flip > .lreel{order:-1}
.lstep h3{margin:0;font:600 clamp(1.5rem,3vw,2.25rem)/1.1 var(--fd);letter-spacing:-.022em;color:var(--text-primary);text-wrap:balance}
.lstep .lnum{display:block;font:500 13px/1 var(--fd);color:var(--accent-text);margin-bottom:14px}
.lstep p{margin:16px 0 0;max-width:52ch;font:400 17px/1.7 var(--fb)}
@media (max-width:900px){
  .lstep,.lstep--flip{grid-template-columns:1fr;gap:26px}
  .lstep--flip > .lreel{order:0}
  .lstep > .lreel{max-width:340px}
}

/* The build gallery: portrait clips, three across. */
.lgrid{display:grid;grid-template-columns:repeat(3,1fr);gap:20px;padding:0 var(--gut)}
@media (max-width:900px){.lgrid{grid-template-columns:1fr 1fr;gap:16px}}
@media (max-width:560px){.lgrid{grid-template-columns:1fr}}

/* Who it is for. */
.lwho{display:grid;grid-template-columns:repeat(4,1fr);gap:0;border-top:1px solid var(--line-strong);border-bottom:1px solid var(--line-strong)}
.lwho > div{padding:22px 20px;border-right:1px solid var(--line-soft)}
.lwho > div:last-child{border-right:0}
.lwho b{display:block;font:600 16px/1.3 var(--fd);color:var(--text-primary)}
.lwho span{display:block;margin-top:8px;font:400 14px/1.55 var(--fb);color:var(--text-tertiary)}
@media (max-width:900px){
  .lwho{grid-template-columns:1fr 1fr}
  .lwho > div:nth-child(2n){border-right:0}
  .lwho > div{border-bottom:1px solid var(--line-soft)}
}
@media (max-width:520px){.lwho{grid-template-columns:1fr}.lwho > div{border-right:0}}

/* The funnel. */
.lfunnel{display:grid;gap:0;margin-top:32px;border-top:2px solid var(--line-strong)}
.lfunnel > div{display:grid;grid-template-columns:110px 1fr;gap:24px;padding:20px 0;border-bottom:1px solid var(--line-soft);align-items:baseline}
.lfunnel b{font:500 13px/1.4 var(--fd);color:var(--accent-text)}
.lfunnel p{margin:0;font:400 16px/1.65 var(--fb)}
@media (max-width:640px){.lfunnel > div{grid-template-columns:1fr;gap:6px}}

/* An authored image can carry any intrinsic width. Cap it so a wide one
   can never blow out its grid track again. */
[data-post-body] img{max-width:100%;height:auto}
[data-post-body] pre,[data-post-body] table{max-width:100%;overflow-x:auto}
