﻿/* Fence Heroes proposal engine â€” interface styles.
 *
 * Used one-handed, standing in somebody's garden, often in sunlight. So: light
 * ground, strong contrast, large touch targets.
 *
 * Rules this sheet follows, deliberately:
 *   - every button is ONE flat colour. No gradients, no second-colour border.
 *     Hover deepens that same colour. There is no press state, so nothing
 *     shifts or squashes under a thumb.
 *   - colour has three roles only: primary, secondary, tertiary. Each has one
 *     bright tone and two light shades of it. Bright where something matters,
 *     light shades everywhere else.
 *   - controls have no outlines. Shape comes from fill and shadow.
 *
 * Class names and structure are unchanged; this is the visual layer only. The
 * proposal PDF is Chris's artwork and is not styled from here at all.
 */

:root{
  /* ---- colour ------------------------------------------------------------- */
  /* primary: green. The brand, and every action.
     Set so white text on it clears 4.5:1. A brighter green measured 3.2:1, which
     is not enough on a phone held in sunlight, which is where this gets used. */
  --primary:#0a8260; --primary-strong:#086d51; --primary-deep:#075740;
  --primary-100:#d4f2e7; --primary-50:#edfbf6;

  /* secondary: amber, from the Fence Heroes mark. Attention, and fixed states. */
  --secondary:#f0a521; --secondary-strong:#d18d0d; --secondary-deep:#8a5c07;
  --secondary-100:#fdeeca; --secondary-50:#fef9ec;

  /* tertiary: blue. Neutral information, so it never competes with an action. */
  --tertiary:#3b8ed0; --tertiary-strong:#2d74af; --tertiary-deep:#1f5480;
  --tertiary-100:#d8e9f9; --tertiary-50:#eff6fd;

  /* ink and ground */
  --ink:#12241e; --soft:#5c6f68; --faint:#93a59d;
  --bg:#f3f7f5; --card:#ffffff;
  --fill:#f2f6f4;          /* filled fields and tracks */
  --fill-2:#e8efec;        /* the tone under a fill */
  --line:rgba(18,36,30,.06);

  --danger:#d64b4b; --danger-strong:#bd3a3a; --danger-100:#fbe1e1; --danger-50:#fdf3f3;

  /* What sits ON a filled primary button, and the dark bar at the top of an
     overlay. Both flip in night mode, which is why they are tokens: a bright
     green button needs dark text, not white. */
  --on-primary:#ffffff;
  /* Amber is light in both themes, so what sits on it is dark in both. Red goes
     the other way: dark red by day takes white, the paler night red does not. */
  --on-secondary:#412c06;
  --on-danger:#ffffff;
  /* The filled red button, kept separate from --danger: the border and the text
     can be the lighter red, a button carrying white text cannot. */
  --danger-btn:#a82f28; --danger-btn-hover:#8f251f;
  --bar-bg:var(--primary-deep); --bar-ink:#ffffff;
  /* The wash over the background photograph. */
  --hero-1:rgba(255,255,255,.86); --hero-2:rgba(255,255,255,.74); --hero-3:rgba(243,247,245,.93);

  /* aliases, so older rules keep working against the new system */
  --accent:var(--primary); --accent-dark:var(--primary-deep);
  --accent-soft:var(--primary-100); --accent-tint:var(--primary-50);
  --sand:var(--secondary-strong); --sand-soft:var(--secondary-100);
  --line-2:var(--line); --bg-2:var(--fill-2); --danger-soft:var(--danger-50);

  --sans:"Segoe UI Variable Text",system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;
  --serif:Georgia,"Times New Roman",serif;

  /* depth: soft and diffuse, two stops */
  --sh-1:0 1px 2px rgba(18,36,30,.04), 0 4px 10px -4px rgba(18,36,30,.06);
  --sh-2:0 2px 4px rgba(18,36,30,.04), 0 10px 24px -8px rgba(18,36,30,.09);
  --sh-3:0 4px 8px rgba(18,36,30,.04), 0 24px 56px -20px rgba(18,36,30,.13);
  --sh-focus:0 0 0 4px rgba(17,163,122,.16);

  --r-sm:12px; --r-md:16px; --r-lg:22px; --r-xl:28px; --r-pill:999px;

  --ease:cubic-bezier(.22,.61,.36,1);
  --fast:140ms; --mid:240ms; --slow:400ms;
}

/* ---- night mode ----------------------------------------------------------
 * The same three roles, inverted: the bright tone gets brighter so it still
 * carries on a dark ground, and the "light shade" slots become dark shades used
 * as tinted fills. Nothing else in the sheet changes, because everything below
 * reads from these tokens.
 */
html[data-theme="dark"]{
  --primary:#2ec79c; --primary-strong:#23ab85; --primary-deep:#8fe8cd;
  --primary-100:#123a30; --primary-50:#102c25;

  --secondary:#f2b44a; --secondary-strong:#dd9c2c; --secondary-deep:#f8d69f;
  --secondary-100:#3a2b12; --secondary-50:#2a200f;

  --tertiary:#5cabe8; --tertiary-strong:#3f8cca; --tertiary-deep:#aed6f7;
  --tertiary-100:#132a3c; --tertiary-50:#0f2030;

  --ink:#e9f1ed; --soft:#a5b5af; --faint:#7c8d87;
  --bg:#0c1512; --card:#151f1b;
  --fill:#1c2824; --fill-2:#26332e;
  --line:rgba(255,255,255,.07);

  --danger:#ef7676; --danger-strong:#f28d8d; --danger-100:#3d1f1f; --danger-50:#2c1717;

  --on-primary:#06201a;
  --on-secondary:#2a200f;
  --on-danger:#2a1010;
  --danger-btn:#f28d8d; --danger-btn-hover:#f8a8a8;
  --bar-bg:#0a1512; --bar-ink:#ffffff;
  --hero-1:rgba(12,21,18,.72); --hero-2:rgba(12,21,18,.80); --hero-3:rgba(12,21,18,.94);

  --sh-1:0 1px 2px rgba(0,0,0,.30), 0 4px 12px -4px rgba(0,0,0,.40);
  --sh-2:0 2px 6px rgba(0,0,0,.32), 0 12px 28px -10px rgba(0,0,0,.46);
  --sh-3:0 4px 10px rgba(0,0,0,.34), 0 26px 60px -22px rgba(0,0,0,.56);
  --sh-focus:0 0 0 4px rgba(46,199,156,.24);
}

