
/* ================================================================ JC BUILDINGS (rebuilt 2026-10-16 b)
   Design layer for the one-page kind. onepage_patterns.py emits the classes; this
   decides what they look like. Rewritten per client.
   ============================================================================ */
@font-face{font-family:"Fraunces";src:url(fonts/fraunces-normal.woff2) format("woff2");
 font-weight:300 900;font-style:normal;font-display:swap}
@font-face{font-family:"Fraunces";src:url(fonts/fraunces-italic.woff2) format("woff2");
 font-weight:300 900;font-style:italic;font-display:swap}
@font-face{font-family:"Source Sans 3";src:url(fonts/sourcesans3-normal.woff2) format("woff2");
 font-weight:200 900;font-style:normal;font-display:swap}
@font-face{font-family:"Source Sans 3";src:url(fonts/sourcesans3-italic.woff2) format("woff2");
 font-weight:200 900;font-style:italic;font-display:swap}
/* Georgia sized to Fraunces' metrics (2026-10-18): while the woff2 is still loading the fallback
   holds the same line breaks, so the swap does not reflow the hero (widths/ascent measured
   from fraunces-normal.woff2 vs georgia.ttf) */
@font-face{font-family:"Fraunces Fallback";src:local("Georgia");size-adjust:115.8%;
 ascent-override:84.5%;descent-override:22%;line-gap-override:0%}

:root{
  --paper:#f6f5f2;  --paper2:#ebe9e4;  --ink:#23252a;  --ink2:#5c6068;  --line:#d9d7d1;
  /* HIS COLOURS (2026-09-18, round 1: "Custom (accent #00b4df on #f6f5f2)"). The paper is
     the one it always was; the accent is his. #00b4df is 2.24:1 on that paper, so it is a
     SURFACE colour only - a filled button, the call bar, a bar, a mark - and the text that
     sits on it is --ink (6.28:1), never white (2.44:1). Everywhere the accent is a WORD or
     a HAIRLINE it is --accent-ink: the same hue scaled to 0.635, which reads 5.07:1 on the
     paper and 4.56:1 on the band. --accent-d is the darkest shade of the hue that still
     carries --ink, so a hover reads as a change (4.54:1).
     All three come from library/parts/accent_ink.py - never picked by eye. */
  --accent:#00b4df; --accent-d:#0098bc; --accent-ink:#00728e; --rad:10px; --wrap:1180px;
  --card:#fff; --ftr:var(--ink); --ftr-tx:#c9cbd0;
  /* sticky call bar (2026-09-15, Victor: "the buttons are huge on the preview") - one set of
     tokens, stepped down by viewport HEIGHT so the bar stays compact in the short dashboard
     iframe and never grows past this size anywhere. */
  --cb-fs:14.5px; --cb-pad:11px; --cb-min:42px; --cb-gap:8px; --cb-bar:8px; --cb-room:58px;
  /* header (2026-09-15, Victor: "shrink the header a bit too, like the bottom buttons") -
     same idea as the call bar: one token set, a notch smaller than before at phone size and
     stepped down by viewport HEIGHT for the dashboard's short preview iframe. The hero's top
     room rides the same tokens so nothing ever tucks under the bar. Never larger than this. */
  --hd-min:58px; --hd-fs:20px; --hd-mark:26px; --hd-gap:18px; --hd-nav:14.5px;
  --hd-bpad:10px; --hd-ctapad:10px; --hd-telpad:10px; --hd-top:48px; --hd-topm:26px;
  --serif:"Fraunces","Fraunces Fallback",Georgia,"Times New Roman",serif;
  --sans:"Source Sans 3",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Arial,sans-serif;
}
*{box-sizing:border-box}
html{-webkit-text-size-adjust:100%;scroll-behavior:smooth;scroll-padding-top:calc(var(--hd-min) + 14px);overflow-x:clip}
@media (prefers-reduced-motion:reduce){html{scroll-behavior:auto}}
body{margin:0;background:var(--paper);color:var(--ink);font:400 17.5px/1.6 var(--sans);
 overflow-x:clip}
/* room for the sticky call bar - phones only, where the bar shows (Victor 2026-09-14: "do we
   purposely have space after the footer?") */
@media (max-width:760px){body{padding-bottom:var(--cb-room)}}
/* short viewports (his dashboard shows this page in an iframe as little as ~140-450px tall):
   the bar shrinks with the room it has instead of covering the page */
@media (max-height:560px){
  :root{--cb-fs:13.5px; --cb-pad:8px; --cb-min:38px; --cb-gap:6px; --cb-bar:6px; --cb-room:50px;
   --hd-min:48px; --hd-fs:18px; --hd-mark:22px; --hd-gap:14px; --hd-nav:14px;
   --hd-bpad:7px; --hd-ctapad:7px; --hd-telpad:7px; --hd-top:32px; --hd-topm:18px}
}
@media (max-height:380px){
  :root{--cb-fs:12.5px; --cb-pad:6px; --cb-min:34px; --cb-gap:4px; --cb-bar:4px; --cb-room:44px;
   --hd-min:42px; --hd-fs:16.5px; --hd-mark:19px; --hd-gap:12px; --hd-nav:13.5px;
   --hd-bpad:5px; --hd-ctapad:5px; --hd-telpad:6px; --hd-top:22px; --hd-topm:12px}
}
img{max-width:100%;height:auto;display:block}
a{color:var(--accent-ink)}
h1,h2,h3,h4{font-family:var(--serif);font-weight:500;letter-spacing:-.01em;margin:0;
 text-wrap:balance;font-variation-settings:"SOFT" 30,"WONK" 0}
.wrap{width:100%;max-width:var(--wrap);margin:0 auto;padding:0 20px}
.skip{position:absolute;left:-9999px}
.skip:focus{left:8px;top:8px;background:var(--accent);color:var(--ink);padding:10px 14px;
 border-radius:8px;z-index:200}
.btn{display:inline-block;text-decoration:none;font-weight:600;font-size:16.5px;
 padding:13px 22px;border-radius:99px;border:1.5px solid transparent;cursor:pointer;
 font-family:var(--sans);line-height:1.2}
.btn:active{transform:translateY(1px)}
/* HIS ACCENT CARRIES INK, NOT WHITE (2026-09-18): white on #00b4df is 2.44:1. The filled
   button keeps his colour and takes the page's own ink at 6.28:1; the hover shade is the
   darkest the hue goes while ink still passes (4.54:1). */
