/* ============================================================
   Point of View Web Solutions — build + managed operation
   One stylesheet. No framework, no build step.
   Change the tokens in :root and the whole site follows.
   ============================================================ */

:root{
  --bg:       #FAF9F6;   /* page                       */
  --bg-2:     #F1EFEA;   /* alternating section        */
  --surf:     #FFFFFF;   /* cards, panels              */
  --surf-2:   #F6F3EE;   /* raised / hover             */

  /* Blue clears AA both ways -- 5.2:1 under white as a fill, 4.9:1 as
     text on the page -- so unlike the gold it needs no separate colour
     to stay legible. --accent-ink is the same family a shade deeper,
     used where text wants a little more weight than the fill blue.
       --accent      fills  -- buttons, chips, dots     5.2:1 with --on-accent
       --accent-ink  text   -- eyebrows, ticks, labels  6.3:1 on --bg        */
  --accent:   #2563EB;
  --accent-rgb: 37,99,235;
  --accent-hi:#1D53CC;
  --accent-ink:#1D53CC;
  --on-accent:#FFFFFF;
  --accent-2: #7C3AED;   /* secondary                  */

  /* Three jobs, three colours -- never the same colour for two of them.
     accent  = actions: buttons, links, ticks, focus
     signal  = availability: "taking on new builds"
     ok/warn/bad = status semantics only, never branding            */
  --signal:     #D97207;     /* availability -- amber   */
  --signal-rgb: 217,114,7;
  --ok:       #12A150;
  --ok-rgb:   18,161,80;
  --warn:     #B8860B;
  /* build-time marker for unfinished content. Deliberately a hue the
     brand never uses -- not the blue, not the violet, not the amber --
     so it can never be mistaken for a design choice. */
  --flag:     #B0186B;
  --flag-bg:  rgba(176,24,107,.10);
  --bad:      #C0392B;

  --text:     #414D5C;
  --head:     #0C1420;
  --muted:    #69747F;
  --line:     rgba(12,20,32,.11);
  --line-2:   rgba(12,20,32,.20);
  --grid:     rgba(12,20,32,.05);      /* hero grid rules */
  --nav-bg:   rgba(250,249,246,.84);   /* blurred nav bar */
  --raise:    rgba(12,20,32,.02);      /* panel/term bars */
  --shadow:   0 1px 2px rgba(12,20,32,.04), 0 10px 30px -14px rgba(12,20,32,.16);
  /* the terminal reads as a terminal in every theme, so it keeps dark
     surfaces of its own rather than inheriting the page's */
  --term-bg:   #10151F;
  --term-fg:   #C3CCD9;
  --term-dim:  #7C8798;
  --term-line: rgba(255,255,255,.09);
  --term-raise:rgba(255,255,255,.02);

  --display: "Space Grotesk", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Inter, Roboto, "Helvetica Neue", Arial, sans-serif;
  --mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  --wrap: 1180px;
  --pad: clamp(20px, 5vw, 40px);
  --r: 12px;
}

*,*::before,*::after{ box-sizing:border-box; }
html{ -webkit-text-size-adjust:100%; scroll-behavior:smooth; }
@media (prefers-reduced-motion: reduce){ html{ scroll-behavior:auto; } }

body{
  margin:0;
  background:var(--bg);
  color:var(--text);
  font-family:var(--sans);
  font-size:16.5px;
  line-height:1.68;
  -webkit-font-smoothing:antialiased;
  overflow-x:hidden;
}
img{ max-width:100%; display:block; }
a{ color:inherit; }

h1,h2,h3{ font-family:var(--display); color:var(--head); font-weight:600; line-height:1.1; letter-spacing:-.025em; margin:0 0 .5em; }
h1{ font-size:clamp(2.5rem, 6vw, 4.1rem); letter-spacing:-.04em; }
h2{ font-size:clamp(1.9rem, 4vw, 2.9rem); margin-bottom:.35em; }
h3{ font-size:1.22rem; letter-spacing:-.02em; }
p{ margin:0 0 1.1em; }
strong{ color:var(--head); font-weight:600; }
.hl{ color:var(--accent-ink); }

.sr{ position:absolute; width:1px; height:1px; padding:0; margin:-1px; overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0; }
.skip{ position:absolute; left:-9999px; top:0; z-index:100; background:var(--accent); color:var(--on-accent); padding:12px 18px; font-weight:600; }
.skip:focus{ left:12px; top:12px; }
:focus-visible{ outline:2px solid var(--accent); outline-offset:3px; border-radius:4px; }

.wrap{ width:100%; max-width:var(--wrap); margin:0 auto; padding-left:var(--pad); padding-right:var(--pad); }
.wrap--narrow{ max-width:780px; }