*{ box-sizing:border-box; }
html{
  -webkit-text-size-adjust:100%;
  color-scheme:light dark;
  background:var(--bg);
  /* Light shades of the three tones, very faint. */
  background-image:
    radial-gradient(1100px 640px at 6% -12%, var(--card), transparent 62%),
    radial-gradient(760px 520px at 98% 0%, var(--primary-50), transparent 60%),
    radial-gradient(680px 460px at 78% 100%, var(--secondary-50), transparent 58%);
  background-attachment:fixed;
}
body{
  margin:0; color:var(--ink); font-family:var(--sans); line-height:1.5;
  background:transparent; overflow-x:hidden;
  -webkit-font-smoothing:antialiased;
}
/* Fence Heroes' own work behind the top of the page: one of Chris's job
   photographs, washed almost white so the cards and the type over it stay
   completely clear. Bright, not decorative. Fixed, so it behaves like a window
   rather than scrolling wallpaper. */
body::before{
  content:""; position:fixed; inset:0 0 auto 0; height:min(46vh,430px); z-index:-1;
  background-image:
    linear-gradient(180deg,
      var(--hero-1) 0%,
      var(--hero-2) 26%,
      var(--hero-3) 66%,
      var(--bg) 100%),
    url("hero.jpg");
  background-size:cover, cover;
  background-position:center top, center 34%;
  background-repeat:no-repeat, no-repeat;
  pointer-events:none;
}
::selection{ background:var(--primary-100); }
:focus-visible{ outline:2px solid var(--primary); outline-offset:2px; }

.shell{ max-width:540px; margin:0 auto; padding:26px 16px 64px; }

/* ---- masthead ------------------------------------------------------------- */
.masthead{ text-align:center; margin-bottom:20px; animation:drop var(--slow) var(--ease) both; }
.logo-fh{ display:block; width:auto; max-width:236px; height:auto; margin:0 auto 2px;
  transition:background var(--mid) var(--ease), padding var(--mid) var(--ease); }
/* Chris's mark is dark green type with orange bars, so at night it would sit
   dark on dark. It gets a light plate rather than a filter, because recolouring
   it would lose the orange and it is not ours to change. */
html[data-theme="dark"] .logo-fh{
  background:rgba(255,255,255,.95); padding:14px 20px; border-radius:var(--r-lg);
  box-shadow:var(--sh-2); max-width:264px;
}
.logo-group{ display:flex; align-items:center; justify-content:center; gap:8px; margin:2px 0 10px; }
.logo-group .pg{ font-size:9.5px; letter-spacing:.15em; text-transform:uppercase; color:var(--faint); font-weight:700; }
.logo-ll{ height:40px; width:auto; border-radius:8px; }
.eyebrow{
  display:inline-block; font-size:10.5px; letter-spacing:.18em; text-transform:uppercase;
  color:var(--primary-deep); font-weight:800; padding:6px 13px; border-radius:var(--r-pill);
  background:var(--primary-100);
}
.eyebrow.preview{ color:var(--secondary-deep); background:var(--secondary-100); }
.wordmark{ font-family:var(--serif); font-weight:500; font-size:26px; margin:6px 0 0; letter-spacing:-.01em; }

/* Day / night. One flat fill, hover only, and the label says what pressing it
   will do rather than what is already on screen. */
.mast-row{ display:flex; align-items:center; justify-content:center; gap:9px; flex-wrap:wrap; }
.themebtn{
  display:inline-flex; align-items:center; gap:8px; border:0; cursor:pointer;
  padding:6px 14px 6px 12px; border-radius:var(--r-pill); font:inherit;
  font-size:10.5px; font-weight:800; letter-spacing:.14em; text-transform:uppercase;
  background:var(--fill); color:var(--soft);
  transition:background var(--mid) var(--ease), color var(--mid) var(--ease);
}
.themebtn:hover{ background:var(--fill-2); color:var(--ink); }
/* A filled disc in day mode, a crescent at night, drawn rather than an icon file. */
.themebtn-icon{
  width:13px; height:13px; border-radius:50%; background:currentColor; flex:none;
  transition:box-shadow var(--mid) var(--ease), background var(--mid) var(--ease);
}
html[data-theme="dark"] .themebtn-icon{
  background:transparent; box-shadow:inset -4px -1.5px 0 0 currentColor;
}

/* ---- the card the app lives in ------------------------------------------- */
.card{
  position:relative; background:var(--card); border-radius:var(--r-xl); padding:22px;
  box-shadow:var(--sh-3); animation:rise var(--slow) var(--ease) both 60ms;
}
.cardhead{ display:flex; align-items:center; justify-content:space-between; margin-bottom:20px; }
.brandmark{ display:flex; align-items:center; gap:10px; font-weight:700; font-size:14.5px; letter-spacing:-.005em; }
.mk{
  display:grid; place-items:center; width:34px; height:34px; border-radius:50%;
  background:var(--primary); color:var(--on-primary); font-size:12.5px; font-weight:800; letter-spacing:.02em;
}
.who{
  font-size:12px; font-weight:700; color:var(--primary-deep); background:var(--primary-100);
  padding:7px 13px; border-radius:var(--r-pill); max-width:55%; overflow:hidden;
  text-overflow:ellipsis; white-space:nowrap;
}

/* ---- stepper ------------------------------------------------------------- */
.steps{ display:flex; align-items:flex-start; margin-bottom:26px; }
.step{ display:flex; flex-direction:column; align-items:center; gap:9px; }
.step i{
  width:12px; height:28px; border-radius:var(--r-pill); background:var(--fill-2); display:block;
  transition:background var(--mid) var(--ease), transform var(--mid) var(--ease);
}
.step span{
  font-size:9.5px; letter-spacing:.13em; text-transform:uppercase; color:var(--faint); font-weight:800;
  transition:color var(--mid) var(--ease);
}
.step.on i{ background:var(--primary); transform:scaleY(1.14); }
.step.on span{ color:var(--primary-deep); }
.step.done i{ background:var(--secondary); }
.step.done span{ color:var(--secondary-deep); }
.bar{
  flex:1; height:4px; border-radius:var(--r-pill); background:var(--fill-2); margin:12px 9px 0;
  position:relative; overflow:hidden;
}
.bar::after{
  content:""; position:absolute; inset:0; background:var(--secondary); border-radius:var(--r-pill);
  transform:scaleX(0); transform-origin:left center; transition:transform var(--slow) var(--ease);
}
.bar.done::after{ transform:scaleX(1); }