.btn-a{background:var(--accent);color:var(--ink)}
.btn-a:hover{background:var(--accent-d)}
.btn-b{background:transparent;color:var(--ink);border-color:var(--ink)}
.btn-b:hover{background:var(--paper2)}

/* ---------- header ---------- */
.hdr{position:sticky;top:0;z-index:100;background:color-mix(in srgb,var(--paper) 92%,transparent);
 backdrop-filter:saturate(160%) blur(10px);border-bottom:1px solid var(--line)}
.hdr-in{display:flex;align-items:center;gap:var(--hd-gap);min-height:var(--hd-min)}
.brand{font-family:var(--serif);font-weight:600;font-size:var(--hd-fs);letter-spacing:.01em;
 text-decoration:none;color:var(--ink);white-space:nowrap;font-variation-settings:"SOFT" 60;
 display:inline-flex;align-items:center;gap:10px}
.brand .mark{width:var(--hd-mark);height:auto;color:var(--accent);flex:0 0 auto}
.nav{margin-left:auto;display:flex;align-items:center;gap:20px}
.nav a{font-size:var(--hd-nav);font-weight:600;text-decoration:none;color:var(--ink2);padding:6px 0;
 border-bottom:2px solid transparent}
.nav a:hover{color:var(--ink)}
.nav a.on{color:var(--ink);border-bottom-color:var(--accent-ink)}
.hdr-tel{color:var(--ink)!important;font-variant-numeric:tabular-nums;padding:var(--hd-telpad) 0!important}   /* a 44px thumb target (2026-09-15) */
.hdr-cta{padding:var(--hd-ctapad) 18px!important;font-size:var(--hd-nav)!important;color:var(--ink)!important;
 border-bottom:0!important}
.burger{display:none;margin-left:auto;background:none;border:0;padding:var(--hd-bpad);cursor:pointer}
.burger span{display:block;width:24px;height:2px;background:var(--ink);margin:5px 0}

/* ---------- hero: words left, one framed photo right ---------- */
.shero{padding:var(--hd-top) 0 30px;container-type:inline-size;overflow:hidden}
.shero-in{display:grid;grid-template-columns:repeat(12,1fr);gap:28px;align-items:center}
.shero-tx{grid-column:span 5}
.shero-ph{grid-column:span 7;margin:0;position:relative}
.shero-ph img{border-radius:var(--rad);aspect-ratio:4/3;object-fit:cover;width:100%;
 position:relative;z-index:1}
.shero-ph::after{content:"";position:absolute;inset:24px -24px -24px 24px;background:var(--paper2);
 border-radius:var(--rad);z-index:0}
.kicker{display:inline-block;font-size:12.5px;font-weight:700;letter-spacing:.18em;
 text-transform:uppercase;color:var(--accent-ink);margin-bottom:16px}
.shero h1{font-size:clamp(40px,6.4vw,78px);line-height:1.02;max-width:14ch;
 font-variation-settings:"opsz" 144,"SOFT" 30}
.shero-sub{margin:20px 0 26px;font-size:clamp(18px,1.6vw,21px);color:var(--ink2);max-width:42ch}
.shero-act{display:flex;align-items:center;gap:16px;flex-wrap:wrap}
.or{color:var(--ink2);font-size:16px}
.or a{color:var(--ink);font-weight:600;text-decoration:none;border-bottom:1.5px solid var(--accent-ink);display:inline-block;padding:9px 0}   /* thumb target */
@container (max-width:760px){
  .shero-tx,.shero-ph{grid-column:span 12}
  .shero-ph{order:-1;margin:0 14px 18px 0}
  .shero-ph::after{inset:14px -14px -14px 14px}
}

/* ---------- sections ---------- */
.sec{padding:64px 0}
.sec h2{font-size:clamp(30px,4.4vw,54px);margin-bottom:10px;font-variation-settings:"opsz" 96,"SOFT" 30}
.dek{margin:0 0 30px;font-size:19px;color:var(--ink2);max-width:60ch}
.sec h2+ .wcards,.sec h2+ .wall,.sec h2+ .steps,.sec h2+ .prose,.sec h2+ .cgrid{margin-top:30px}
.band{background:var(--paper2)}
.tight{padding:34px 0}
.prose p{font-size:19.5px;max-width:58ch;margin:0 0 16px;color:var(--ink)}

/* what I build - cards on a 12-track flow */
.wcards{display:grid;grid-template-columns:repeat(12,1fr);gap:22px;container-type:inline-size}
/* NO CARD CHROME (design pass 2026-09-13, Victor: "modern"): the boxes-with-borders look
   is the template tell. A hairline on top, the photo bare, the title big, space does the
   rest - the Bar Mordecai / Firebrand move from the reference set. */
.wcard{grid-column:span 4;text-decoration:none;color:inherit;display:flex;flex-direction:column;
 border-top:1.5px solid var(--ink);padding-top:16px}
.wcard img{aspect-ratio:3/2;object-fit:cover;width:100%;border-radius:var(--rad);margin-bottom:16px}
.wcard h3{font-size:clamp(24px,2.4vw,30px);padding:0}
.wcard p{margin:6px 0 0;color:var(--ink2);font-size:16.5px;max-width:34ch}
.wcard:hover h3{color:var(--accent-ink)}
/* they are LINKS (round 5): the arrow says so without a box around it */
.wcard h3::after{content:"\2192";color:var(--accent-ink);display:inline-block;margin-left:10px;transition:transform .2s ease}
.wcard:hover h3::after{transform:translateX(4px)}
.wcard:active{background:var(--paper2)}
.wcard img{transition:transform .3s ease}
.wcard:hover img{transform:scale(1.02)}
.wcards .wcard:nth-child(4),.wcards .wcard:nth-child(5){grid-column:span 6;flex-direction:row;
 align-items:baseline;gap:14px;padding-top:14px;border-top-width:1px;border-top-color:var(--line)}