/* faint technical grid, used behind hero + contact */
.grid-bg{
  position:absolute; inset:0; z-index:0; pointer-events:none;
  background-image:
    linear-gradient(to right, var(--grid) 1px, transparent 1px),
    linear-gradient(to bottom, var(--grid) 1px, transparent 1px);
  background-size:72px 72px;
  -webkit-mask-image:radial-gradient(ellipse 90% 70% at 50% 0%, #000 25%, transparent 78%);
          mask-image:radial-gradient(ellipse 90% 70% at 50% 0%, #000 25%, transparent 78%);
}

/* ── buttons ───────────────────────────────────────────── */
.btn{
  display:inline-flex; align-items:center; justify-content:center; gap:.5em;
  background:var(--accent); color:var(--on-accent);
  font:600 15.5px/1 var(--sans); letter-spacing:.01em;
  padding:15px 24px; border:0; border-radius:8px;
  text-decoration:none; cursor:pointer; white-space:nowrap;
  box-shadow:0 0 0 1px rgba(var(--accent-rgb),.4), 0 10px 30px -12px rgba(var(--accent-rgb),.6);
  transition:transform .16s ease, box-shadow .16s ease, background .16s ease;
}
.btn:hover{ background:var(--accent-hi); transform:translateY(-2px); box-shadow:0 0 0 1px rgba(var(--accent-rgb),.6), 0 16px 34px -14px rgba(var(--accent-rgb),.8); }
.btn:active{ transform:translateY(0); }
.btn:disabled{ opacity:.6; cursor:default; transform:none; }
.btn--sm{ padding:10px 18px; font-size:14.5px; }
.btn--full{ width:100%; padding:17px; font-size:16px; }
.btn--ghost{ background:transparent; color:var(--head); border:1px solid var(--line-2); box-shadow:none; }
.btn--ghost:hover{ background:var(--surf-2); border-color:var(--accent); color:var(--accent-ink); }

/* ── nav ───────────────────────────────────────────────── */
.nav{
  position:sticky; top:0; z-index:50;
  background:var(--nav-bg);
  backdrop-filter:saturate(150%) blur(14px);
  -webkit-backdrop-filter:saturate(150%) blur(14px);
  border-bottom:1px solid transparent;
  transition:border-color .25s ease;
}
.nav.is-stuck{ border-bottom-color:var(--line); }
.nav__inner{ display:flex; align-items:center; justify-content:space-between; min-height:68px; gap:20px; }

/* min-height so the whole lockup is a 44px target -- it was 145x30, and
   it is the way back to the home page from every other page. */
.brand{ display:inline-flex; align-items:center; gap:11px; text-decoration:none; color:var(--head);
        min-height:44px; }
.brand__mark{ width:30px; height:30px; flex:0 0 auto; }
.brand__frame{ fill:none; stroke:var(--accent-ink); stroke-width:2.3; stroke-linecap:round; stroke-linejoin:round; }
.brand__dot{ fill:var(--accent); }
.brand:hover .brand__dot{ fill:var(--accent-hi); }
.brand__text{ display:flex; flex-direction:column; line-height:1.05; }
.brand__name{ font-family:var(--display); font-weight:600; font-size:16.5px; letter-spacing:-.025em; }
.brand__sub{
  font-family:var(--mono); font-size:9.5px; font-weight:400;
  letter-spacing:.24em; text-transform:uppercase; color:var(--muted); margin-top:3px;
}

.nav__links{ display:flex; align-items:center; gap:26px; }
.nav__links a{ text-decoration:none; font-size:14.5px; font-weight:500; font-family:var(--mono); }
/* Colour is set separately and excludes .btn. ".nav__links a" out-specifies
   ".btn" (0,1,1 against 0,1,0), so a colour here would win over the button's
   own --on-accent and paint body text onto the accent fill. That was
   invisible while the accent was gold and both colours were dark; the
   moment --on-accent went white the nav button became unreadable. */
.nav__links a:not(.btn){ color:var(--text); }
.nav__links a:not(.btn):hover{ color:var(--accent-ink); }
/* the phone sits between the links and the CTA: findable without competing
   with it, and it is the whole point that it looks tappable on a phone */
/* The phone number used to live in this bar, in two copies -- one in the
   menu for desktop, one beside the toggle for phones. Both are gone. The
   number is in the footer, the contact section and the schema, which is
   where Google reads it from; at the top it only turned enquiries into
   cold calls, and an enquiry arrives written down.
   The toggle stays right-aligned on its own: .nav__inner is
   space-between, and .nav__links is out of flow on mobile, so brand and
   toggle are the only two children left to space apart. */
@media (max-width:900px){
  /* the brand must not wrap */
  .brand__name, .brand__sub{ white-space:nowrap; }
}
.nav__toggle{ display:none; background:none; border:0; padding:10px; cursor:pointer; }
.bars i{ display:block; width:22px; height:2px; background:var(--head); border-radius:2px; margin:5px 0; transition:transform .25s ease, opacity .2s ease; }
.nav.is-open .bars i:nth-child(1){ transform:translateY(7px) rotate(45deg); }
.nav.is-open .bars i:nth-child(2){ opacity:0; }
.nav.is-open .bars i:nth-child(3){ transform:translateY(-7px) rotate(-45deg); }

@media (max-width:920px){
  .nav__toggle{ display:block; }
  .nav__links{
    position:absolute; left:0; right:0; top:100%;
    flex-direction:column; align-items:stretch; gap:0;
    background:var(--bg-2); border-bottom:1px solid var(--line);
    padding:8px var(--pad) 22px; display:none;
  }
  .nav.is-open .nav__links{ display:flex; }
  .nav__links a{ padding:14px 0; border-bottom:1px solid var(--line); font-size:16px; }
  .nav__links .btn{ margin-top:18px; border-bottom:0; justify-content:center; }
}

/* ── hero ──────────────────────────────────────────────── */
.hero{ position:relative; padding:clamp(56px,8vw,104px) 0 clamp(60px,8vw,96px); overflow:hidden; }
.hero__glow{
  position:absolute; z-index:0; top:-320px; left:50%; transform:translateX(-50%);
  width:1100px; height:760px; pointer-events:none;
  background:radial-gradient(ellipse at center, rgba(var(--accent-rgb),.16), rgba(110,139,255,.08) 42%, transparent 70%);
}
.hero__inner{ position:relative; z-index:2; display:grid; grid-template-columns:1.05fr .95fr; gap:56px; align-items:center; }
@media (max-width:1000px){ .hero__inner{ grid-template-columns:1fr; gap:44px; } }
/* grid children default to min-width:auto, which lets the pre-formatted
   terminal push the whole page wider than the viewport. Pin them. */
.hero__inner > *, .split > *, .cards > *, .tiers > *, .work > *{ min-width:0; }

.status{
  display:inline-flex; align-items:center; gap:9px;
  font-family:var(--mono); font-size:12.5px; letter-spacing:.02em; color:var(--head);
  background:linear-gradient(rgba(var(--signal-rgb),.08), rgba(var(--signal-rgb),.08)), var(--surf);
  border:1px solid rgba(var(--signal-rgb),.45); border-radius:999px;
  padding:7px 15px 7px 12px; margin:0 0 26px;
}
.dot{
  --pulse-rgb:var(--signal-rgb);
  width:7px; height:7px; border-radius:50%; flex:0 0 auto;
  background:rgb(var(--pulse-rgb));
  animation:pulse 2.8s ease-out infinite;
}
/* "all systems operational" is a passing check, not branding */
.dot--ok{ --pulse-rgb:var(--ok-rgb); }
@keyframes pulse{ 0%{box-shadow:0 0 0 0 rgba(var(--pulse-rgb),.5);} 70%{box-shadow:0 0 0 8px rgba(var(--pulse-rgb),0);} 100%{box-shadow:0 0 0 0 rgba(var(--pulse-rgb),0);} }
@media (prefers-reduced-motion: reduce){ .dot{ animation:none; } }

.hero h1{ margin-bottom:.4em; }
.lede{ font-size:clamp(1.03rem,1.7vw,1.18rem); line-height:1.6; max-width:38em; color:var(--text); }
.hero__cta{ display:flex; flex-wrap:wrap; gap:13px; margin:32px 0 0; }
/* the third path, as a line under the two buttons rather than a third
   button -- three buttons is a menu, and this one is for the person who
   would rather talk before typing */
.hero__alt{ flex:0 0 100%; margin-top:4px; font-size:14.5px; color:var(--accent-ink); text-decoration:none; }
.hero__alt:hover, .hero__alt:focus-visible{ text-decoration:underline; }
.hero__facts{
  list-style:none; padding:26px 0 0; margin:44px 0 0;
  display:grid; grid-template-columns:repeat(3,1fr); gap:20px;
  border-top:1px solid var(--line);
}
.hero__facts strong{ display:block; font-family:var(--mono); font-size:1.22rem; color:var(--head); letter-spacing:-.02em; }
.hero__facts strong em{ font-style:normal; font-size:.7em; color:var(--muted); }
.hero__facts span{ font-family:var(--mono); font-size:12px; color:var(--muted); letter-spacing:.03em; }
@media (max-width:560px){ .hero__facts{ grid-template-columns:1fr; gap:14px; } }

/* terminal */
.term{
  min-width:0;
  background:var(--term-bg); border:1px solid var(--term-line); border-radius:var(--r);
  overflow:hidden; background:var(--term-bg); box-shadow:0 40px 80px -40px rgba(0,0,0,.5), 0 0 0 1px rgba(var(--accent-rgb),.06);
}
.term__bar{ display:flex; align-items:center; gap:7px; padding:12px 14px; border-bottom:1px solid var(--term-line); background:var(--term-raise); }
.term__bar span{ width:10px; height:10px; border-radius:50%; background:var(--line-2); }
.term__bar span:first-child{ background:#FF5F57; }
.term__bar span:nth-child(2){ background:#FEBC2E; }
.term__bar span:nth-child(3){ background:#28C840; }
.term__bar p{ margin:0 0 0 10px; font-family:var(--mono); font-size:11.5px; color:var(--term-dim); }
.term__body{ margin:0; padding:20px 18px 22px; overflow-x:auto; }
.term__body code{ font-family:var(--mono); font-size:12.6px; line-height:1.95; color:var(--term-fg); white-space:pre; }
.c-dim{ color:var(--term-dim); }
.c-key{ color:#6FA0FF; }
.c-ok{ color:#3DD68C; }
.c-bad{ color:#FF7B72; }
.c-warn{ color:#E3B85A; }
@media (max-width:420px){ .term__body code{ font-size:11.4px; } }

/* ── credibility strip ─────────────────────────────────── */
.strip{ border-top:1px solid var(--line); border-bottom:1px solid var(--line); background:var(--bg-2); }
.strip__inner{ display:flex; align-items:center; gap:34px; flex-wrap:wrap; padding-top:22px; padding-bottom:22px; }
.strip__label{ margin:0; font-family:var(--mono); font-size:11.5px; letter-spacing:.16em; text-transform:uppercase; color:var(--muted); }
.strip__list{ display:flex; flex-wrap:wrap; gap:14px 34px; list-style:none; margin:0; padding:0; }
.strip__list li{ font-family:var(--display); font-size:1.05rem; font-weight:500; color:var(--head); opacity:.72; }

/* ── sections ──────────────────────────────────────────── */
.section{ position:relative; padding:clamp(64px,8.5vw,112px) 0; }
.section--panel{ background:var(--bg-2); border-top:1px solid var(--line); border-bottom:1px solid var(--line); }

/* Dark band. NOT USED on the page right now -- the design is light
   throughout by choice. Kept because it costs nothing and it is one class
   on one <section> away: every component reads its colours from tokens,
   so redefining them here is the entire theme switch. */
.section--dark{
  --ok:#3DD68C; --ok-rgb:61,214,140;
  --flag:#F19ACB; --flag-bg:rgba(241,154,203,.16);
  --bg:#0B1120; --bg-2:#0B1120; --surf:#131B2E; --surf-2:#1B2438;
  --text:#B4BECD; --head:#F4F6F9; --muted:#7C8798;
  --line:rgba(255,255,255,.11); --line-2:rgba(255,255,255,.19);
  --grid:rgba(255,255,255,.055); --raise:rgba(255,255,255,.025);
  --shadow:0 24px 60px -34px rgba(0,0,0,.9);
  /* on navy the blue lifts to 7.3:1, and text and fill converge */
  --accent:#6FA0FF; --accent-rgb:111,160,255; --accent-hi:#8AB4FF;
  --accent-ink:#6FA0FF; --on-accent:#04122E;
  --signal:#F0B27A; --signal-rgb:240,178,122;
  --accent-2:#B48CF5;
  background:var(--bg); color:var(--text);
  border-top:1px solid rgba(255,255,255,.08); border-bottom:1px solid rgba(255,255,255,.08);
}
.eyebrow{
  font-family:var(--mono); font-size:12px; font-weight:500;
  letter-spacing:.16em; text-transform:uppercase; color:var(--accent-ink); margin:0 0 16px;
}
.section__lede{ font-size:1.06rem; max-width:47em; margin-bottom:48px; color:var(--text); }

/* ── cards ─────────────────────────────────────────────── */
.cards{ display:grid; gap:18px; }
.cards--3{ grid-template-columns:repeat(3,1fr); }
@media (max-width:920px){ .cards--3{ grid-template-columns:1fr 1fr; } }
@media (max-width:640px){ .cards--3{ grid-template-columns:1fr; } }

.card{
  position:relative; background:var(--surf); border:1px solid var(--line);
  border-radius:var(--r); padding:28px 26px;
  transition:border-color .2s ease, transform .2s ease, background .2s ease;
}
.card:hover{ border-color:var(--line-2); background:var(--surf-2); transform:translateY(-3px); box-shadow:var(--shadow); }
.card p:last-child,.card ul:last-child{ margin-bottom:0; }
.card--feature{ border-color:rgba(var(--accent-rgb),.45); }
.card__ix{ display:block; font-family:var(--mono); font-size:11.5px; letter-spacing:.14em; color:var(--accent-ink); margin-bottom:14px; }
.card__sub{ font-family:var(--mono); font-size:12.5px; color:var(--muted); margin:-4px 0 16px; }
/* The plan price. Larger than .tier__band because on the build tiers the
   number is a range you have to qualify for, and here it is the actual
   figure you pay -- the thing somebody came to this section to find.
   Selector is .card .card__price, not .card__price: `.card p` below sets a
   font-size and, being a class plus an element, outranks a bare class. */
.card .card__price{ font-family:var(--mono); font-size:1.75rem; color:var(--head);
  line-height:1; margin:2px 0 12px; letter-spacing:-.02em; }
.card .card__price span{ font-size:.78rem; color:var(--muted); letter-spacing:.02em; }
.card__flag,.tier__flag{
  position:absolute; top:-10px; left:24px;
  background:var(--accent); color:var(--on-accent);
  font-family:var(--mono); font-size:10.5px; font-weight:700; letter-spacing:.1em; text-transform:uppercase;
  padding:5px 11px; border-radius:5px;
}
.card h3{ font-size:1.15rem; }
.card p{ font-size:15.3px; }

/* ── run / ops split ───────────────────────────────────── */
.split{ display:grid; grid-template-columns:1.15fr .85fr; gap:34px; align-items:start; }
@media (max-width:920px){ .split{ grid-template-columns:1fr; } }

.ops{ list-style:none; margin:0; padding:0; border-top:1px solid var(--line); }
.ops li{ display:grid; grid-template-columns:132px 1fr; gap:18px; padding:18px 0; border-bottom:1px solid var(--line); }
@media (max-width:560px){ .ops li{ grid-template-columns:1fr; gap:5px; } }
.ops__k{ font-family:var(--mono); font-size:12.5px; letter-spacing:.06em; color:var(--accent-ink); padding-top:3px; }
.ops__v{ font-size:15.4px; }

.panel{ background:var(--surf); border:1px solid var(--line); border-radius:var(--r); overflow:hidden; box-shadow:var(--shadow); }
.panel__head{ display:flex; align-items:center; gap:9px; padding:14px 20px; border-bottom:1px solid var(--line); background:var(--raise); }
.panel__head p{ margin:0; font-family:var(--mono); font-size:12px; letter-spacing:.05em; color:var(--muted); }
/* commitments, not measurements -- the panel states what the plan
   obliges us to do, so nothing here needs a number to back it up */
.commit{ list-style:none; margin:0; padding:6px 20px; }
.commit li{ padding:15px 0; border-bottom:1px solid var(--line); }
.commit li:last-child{ border-bottom:0; }
.commit strong{ display:block; font-size:15.5px; margin-bottom:3px; }
.commit span{ font-size:14.3px; color:var(--muted); line-height:1.55; }

.metrics{ margin:0; padding:6px 20px; }
.metrics div{ display:flex; align-items:baseline; justify-content:space-between; gap:14px; padding:16px 0; border-bottom:1px solid var(--line); }
.metrics dt{ font-size:13.6px; color:var(--muted); font-family:var(--mono); letter-spacing:.01em; }
.metrics dd{ margin:0; font-family:var(--mono); font-size:1.5rem; font-weight:700; color:var(--head); letter-spacing:-.03em; }
.metrics dd em{ font-style:normal; font-size:.62em; color:var(--accent); }
.panel__foot{ margin:0; padding:18px 20px 20px; font-size:13.8px; color:var(--muted); }

/* ── tiers ─────────────────────────────────────────────── */
/* stretch, not start: the three tiers hold different numbers of lines, so
   align-items:start left them ending at 603, 750 and 694px -- three
   different bottom edges on the one row a visitor is comparing across.
   Stretching them and pushing the duration down with margin-top:auto puts
   every "2-3 weeks" on the same line. */
/* The One Page entry tier. A wide band above the grid rather than a
   fourth column: it is a different product with a scope wall, not a
   cheaper Launch, and a card beside the other three reads as the latter.
   A whole-block link, so the tap target on a phone is the band. */
.entry{ display:flex; flex-wrap:wrap; align-items:center; gap:14px 22px;
        margin:0 0 18px; padding:20px 24px; text-decoration:none;
        background:var(--surf); border:1px solid var(--line); border-radius:var(--r);
        border-left:3px solid var(--accent); transition:border-color .2s ease, transform .2s ease; }
.entry:hover, .entry:focus-visible{ border-color:rgba(var(--accent-rgb),.5); transform:translateY(-1px); }
.entry__k{ font-family:var(--mono); font-size:11.5px; letter-spacing:.14em; color:var(--muted); }
.entry__body{ flex:1 1 320px; }
.entry__h{ display:block; font-size:1.15rem; color:var(--head); margin-bottom:5px; }
.entry__for{ display:block; color:var(--muted); font-size:14.8px; line-height:1.55; }
.entry__go{ font-family:var(--mono); font-size:12.5px; color:var(--accent-ink); white-space:nowrap; }
@media (max-width:640px){ .entry__k{ display:none; } }

.tiers{ display:grid; grid-template-columns:repeat(3,1fr); gap:18px; align-items:stretch; }
@media (max-width:980px){ .tiers{ grid-template-columns:1fr; } }
.tier{ position:relative; background:var(--surf); border:1px solid var(--line); border-radius:var(--r);
  padding:30px 26px 26px; display:flex; flex-direction:column; }
.tier--feature{ border-color:rgba(var(--accent-rgb),.45); box-shadow:0 0 0 1px rgba(var(--accent-rgb),.12), 0 30px 60px -34px rgba(var(--accent-rgb),.45); }
.tier__flag{ left:26px; }
.tier__k{ font-family:var(--mono); font-size:11.5px; letter-spacing:.14em; color:var(--muted); margin:0 0 10px; }
.tier h3{ font-size:1.45rem; margin-bottom:10px; }
.tier__band{
  font-family:var(--mono); font-size:12.5px; color:var(--accent-ink);
  letter-spacing:.02em; margin:-6px 0 12px;
}
.tier__for{ color:var(--muted); font-size:14.8px; line-height:1.55; min-height:4.4em; margin-bottom:20px; padding-bottom:20px; border-bottom:1px solid var(--line); }
@media (max-width:980px){ .tier__for{ min-height:0; } }
.tier__time{ margin:22px 0 0; margin-top:auto; padding-top:16px; border-top:1px solid var(--line); font-family:var(--mono); font-size:13px; color:var(--accent-ink); letter-spacing:.05em; }

.ticks{ list-style:none; padding:0; margin:0; }
.ticks li{ position:relative; padding:0 0 11px 26px; font-size:15.2px; line-height:1.5; }
.ticks li::before{
  content:""; position:absolute; left:2px; top:.42em;
  width:10px; height:5.5px; border-left:2px solid var(--accent-ink); border-bottom:2px solid var(--accent-ink);
  transform:rotate(-45deg);
}
.ticks--tight li{ padding-bottom:9px; font-size:14.8px; }

.price-line{
  margin:40px 0 0; padding:24px 28px;
  background:var(--surf); border:1px solid var(--line); border-left:2px solid var(--accent);
  border-radius:var(--r);
  /* grid, not flex-wrap: the button belongs beside the text, and wrapping
     it onto its own line left a dead band of white across the callout */
  display:grid; grid-template-columns:1fr auto; align-items:center; gap:24px;
}
.price-line p{ margin:0; font-size:1rem; max-width:62ch; }
@media (max-width:760px){
  .price-line{ grid-template-columns:1fr; gap:18px; }
  .price-line .btn{ justify-self:start; }
}

.managed{ margin-top:clamp(56px,7vw,88px); padding-top:clamp(40px,5vw,56px); border-top:1px solid var(--line); }
.managed__h{ font-size:clamp(1.4rem,2.6vw,1.9rem); margin-bottom:8px; }
.managed__lede{ color:var(--muted); font-size:15.4px; margin-bottom:32px; max-width:52em; }

/* ── work ──────────────────────────────────────────────── */
/* auto-fit, not a hardcoded two. A third project in a two-column grid
   leaves an orphan on its own row -- the same ragged shape the dashboard
   used to open with. This fills whatever the row can take and needs no
   edit the next time one is added. */
.work{ display:grid; grid-template-columns:repeat(auto-fit,minmax(290px,1fr));
  gap:34px 28px; margin-top:40px; }
@media (max-width:820px){ .work{ grid-template-columns:1fr; gap:34px; } }
.proj__shot{
  display:flex; align-items:center; justify-content:center;
  aspect-ratio:16/9; border-radius:var(--r); text-decoration:none; overflow:hidden;
  border:1px solid var(--line);
  transition:transform .28s ease, border-color .28s ease;
}
.proj__shot:hover{ transform:translateY(-4px); border-color:rgba(var(--accent-rgb),.6); box-shadow:var(--shadow); }
.proj__shot--a{ background:linear-gradient(135deg,#1E3A6E,#131B2E 74%); }
.proj__shot--b{ background:linear-gradient(135deg,#242C3D,#0C1420 74%); }
.proj__shot--c{ background:linear-gradient(135deg,#2A3550,#141A28 74%); }
.proj__meta{ padding-top:16px; }
.proj__meta h3{ font-size:1.12rem; margin-bottom:6px; }
.proj__type{ font-family:var(--mono); font-size:12px; letter-spacing:.08em; color:var(--accent-ink); margin-bottom:9px; }
.proj__meta p{ font-size:14.8px; margin-bottom:10px; }
.tag{
  font-family:var(--mono); font-style:normal; font-size:10.5px; font-weight:500;
  letter-spacing:.1em; text-transform:uppercase; color:var(--accent-2);
  border:1px solid rgba(110,139,255,.4); border-radius:4px; padding:3px 7px;
  vertical-align:middle; margin-left:7px;
}

/* ── process ───────────────────────────────────────────── */
.steps{ list-style:none; padding:0; margin:44px 0 0; display:grid; grid-template-columns:repeat(4,1fr); gap:28px; }
@media (max-width:920px){ .steps{ grid-template-columns:1fr 1fr; gap:32px; } }
@media (max-width:560px){ .steps{ grid-template-columns:1fr; } }
.steps li{ padding-top:20px; border-top:1px solid var(--line-2); }
.steps__n{ display:block; font-family:var(--mono); font-size:12px; letter-spacing:.16em; color:var(--accent-ink); margin-bottom:14px; }
.steps h3{ margin-bottom:8px; }
.steps p{ margin:0; font-size:15.2px; }

/* ── faq ───────────────────────────────────────────────── */
.faq{ margin-top:40px; border-top:1px solid var(--line); }
.faq details{ border-bottom:1px solid var(--line); }
.faq summary{
  cursor:pointer; list-style:none; padding:20px 44px 20px 0; position:relative;
  font-family:var(--display); font-size:1.1rem; font-weight:500; color:var(--head);
}
.faq summary::-webkit-details-marker{ display:none; }
.faq summary:hover{ color:var(--accent-ink); }
.faq summary::after{
  content:""; position:absolute; right:8px; top:50%; width:10px; height:10px; margin-top:-8px;
  border-right:2px solid var(--accent); border-bottom:2px solid var(--accent);
  transform:rotate(45deg); transition:transform .25s ease;
}
.faq details[open] summary::after{ transform:rotate(-135deg); margin-top:-3px; }
.faq details p{ margin:0 0 22px; padding-right:20px; max-width:64ch; font-size:15.4px; }

/* ── contact ───────────────────────────────────────────── */
.section--start{ overflow:hidden; }
.section--start .grid-bg{ opacity:.6; }
.section--start .wrap{ position:relative; z-index:2; }
.form{
  display:grid; grid-template-columns:1fr 1fr; gap:16px;
  background:var(--surf); border:1px solid var(--line); border-radius:var(--r); padding:30px;
  box-shadow:var(--shadow);
}
@media (max-width:640px){ .form{ grid-template-columns:1fr; padding:22px; } }
.field{ display:flex; flex-direction:column; gap:7px; }
.field--full{ grid-column:1/-1; }
.form label{ font-family:var(--mono); font-size:12.5px; letter-spacing:.05em; color:var(--text); }
.opt{ color:var(--muted); }
.form input,.form textarea,.form select{
  font:inherit; font-size:16px; color:var(--head);
  background:var(--bg); border:1px solid var(--line-2); border-radius:8px;
  padding:13px 14px; width:100%;
  transition:border-color .16s ease, box-shadow .16s ease;
}
.form textarea{ resize:vertical; }
/* rows="5" reads well on a desktop and costs the submit button its place
   on a phone. With the keyboard up the viewport is about 464px, and
   measured at 390x844, "Request a quote" sat 35px below the fold once the
   message box was focused -- you type the enquiry and the button you need
   is not on screen. Shorter here only; it is still resizable, and .form is
   used by this one form. */
@media (max-width:600px){
  .form textarea{ height:5.5em; min-height:0; }
}
.form select{ appearance:none; background-image:linear-gradient(45deg,transparent 50%,var(--accent) 50%),linear-gradient(135deg,var(--accent) 50%,transparent 50%); background-position:calc(100% - 20px) 21px,calc(100% - 14px) 21px; background-size:6px 6px; background-repeat:no-repeat; }
.form select option{ background:var(--bg); color:var(--head); }
.form input::placeholder,.form textarea::placeholder{ color:#586376; }
.form input:focus,.form textarea:focus,.form select:focus{ border-color:var(--accent); box-shadow:0 0 0 3px rgba(var(--accent-rgb),.14); outline:none; }
/* Room for the submit button when the on-screen keyboard is up.
   Tapping the last field scrolls it into view, and on a 390x844 phone the
   keyboard leaves about 464px: measured, the message box landed with
   "Request a quote" 26px below the fold, so you typed your enquiry and
   the button you needed was not on screen. scroll-margin-bottom makes the
   browser scroll that much further, which brings the button up with the
   field. Measured against a real 464px viewport, not a guess at one --
   the same check run on book.php and start.php showed their buttons
   already visible, so this rule is here for the length of THIS form. */
.form input,.form textarea,.form select{ scroll-margin-bottom:96px; }
.form .btn{ grid-column:1/-1; }
.hp{ position:absolute; left:-9999px; opacity:0; height:0; width:0; }
.form__alt{
  grid-column:1/-1; margin:0; text-align:center;
  font-size:14px; color:var(--muted); line-height:1.55;
}
.form__alt a{ color:var(--accent-ink); font-weight:600; }

.form__note{ grid-column:1/-1; margin:0; font-family:var(--mono); font-size:13px; color:var(--muted); text-align:center; }
.form__note a{ color:var(--accent-ink); }
.form__hours{ margin-top:6px; font-size:13px; color:var(--muted); text-align:center; }
.form__status{ grid-column:1/-1; margin:0; font-family:var(--mono); font-size:13.5px; text-align:center; color:var(--accent-ink); }

/* ── footer ────────────────────────────────────────────── */
.foot{ padding:52px 0 30px; background:var(--bg-2); border-top:1px solid var(--line); }
.foot__inner{ display:flex; justify-content:space-between; align-items:flex-start; gap:30px; flex-wrap:wrap; }
.foot__tag{ margin:12px 0 0; font-size:15px; color:var(--muted); }
.foot__links{ display:flex; flex-wrap:wrap; gap:8px 26px; }
.foot__links a{ text-decoration:none; font-family:var(--mono); font-size:13.5px; color:var(--muted); }
.foot__links a:hover{ color:var(--accent-ink); }
/* Footer links are standalone tap targets, not links inside a sentence,
   so on a phone they get real vertical room rather than the 23px a bare
   13.5px line box gives them. The negative margin keeps the row looking
   the same -- the padding is hit area, not layout. */
@media (max-width:640px){
  .foot__links{ gap:2px 26px; }
  .foot__links a{ display:inline-block; padding:10px 0; margin:-4px 0; }
}
.foot__base{
  display:flex; justify-content:space-between; gap:16px; flex-wrap:wrap;
  margin-top:40px; padding-top:20px; border-top:1px solid var(--line);
  font-family:var(--mono); font-size:12px; color:var(--muted);
}
.foot__base p{ margin:0; display:flex; align-items:center; gap:8px; }

/* ── unfinished content ────────────────────────────────────
   Anything still carrying real placeholder copy is marked
   [data-placeholder]. It is deliberately loud: this content
   must never reach a client by accident. Remove the attribute
   when the real words go in, and the warning disappears.     */
[data-placeholder]{ position:relative; }
[data-placeholder]::after{
  content:"placeholder";
  position:absolute; top:10px; right:10px; z-index:2;
  font-family:var(--mono); font-size:9.5px; font-weight:500;
  letter-spacing:.12em; text-transform:uppercase;
  color:var(--flag); background:var(--flag-bg);
  border:1px solid var(--flag); border-radius:4px;
  padding:3px 7px; pointer-events:none;
}
.proj__result[data-placeholder]::after{ top:-2px; right:0; }

/* ── proof / testimonials ──────────────────────────────── */
/* ── about ─────────────────────────────────────────────── */
/* ── assurances ────────────────────────────────────────── */
.assure{
  list-style:none; display:grid; grid-template-columns:repeat(3,1fr);
  gap:2px 34px; margin:34px 0 0; padding:26px 0 0; border-top:1px solid var(--line);
}
@media (max-width:840px){ .assure{ grid-template-columns:1fr; gap:20px; } }
.assure li{ position:relative; padding-left:28px; }
.assure li::before{
  content:""; position:absolute; left:1px; top:.42em;
  width:11px; height:6px; border-left:2px solid var(--ok); border-bottom:2px solid var(--ok);
  transform:rotate(-45deg);
}
.assure strong{ display:block; font-size:15.5px; margin-bottom:3px; }
.assure span{ font-size:14.5px; color:var(--muted); line-height:1.55; }

/* ── How the price gets paid ──
   Two cards of equal weight. Neither is styled as the recommended one:
   the recommendation belongs in the conversation, and a highlighted
   "spread it" card reads as a nudge toward financing. */
.pay{ margin:40px 0 0; padding:32px 0 0; border-top:1px solid var(--line); }
.pay__head h3{ font-size:clamp(1.25rem,2.2vw,1.55rem); margin:0 0 6px; }
.pay__head p{ color:var(--muted); font-size:15.2px; margin:0 0 22px; max-width:52em; }
.pay__opts{ display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:18px; }
@media (max-width:720px){ .pay__opts{ grid-template-columns:1fr; } }
.pay__opt{ background:var(--surf); border:1px solid var(--line); border-radius:var(--r); padding:22px 24px; min-width:0; }
.pay__opt h4{ font-size:1.2rem; margin:2px 0 14px; }
.pay__lines{ display:grid; grid-template-columns:auto 1fr; gap:7px 18px; margin:0 0 16px; font-size:14.6px; }
.pay__lines dt{ color:var(--muted); white-space:nowrap; }
.pay__lines dd{ margin:0; color:var(--text); }
.pay__eg{ font-size:14.6px; margin:0; padding-top:14px; border-top:1px solid var(--line); color:var(--muted); }
.pay__eg strong{ font-family:var(--mono); color:var(--head); font-weight:500; }
.pay__fine{ font-size:14px; color:var(--muted); line-height:1.6; margin:18px 0 0; max-width:66em; }
.managed__fine{ font-size:14px; color:var(--muted); line-height:1.6; margin:22px 0 0; max-width:66em; }

/* ── work: results line, and screenshots when they exist ── */
.proj__url{
  display:inline-block; font-family:var(--mono); font-size:12.5px;
  color:var(--accent-ink); text-decoration:none; letter-spacing:.01em;
  border-bottom:1px solid rgba(var(--accent-rgb),.35); padding-bottom:1px;
}
.proj__url:hover{ border-bottom-color:var(--accent); }
/* the tile is a little browser window: chrome bar, then the page itself.
   The thumbnail sits above the gradient, so if it fails to load the
   label underneath shows through instead of an empty box. */
.proj__shot{ position:relative; display:block; padding:0; }
.proj__chrome{
  position:absolute; inset:0 0 auto 0; z-index:3; height:26px;
  display:flex; align-items:center; gap:5px; padding:0 10px;
  background:#1B2333; border-radius:var(--r) var(--r) 0 0;
}
.proj__chrome i{ width:7px; height:7px; border-radius:50%; background:rgba(255,255,255,.28); }
.proj__chrome b{
  margin-left:8px; font-family:var(--mono); font-size:10px; font-weight:400;
  color:rgba(255,255,255,.55); letter-spacing:.02em; overflow:hidden; white-space:nowrap;
}
/* The real screenshot. A background-image rather than an <img> on purpose:
   if the file is missing it simply paints nothing and the fallback label
   below shows through instead of a broken-image icon.

   Real <img> elements, not CSS backgrounds. They were backgrounds and
   marked aria-hidden as decoration, which is a defensible accessibility
   call and the wrong one for search: this is the portfolio, the proof
   that the work exists, and Google cannot crawl a background-image at
   all. As <img> they carry alt text, can rank in image search, and their
   width/height stop the cards shifting as they load. */
.proj__img{
  position:absolute; inset:26px 0 0 0; z-index:2;
  width:100%; height:calc(100% - 26px);
  object-fit:cover; object-position:top center;
}
/* WebP, resized to 900px wide -- a shade over 2x the 414px slot these
   sit in. They were 1414x1062 and 1715x1053 PNGs, 2.02MB between them,
   on a page that sells sub-second loads and runs a speed checker on other
   people's sites. PNG is lossless, which is exactly why a photographic
   screenshot in it weighs megabytes. 63KB now. */

.proj__fallback{
  position:absolute; inset:26px 0 0 0; z-index:1;
  display:flex; align-items:center; justify-content:center;
  font-family:var(--mono); font-size:clamp(1rem,2vw,1.25rem); color:#F4F6F9;
}

/* ── contact: the reply promise ────────────────────────── */
.form__reply{
  grid-column:1/-1; margin:0; display:flex; align-items:center; justify-content:center; gap:9px;
  font-family:var(--mono); font-size:13px; color:var(--text);
}

/* ── reveal on scroll ──────────────────────────────────── */
.reveal{ opacity:0; transform:translateY(14px); transition:opacity .55s ease, transform .55s ease; }
.reveal.is-in{ opacity:1; transform:none; }
@media (prefers-reduced-motion: reduce){ .reveal{ opacity:1; transform:none; transition:none; } }

/* ------------------------------------------------------------ back to top
   The page is long on a phone and the footer is a long way from the
   contact form. Sits clear of the thumb's natural resting spot and only
   appears once there is something to go back to. */
.totop{
  position:fixed; right:16px; bottom:calc(16px + env(safe-area-inset-bottom, 0px));
  width:46px; height:46px; border-radius:50%; z-index:60;
  display:grid; place-items:center; cursor:pointer;
  background:var(--surf); color:var(--accent-ink);
  border:1px solid var(--line-2);
  box-shadow:0 2px 6px rgba(12,20,32,.10), 0 14px 30px -12px rgba(12,20,32,.28);
  opacity:0; transform:translateY(10px); pointer-events:none;
  transition:opacity .18s ease, transform .18s ease, border-color .18s ease;
}
.totop.is-in{ opacity:1; transform:none; pointer-events:auto; }
.totop:hover{ border-color:var(--accent); color:var(--accent); }
.totop:focus-visible{ outline:2px solid var(--accent); outline-offset:3px; }
@media (prefers-reduced-motion: reduce){ .totop{ transition:none; } }

/* A 23px-wide tap target is a miss more often than a hit. The icon-only
   phone button under 400px keeps its icon but not its width. */
@media (max-width:400px){
}

/* The offer sits under the example audit, because the thing directly above
   it is a picture of exactly what the visitor is being offered. */
.term__cta{ margin:0; padding:14px 18px; border-top:1px solid var(--term-line);
            background:var(--term-raise); font-size:13.5px; color:var(--term-dim);
            line-height:1.55; }
.term__cta a{ color:#7FB0FF; font-weight:500; }
.term__cta a:hover{ color:#fff; }

/* Replacing inline style attributes on the static pages, so the
   Content-Security-Policy can forbid them outright. */
.lead-lg{ font-size:1.1rem; }
.mt-32{ margin-top:32px; }
.mt-28{ margin-top:28px; }

/* The 404 page. These three rules were a <style> block in 404.html; CSP
   forbids inline style, so they live here. Scoped to the body class so
   they cannot leak onto any other page. */
.four-page{ display:flex; align-items:center; min-height:100vh; position:relative; }
.four{ position:relative; z-index:2; max-width:660px; }
.four pre{ font-family:var(--mono); font-size:13px; color:var(--muted);
  background:var(--surf); border:1px solid var(--line); border-radius:var(--r);
  padding:18px 20px; margin:0 0 30px; overflow-x:auto; }

/* The contact form needs JavaScript to fetch a CSRF token, so with it off
   the form is hidden and this stands in its place. Inside <noscript>, so
   it only ever exists in the case it describes. */
.form__noscript{ background:var(--surf); border:1px solid var(--signal);
  border-radius:var(--r); padding:16px 20px; font-size:15px; color:var(--text);
  margin:0 0 20px; }
.form__noscript a{ color:var(--accent-ink); }

/* ── Cookie consent ──────────────────────────────────────────────────
   Built by assets/js/consent.js. Dark card in every theme, bottom
   centre, one wide button. The X and Escape mean "essential only" --
   dismissing a question is not answering yes to it. */
.consent{ position:fixed; inset:auto 0 0 0; z-index:90; display:flex; justify-content:center;
          padding:0 16px 16px; pointer-events:none; }
.consent__card{ pointer-events:auto; position:relative; width:100%; max-width:460px;
                background:#131B2E; color:#E6EAF2; border:1px solid rgba(255,255,255,.12);
                border-radius:var(--r); padding:26px 26px 20px;
                box-shadow:0 24px 60px -20px rgba(0,0,0,.65); }
.consent__h{ margin:0 0 10px; font-size:17px; font-weight:600; text-align:center; color:#FFFFFF; }
.consent__p{ margin:0 0 18px; font-size:14px; line-height:1.55; color:#B8C0CE; }

.consent__accept{ display:block; width:100%; background:#FFFFFF; color:#0C1420;
                  border:1px solid rgba(255,255,255,.25); box-shadow:none; }
.consent__accept:hover{ background:#F1EFEA; color:#0C1420; box-shadow:none; }
/* 44px minimum on all three controls. These are the only way to answer
   the cookie question, and on a phone they measured 34x36 for the close
   and 80x22 for "Essential only" -- the two that mean "no". */
.consent__x{ position:absolute; top:4px; right:6px; background:none; border:0; color:#FFFFFF;
             font-size:24px; line-height:1; cursor:pointer; padding:6px 10px; border-radius:8px;
             display:flex; align-items:center; justify-content:center;
             min-width:44px; min-height:44px; }
.consent__x:hover{ background:rgba(255,255,255,.08); }
.consent__links{ margin:14px 0 0; text-align:center; font-size:13px; color:#B8C0CE; }
.consent__links a, .consent__link{ color:#FFFFFF; text-decoration:underline; background:none;
                                   border:0; font:inherit; cursor:pointer;
                                   display:inline-flex; align-items:center;
                                   min-height:44px; padding:0 4px; }
.consent__links a:hover, .consent__link:hover{ color:#B8C0CE; }
@media (prefers-reduced-motion:no-preference){
  .consent__card{ animation:consentIn .35s ease both; }
}
@keyframes consentIn{ from{ opacity:0; transform:translateY(14px); } to{ opacity:1; transform:none; } }