/* ---- panes --------------------------------------------------------------- */
/* Coming out of display:none restarts these, so each step animates in without a
   line of JavaScript. */
.pane:not(.hidden) > *{ animation:rise var(--mid) var(--ease) both; }
.pane:not(.hidden) > *:nth-child(1){ animation-delay:0ms; }
.pane:not(.hidden) > *:nth-child(2){ animation-delay:30ms; }
.pane:not(.hidden) > *:nth-child(3){ animation-delay:60ms; }
.pane:not(.hidden) > *:nth-child(4){ animation-delay:90ms; }
.pane:not(.hidden) > *:nth-child(5){ animation-delay:120ms; }
.pane:not(.hidden) > *:nth-child(n+6){ animation-delay:150ms; }

.panetitle{ font-family:var(--serif); font-weight:500; font-size:25px; margin:0 0 6px; letter-spacing:-.015em; }
.panesub{ margin:0 0 6px; color:var(--soft); font-size:14px; }

/* ---- fields: filled, no outline ----------------------------------------- */
.lbl{
  display:block; font-size:11px; font-weight:800; letter-spacing:.07em; text-transform:uppercase;
  color:var(--soft); margin:18px 0 8px;
}
/* Every text-like input, not just type=text: the customer email and mobile use
   type=email and type=tel so phones offer the right keyboard, and they must look
   identical to the rest of the form. */
/* input[type=number] is in here too: the quantity and price boxes are numbers,
   and without it they kept the browser's own white, which looked wrong beside
   the filled fields in day mode and stayed glaring white at night. */
input[type=text], input[type=email], input[type=tel], input[type=number],
textarea, select.field{
  width:100%; padding:13px 15px; font:inherit; color:var(--ink);
  background:var(--fill); border:0; border-radius:var(--r-md);
  transition:background var(--fast) var(--ease), box-shadow var(--fast) var(--ease);
}
input[type=number]:hover{ background:var(--fill-2); }
input[type=number]:focus{ outline:0; background:var(--card); box-shadow:var(--sh-focus); }
input[type=text]::placeholder, input[type=email]::placeholder,
input[type=tel]::placeholder, textarea::placeholder{ color:var(--faint); }
input[type=text]:hover, input[type=email]:hover, input[type=tel]:hover,
textarea:hover, select.field:hover{ background:var(--fill-2); }
input[type=text]:focus, input[type=email]:focus, input[type=tel]:focus,
textarea:focus, select.field:focus{ outline:0; background:var(--card); box-shadow:var(--sh-focus); }
textarea{ resize:vertical; min-height:116px; line-height:1.6; }
select.field{
  appearance:none; padding-right:40px; line-height:1.5; cursor:pointer;
  background-image:linear-gradient(45deg,transparent 50%,var(--soft) 50%),
                   linear-gradient(135deg,var(--soft) 50%,transparent 50%);
  background-position:calc(100% - 21px) calc(50% - 2px), calc(100% - 16px) calc(50% - 2px);
  background-size:5px 5px, 5px 5px; background-repeat:no-repeat;
}
select.field:focus{
  background-image:linear-gradient(45deg,transparent 50%,var(--primary) 50%),
                   linear-gradient(135deg,var(--primary) 50%,transparent 50%);
}
/* He types these, he does not nudge them, and the arrows crowd a narrow field. */
input[type=number]{ -moz-appearance:textfield; appearance:textfield; }
input[type=number]::-webkit-outer-spin-button,
input[type=number]::-webkit-inner-spin-button{ -webkit-appearance:none; margin:0; }

.row2{ display:flex; gap:12px; align-items:flex-end; flex-wrap:wrap; }
.row2 > div{ flex:1; min-width:150px; }
.toggle{
  display:flex; align-items:center; gap:11px; padding:13px 15px; border:0;
  border-radius:var(--r-md); font-size:13.5px; font-weight:700; cursor:pointer; white-space:nowrap;
  background:var(--fill); color:var(--ink);
  transition:background var(--mid) var(--ease), color var(--mid) var(--ease);
}
.toggle:hover{ background:var(--fill-2); }
.toggle:has(input:checked){ background:var(--primary-100); color:var(--primary-deep); }
.toggle input{ width:19px; height:19px; accent-color:var(--primary); }

.namegrid{ display:grid; grid-template-columns:76px 1fr 1fr; gap:8px; }
.namegrid input{ padding:12px 12px; font-size:13.5px; }

/* ---- page pills ---------------------------------------------------------- */
.pills{ display:flex; flex-wrap:wrap; gap:8px; }
.pill{
  border:0; background:var(--fill); color:var(--ink); border-radius:var(--r-pill);
  padding:11px 17px; font:inherit; font-size:13.5px; font-weight:600; cursor:pointer; user-select:none;
  transition:background var(--mid) var(--ease), color var(--mid) var(--ease);
}
.pill:hover{ background:var(--fill-2); }
.pill.on{ background:var(--primary); color:var(--on-primary); font-weight:700; }
.pill.on:hover{ background:var(--primary-strong); }
.pill.on::before{ content:"\2713"; margin-right:8px; font-weight:800; }
/* Pages Chris has not designed yet: visible, but not selectable. */
.pill.soon{ background:transparent; box-shadow:inset 0 0 0 1.5px var(--fill-2); color:var(--faint); cursor:not-allowed; }
.pill.soon:hover{ background:transparent; }
.soonTag{ margin-left:8px; font-size:9.5px; letter-spacing:.09em; text-transform:uppercase; color:var(--secondary-deep); font-weight:800; }