.wcards .wcard:nth-child(4) h3,.wcards .wcard:nth-child(5) h3{white-space:nowrap;font-size:24px}
.wcards .wcard:nth-child(4) p,.wcards .wcard:nth-child(5) p{margin:0;max-width:none}
@media (max-width:1000px){.wcard{grid-column:span 6}}
@media (max-width:640px){
  /* ON A PHONE THE CARDS ARE A LIST (2026-09-13): three stacked photos here duplicated the
     wall right under them - two screens before the work. Title + one line; the wall is
     the photo moment. */
  .wcards{gap:0}
  .wcard{padding:14px 28px 14px 0;border-top:1px solid var(--line);position:relative}
  .wcard h3::after{position:absolute;right:2px;top:14px}
  .wcard:first-child{border-top:1.5px solid var(--ink)}
  .wcard img{display:none}
  .wcard h3{font-size:24px}
  .wcard p{margin-top:4px}
  .wcard,.wcards .wcard:nth-child(4),.wcards .wcard:nth-child(5){grid-column:span 12}
  .wcards .wcard:nth-child(4),.wcards .wcard:nth-child(5){flex-direction:column;align-items:stretch;gap:4px}
}

/* the wall: 12 tracks, landscape 8 @ 3:2, portrait 4 @ 3:4 - same height, no notch */
.wall,.jgrid{display:grid;grid-template-columns:repeat(12,1fr);grid-auto-flow:dense;gap:16px;
 container-type:inline-size}
/* NO IMAGE TOO BIG (Victor 2026-09-13): landscape = half width @ 3:2, portrait = a quarter
   @ 3:4 - both four tracks tall, so rows stay flush and nothing runs edge to edge. */
.tile{margin:0;grid-column:span 6;position:relative}
.tile.tall{grid-column:span 3}
.tile-b{display:block;width:100%;padding:0;border:0;background:var(--paper2);border-radius:var(--rad);
 overflow:hidden;cursor:zoom-in}
.tile-b img{width:100%;aspect-ratio:3/2;object-fit:cover}
.tile.tall .tile-b img{aspect-ratio:3/4}
.tile figcaption{font-size:14.5px;color:var(--ink2);padding:8px 2px 0}
.tile figcaption:empty:not([contenteditable]){display:none}   /* captions off (2026-10-15): an empty caption is no band, not even on hover */
.crew{font-style:italic;color:var(--ink2)}
.crew::before{content:"\00b7\00a0"}
.wall[data-filter="building"] .tile:not([data-k="building"]),
.wall[data-filter="shed"] .tile:not([data-k="shed"]),
.wall[data-filter="barn"] .tile:not([data-k="barn"]),
.wall[data-filter="garage"] .tile:not([data-k="garage"]){display:none}
@media (min-width:701px){.wall,.jgrid{gap:10px}}
@container (max-width:700px){
  .tile{grid-column:span 12}
  .tile.tall{grid-column:span 6}
  .tile-b img{aspect-ratio:3/2}
  .tile.tall .tile-b img{aspect-ratio:3/4}
}
/* the jobs page: a "Going up" strip, then three level three-up card grids */
.jump{margin:0 0 34px}
.jump .chip{text-decoration:none}
.jstrip{margin:0 0 54px}
.strip{display:grid;grid-auto-flow:column;grid-auto-columns:clamp(170px,19vw,230px);gap:14px;overflow-x:auto;
 scroll-snap-type:x mandatory;padding:2px 2px 10px;-webkit-overflow-scrolling:touch;scrollbar-width:thin}
.strip .tile{margin:0;scroll-snap-align:start}
.strip .tile-b{display:block;width:100%;padding:0;border:0;background:var(--paper2);border-radius:var(--rad);
 overflow:hidden;cursor:zoom-in}
.strip .tile-b img{width:100%;aspect-ratio:3/4;object-fit:cover}
.strip figcaption{font-size:13.5px;color:var(--ink2);padding:8px 2px 0}
.jcat{margin:0 0 60px;scroll-margin-top:84px}
.jcat-h{display:flex;align-items:baseline;justify-content:space-between;gap:20px;flex-wrap:wrap;
 padding-top:26px;border-top:2px solid var(--ink);margin:0 0 22px}
.jcat h2{font-size:clamp(28px,3.6vw,44px);margin:0}
.jcat .dek{margin:0;font-size:16.5px;max-width:44ch}
.jcards{display:grid;grid-template-columns:repeat(12,1fr);gap:22px}
.jcard{grid-column:span 4;min-width:0;background:var(--card);border:1px solid var(--line);border-radius:14px;
 overflow:hidden;display:flex;flex-direction:column;transition:transform .2s ease,box-shadow .2s ease}
.jcard:hover{transform:translateY(-2px);box-shadow:0 18px 40px -24px rgba(0,0,0,.35)}
.jc-cover{position:relative}
.jc-cover .tile-b{display:block;width:100%;padding:0;border:0;background:var(--paper2);cursor:zoom-in}
.jc-cover .tile-b img{width:100%;aspect-ratio:4/3;object-fit:cover;display:block}
.jc-n{position:absolute;right:10px;bottom:10px;font:600 12.5px/1 var(--sans);padding:6px 10px;border-radius:999px;
 color:#fff;background:rgba(20,22,26,.62);backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);pointer-events:none}
.jc-th{display:grid;grid-template-columns:repeat(6,1fr);gap:4px;padding:4px 4px 0}
.jc-th .tile-b{display:block;padding:0;border:0;background:var(--paper2);border-radius:6px;overflow:hidden;cursor:zoom-in}
.jc-th .tile-b img{width:100%;aspect-ratio:1;object-fit:cover;display:block}
.jc-t{padding:14px 16px 16px;display:flex;align-items:baseline;gap:10px;flex-wrap:wrap}
.jc-t h3{font-size:20px;margin:0}
.jc-t .crew{font-size:14px}
.jc-t .crew::before{content:""}
@media (max-width:1000px){.jcard{grid-column:span 6}}
@media (max-width:600px){.jcards{gap:16px}.jcard{grid-column:span 12}.jc-th{grid-template-columns:repeat(6,1fr)}}
/* FILM CARDS (2026-10-16, Victor: the sub photos "don't even feel like a button"): a multi-photo
   card is a gallery in place - tap the photo, the count pill or a tile and the main photo swaps
   (JS: "gallery cards"). One-photo cards keep the plain cover above. */
.jc-main{display:block;width:100%;padding:0;border:0;background:var(--paper2);cursor:pointer;touch-action:pan-y;user-select:none;-webkit-user-select:none}
.jc-main picture{display:block}
.jc-main img{width:100%;aspect-ratio:4/3;object-fit:cover;display:block;transition:opacity .15s ease}
.jc-nb{position:absolute;right:10px;bottom:10px;display:inline-flex;align-items:center;gap:6px;
 font:600 13px/1 var(--sans);padding:9px 12px 9px 10px;border-radius:999px;color:#fff;cursor:pointer;
 background:rgba(0,0,0,.6);border:1px solid rgba(255,255,255,.3);box-shadow:0 4px 14px -2px rgba(0,0,0,.35);
 backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);transition:background .15s ease,border-color .15s ease}
