/* Odd Job Junky — homepage design system.
   ---------------------------------------------------------------------------
   Selling into towns where the median household income is $150k+, so the page has to
   feel like a company that turns up on time. That means restraint, not decoration:
   generous whitespace, one accent colour, a real type scale, and motion only where it
   earns its place. Every class the quote flow already uses is styled here - the markup
   and the script were not touched, so nothing in the funnel can break from a restyle. */

:root{
  /* Brand. Mirrors brand/assets/tokens.css. */
  --orange:#F26F22; --orange-dk:#D45B12; --orange-soft:#FFF3EB;
  --ink:#161719; --ink-2:#3E4147; --muted:#6B7280;
  --paper:#FAFAF8; --card:#FFFFFF; --line:#E7E9EE; --line-2:#F0F2F5;
  --ok:#12805C; --ok-soft:#F0FBF6; --ok-line:#BFE6D5;
  --warn-soft:#FFF8EC; --warn-line:#F3DCB0;
  --err:#B3261E; --err-soft:#FDF3F2; --err-line:#F2CFCB;

  /* One shadow ramp, used sparingly. Borders do most of the work. */
  --sh-1:0 1px 2px rgba(20,22,26,.04), 0 1px 1px rgba(20,22,26,.03);
  --sh-2:0 4px 16px rgba(20,22,26,.06), 0 1px 2px rgba(20,22,26,.04);
  --sh-3:0 18px 48px rgba(20,22,26,.10), 0 2px 8px rgba(20,22,26,.04);

  --r-sm:10px; --r:14px; --r-lg:20px; --r-xl:28px;
  --wrap:1080px; --narrow:720px;

  /* From the logo. See the note in index.html's head. */
  --f-display:'Roboto Slab',Georgia,serif;
  --f-body:'IBM Plex Sans',ui-sans-serif,system-ui,-apple-system,"Segoe UI",sans-serif;
  --f-mono:'IBM Plex Mono',ui-monospace,SFMono-Regular,monospace;
}