/* ---- buttons: one flat colour, hover only ------------------------------- */
.cta{
  width:100%; margin-top:22px; padding:17px; font:inherit; font-size:15px; font-weight:700;
  letter-spacing:.005em; border:0; border-radius:var(--r-pill);
  background:var(--primary); color:var(--on-primary); cursor:pointer; box-shadow:var(--sh-2);
  transition:background var(--mid) var(--ease), box-shadow var(--mid) var(--ease);
}
.cta:hover{ background:var(--primary-strong); box-shadow:var(--sh-3); }
.cta:disabled{ background:var(--fill-2); color:var(--faint); cursor:default; box-shadow:none; }
.cta.ghost{ background:var(--fill); color:var(--ink); margin-top:10px; box-shadow:none; }
.cta.ghost:hover{ background:var(--fill-2); box-shadow:none; }
.linkbtn{
  display:block; width:100%; margin-top:16px; background:none; border:0; color:var(--soft);
  font:inherit; font-size:13px; cursor:pointer; text-decoration:underline; text-underline-offset:3px;
  transition:color var(--fast) var(--ease);
}
.linkbtn:hover{ color:var(--primary-deep); }
.status{ text-align:center; color:var(--soft); font-size:13px; min-height:18px; margin:14px 0 0; }
.status.err{ color:var(--danger-strong); }

/* Secondary actions, one flat fill each. */
.addrow{
  margin-top:10px; font:inherit; font-size:13.5px; font-weight:700; padding:13px 19px;
  background:var(--fill); border:0; border-radius:var(--r-pill); cursor:pointer; color:var(--primary-deep);
  transition:background var(--mid) var(--ease), color var(--mid) var(--ease);
}
.addrow:hover{ background:var(--primary-100); }
.addrow.danger{ color:var(--danger-strong); }
.addrow.danger:hover{ background:var(--danger-100); }
.regen{
  margin-top:10px; font:inherit; font-size:12.5px; font-weight:700; padding:10px 16px;
  background:var(--fill); border:0; border-radius:var(--r-pill); cursor:pointer; color:var(--ink);
  transition:background var(--mid) var(--ease);
}
.regen:hover{ background:var(--fill-2); }

/* ---- page cards on the review step ------------------------------------- */
.pages{ display:flex; flex-direction:column; gap:12px; }
.pcard{
  border:0; border-radius:var(--r-lg); padding:16px; background:var(--card); box-shadow:var(--sh-1);
  transition:box-shadow var(--mid) var(--ease), opacity var(--mid) var(--ease);
}
.pcard:focus-within{ box-shadow:var(--sh-2); }
.pcard-head{ display:flex; align-items:center; justify-content:space-between; gap:9px; margin-bottom:10px; }
.pcard-title{ font-weight:700; font-size:14px; flex:1; min-width:0; letter-spacing:-.005em; }
.pcard-title-input{
  flex:1; min-width:0; font:inherit; font-weight:700; font-size:14px; padding:9px 12px;
  border:0; border-radius:var(--r-sm); color:var(--ink); background:var(--fill);
  transition:background var(--fast) var(--ease), box-shadow var(--fast) var(--ease);
}
.pcard-title-input:focus{ outline:0; background:var(--card); box-shadow:var(--sh-focus); }
.excl{
  border:0; background:none; color:var(--faint); font-size:19px; line-height:1; cursor:pointer;
  padding:4px 9px; border-radius:var(--r-pill); white-space:nowrap; flex:none;
  transition:color var(--fast) var(--ease), background var(--fast) var(--ease);
}
.excl:hover{ color:var(--danger-strong); background:var(--danger-100); }
.pcard.excluded{ opacity:.5; }
.pcard.excluded .pcard-title, .pcard.excluded .pcard-title-input{ text-decoration:line-through; }
.pcard.excluded .excl{ font-size:12px; font-weight:800; color:var(--primary-deep); }
.count{
  font-size:11px; font-weight:800; padding:5px 11px; border-radius:var(--r-pill);
  background:var(--primary-100); color:var(--primary-deep); white-space:nowrap;
  transition:background var(--mid) var(--ease), color var(--mid) var(--ease);
}
.count.over{ background:var(--danger-100); color:var(--danger-strong); }
.count.fixed{ background:var(--tertiary-100); color:var(--tertiary-deep); }
/* Fixed, scrollable height (no per-keystroke auto-resize) so the page does not
   jump around while editing on a phone. */
.pcard textarea{ height:154px; font-size:14px; resize:vertical; overflow-y:auto; }
.pcard textarea.tall{ height:284px; }

/* A page the model could not write. The standby wording reads plausibly, so this
   has to be loud enough that it never reaches a customer by accident. */
.pcard.degraded{ background:var(--danger-50); box-shadow:inset 0 0 0 1.5px var(--danger-100), var(--sh-1); }
.pcard.degraded .pcard-title::after{ content:" Â· standby wording"; color:var(--danger-strong); font-weight:700; font-size:11.5px; }

/* ---- the finished step -------------------------------------------------- */
.done{ text-align:center; padding:12px 0 4px; }
.tick{
  width:64px; height:64px; margin:0 auto 16px; border-radius:50%;
  background:var(--primary-100); color:var(--primary-deep); font-size:28px; font-weight:800;
  display:grid; place-items:center; animation:pop 520ms var(--ease) both;
}

/* ---- one-off rows ------------------------------------------------------- */
.img-row{ display:flex; gap:8px; align-items:center; }
.img-row .cap{ flex:1; min-width:0; padding:11px 13px; font-size:13.5px; }
.img-row .upload{
  flex:none; padding:12px 16px; font-size:13px; font-weight:700; color:var(--primary-deep);
  background:var(--fill); border:0; border-radius:var(--r-pill); cursor:pointer; white-space:nowrap;
  transition:background var(--mid) var(--ease);
}
.img-row .upload:hover{ background:var(--primary-100); }
.img-row .del, .cost-row .del, .saved-row .del, .run-head .del{
  border:0; background:none; color:var(--faint); font-size:20px; line-height:1; cursor:pointer;
  padding:4px 9px; border-radius:var(--r-pill); flex:none;
  transition:color var(--fast) var(--ease), background var(--fast) var(--ease);
}
.img-row .del:hover, .cost-row .del:hover, .saved-row .del:hover, .run-head .del:hover{
  color:var(--danger-strong); background:var(--danger-100);
}