.jc-nb:hover{background:rgba(48,50,56,.78);border-color:rgba(255,255,255,.7)}
.jc-nb svg{width:14px;height:14px;flex:none}
.jc-fs{display:flex;flex-wrap:nowrap;gap:8px;padding:12px;overflow-x:auto;position:relative;
 scrollbar-width:thin;-webkit-overflow-scrolling:touch}
.jc-f{flex:0 0 56px;width:56px;height:56px;padding:0;border:1px solid var(--line);border-radius:6px;overflow:hidden;
 background:var(--paper2);cursor:pointer;opacity:.7;transition:opacity .15s ease,box-shadow .15s ease}
.jc-f:hover,.jc-f:focus-visible{opacity:1}
.jc-f.on{opacity:1;border-color:var(--accent);box-shadow:0 0 0 2px var(--accent)}
.jc-f picture{display:block;width:100%;height:100%}
.jc-f img{width:100%;height:100%;object-fit:cover;display:block}
.jc-fs+.jc-t{padding-top:2px}
.job-h{display:flex;align-items:baseline;gap:12px;flex-wrap:wrap;margin:0 0 12px}
.job-h h3{font-size:clamp(20px,2.3vw,26px)}
.job-l{margin:0;color:var(--ink2);font-size:16px;flex-basis:100%}
.more{margin:30px 0 0}

/* filter chips (wall + the form) */
.chips{display:flex;flex-wrap:wrap;gap:8px;margin:0 0 22px}
.chip{font:600 15px/1 var(--sans);padding:10px 15px;border-radius:99px;border:1.5px solid var(--line);
 background:var(--card);color:var(--ink2);cursor:pointer}