*{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
html,body{margin:0}
body{
  background:var(--paper); color:var(--ink);
  font:17px/1.6 var(--f-body);
  -webkit-font-smoothing:antialiased; text-rendering:optimizeLegibility;
}
/* Anything countable — prices, ZIPs, quantities — in the mono face with
   tabular figures, so digits hold their column as values change. */
.pr,.rng,.box b,.money,input[inputmode="numeric"]{
  font-family:var(--f-mono); font-variant-numeric:tabular-nums;
}
img{max-width:100%}
a{color:var(--orange-dk)}
:focus-visible{outline:2.5px solid var(--orange); outline-offset:2px; border-radius:6px}

h1,h2,h3{font-family:var(--f-display); font-weight:800; letter-spacing:-.024em; line-height:1.1; margin:0}
/* The panel titles inside the quote card carry the display face too, so the
   form reads as part of the same object rather than a bolted-on widget. */
.ttl{font-family:var(--f-display); font-weight:700}
.eyebrow{font-size:13px; font-weight:700; letter-spacing:.09em; text-transform:uppercase;
         color:var(--orange-dk); margin:0 0 14px}

/* ---------------------------------------------------------------- header -- */
header{position:sticky; top:0; z-index:40; background:rgba(250,250,248,.86);
       backdrop-filter:saturate(180%) blur(12px); border-bottom:1px solid var(--line)}
.bar{max-width:var(--wrap); margin:0 auto; padding:13px 22px; display:flex; align-items:center; gap:14px}
.bar img{height:34px; width:auto; display:block}
.bar .ph{margin-left:auto; font-weight:700; color:var(--ink); text-decoration:none;
         white-space:nowrap; font-size:15px; padding:9px 15px; border-radius:999px;
         border:1px solid var(--line); background:var(--card); transition:.16s}
.bar .ph:hover{border-color:var(--orange); color:var(--orange-dk)}
@media(max-width:560px){ .bar{padding:11px 16px} .bar .ph{font-size:14px; padding:8px 13px} }

/* ------------------------------------------------------------------ hero --
   Two columns: copy left, animated scene right. Centred full-width copy pushed
   the quote card an entire screen down, so the first thing a visitor could
   actually DO was invisible on arrival. The scene keeps every pixel of its
   character; it just stops being the only thing above the fold.
   .herowrap is the positioning context for the stamp. */
.herowrap{position:relative; max-width:var(--wrap); margin:0 auto; padding:34px 22px 0;
          display:grid; grid-template-columns:minmax(0,1fr) minmax(0,1.05fr);
          gap:30px; align-items:center}
.hero{position:relative; z-index:1; max-width:none; margin:0; padding:0; text-align:left}
.hero h1{font-size:clamp(30px,3.7vw,46px); margin:0 0 14px}
.hero h1 em{font-style:normal; color:var(--orange-dk)}
.hero p{color:var(--ink-2); font-size:clamp(16px,1.5vw,18px); margin:0; max-width:44ch}
@media(max-width:900px){
  /* Copy, then the quote card, THEN the scene. The animation is character, not
     a gate - it must never push the first action below the fold on a phone.
     display:contents dissolves the wrapper so .hero, .scene and .card become
     siblings in <main> and can be ordered against each other. */
  main{display:flex; flex-direction:column}
  .herowrap{display:contents}
  .hero{order:1; max-width:var(--wrap); margin:0 auto; width:100%; padding:30px 22px 0}
  .card{order:2}
  .scene{order:3}
  /* Everything else has to be ordered too. flex `order` defaults to 0, so the
     content sections below outranked the hero, the quote card and the scene
     and rendered ABOVE them - the page opened on "Why people book us" with no
     way to start a quote. Anything unordered lands after the funnel. */
  main > *:not(.hero):not(.card):not(.scene):not(.stamp){order:4}
}
@media(max-width:560px){ .hero{padding:26px 18px 0} }

/* The animated scene. An <img>-referenced SVG: CSS animation still runs, but it is
   sandboxed from the page and cached on its own, so it cannot slow or break the quote. */
.scene{max-width:none; margin:0; padding:0}
@media(max-width:900px){ .scene{max-width:var(--wrap); margin:22px auto 0; padding:0 22px} }
.scene-in{position:relative; border-radius:var(--r-xl); overflow:hidden;
          background:linear-gradient(180deg,#EAF3FB 0%,#F4F8F1 62%,#EEF4E9 100%);
          border:1px solid var(--line); box-shadow:var(--sh-2)}
.scene-in object{display:block; width:100%; aspect-ratio:1000/520; border:0;
                 /* Decorative: it must never swallow a tap aimed at the quote card. */
                 pointer-events:none}
@media(max-width:560px){ .scene{padding:0 14px} .scene-in{border-radius:var(--r-lg)} }

/* ------------------------------------------------------------- quote card -- */
.card{max-width:var(--narrow); margin:18px auto 0; background:var(--card);
      border:1px solid var(--line); border-radius:var(--r-xl);
      box-shadow:var(--sh-3); overflow:hidden; scroll-margin-top:86px}
@media(max-width:560px){ .card{margin:24px 14px 0; border-radius:var(--r-lg)} }

.steps{display:flex; gap:6px; padding:18px 26px 2px}
.steps i{flex:1; height:4px; border-radius:3px; background:var(--line-2); transition:background .35s}
.steps i.on{background:var(--orange)}

.panel{padding:16px 26px 30px}
.panel[hidden]{display:none}
@media(max-width:560px){ .panel{padding:14px 18px 24px} .steps{padding:16px 18px 2px} }

.qhead{font-size:23px; font-weight:800; letter-spacing:-.02em; margin:8px 0 5px}
.qsub{color:var(--muted); font-size:15px; margin:0 0 20px}

/* option buttons */
.grid{display:grid; grid-template-columns:repeat(auto-fill,minmax(168px,1fr)); gap:11px}
.opt{border:1.5px solid var(--line); background:var(--card); border-radius:var(--r);
     padding:15px 14px; font:inherit; font-weight:600; text-align:left; cursor:pointer;
     color:var(--ink); transition:.15s; box-shadow:var(--sh-1)}
.opt:hover{border-color:#CFD4DC; transform:translateY(-1px); box-shadow:var(--sh-2)}
.opt[aria-pressed="true"]{border-color:var(--orange); background:var(--orange-soft);
                          box-shadow:0 0 0 3px rgba(242,111,34,.12); position:relative}
/* A checkmark on the chosen tile. The copy already says "pick everything you
   need doing - one visit, one price", but a tinted border alone reads as a
   radio button, so people pick one job and move on. That silently caps every
   basket at a single line. The tick is what says "and also". */
.opt[aria-pressed="true"]::after{
  content:"✓"; position:absolute; top:8px; right:9px;
  width:20px; height:20px; border-radius:50%;
  background:var(--orange); color:#fff;
  display:grid; place-items:center; font-size:12px; font-weight:700; line-height:1;
}
/* The parts question and the time windows are genuinely pick-one, so no tick
   there - it would promise multi-select the form does not offer. */
#sup .opt[aria-pressed="true"]::after,
.grid3 .opt[aria-pressed="true"]::after{content:none}
.opt small{display:block; font-weight:400; color:var(--muted); font-size:13px; margin-top:3px; padding-right:16px}

/* fields */
.row{display:flex; gap:14px; flex-wrap:wrap}
.field{flex:1 1 210px; margin:12px 0}
.field label,.lbl{display:block; font-weight:650; font-size:15px; margin-bottom:6px}
input[type=text],input[type=tel],input[type=email],input[type=number],textarea,select{
  font:inherit; width:100%; padding:13px 14px; border:1.5px solid var(--line);
  border-radius:var(--r); background:var(--card); color:var(--ink); transition:.15s}
input:focus,textarea:focus{border-color:var(--orange); outline:none;
  box-shadow:0 0 0 3px rgba(242,111,34,.13)}
textarea{resize:vertical; min-height:96px}
label{font-weight:650; font-size:15px}

/* buttons */
.actions{display:flex; gap:11px; flex-wrap:wrap; margin-top:24px; align-items:center}
.btn{background:var(--orange); color:#fff; border:0; border-radius:var(--r);
     padding:14px 24px; font:inherit; font-weight:700; cursor:pointer;
     text-decoration:none; display:inline-block; transition:.16s; box-shadow:var(--sh-1)}
.btn:hover{background:var(--orange-dk); box-shadow:var(--sh-2)}
.btn:active{transform:translateY(1px)}
.btn[disabled]{opacity:.5; cursor:default; box-shadow:none}
.btn.ghost{background:var(--card); color:var(--ink); border:1.5px solid var(--line)}
.btn.ghost:hover{background:var(--paper); border-color:#CFD4DC}

/* price */
.price{text-align:center; padding:12px 0 4px}
.rng{font-size:clamp(40px,8vw,58px); font-weight:800; letter-spacing:-.035em; line-height:1}
.hi{color:var(--muted); font-size:15px; margin-top:8px}
.split{display:grid; grid-template-columns:1fr 1fr; gap:12px; margin:22px 0 6px}
@media(max-width:520px){ .split{grid-template-columns:1fr} }
.box{border:1px solid var(--line); border-radius:var(--r); padding:15px 16px; background:var(--paper)}
.box .lbl{color:var(--muted); font-size:13px; font-weight:600; margin-bottom:3px}
.box b{font-size:20px; letter-spacing:-.02em}

/* messages */
.note,.fine{color:var(--muted); font-size:14px; line-height:1.55}
.err,.warn{border-radius:var(--r); padding:12px 14px; font-size:15px}
.err{background:var(--err-soft); border:1px solid var(--err-line); color:var(--err)}
.warn{background:var(--warn-soft); border:1px solid var(--warn-line); color:#7A5B18}

/* photos */
.thumbs{display:flex; gap:10px; flex-wrap:wrap; margin-top:12px}
.thumb{position:relative; width:88px; height:88px; border-radius:var(--r-sm); overflow:hidden;
       border:1px solid var(--line); background:var(--paper)}
.thumb img{width:100%; height:100%; object-fit:cover; display:block}
.thumb button{position:absolute; top:4px; right:4px; width:24px; height:24px; border:0;
  border-radius:50%; background:rgba(0,0,0,.62); color:#fff; font-size:15px; line-height:1;
  cursor:pointer; display:grid; place-items:center}

/* consent + confirmation */
.consent{border:1px solid var(--line); border-radius:var(--r); padding:14px 16px 16px;
         margin:22px 0 0; background:var(--paper)}
.consent legend{font-size:13px; color:var(--muted); padding:0 6px; font-weight:600}
.chk{display:flex; gap:11px; align-items:flex-start; margin:10px 0; font-size:14.5px;
     line-height:1.5; cursor:pointer; font-weight:400}
.chk input{margin-top:3px; flex:0 0 auto; width:18px; height:18px; accent-color:var(--orange)}
.okbox{border:1px solid var(--ok-line); background:var(--ok-soft); border-radius:var(--r); margin:16px 0}
.okrow{display:flex; justify-content:space-between; gap:14px; padding:13px 16px;
       border-bottom:1px solid rgba(18,128,92,.13)}
.okrow:last-child{border-bottom:0}
.okrow span{color:var(--muted); font-size:14px}
.okrow strong{text-align:right}

.spin{display:inline-block; width:15px; height:15px; border:2px solid rgba(255,255,255,.4);
      border-top-color:#fff; border-radius:50%; animation:spin .7s linear infinite; vertical-align:-2px}
@keyframes spin{to{transform:rotate(360deg)}}

/* ------------------------------------------------------------- sections --- */
.sec{max-width:var(--wrap); margin:0 auto; padding:64px 22px}
.sec h2{font-size:clamp(25px,3.4vw,34px); margin:0 0 10px}
.sec .lede{color:var(--ink-2); max-width:56ch; margin:0 0 30px; font-size:17px}
@media(max-width:560px){ .sec{padding:46px 18px} }

.trust{display:grid; grid-template-columns:repeat(auto-fit,minmax(226px,1fr)); gap:16px}
.trust div{background:var(--card); border:1px solid var(--line); border-radius:var(--r-lg);
           padding:22px 22px 24px; box-shadow:var(--sh-1)}
.trust b{display:block; font-size:17px; margin-bottom:6px; letter-spacing:-.015em}
.trust p{margin:0; color:var(--muted); font-size:15px; line-height:1.55}

.how{counter-reset:s; display:grid; grid-template-columns:repeat(auto-fit,minmax(250px,1fr)); gap:18px}
.how li{list-style:none; background:var(--card); border:1px solid var(--line);
        border-radius:var(--r-lg); padding:24px 22px; box-shadow:var(--sh-1)}
.how li::before{counter-increment:s; content:counter(s); display:grid; place-items:center;
  width:34px; height:34px; border-radius:50%; background:var(--orange-soft);
  color:var(--orange-dk); font-weight:800; font-size:16px; margin-bottom:13px}
.how b{display:block; margin-bottom:5px; font-size:17px}
.how p{margin:0; color:var(--muted); font-size:15px; line-height:1.55}

.rates{background:var(--card); border:1px solid var(--line); border-radius:var(--r-lg);
       overflow:hidden; box-shadow:var(--sh-1)}
.rates div{display:flex; justify-content:space-between; align-items:baseline; gap:16px;
           padding:15px 20px; border-bottom:1px solid var(--line-2)}
.rates div:last-child{border-bottom:0}
.rates span{font-weight:600}
.rates b{color:var(--orange-dk); white-space:nowrap}
.rates small{display:block; color:var(--muted); font-weight:400; font-size:13.5px; margin-top:2px}

/* ------------------------------------------------------------------ foot -- */
footer{border-top:1px solid var(--line); background:var(--card); margin-top:20px}
.foot{max-width:var(--wrap); margin:0 auto; padding:34px 22px; display:flex;
      flex-wrap:wrap; gap:14px 26px; align-items:center; color:var(--muted); font-size:15px}
.foot a{color:var(--ink); text-decoration:none; font-weight:600}
.foot a:hover{color:var(--orange-dk)}
.foot .sp{margin-left:auto}
/* Second footer row: the big-job pages. Wraps on a phone; each link is a 44px tap target. */
.foot-jobs{padding-top:0; gap:4px 18px; font-size:14px}
.foot-jobs a{font-weight:500}
.foot a{min-height:44px; display:inline-flex; align-items:center}
.bar > a:first-child{display:flex; align-items:center; min-height:44px}
.bar .ph{min-height:44px; display:inline-flex; align-items:center}
/* Big-jobs list on the homepage: the job names are links to their own pages. */
.rates.big span a{display:inline-flex; align-items:center; min-height:44px; color:var(--ink); text-decoration-color:var(--orange); text-decoration-thickness:2px; text-underline-offset:3px}
.rates.big span a:hover{color:var(--orange-dk)}
.rates.big b{font-family:var(--f-body); font-weight:700}

@media (prefers-reduced-motion: reduce){
  *{animation-duration:.001ms!important; animation-iteration-count:1!important;
    transition-duration:.001ms!important; scroll-behavior:auto!important}
}

/* Address typeahead. Positioned inside the field wrapper, above everything in the card. */
.suggest{position:absolute; z-index:30; left:0; right:0; top:calc(100% + 4px);
  margin:0; padding:5px; list-style:none; background:var(--card);
  border:1px solid var(--line); border-radius:var(--r); box-shadow:var(--sh-3); max-height:270px; overflow:auto}
.suggest li{padding:11px 12px; border-radius:var(--r-sm); cursor:pointer; font-size:15px; line-height:1.35}
.suggest li:hover,.suggest li.on{background:var(--orange-soft); color:var(--orange-dk)}
.suggest .vfd{float:right; font-size:11px; font-weight:700; letter-spacing:.05em;
  text-transform:uppercase; color:var(--ok); background:var(--ok-soft);
  border:1px solid var(--ok-line); border-radius:999px; padding:1px 8px; margin-left:8px}

/* Scheduling: a horizontally scrolling day strip, then three time-window tiles. */
.sched{margin:22px 0 4px}
.daystrip{display:flex; gap:8px; overflow-x:auto; padding:2px 2px 8px; scroll-snap-type:x mandatory}
.daystrip::-webkit-scrollbar{height:6px}
.daystrip::-webkit-scrollbar-thumb{background:var(--line); border-radius:3px}
.day{flex:0 0 auto; width:62px; scroll-snap-align:start; border:1.5px solid var(--line);
     background:var(--card); border-radius:var(--r); padding:9px 4px 8px; cursor:pointer;
     font:inherit; text-align:center; transition:.15s; box-shadow:var(--sh-1)}
.day:hover{border-color:#CFD4DC; transform:translateY(-1px)}
.day[aria-pressed="true"]{border-color:var(--orange); background:var(--orange-soft);
                          box-shadow:0 0 0 3px rgba(242,111,34,.12)}
.day .dow{display:block; font-size:12px; color:var(--muted); text-transform:uppercase; letter-spacing:.04em}
.day .num{display:block; font-size:21px; font-weight:800; line-height:1.15; letter-spacing:-.02em}
.day .mon{display:block; font-size:11px; color:var(--muted); text-transform:uppercase}
.day[aria-pressed="true"] .dow,.day[aria-pressed="true"] .mon{color:var(--orange-dk)}
.grid3{display:grid; grid-template-columns:repeat(3,1fr); gap:10px}
@media(max-width:460px){ .grid3{grid-template-columns:1fr} }
/* The catch-all tile reads as an alternative, not another service. */
.opt.other{border-style:dashed; background:var(--paper)}
.opt.other[aria-pressed="true"]{border-style:solid}

/* Labelled stepper. Naming each step is the difference between a progress bar and a map. */
.steps{display:flex;gap:8px;list-style:none;margin:0;padding:18px 26px 4px}
.steps li{flex:1;display:flex;align-items:center;gap:9px;padding:9px 4px 12px;
  border-bottom:3px solid var(--line-2);color:var(--muted);font-size:14.5px;transition:.25s}
.steps .n{flex:0 0 auto;width:25px;height:25px;border-radius:50%;display:grid;place-items:center;
  background:var(--line-2);color:var(--muted);font-weight:800;font-size:13px;transition:.25s}
.steps li.on{border-bottom-color:var(--orange);color:var(--ink);font-weight:650}
.steps li.on .n{background:var(--orange);color:#fff}
.steps li.done{border-bottom-color:#F6C9A6;color:var(--ink-2)}
.steps li.done .n{background:var(--ok);color:#fff;font-size:0}
.steps li.done .n::after{content:"\2713";font-size:14px}
@media(max-width:560px){
  .steps{padding:16px 16px 2px;gap:6px}
  .steps li{font-size:0;gap:0;justify-content:center}
  .steps li.on .t{font-size:13.5px;margin-left:8px}
}

/* ── "We heart odd jobs" rubber stamp ──────────────────────────────────────
   Three things make ink read as stamped rather than printed:
     1. rotation at an odd angle - a real stamp is never square to the page
     2. mix-blend-mode: multiply, so the ink sits IN the paper, not on top
     3. a noise mask, so the ink breaks up the way a rubber die actually does
   The noise is an inline SVG turbulence filter - no image, no extra request,
   and it scales to any size. */
:root{
  --stamp-noise:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='190' height='190'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.68' numOctaves='4'/><feColorMatrix type='matrix' values='0 0 0 0 0, 0 0 0 0 0, 0 0 0 0 0, 0 0 0 -0.5 1.02'/></filter><rect width='190' height='190' filter='url(%23n)'/></svg>");
}
.stamp{
  --ink:#C8322B;              /* stamp-pad red - pure #F00 reads as digital */
  /* Moved out of the text column and turned into a watermark.
     At top:82px right:26px it clipped the headline around 1280px and, on a
     phone, printed on top of the paragraph that explains what we do - and the
     430px breakpoint below used to hide it entirely, losing the one bit of
     character on the smallest screens. Now it sits behind the hero, just left
     of centre, at every size. */
  /* Position chosen by eye, 2026-08-14: dropped 38px so the heart clears the
     headline, and nudged right so WE, the heart and ODD JOBS all sit in open
     space rather than behind type or on top of the truck. */
  position:absolute; top:calc(50% + 38px); left:47%; z-index:2;
  width:275px; height:275px; border-radius:50%;
  border:7px solid currentColor; box-shadow:0 0 0 5px currentColor inset;
  display:grid; place-content:center; text-align:center;
  transform:translate(-50%,-50%) rotate(-9deg); line-height:1.12;
  color:var(--ink); mix-blend-mode:multiply; opacity:.32;
  text-transform:uppercase; letter-spacing:.08em;
  user-select:none; pointer-events:none;
  -webkit-mask-image:var(--stamp-noise); mask-image:var(--stamp-noise);
  -webkit-mask-size:290px 290px; mask-size:290px 290px;
}
.stamp .top,.stamp .bot{font-size:27px;font-weight:900}
.stamp .hrt{font-size:56px;line-height:1;margin:3px 0}
.stamp .rule{height:5px;background:currentColor;margin:10px auto;width:64%}
.stamp i{font-style:normal}

/* Scale it down rather than crowd a phone header, and keep it clear of the card. */
@media(max-width:900px){
  /* .herowrap is display:contents here, so it is no longer a containing block
     and the stamp resolves against <main> - i.e. the whole document. A
     percentage top would land it somewhere down by the price list. Anchor it
     with a fixed offset from the top of main instead, which is the hero. */
  /* Sized and seated to stay inside the copy block. Any lower and it prints
     over the stepper labels, which is the one place on a phone where the
     customer needs to read where they are. */
  .stamp{width:172px;height:172px;top:64px;left:50%;border-width:5px;opacity:.24;
         transform:translate(-50%,0) rotate(-9deg);
         -webkit-mask-size:230px 230px;mask-size:230px 230px}
  .stamp .top,.stamp .bot{font-size:17px} .stamp .hrt{font-size:34px}
  .stamp .rule{height:4px;margin:7px auto}
}
@media(max-width:430px){
  /* Shrinks rather than disappearing - it is the bit of character worth
     keeping on a phone. Lighter, because a narrow column leaves the type
     less room to survive the competition. */
  .stamp{width:146px;height:146px;top:56px;left:50%;border-width:4px;opacity:.22;
         transform:translate(-50%,0) rotate(-9deg);
         -webkit-mask-size:190px 190px;mask-size:190px 190px}
  .stamp .top,.stamp .bot{font-size:15px} .stamp .hrt{font-size:29px}
  .stamp .rule{height:3px;margin:6px auto}
}