/* ---- the money editor -------------------------------------------------- */
.costs-editor{ margin:4px 0 18px; text-align:left; }
.cost-rows{ display:flex; flex-direction:column; gap:8px; }
.cost-row{ display:flex; gap:8px; align-items:center; animation:rise var(--fast) var(--ease) both; }
.cost-row .desc{ flex:1; min-width:0; }
.cost-row .qty{ width:58px; text-align:center; }
.cost-row .price{ width:100px; }
.cost-row input{ padding:11px 12px; font-size:13.5px; }
.cost-totals{ margin-top:15px; font-size:13.5px; color:var(--soft); }
.cost-totals .row{ display:flex; justify-content:space-between; gap:12px; padding:5px 2px; }
.cost-totals .row span:last-child{ font-variant-numeric:tabular-nums; }
.cost-totals .grand{
  font-weight:800; color:var(--ink); border-top:1px solid var(--line);
  margin-top:6px; padding-top:10px; font-size:16px;
}
.cost-totals .muted{ color:var(--faint); font-size:12.5px; font-style:italic; }
.cost-totals .warn{
  margin-top:10px; padding:11px 13px; border-radius:var(--r-sm);
  background:var(--danger-50); color:var(--danger-strong); font-size:12.5px; font-weight:700;
}

/* Add another page without leaving the review screen. */
.addpage{ margin-top:16px; padding:16px; border-radius:var(--r-lg); background:var(--fill); }
.addpage input{ padding:12px 13px; font-size:13.5px; background:var(--card); }
.addpage .addrow{ margin-right:6px; background:var(--card); }
.addpage .addrow:hover{ background:var(--primary-100); }

/* Costs: the job, then the options that stay out of the total. */
.costcol + .costcol{ margin-top:20px; padding-top:18px; border-top:1px solid var(--line); }
.costcol-head{ font-size:11px; font-weight:800; letter-spacing:.09em; text-transform:uppercase; color:var(--primary-deep); }
.costcol.options .costcol-head{ color:var(--secondary-deep); }
.costnote{ font-size:12.5px; margin:4px 0 11px; }