.chip:hover{border-color:var(--ink2)}
.chip.on{background:var(--ink);color:#fff;border-color:var(--ink)}

/* the close on the extra pages: the way back to the estimate */
.close{padding:40px 0 56px;border-top:1px solid var(--line)}
.close h2{font-size:clamp(26px,3.6vw,40px);margin-bottom:18px}

/* the reviews page's three-photo peek under the ask (no review yet) */
.peek{margin:44px 0 0}
.peek .tile{grid-column:span 4}
@media (max-width:700px){.peek .tile{grid-column:span 12}}

/* steps */
.steps{list-style:none;margin:0;padding:0;display:grid;
 grid-template-columns:repeat(12,1fr);gap:22px}
/* NO COUNTERS (Victor 2026-09-13: "numbers everywhere are weird") - the order is the order */
.steps li{grid-column:span 4;padding:18px 0 0;border-top:1px solid var(--line)}   /* three steps, three columns */
.steps h4{font-size:20px;margin-bottom:6px}
.steps p{margin:0;color:var(--ink2);font-size:16px}
@media (max-width:900px){.steps li{grid-column:span 6}}
@media (max-width:520px){.steps{gap:14px}.steps li{grid-column:span 6;padding-top:12px}
 .steps h4{font-size:18px}.steps p{font-size:15px}}

/* quote */
.bigq{margin:0;max-width:30ch}
.bigq p{font-family:var(--serif);font-style:italic;font-size:clamp(26px,3.6vw,40px);line-height:1.2;margin:0 0 14px}
.bigq cite{font-style:normal;color:var(--ink2);font-size:16px}

/* reviews page: quotes above, the ask below */
.revs{display:grid;gap:34px;margin-bottom:44px}
.ask{background:var(--card);border:1px solid var(--line);border-radius:var(--rad);padding:28px 24px;max-width:640px}
.ask h3{font-size:30px;margin-bottom:8px}
.ask p{margin:0 0 18px;color:var(--ink2);font-size:18px}
.ask-act{display:flex;gap:12px;flex-wrap:wrap;margin:0!important}

/* two columns */
.twocol{display:grid;grid-template-columns:7fr 5fr;gap:34px}
.twocol h3{font-size:26px;margin-bottom:8px}
.twocol p{margin:0;font-size:18px;color:var(--ink);max-width:44ch}
@media (max-width:640px){.twocol{grid-template-columns:1fr}}

/* contact */
.cgrid{display:grid;grid-template-columns:7fr 5fr;gap:40px;align-items:start}
.cside .big{margin:0 0 8px}
.cside .big a{font-family:var(--serif);font-size:clamp(28px,3.4vw,40px);text-decoration:none;color:var(--ink);
 font-variant-numeric:tabular-nums}
.cside p{color:var(--ink2);margin:0}
@media (max-width:820px){.cgrid{grid-template-columns:1fr}.cside{order:-1}}
.lform{background:var(--card);border:1px solid var(--line);border-radius:var(--rad);padding:26px 22px 22px}
.fq{margin-bottom:18px}
.fq label,.fq .fl{display:block;font-weight:600;font-size:15.5px;margin-bottom:6px}
.fq small{font-weight:400;color:var(--ink2)}
.fh{display:block;font-size:14px;color:var(--ink2);margin:-4px 0 8px}
.fq input,.fq textarea{width:100%;font:inherit;padding:12px 13px;border:1.5px solid var(--line);
 border-radius:8px;background:var(--paper)}
.fq input:focus,.fq textarea:focus{outline:2px solid var(--accent-ink);border-color:transparent}
.fchips{margin:2px 0 4px}
.lform .btn{width:100%;text-align:center;font-size:17px;padding:15px 22px}
.fnote{margin:12px 0 0;font-size:14.5px;color:var(--ink2);text-align:center}
.fok{margin:14px 0 0;font-weight:600;color:var(--accent-ink);text-align:center;font-size:18px}
.ferr{margin:12px 0 0;color:#8a2a1f;text-align:center}
.fsms{margin:16px 0 0;color:var(--ink2);font-size:16px}
.fsms a{font-weight:600}
.lform.sent .fq,.lform.sent .btn,.lform.sent .fnote{display:none}

/* footer */
.ftr{background:var(--ftr);color:var(--ftr-tx);margin-top:30px;padding:44px 0 0}
.ftr-in{display:flex;justify-content:space-between;gap:30px;flex-wrap:wrap;padding-bottom:30px}
.ftr-brand b{display:block;color:#fff;font-family:var(--serif);font-size:24px;margin-bottom:6px;font-weight:500}
.ftr-brand span,.ftr-fx span,.ftr-fx a{display:block;font-size:15.5px;margin-bottom:3px}
.ftr-fx a{color:#fff;text-decoration:none;font-weight:600}
/* the profile link (BUSINESS["socials"]) is a PILL - glyph + handle - drawn by the factory's
   SOC_CSS (2026-09-18, Victor: "make the Instagram link at the bottom fancier looking").
   Here only the knobs: on this dark footer ground (#23252a) the glyph takes --accent
   #00b4df at 6.4:1, NOT --accent-ink, which is the paper-side hue and reads 1.9:1 here. */
.ftr-fx{--soc-accent:var(--accent)}
.ftr-legal{display:flex;justify-content:space-between;gap:16px;flex-wrap:wrap;font-size:13.5px;
 color:#8f929a;border-top:1px solid #3a3d44;padding-top:16px;padding-bottom:18px}

/* sticky call bar (phones) */
.callbar{position:fixed;left:0;right:0;bottom:0;z-index:110;display:none;background:var(--card);
 border-top:1px solid var(--line);
 padding:var(--cb-bar) 10px calc(var(--cb-bar) + env(safe-area-inset-bottom));gap:var(--cb-gap)}
.cb{flex:1;text-align:center;text-decoration:none;font-weight:700;font-size:var(--cb-fs);
 line-height:1.25;padding:var(--cb-pad) 6px;min-height:var(--cb-min);
 display:flex;align-items:center;justify-content:center;border-radius:10px}
.cb-a{background:var(--ftr);color:#fff}
.cb-b{background:var(--paper2);color:var(--ink)}
.cb-c{background:var(--accent);color:var(--ink);flex:1.4}

/* lightbox */
.lb{position:fixed;inset:0;z-index:300;background:rgba(20,22,26,.94);display:flex;align-items:center;
 justify-content:center}
.lb[hidden]{display:none}
.lb figure{margin:0;max-width:min(96vw,1400px);max-height:92vh;display:flex;flex-direction:column;align-items:center}
.lb img{max-width:96vw;max-height:84vh;width:auto;height:auto;border-radius:6px}
.lb figcaption{color:#e6e7ea;margin-top:12px;font-size:16px;text-align:center}
.lb button{position:absolute;background:rgba(255,255,255,.12);color:#fff;border:0;font-size:34px;
 width:52px;height:52px;border-radius:50%;cursor:pointer;line-height:1}
.lb button:hover{background:rgba(255,255,255,.24)}
.lb-x{top:14px;right:14px}
.lb-p{left:10px;top:50%;transform:translateY(-50%)}
.lb-n{right:10px;top:50%;transform:translateY(-50%)}

/* ============================ THE EDITORIAL LOOK (?look=editorial, round 3) ==============
   Everything in this block is gated on body.look-editorial. Without the param the site is
   byte-for-byte the clean look. Glass only ever sits over a PHOTO (the hero, the lightbox,
   the call bar over scrolling content) - on flat ground it is just a lighter box. */
.shero.v2{display:none}
.look-editorial .shero.v1{display:none}
.look-editorial .shero.v2{display:flex;position:relative;min-height:min(86vh,760px);align-items:flex-end;
 padding:0 0 48px;overflow:hidden;background:#2b2f33 linear-gradient(180deg,#3a3f43 0%,#2b2f33 55%,#212427 100%)}
.shero-bg{position:absolute;inset:0;margin:0}
.shero-bg img{width:100%;height:100%;object-fit:cover;display:block;transition:opacity .5s ease}
/* site.js sets .hero-wait only while the hero photo is still downloading (no JS = no fade) */
.hero-wait .shero-bg img{opacity:0}
.shero-bg::after{content:"";position:absolute;inset:0;
 background:linear-gradient(180deg,rgba(20,22,26,0) 40%,rgba(20,22,26,.55) 100%)}
.shero-bg::before{content:"";position:absolute;inset:0;z-index:1;pointer-events:none;opacity:.5;
 mix-blend-mode:soft-light;background:url(data:image/png;base64,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) repeat}
.shero.v2 .wrap{position:relative;z-index:2}
/* the card is a rounded cream panel even before (or without) the blur - never a black slab
   while a busy PC is still compositing (2026-10-18) */
.glass{background:rgba(246,245,242,.88);border:1px solid rgba(255,255,255,.5);
 border:1px solid color-mix(in srgb,#fff 50%,transparent);border-radius:16px;overflow:hidden;
 isolation:isolate;will-change:transform}
@supports ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
 .glass{background:color-mix(in srgb,var(--paper) 62%,transparent);backdrop-filter:blur(20px) saturate(160%);
  -webkit-backdrop-filter:blur(20px) saturate(160%)}
}
.shero-card{max-width:720px;padding:32px 34px 30px}
.shero.v2 h1{font-size:clamp(44px,7vw,92px);line-height:.98;max-width:12ch;letter-spacing:-.02em;
 font-variation-settings:"opsz" 144,"SOFT" 30}
.shero.v2 .shero-sub{margin:16px 0 22px}
.look-editorial .hdr{background:color-mix(in srgb,var(--paper) 60%,transparent);
 backdrop-filter:blur(18px) saturate(160%);-webkit-backdrop-filter:blur(18px) saturate(160%)}
.look-editorial .lb figcaption{background:rgba(20,22,26,.55);backdrop-filter:blur(12px);
 -webkit-backdrop-filter:blur(12px);padding:10px 18px;border-radius:10px}
.look-editorial .callbar{background:color-mix(in srgb,var(--card) 70%,transparent);
 backdrop-filter:blur(16px) saturate(160%);-webkit-backdrop-filter:blur(16px) saturate(160%)}
.look-editorial .kicker::after{content:"";display:inline-block;width:48px;height:1.5px;background:var(--accent-ink);
 vertical-align:middle;margin-left:12px}
.look-editorial .tile-b{box-shadow:inset 0 0 0 1px rgba(0,0,0,.06)}
.look-editorial .tile-b img{position:relative;z-index:0}
@media (hover:hover){
  .look-editorial .tile{overflow:hidden;border-radius:var(--rad)}
  .look-editorial .tile figcaption{position:absolute;left:0;right:0;bottom:0;margin:0;padding:12px 14px;
   color:#fff;background:rgba(20,22,26,.55);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);
   transform:translateY(100%);transition:transform .28s ease;z-index:1}
  .look-editorial .tile figcaption .crew{color:#e6e7ea}
  .look-editorial .tile:hover figcaption,.look-editorial .tile:focus-within figcaption{transform:none}
}
.look-editorial .rv{opacity:0;transform:translateY(12px);transition:opacity .6s ease,transform .6s ease}
.look-editorial .rv.in{opacity:1;transform:none}
@media (prefers-reduced-motion:reduce){.look-editorial .rv{opacity:1;transform:none;transition:none}}
@media (max-width:760px){
  /* PHONE (2026-09-13, Victor: the card sat right on the shed): the photo is the top,
     cropped to the shed (right third of the frame), the card sits below on the page
     ground and tucks up over the photo's bottom edge. The photo is never flipped. */
  .look-editorial .shero.v2{display:block;min-height:auto;padding:0 0 8px;background:var(--paper)}
  /* 2026-09-22 (Victor: "the glass touches the top"): 66vh of photo + a 475px card ran the
     card 100px past the first screen, so reading it meant scrolling its top edge up under the
     glass nav. The photo is now sized off the SMALL viewport (svh, vh fallback) and the whole
     card fits above the call bar; the photo is never shorter than the tuck + 84px, so the
     card's top always clears the nav by that much on any phone height. */
  .shero-bg{position:relative;height:clamp(180px,44vh,420px);height:clamp(180px,44svh,420px)}
  .shero-bg img{object-position:68% 40%}
  .shero-bg::after{background:linear-gradient(180deg,rgba(20,22,26,0) 60%,rgba(20,22,26,.3) 100%)}
  /* the card tucks well up over the photo so the glass has the shed behind it (Victor
     2026-09-14: "mobile doesn't have the see-through glass window like the desktop") */
  .shero.v2 .wrap{margin-top:-96px}
  .shero-card{padding:22px 20px 20px;scroll-margin-top:84px}
  .shero.v2 h1{font-size:clamp(34px,10vw,44px)}
}

/* phones */
@media (max-width:760px){
  .burger{display:block}
  .nav{display:none;position:absolute;top:100%;left:0;right:0;background:var(--paper);
   flex-direction:column;align-items:stretch;gap:0;padding:8px 20px 18px;border-bottom:1px solid var(--line)}
  .nav.open{display:flex}
  .nav a{padding:13px 0;border-bottom:1px solid var(--line)}
  .nav a.on{border-bottom-color:var(--line);color:var(--accent-ink)}
  .hdr-cta{text-align:center;margin:12px 0 0}
  .callbar{display:flex}
  .shero{padding:var(--hd-topm) 0 10px}
  .sec{padding:48px 0}
  .lb-p,.lb-n{display:none}
}

/* ---- the shared focus ring, re-inked (2026-09-18) ------------------------------------
   onepage_patterns.FOCUS_CSS draws every focus ring in var(--accent) and is appended AFTER
   this file on purpose, so a design cannot delete it. His accent is 2.24:1 on the paper -
   below the 3:1 a focus indicator owes - and the ring is the one piece of furniture a
   keyboard reader has. The selector list is the part's own with `html` in front of it, so
   it wins on SPECIFICITY rather than on source order: the ring still comes from the shared
   part, in the readable shade of his own colour. */
html a:focus-visible,html button:focus-visible,html input:focus-visible,
html select:focus-visible,html textarea:focus-visible,html summary:focus-visible,
html [tabindex]:focus-visible{outline-color:var(--accent-ink)}

/* ---- swipe (library/parts/swipe.js, SWIPE=True) ---------------------------------
   The rails, their navigation, and the full-screen viewer. Appended to site.css by
   onepage.py only when the site opts in, so every other site's CSS is byte-for-byte what
   it was. PHONE RAILS (.wall, .jcards) are class-gated AND media-gated - a desktop never
   sees a flex row even for a frame. ALWAYS RAILS (.strip) keep the layout they already
   had; the part only hangs navigation on them. */
.swwrap{position:relative}
/* THE GOING-UP STRIP SIZES ITS OWN FRAMES (2026-09-17). .strip sets grid-auto-columns
   170-230px, but the wall's `.tile{grid-column:span 6}` / `.tile.tall{span 3}` leaked into
   it - the strip has no container-type, so the @container override never applied and every
   frame came out three implicit columns wide: 717px tall on a 390px phone, one frame filling
   the screen. The frames take the columns the strip declares. */
.strip>.tile{grid-column:auto}
.swdots{display:flex;justify-content:center;gap:7px;margin:12px 0 0}
.swdots[hidden]{display:none}
.swdots span{width:7px;height:7px;border-radius:999px;background:var(--line);
 transition:background .18s ease,transform .18s ease}
.swdots span.on{background:var(--accent-ink,var(--accent));transform:scale(1.35)}
/* the arrows appear only on a rail that can actually move (.swnav) - never a control
   that does nothing.
   THE ARROW IS CENTRED ON THE PHOTO, NOT ON THE TILE (2026-09-17, Victor on his phone:
   "the navigation for the work photos at the bottom of the page are over text"). top:50% of
   the wrap is 50% of the tile, caption included - on a short tile that put the disc squarely
   on the caption's first words. swipe.js measures the photo band of the first tile and sets
   --swmid to its middle; the 50% fallback is what a rail with no photo in it gets. */
.swarrow{display:none;position:absolute;top:var(--swmid,50%);transform:translateY(-50%);z-index:3;
 width:44px;height:44px;border-radius:999px;border:1px solid var(--line);cursor:pointer;
 background:rgba(255,255,255,.92);color:#16181c;font:400 28px/1 var(--sans);
 align-items:center;justify-content:center;padding:0 0 3px;
 box-shadow:0 6px 18px -8px rgba(0,0,0,.45);-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px)}
.swwrap.swnav>.swarrow{display:flex}
.swarrow:hover{background:#fff}
.swarrow-p{left:6px}
.swarrow-n{right:6px}
@media (max-width:760px){
  .wall.swrail,.jcards.swrail{display:flex;flex-wrap:nowrap;gap:12px;overflow-x:auto;
   scroll-snap-type:x mandatory;-webkit-overflow-scrolling:touch;scrollbar-width:none;
   padding:2px 0 4px;margin:0;grid-template-columns:none}
  .wall.swrail::-webkit-scrollbar,.jcards.swrail::-webkit-scrollbar{display:none}
  .wall.swrail>.tile,.jcards.swrail>.jcard{flex:0 0 84%;max-width:84%;scroll-snap-align:start;
   grid-column:auto}
  .wall.swrail>.tile.tall{flex:0 0 84%;max-width:84%}
  /* ONE PHOTO HEIGHT PER RAIL (2026-09-17, Victor: "have images aligned so one isn't way
     taller than the one before it"). The wall is built of two crops - landscape tiles at
     3:2 and portrait ones at 3:4 - which tessellate in the desktop grid and then, laid out
     as one flex row, put a 392px photo next to a 196px one. Inside a rail every photo takes
     the wall's own landscape crop, so the row of photos is flush and the flex stretch that
     already made the tile boxes equal now makes the pictures equal too. */
  .wall.swrail>.tile .tile-b img,.wall.swrail>.tile.tall .tile-b img{aspect-ratio:3/2}
  .swarrow{width:40px;height:40px;font-size:25px}
}
/* the swipe nudge's pill - opt-in per rail (data-swhint), built by swipe.js at runtime so
   its one word never lands in the HTML the word and glance gates read. Top right of the
   photo, clear of the arrows' band, and it goes on the first real swipe or after 4s. */
.swhint{position:absolute;top:10px;right:10px;z-index:4;pointer-events:none;
 font:700 12px/1 var(--sans);letter-spacing:.09em;text-transform:uppercase;color:var(--accent-ink,var(--accent));
 background:rgba(255,255,255,.94);border:1px solid var(--line);border-radius:999px;
 padding:7px 11px;white-space:nowrap;box-shadow:0 6px 18px -8px rgba(0,0,0,.45);
 transition:opacity .35s ease}
.swhint-out{opacity:0}
/* the viewer - one per page, built by the part at runtime. The ground is OPAQUE: the page
   behind it must not be readable through the photo (Victor, 2026-09-15). */
.swv{position:fixed;inset:0;z-index:400;background:#0b0b0b;display:flex;
 align-items:center;justify-content:center;padding:18px}
.swv[hidden]{display:none}
.swv-f{margin:0;max-width:min(96vw,1400px);max-height:92vh;display:flex;flex-direction:column;
 align-items:center;touch-action:pan-y;cursor:grab}
.swv-f img{max-width:94vw;max-height:76vh;width:auto;height:auto;object-fit:contain;border-radius:6px;
 -webkit-user-drag:none;user-select:none;pointer-events:none}
.swv-f figcaption{color:#e6e7ea;margin-top:14px;font-size:16px;text-align:center;max-width:44ch}
/* the viewer's controls have to read on a bright photo as well as a dark one: a dark
   translucent disc with a light ring, never a faint white wash */
.swv button{position:absolute;background:rgba(18,18,18,.62);color:#fff;
 border:1px solid rgba(255,255,255,.45);-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);
 line-height:1;width:44px;height:44px;border-radius:999px;cursor:pointer;font-size:30px;
 display:flex;align-items:center;justify-content:center;padding:0 0 3px}
.swv button:hover{background:rgba(18,18,18,.85);border-color:#fff}
.swv-x{top:14px;right:14px;font-size:26px;padding:0}
.swv-p{left:12px;top:50%;transform:translateY(-50%)}
.swv-nx{right:12px;top:50%;transform:translateY(-50%)}
.swv-n{position:absolute;top:22px;left:50%;transform:translateX(-50%);color:#cfd2d7;
 font:600 14px/1 var(--sans);letter-spacing:.04em}
html.swv-lock,body.swv-lock{overflow:hidden;overscroll-behavior:none}
@media (prefers-reduced-motion:no-preference){
  .swv-f.swv-in{animation:swvin .18s ease}
  @keyframes swvin{from{opacity:.4}to{opacity:1}}
}
@media (max-width:760px){.swv{padding:10px}.swv-p{left:6px}.swv-nx{right:6px}}

/* ---- numbered steps (site_data.NUM_STEPS) --------------------------------------------
   Appended to site.css only for a site that asks for them, so nothing else moves a byte.
   The numeral is the size of the words beside it, in the site's own accent, set in the
   display face: a figure you read at arm's length, not a label. On a phone it is one
   column with the numerals in a line down the left and a thread drawn between them, so
   the eye has the order before it reads a word. */
.steps.steps-n{gap:26px}
.steps.steps-n li{display:flex;align-items:flex-start;gap:16px;
 border-top:1px solid var(--line);padding:18px 0 0}
.steps.steps-n .stn{flex:0 0 auto;width:46px;height:46px;border-radius:999px;
 border:1.5px solid var(--accent-ink,var(--accent));color:var(--accent-ink,var(--accent));background:var(--card);
 font:500 23px/1 var(--serif);display:flex;align-items:center;justify-content:center;
 padding-bottom:2px}
.steps.steps-n .stb{min-width:0}
.steps.steps-n h4{margin:0 0 6px;line-height:1.25}
@media (max-width:520px){
  .steps.steps-n{grid-template-columns:1fr;gap:0}
  .steps.steps-n li{grid-column:span 12;border-top:0;padding:0 0 24px;position:relative}
  /* the thread runs from under one numeral to the top of the next - never past the last */
  .steps.steps-n li:not(:last-child)::before{content:"";position:absolute;left:23px;top:50px;
   bottom:2px;width:1.5px;background:var(--line)}
  .steps.steps-n .stn{width:42px;height:42px;font-size:21px;background:var(--paper)}
  .steps.steps-n li:not(:last-child)::before{left:21px}
}

/* ---- the number is tappable (site_data.TEL_CUE) --------------------------------------
   2026-09-17, Victor: "make it slightly more clear that you can click the phone number to
   call or text." Every printed number was already a tel:/sms: link and none of them looked
   like one. So: the accent colour, a real underline held off the baseline, and a handset
   glyph in front of it - the glyph is a MASK over currentColor, so it is the accent beside
   the accent and white in the footer, and it carries no words. Selected by href, so a
   number added anywhere later is styled the day it is printed, and excluded on the three
   places that are already unmistakably buttons: the sticky Call/Text bar (.cb), the header's
   own number (.hdr-tel) and the review page's buttons (.btn).
   The FOOTER keeps its own white: accent teal on the dark footer ground is unreadable. */
a[href^="tel:"]:not(.cb):not(.btn):not(.hdr-tel),
a[href^="sms:"]:not(.cb):not(.btn):not(.hdr-tel){
 text-decoration:underline;text-decoration-thickness:1.5px;text-underline-offset:3px}
.sec a[href^="tel:"]:not(.cb):not(.btn),.sec a[href^="sms:"]:not(.cb):not(.btn),
.hero a[href^="tel:"]:not(.cb):not(.btn),.hero a[href^="sms:"]:not(.cb):not(.btn),
.shero a[href^="tel:"]:not(.cb):not(.btn),.shero a[href^="sms:"]:not(.cb):not(.btn){
 color:var(--accent-ink,var(--accent))}
a[href^="tel:"]:not(.cb):not(.btn):not(.hdr-tel)::before,
a[href^="sms:"]:not(.cb):not(.btn):not(.hdr-tel)::before{
 content:"";display:inline-block;width:.86em;height:.86em;margin-right:.34em;
 vertical-align:-.06em;background:currentColor;
 -webkit-mask:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%3E%3Cpath%20d='M9.4%204H5.6C4.7%204%204%204.7%204%205.6%204%2013.6%2010.4%2020%2018.4%2020c.9%200%201.6-.7%201.6-1.6v-3.8c0-.7-.5-1.3-1.2-1.4l-2.6-.4c-.5-.1-1%20.1-1.4.5l-1.3%201.3c-2-1.2-3.7-2.9-4.9-4.9l1.3-1.3c.4-.4.6-.9.5-1.4l-.4-2.6C10.7%204.5%2010.1%204%209.4%204z'/%3E%3C/svg%3E") center/contain no-repeat;
 mask:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%3E%3Cpath%20d='M9.4%204H5.6C4.7%204%204%204.7%204%205.6%204%2013.6%2010.4%2020%2018.4%2020c.9%200%201.6-.7%201.6-1.6v-3.8c0-.7-.5-1.3-1.2-1.4l-2.6-.4c-.5-.1-1%20.1-1.4.5l-1.3%201.3c-2-1.2-3.7-2.9-4.9-4.9l1.3-1.3c.4-.4.6-.9.5-1.4l-.4-2.6C10.7%204.5%2010.1%204%209.4%204z'/%3E%3C/svg%3E") center/contain no-repeat}
/* the number in the hero is a 9px-padded thumb target with its own accent rule underneath -
   the border-bottom it already wore would read as a second underline */
.or a[href^="sms:"]{border-bottom:0}
/* the one place words are spent (the contact block, under the big number) */
.ctel-cue{margin:0 0 6px;color:var(--ink2);font:600 13px/1.2 var(--sans);
 letter-spacing:.07em;text-transform:uppercase}

/* ---- the footer's profile pill (BUSINESS["socials"]) ---------------------------------
   2026-09-18, Victor: "make the Instagram link at the bottom fancier looking, maybe use the
   actual Instagram logo." Written ONLY into a build whose site_data declares socials, so a
   site without one carries not a byte of this. Deliberately sets no font-size: the design's
   own `.ftr-fx a` size is the footer's text size, and the pill is that size everywhere.
   44px min-height is the phone tap target, and it holds on desktop too - the pill is the
   only tappable word in that column that is not a phone number.
   Knobs a design can set: --soc-accent (the glyph and the hover hairline), --soc-line,
   --soc-bg, --soc-bg-h. The default accent is the site's own, which on a dark footer is
   --accent (the bright surface hue), not --accent-ink (that one is drawn for paper). */
/* 2026-10-20: the pills sit in ONE flex row (.ftr-socs): equal gap, wraps cleanly on a phone,
   every pill the same height and on the same centre line. Loose inline-flex pills were
   baseline-aligned: a pill whose first item is a glyph (display:block svg -> its baseline is
   the glyph's bottom edge) rode ~4.5px higher than a text-only pill beside it. */
.ftr-fx .ftr-socs{display:flex;flex-wrap:wrap;align-items:center;justify-content:flex-start;
 gap:9px;max-width:100%;margin:11px 0 0}
.ftr-fx a.ftr-soc{display:inline-flex;align-items:center;gap:9px;box-sizing:border-box;
 margin:0;padding:10px 14px;min-height:44px;border-radius:999px;vertical-align:middle;
 border:1px solid var(--soc-line,rgba(255,255,255,.26));
 background:var(--soc-bg,rgba(255,255,255,.045));
 text-decoration:none;line-height:1.2;
 transition:border-color .16s ease,background-color .16s ease}
.ftr-fx a.ftr-soc .soc-g{width:1.2em;height:1.2em;flex:0 0 auto;display:block;
 color:var(--soc-accent,var(--accent,currentColor))}
/* a footer design that gives every `.ftr-fx span` a stacking margin would push the handle
   1.5px off the glyph's centre inside the pill - measured, not guessed (2026-09-18) */
.ftr-fx a.ftr-soc .soc-h{display:block;margin:0}
.ftr-fx a.ftr-soc:hover,.ftr-fx a.ftr-soc:focus-visible{
 border-color:var(--soc-accent,var(--accent,currentColor));
 background:var(--soc-bg-h,rgba(255,255,255,.09))}

/* THE HONEYPOT (2026-09-17). A field only a bot fills. It is taken out of the flow rather
   than display:none'd - a field that is display:none is the one pattern the cheap bots have
   learned to skip - and it is out of the tab order, out of the accessibility tree and out of
   the autofill. Nothing here is decoration, so it lives in the factory, not in a design. */
.hp{position:absolute;left:-9999px;top:auto;width:1px;height:1px;overflow:hidden}

/* THE FOCUS RING (2026-09-17, Fable's review: there was no :focus-visible rule anywhere, so
   a keyboard reader got the browser's default ring on a designed page - or, where a design
   had set outline:0 on its inputs, nothing at all). One rule, every interactive thing, the
   site's own accent. :focus-visible, so a mouse click does not draw it.

   NOT written with :where(): a design that says `.lform input:focus{outline:0}` would beat a
   zero-specificity rule and the ring would be gone again. This is appended AFTER design.CSS
   and matches its specificity, so it wins on source order - deliberately. */
a:focus-visible,button:focus-visible,input:focus-visible,select:focus-visible,
textarea:focus-visible,summary:focus-visible,[tabindex]:focus-visible{
 outline:2px solid var(--accent);outline-offset:2px}
.hp input:focus-visible{outline:0}