/* ---- saved proposals, kept on the phone -------------------------------- */
.saved{ margin-bottom:6px; }
.saved-list{ display:flex; flex-direction:column; gap:8px; }
.saved-row{ display:flex; align-items:center; gap:4px; }
.saved-open{
  flex:1; min-width:0; display:flex; justify-content:space-between; align-items:baseline; gap:10px;
  text-align:left; padding:15px 44px 15px 17px; background:var(--fill); border:0;
  border-radius:var(--r-md); font:inherit; color:var(--ink); cursor:pointer; position:relative;
  transition:background var(--mid) var(--ease);
}
.saved-open::after{
  content:""; position:absolute; right:18px; top:50%; width:7px; height:7px;
  border-right:2px solid var(--faint); border-top:2px solid var(--faint);
  transform:translateY(-50%) rotate(45deg);
  transition:border-color var(--fast) var(--ease);
}
.saved-open:hover{ background:var(--primary-100); }
.saved-open:hover::after{ border-color:var(--primary-deep); }
.saved-open strong{ font-size:13.5px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.saved-open span{ font-size:11.5px; color:var(--faint); white-space:nowrap; flex:none; }
.savednote{ text-align:center; font-size:12px; color:var(--faint); margin:12px 0 0; min-height:16px; }
.savednote.err{ color:var(--danger-strong); }

/* Per-page AI toggle on the one-off pages. */
.aitick{
  display:flex; align-items:center; gap:7px; padding:11px 13px; border:0;
  border-radius:var(--r-pill); font-size:12px; font-weight:800; color:var(--ink); cursor:pointer; flex:none;
  background:var(--fill); transition:background var(--mid) var(--ease), color var(--mid) var(--ease);
}
.aitick:hover{ background:var(--fill-2); }
.aitick:has(input:checked){ background:var(--primary-100); color:var(--primary-deep); }
.aitick input{ width:16px; height:16px; accent-color:var(--primary); }

.foot{ text-align:center; color:var(--faint); font-size:12px; margin-top:18px; }

.hidden{ display:none !important; }

/* ---- overlays ---------------------------------------------------------- */
.overlay{ position:fixed; inset:0; z-index:20; background:var(--bg); display:flex; flex-direction:column;
  animation:fade var(--mid) var(--ease) both; }
.overlay-bar{
  display:flex; gap:8px; justify-content:flex-end; align-items:center; padding:13px 15px;
  background:var(--bar-bg); position:relative; z-index:1;
}
.overlay .ghost{
  background:var(--card); border:0; color:var(--ink); padding:11px 17px; border-radius:var(--r-pill);
  font:inherit; font-weight:700; font-size:13.5px; cursor:pointer;
  transition:background var(--mid) var(--ease);
}
.overlay .ghost:hover{ background:var(--primary-100); }
.overlay iframe{ flex:1; width:100%; border:0; background:#fff; }

/* ---- Stage 2: materials and costing ------------------------------------ */
.calc-card{ margin-bottom:14px; }
.calc-card .setlink{ width:auto; margin:0; flex:none; font-size:12px; font-weight:700; }

/* One card per run: the rear boundary and the sides are separate measurements
   that share one order list. */
.run{ animation:rise var(--mid) var(--ease) both; }
.run + .run{ margin-top:16px; padding-top:16px; border-top:1px solid var(--line); }
.run-head{ display:flex; align-items:center; gap:10px; margin-top:10px; }
.run-label{
  flex:1; min-width:0; padding:11px 13px; font:inherit; font-size:13px; font-weight:700;
  border:0; border-radius:var(--r-sm); color:var(--ink); background:var(--fill);
  transition:background var(--fast) var(--ease), box-shadow var(--fast) var(--ease);
}
.run-label:focus{ outline:0; background:var(--card); box-shadow:var(--sh-focus); }
.run-sub{ font-size:13.5px; font-weight:800; color:var(--primary-deep); white-space:nowrap; font-variant-numeric:tabular-nums; }

/* Two measurements per row on a phone, so the whole job fits on one screen. */
.calc-grid{ display:grid; grid-template-columns:1fr 1fr; gap:0 12px; }
.calc-field .lbl{ margin:14px 0 7px; }
.calc-field .unit{ color:var(--faint); font-weight:700; text-transform:none; letter-spacing:0; }
.calc-field input, .calc-field select{
  width:100%; padding:12px 13px; font:inherit; font-size:14px; border:0;
  border-radius:var(--r-sm); color:var(--ink); background:var(--fill);
  transition:background var(--fast) var(--ease), box-shadow var(--fast) var(--ease);
}
.calc-field select{ appearance:none; cursor:pointer;
  background-image:linear-gradient(45deg,transparent 50%,var(--soft) 50%),
                   linear-gradient(135deg,var(--soft) 50%,transparent 50%);
  background-position:calc(100% - 18px) calc(50% - 2px), calc(100% - 13px) calc(50% - 2px);
  background-size:5px 5px, 5px 5px; background-repeat:no-repeat; padding-right:34px; }
.calc-field input:focus, .calc-field select:focus{ outline:0; background:var(--card); box-shadow:var(--sh-focus); }
.calc-hint{ margin:6px 0 0; font-size:11.5px; color:var(--faint); line-height:1.4; }

.calc-result{ margin-top:18px; animation:fade var(--mid) var(--ease) both; }
.calc-build{ display:flex; flex-wrap:wrap; gap:7px; margin-bottom:13px; }
.calc-build .chip{
  font-size:11.5px; font-weight:700; color:var(--primary-deep); background:var(--primary-100);
  padding:6px 12px; border-radius:var(--r-pill); font-variant-numeric:tabular-nums;
}

/* The order list can be wider than a phone, so it scrolls on its own. */
.calc-tablewrap{
  overflow-x:auto; -webkit-overflow-scrolling:touch; border-radius:var(--r-md);
  background:var(--card); box-shadow:var(--sh-1);
}
.calc-table{ width:100%; border-collapse:collapse; font-size:12.5px; }
.calc-table th{
  text-align:left; font-size:9.5px; letter-spacing:.08em; text-transform:uppercase; color:var(--faint);
  font-weight:800; padding:11px 10px 8px; background:var(--fill); white-space:nowrap;
  position:sticky; top:0;
}
.calc-table td{ padding:9px 10px; border-top:1px solid var(--line); vertical-align:top; }
.calc-table tbody tr{ transition:background var(--fast) var(--ease); }
.calc-table tbody tr:hover{ background:var(--primary-50); }
.calc-table .q{ text-align:right; font-weight:800; color:var(--ink); white-space:nowrap; font-variant-numeric:tabular-nums; }
.calc-table .u{ color:var(--faint); white-space:nowrap; }
.calc-table .p{ text-align:right; white-space:nowrap; color:var(--soft); font-variant-numeric:tabular-nums; }

.calc-totals{ margin-top:16px; }
/* His figures. X and W are subtotals feeding Y, so they sit slightly apart. */
.cost-totals .row.sub{
  border-top:1px solid var(--line); margin-top:7px; padding-top:9px;
  color:var(--ink); font-weight:700;
}
.cost-totals .row.sub b, .cost-totals .grand b{
  display:inline-grid; place-items:center; width:20px; height:20px; margin-right:9px;
  border-radius:50%; background:var(--primary-100); color:var(--primary-deep);
  font-size:11px; font-weight:800; vertical-align:-4px;
}
/* The customer price, kept visually separate from his cost figures. */
.calc-price{
  margin-top:18px; padding:16px 17px; border-radius:var(--r-lg); background:var(--primary-50);
}
.calc-price .grand.price{ font-size:20px; border-top-color:var(--primary-100); padding-top:11px; }
.calc-price .grand.price b{ background:var(--card); }

/* Whole-job costs: waste and equipment hire. */
.jobcosts{ margin-top:6px; }
.jobcost-row{ display:flex; align-items:center; gap:12px; padding:10px 0; border-bottom:1px solid var(--line); }
.jobcost-row:last-child{ border-bottom:0; }
.jobcost-row label{ flex:1; min-width:0; cursor:pointer; }
.jobcost-row label span{ display:block; font-size:13.5px; font-weight:700; }
.jobcost-row label em{ display:block; font-style:normal; font-size:11.5px; color:var(--faint); }
.jobcost-row input{
  width:112px; padding:11px 13px; font:inherit; font-size:13.5px; text-align:right;
  border:0; border-radius:var(--r-sm); color:var(--ink); background:var(--fill);
  font-variant-numeric:tabular-nums;
  transition:background var(--fast) var(--ease), box-shadow var(--fast) var(--ease);
}
.jobcost-row input:focus{ outline:0; background:var(--card); box-shadow:var(--sh-focus); }
.calc-notes{ margin:13px 0 0; padding-left:20px; font-size:12px; color:var(--soft); }
.calc-notes li{ margin:3px 0; }
.calc-actions{ display:flex; flex-wrap:wrap; gap:8px; }
.calc-actions .addrow{ flex:1; min-width:150px; text-align:center; }

/* ---- progress ---------------------------------------------------------- */
/* What is happening on the left, the percentage on the right, a track beneath.
   The number is walked frame by frame in progress.js so it never jumps. */
.progress{
  margin-top:16px; padding:15px 17px; background:var(--card); border:0;
  border-radius:var(--r-md); box-shadow:var(--sh-1);
  animation:rise var(--mid) var(--ease) both;
}
.progress-head{ display:flex; align-items:baseline; justify-content:space-between; gap:12px; margin-bottom:11px; }
.progress-label{ font-size:13px; font-weight:600; color:var(--soft); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.progress-pct{
  font-size:21px; font-weight:800; color:var(--primary); font-variant-numeric:tabular-nums;
  letter-spacing:-.02em; flex:none;
}
.progress-track{ height:9px; border-radius:var(--r-pill); background:var(--fill-2); overflow:hidden; }
/* No CSS transition on the width: progress.js walks it every frame, and a
   transition on top of that would fight it and look lumpy. */
.progress-fill{ display:block; height:100%; width:0; border-radius:var(--r-pill); background:var(--primary); }
/* While it is pacing rather than measuring, a light travels along the fill so it
   never looks stalled. */
.progress.indeterminate .progress-fill{ position:relative; overflow:hidden; }
.progress.indeterminate .progress-fill::after{
  content:""; position:absolute; inset:0;
  background:linear-gradient(100deg,transparent 25%,rgba(255,255,255,.5) 50%,transparent 75%);
  transform:translateX(-100%); animation:sheen 1.4s linear infinite;
}
.progress.failed .progress-fill{ background:var(--danger); }
.progress.failed .progress-pct{ color:var(--danger); }

/* ---- the settings screen (only Gareth sees this) ---------------------- */
.overlay.settings .overlay-bar{ justify-content:space-between; }
.setbar-title{ color:var(--bar-ink); font-size:14.5px; font-weight:700; letter-spacing:-.005em; }
.setbar-note{ color:var(--secondary-100); font-size:12px; font-weight:700; margin-left:auto; margin-right:12px; }
.settings-scroll{ flex:1; overflow-y:auto; -webkit-overflow-scrolling:touch; padding:18px 14px 52px; }
.settings-body{ max-width:540px; margin:0 auto; }
.set-block{
  background:var(--card); border:0; border-radius:var(--r-lg); padding:16px; margin-bottom:12px;
  box-shadow:var(--sh-1); animation:rise var(--mid) var(--ease) both;
}
.set-row{ display:flex; align-items:center; gap:10px; padding:9px 0; border-bottom:1px solid var(--line); }
.set-row:last-child{ border-bottom:0; }
.set-name{ flex:1; min-width:0; font-size:13px; }
.set-unit{ font-size:11px; color:var(--faint); white-space:nowrap; }
.set-row input{
  width:96px; padding:10px 12px; font:inherit; font-size:13.5px; text-align:right;
  border:0; border-radius:var(--r-sm); color:var(--ink); background:var(--fill);
  font-variant-numeric:tabular-nums;
  transition:background var(--fast) var(--ease), box-shadow var(--fast) var(--ease);
}
.set-row input:focus{ outline:0; background:var(--card); box-shadow:var(--sh-focus); }
/* Whose prices are these? Shown until he says they are his. The app ships with
   example figures so it runs out of the box, and a confident number built on
   somebody else's guess is the easy way to quote a job badly. */
.calc-warn{
  display:flex; flex-wrap:wrap; align-items:center; gap:10px;
  margin-bottom:15px; padding:13px 15px; border-radius:var(--r-lg);
  background:var(--danger-50); border-left:4px solid var(--danger);
  color:var(--danger-strong); font-size:12.5px; line-height:1.45;
  animation:drop var(--mid) var(--ease) both;
}
.warn-act{
  margin-left:auto; font:inherit; font-size:12.5px; font-weight:700;
  padding:10px 16px; border:0; border-radius:var(--r-pill); cursor:pointer;
  background:var(--danger-btn); color:var(--on-danger);
  transition:background var(--mid) var(--ease);
}
.warn-act:hover{ background:var(--danger-btn-hover); }

/* The same question in the settings, where he can actually answer it. Amber
   rather than red: here it is an instruction, not a live risk. */
.set-check{ border-left:4px solid var(--secondary); }
.set-check .costcol-head{ color:var(--secondary-deep); }
.set-ok{ border-left:4px solid var(--primary); }
.set-confirm{
  width:100%; text-align:center; margin-top:12px;
  background:var(--secondary); color:var(--on-secondary);
}
.set-confirm:hover{ background:var(--secondary-strong); }
.set-example .set-name{ color:var(--soft); }
.set-tag{
  display:inline-block; margin-left:7px; padding:2px 7px; border-radius:var(--r-pill);
  font-size:9.5px; font-weight:800; letter-spacing:.06em; text-transform:uppercase;
  color:var(--secondary-deep); background:var(--secondary-100); vertical-align:middle;
}

.set-footer{ max-width:540px; margin:0 auto; display:flex; flex-direction:column; gap:8px; }
.set-footer .addrow{ margin-top:0; text-align:center; background:var(--card); }
.set-footer .addrow:hover{ background:var(--primary-100); }
.set-footer .addrow.danger:hover{ background:var(--danger-100); }
.upload-lbl{ display:block; }

/* ---- motion ----------------------------------------------------------- */
@keyframes rise{ from{ opacity:0; transform:translateY(9px); } to{ opacity:1; transform:none; } }
@keyframes drop{ from{ opacity:0; transform:translateY(-8px); } to{ opacity:1; transform:none; } }
@keyframes fade{ from{ opacity:0; } to{ opacity:1; } }
@keyframes pop{
  0%{ opacity:0; transform:scale(.74); }
  62%{ opacity:1; transform:scale(1.05); }
  100%{ opacity:1; transform:scale(1); }
}
@keyframes sheen{ to{ transform:translateX(100%); } }

/* Someone who has asked their phone to stop animating things means it. */
@media (prefers-reduced-motion:reduce){
  *, *::before, *::after{
    animation-duration:1ms !important; animation-delay:0ms !important;
    transition-duration:1ms !important; scroll-behavior:auto !important;
  }
}

/* ---- narrow phones --------------------------------------------------- */
@media (max-width:400px){
  .shell{ padding:20px 12px 56px; }
  .card{ padding:17px; border-radius:var(--r-lg); }
  .panetitle{ font-size:23px; }
  .namegrid{ grid-template-columns:66px 1fr 1fr; gap:7px; }
  .cta{ padding:16px; }
}


/* Confirming a delete. The destructive button sits at the opposite end of the
   row from the cross that opened it, so the thumb that pressed the cross comes
   down on Keep. Losing a written proposal to a fumble is not recoverable. */
.saved-row.confirming{
  gap:8px; padding:8px 10px; border-radius:var(--r-lg);
  background:var(--danger-50); border-left:4px solid var(--danger);
  animation:drop var(--fast) var(--ease) both;
}
.saved-del-ask{ flex:1; min-width:0; font-size:12.5px; color:var(--danger-strong); text-align:center; }
.saved-del-yes, .saved-del-no{
  font:inherit; font-size:12.5px; font-weight:700; padding:9px 14px; border:0;
  border-radius:var(--r-pill); cursor:pointer; white-space:nowrap;
  transition:background var(--mid) var(--ease);
}
.saved-del-yes{ background:var(--danger-btn); color:var(--on-danger); }
.saved-del-yes:hover{ background:var(--danger-btn-hover); }
.saved-del-no{ background:var(--fill); color:var(--ink); }
.saved-del-no:hover{ background:var(--fill-2); }

/* ---- starting from a contact HubSpot already holds ---------------------- */
.hslookup{
  background:var(--card); border-radius:var(--r-lg); padding:14px 15px;
  box-shadow:var(--sh-1); margin-bottom:16px;
}
.hslookup input[type=search]{
  width:100%; padding:13px 15px; font:inherit; color:var(--ink);
  border:0; border-radius:var(--r-sm); background:var(--fill);
  -webkit-appearance:none; appearance:none;
  transition:background var(--fast) var(--ease), box-shadow var(--fast) var(--ease);
}
.hslookup input[type=search]:focus{ outline:0; background:var(--card); box-shadow:var(--sh-focus); }
.hs-results{ display:flex; flex-direction:column; gap:6px; }
.hs-results:not(:empty){ margin-top:10px; }
.hs-hit{
  display:flex; flex-direction:column; gap:2px; text-align:left; width:100%;
  font:inherit; padding:11px 13px; border:0; border-radius:var(--r-sm);
  background:var(--fill); color:var(--ink); cursor:pointer;
  transition:background var(--mid) var(--ease);
}
.hs-hit:hover{ background:var(--primary-100); }
.hs-hit strong{ font-size:13.5px; }
.hs-hit span{ font-size:11.5px; color:var(--soft); }
.hs-tag{
  margin-left:7px; padding:2px 7px; border-radius:var(--r-pill);
  font-size:9.5px; font-weight:800; letter-spacing:.06em; text-transform:uppercase;
  color:var(--secondary-deep); background:var(--secondary-100); vertical-align:middle;
}
.hs-note{ font-size:12px; color:var(--soft); margin-top:9px; }
.hs-note.ok{ color:var(--primary-deep); }
.hs-note.err{ color:var(--danger-strong); }

/* A field that is words rather than a number: the custom gate specification,
   which he orders from later, so it takes the whole row. */
.calc-field-wide{ grid-column:1 / -1; }
.calc-field-wide input[type=text]{
  width:100%; padding:13px 15px; font:inherit; color:var(--ink);
  border:0; border-radius:var(--r-sm); background:var(--fill);
  transition:background var(--fast) var(--ease), box-shadow var(--fast) var(--ease);
}
.calc-field-wide input[type=text]:focus{ outline:0; background:var(--card); box-shadow:var(--sh-focus); }

/* A one-off cost he types for this job only: a name, a figure, and a cross. */
.jobcost-row.extra .extra-label{ flex:1; min-width:0; }
.jobcost-row.extra input[type=text]{
  width:100%; padding:11px 13px; font:inherit; font-size:13.5px; color:var(--ink);
  border:0; border-radius:var(--r-sm); background:var(--fill);
  transition:background var(--fast) var(--ease), box-shadow var(--fast) var(--ease);
}
.jobcost-row.extra input[type=text]:focus{ outline:0; background:var(--card); box-shadow:var(--sh-focus); }
#addExtra{ margin-top:8px; }

/* How much of each thing. One row per page he has ticked, so a measurement
   belongs to the page it describes and cannot drift onto another. */
.measures{ background:var(--card); border-radius:var(--r-lg); padding:15px 16px; box-shadow:var(--sh-1); margin:14px 0 4px; }
.m-row{ padding:11px 0; border-bottom:1px solid var(--line); }
.m-row:last-child{ border-bottom:0; }
.m-name{ font-size:13.5px; font-weight:700; margin-bottom:7px; }
.m-name em{ display:block; font-style:normal; font-weight:400; font-size:11.5px; color:var(--faint); margin-top:1px; }
.m-fields{ display:flex; flex-wrap:wrap; gap:7px; align-items:center; }
.m-fields input, .m-fields select{
  flex:1 1 84px; min-width:0; padding:11px 12px; font:inherit; font-size:13.5px; color:var(--ink);
  border:0; border-radius:var(--r-sm); background:var(--fill); -webkit-appearance:none; appearance:none;
  transition:background var(--fast) var(--ease), box-shadow var(--fast) var(--ease);
}
.m-fields input:focus, .m-fields select:focus{ outline:0; background:var(--card); box-shadow:var(--sh-focus); }
.m-fields input[readonly]{ background:var(--fill-2); color:var(--soft); }
.m-unit{ flex:1 1 84px; font-size:12px; color:var(--soft); }

.m-price{ display:flex; align-items:center; gap:8px; margin-top:7px; }
.m-pound{ font-size:13.5px; color:var(--soft); font-weight:700; }
.m-price input{
  flex:1; min-width:0; padding:11px 12px; font:inherit; font-size:13.5px; color:var(--ink);
  border:0; border-radius:var(--r-sm); background:var(--fill);
  transition:background var(--fast) var(--ease), box-shadow var(--fast) var(--ease);
}
.m-price input:focus{ outline:0; background:var(--card); box-shadow:var(--sh-focus); }

/* ---- V1: no signal, and what is waiting -----------------------------------
   One line above the card, and only when there is something to say. He reads it
   holding a phone in one hand in a van, so it says which of two things is true:
   it is saved, or it has gone. Three colours, all already in the palette: amber
   for waiting on the world, blue for working, green for done. */
.netnote{
  display:none; margin:0 0 12px; padding:11px 15px; border-radius:var(--r-pill);
  font-size:12.5px; font-weight:700; line-height:1.4; text-align:center;
}
.netnote.on{ display:block; }
.netnote.off{ background:var(--secondary-100); color:var(--secondary-deep); }
.netnote.busy{ background:var(--tertiary-100); color:var(--tertiary-deep); }
.netnote.done{ background:var(--primary-100); color:var(--primary-deep); }

/* On a saved proposal that could not be written yet. Amber, the same as the
   line at the top, so the two obviously mean the same thing. */
.saved-open .waiting{
  display:block; font-style:normal; font-weight:800; color:var(--secondary-deep);
}

/* ---- V4: the green light ---------------------------------------------------
   A switch, not a checkbox, because he presses it once in his life and it needs
   to say plainly which way it is. The dot is the state: grey off, green on,
   amber when the phone has refused and only its settings can undo that. */
.greenlight{
  display:flex; align-items:center; gap:11px; width:100%; margin-top:12px;
  padding:13px 17px; border:0; border-radius:var(--r-pill); background:var(--fill);
  font-size:13px; font-weight:800; color:var(--soft); cursor:pointer; text-align:left;
  transition:background var(--mid) var(--ease), color var(--mid) var(--ease);
}
.greenlight:hover{ background:var(--fill-2); }
.gl-dot{
  width:11px; height:11px; border-radius:50%; flex:none; background:var(--faint);
  transition:background var(--mid) var(--ease);
}
.greenlight[aria-pressed="true"]{ background:var(--primary-100); color:var(--primary-deep); }
.greenlight[aria-pressed="true"] .gl-dot{ background:var(--primary); }
.greenlight.blocked{ background:var(--secondary-100); color:var(--secondary-deep); cursor:default; }
.greenlight.blocked .gl-dot{ background:var(--secondary-strong); }
