/* ==========================================================================
   Keep Clean Multiservice — "Obra"
   A one-page site dressed for the jobsite: hi-vis
   yellow as the action colour on near-black, warm concrete greys as the
   neutral, thick borders instead of soft shadows, and monospaced tags the way
   equipment plates and spec sheets are set.
   Style reference only — no third-party marks, wordmarks or trade dress.
   ========================================================================== */

:root{
  --hi:#ffc61e;          /* hi-vis / safety yellow */
  --hi-dark:#e3a90a;
  --hi-soft:#fff4d1;

  --ink-rgb:20 20 20;          /* every alpha variant derives from this */
  --ink:rgb(var(--ink-rgb));
  --ink-2:#3d3b38;
  --muted:#423e36;

  /* The light side of the site is matte concrete, not paper. #D1D1CD is the
     base the client picked; everything else is a step up or down from it, so
     plates still lift off the ground and wells still sink into it. Anchoring
     the scale here forced --muted darker: on white it cleared 4.5:1 at
     #6e6a64, on this ground it did not. */
  --paper-rgb:209 209 205;
  --paper:rgb(var(--paper-rgb));   /* #D1D1CD */
  --plate:#dededa;                 /* a step up: cards, panels, focused fields */
  --band:#c6c6c1;                  /* the soft section band: a slab in shade */
  --concrete:#c4c4bf;              /* wells and hovers, a step below the page */
  --concrete-2:#b7b7b1;
  --line:#adada6;
  --line-2:#c1c1ba;
  --bg:var(--paper);

  /* The ground is the face of one of the client's concrete panels, and only
     the face: no joints, no tie holes. tools/concrete.mjs cuts it out and
     removes everything larger than about 60px before wrapping its edges into
     each other -- what gives a tiled photograph away is a blotch you
     recognise repeating, not its grain. With nothing large-scale left, the
     tone is free, so the tile is centred on 209: #D1D1CD, the matte light
     concrete of the original brief. The colour lives in the file, so there
     is no blend mode. */
  --grain:url("/assets/img/concrete.webp");
  --grain-size:600px 503px;

  --maple:#a31621;

  --r:4px;
  --wrap:1200px;
  --gut:clamp(20px,5vw,44px);
  --sec:clamp(60px,7.5vw,110px);

  --sans:"Archivo",system-ui,-apple-system,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
  --mono:"IBM Plex Mono",ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
}

/* Self-hosted. Through Google Fonts the files arrived on a third connection,
   late enough on a slow link that the swap reflowed the hero and pushed CLS
   to 0.09. Served from our own origin and preloaded, they land with the CSS.
   Archivo is variable across 400-800, so two files cover every weight. */
@font-face{font-family:'Archivo';font-style:normal;font-weight:400 800;font-display:swap;
  src:url('/assets/fonts/archivo-400-800-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF}
@font-face{font-family:'Archivo';font-style:normal;font-weight:400 800;font-display:swap;
  src:url('/assets/fonts/archivo-400-800-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:400;font-display:swap;
  src:url('/assets/fonts/ibm-plex-mono-400-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF}
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:400;font-display:swap;
  src:url('/assets/fonts/ibm-plex-mono-400-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:500;font-display:swap;
  src:url('/assets/fonts/ibm-plex-mono-500-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF}
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:500;font-display:swap;
  src:url('/assets/fonts/ibm-plex-mono-500-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:600;font-display:swap;
  src:url('/assets/fonts/ibm-plex-mono-600-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF}
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:600;font-display:swap;
  src:url('/assets/fonts/ibm-plex-mono-600-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}

*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%;scroll-behavior:smooth;scroll-padding-top:96px}
body{margin:0;background-color:var(--bg);background-image:var(--grain);
  background-size:var(--grain-size);color:var(--ink-2);font-family:var(--sans);
  font-size:17px;line-height:1.62;-webkit-font-smoothing:antialiased}
img{max-width:100%;height:auto;display:block}
a{color:inherit;text-decoration:none}
ul,ol{margin:0;padding:0;list-style:none}
p{margin:0 0 1.1em}
h1,h2,h3{font-family:var(--sans);font-weight:800;margin:0 0 .5em;color:var(--ink);
  line-height:1.06;letter-spacing:-.028em;text-wrap:balance}
h1{font-size:clamp(2.2rem,4.6vw,3.7rem);letter-spacing:-.036em}
h2{font-size:clamp(1.7rem,3.2vw,2.6rem);letter-spacing:-.032em}
h3{font-size:1.15rem;font-weight:700;line-height:1.2}
address{font-style:normal}
/* viewport-fit=cover lets content reach the rounded corners, so the gutters
   take whichever is larger: the design gutter or the device's safe area. */
.wrap{width:100%;max-width:var(--wrap);margin-inline:auto;
  padding-inline:max(var(--gut),env(safe-area-inset-left)) max(var(--gut),env(safe-area-inset-right))}
.ico{width:21px;height:21px;flex:none}
.ico.sm{width:16px;height:16px}
.ico.up{transform:rotate(-90deg)}

.skip{position:absolute;left:-9999px;top:10px;z-index:200;background:var(--ink);color:var(--hi);padding:12px 18px}
.skip:focus{left:14px}
/* Two-tone, because no single colour clears every surface here: the yellow
   carries the dark sections, the ink halo carries the white header and the
   yellow band. One of the pair is always well above 3:1. */
:focus-visible{outline:3px solid var(--hi);outline-offset:2px;
  box-shadow:0 0 0 6px var(--ink);border-radius:2px}

/* text selection and the caret ship as browser defaults otherwise */
::selection{background:var(--hi);color:var(--ink)}
body{caret-color:var(--ink)}

/* hazard stripe — the one decorative motif, used as a rule, never as a fill */
.hazard{height:9px;background:repeating-linear-gradient(-45deg,
  var(--hi) 0 14px, var(--ink) 14px 28px)}

/* ---------- buttons ---------- */
.btn{display:inline-flex;align-items:center;justify-content:center;gap:.5em;
  font-family:var(--sans);font-weight:700;font-size:.95rem;letter-spacing:-.008em;
  padding:.82em 1.5em;border:2px solid transparent;border-radius:var(--r);
  cursor:pointer;white-space:nowrap;transition:background .15s,color .15s,border-color .15s}
.btn-lg{padding:.98em 1.8em;font-size:1rem}
.btn-block{width:100%}
.btn-primary{background:var(--hi);color:var(--ink);border-color:var(--hi)}
.btn-primary:hover{background:var(--hi-dark);border-color:var(--hi-dark)}
.btn-dark{background:var(--ink);color:#fff;border-color:var(--ink)}
.btn-dark:hover{background:var(--hi);color:var(--ink);border-color:var(--hi)}
.btn-outline{background:transparent;color:#fff;border-color:rgba(255,255,255,.34)}
.btn-outline:hover{background:#fff;color:var(--ink);border-color:#fff}
.btn-ghost{background:transparent;color:var(--ink);border-color:var(--line);font-weight:600}
.btn-ghost:hover{border-color:var(--ink);background:var(--concrete)}
.btn-accent{background:var(--ink);color:var(--hi);border-color:var(--ink)}
.btn-accent:hover{background:#000}

/* ---------- header ---------- */
.site-header{position:sticky;top:0;z-index:100;
  background-color:rgb(var(--paper-rgb) / .95);background-image:var(--grain);
  background-size:var(--grain-size);
  backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);
  border-bottom:2px solid var(--ink);transition:box-shadow .2s}
.site-header.stuck{box-shadow:0 4px 16px -10px rgb(var(--ink-rgb) / .5)}
.header-in{display:flex;align-items:center;gap:24px;min-height:80px}
/* the logo is a flex item: without this the longer FR nav squeezes it */
.logo{flex:none;display:flex;align-items:center;color:var(--ink)}
.brand-logo{display:block;height:38px;width:auto}
.nav{margin-left:auto;display:flex;align-items:center;gap:26px}
.nav-list{display:flex;align-items:center;gap:4px}
.nav-list a{display:block;padding:.5em .7em;border-radius:var(--r);font-weight:600;
  font-size:.95rem;color:var(--ink);white-space:nowrap;transition:color .15s,background .15s}
.nav-list a:hover{color:var(--ink);background:var(--concrete)}
.nav-actions{display:flex;align-items:center;gap:10px}
.lang{display:inline-flex;align-items:center;gap:.4em;padding:.5em .7em;border-radius:var(--r);white-space:nowrap;
  font-family:var(--mono);font-weight:600;font-size:.78rem;letter-spacing:.08em;
  color:var(--ink-2);border:2px solid var(--line);transition:all .15s}
.lang:hover{border-color:var(--ink);color:var(--ink)}
.burger{display:none;margin-left:auto;width:44px;height:44px;border:2px solid var(--ink);
  background:var(--plate);border-radius:var(--r);cursor:pointer;padding:0;place-items:center}
.burger span{display:block;width:19px;height:2.5px;background:var(--ink);margin:4px auto;transition:transform .22s,opacity .18s}
.burger[aria-expanded="true"] span:nth-child(1){transform:translateY(6.5px) rotate(45deg)}
.burger[aria-expanded="true"] span:nth-child(2){opacity:0}
.burger[aria-expanded="true"] span:nth-child(3){transform:translateY(-6.5px) rotate(-45deg)}

/* ---------- hero ---------- */
.hero{background:var(--ink);color:rgba(245,243,240,.8)}

/* Every crop here is off the top and measured against where the crews stand.
   An early version cropped to a fixed 16:9 box and at 390px hid 72% of the
   frame — every trade except the supervisor. */
/* Stacked by default: photo, then copy riding up onto it. Past 1180 the two
   become copy-left / photo-right, the photo uncropped and its left side
   dissolving into the copy's black. */
.hero-grid{display:grid;grid-template-areas:"shot" "copy"}
.hero-shot{grid-area:shot}
.hero-copy{grid-area:copy}

.hero-shot{margin:0;display:block;background:var(--ink);line-height:0}
/* Capped at the content width so the photograph lines up with every other
   section instead of ending up narrower than the copy underneath it. Past
   that the frame centres and the sides fall away to black. */
.hero-frame{position:relative;max-width:var(--wrap);margin-inline:auto}
/* Stacked, the top 18% of the frame is cropped away: it is sky and the tip of
   the crane, and on a phone that height is worth more to the copy than to the
   weather. The highest hard hat on site sits at 30%, so everyone survives the
   cut with room over their heads. 839 = 1023 x .82. */
.hero-frame{aspect-ratio:1537/839}
.hero-photo{display:block;width:100%;height:100%;object-fit:cover;object-position:50% 100%}

/* The stop colour is the ink at zero alpha, not `transparent`: CSS transparent
   is rgba(0,0,0,0), and interpolating that against the ink puts a dirty grey
   band through the middle of the ramp. */
/* An eleven-stop smoothstep (3t^2 - 2t^3): a two-stop linear gradient reads
   as a band because the eye catches where it stops, and even a smooth-looking
   ramp betrays itself if its slope is non-zero where it meets the flat black.
   The clamps keep the dissolve off both extremes however narrow the frame.
   Stacked, the bottom edge is an overlay rather than a dissolve: the copy
   rides up onto it, so the curve is front-loaded (alpha = t^0.24) to put a
   ground under the title from its first line. The yellow accent is what sets
   that exponent -- #ffc61e needs a darker backing than white to clear 3:1. */
.hero-fade{position:absolute;inset:0;pointer-events:none;opacity:0;transition:opacity .25s;
  /* --fade-l and --fade-r are the sides, and only the split layout uses
     them; the stacked overlay writes its own stops below. The left
     runs a third of the frame so the curve is spread thin enough to be
     imperceptible; the right stops short of the sawyer.

     The stacked overlay writes its own stops. It is solid for the bottom 9%
     and dissolves upward over the next 21%, on a smoothstep whose slope
     tends to zero where it meets the photograph -- so the top of it has no
     edge at all. The title's first line sits at 85.4% of the frame, a
     little past the sweeper's broom, where the ramp is already at .82. */
  --fade-l:clamp(64px,30%,340px);
  --fade-r:clamp(48px,9%,110px);
  background:linear-gradient(to top, var(--ink) 0.0%, var(--ink) 9.0%, rgb(var(--ink-rgb) / 0.9803) 10.75%, rgb(var(--ink-rgb) / 0.9259) 12.5%, rgb(var(--ink-rgb) / 0.8438) 14.25%, rgb(var(--ink-rgb) / 0.7407) 16.0%, rgb(var(--ink-rgb) / 0.6238) 17.75%, rgb(var(--ink-rgb) / 0.5) 19.5%, rgb(var(--ink-rgb) / 0.3762) 21.25%, rgb(var(--ink-rgb) / 0.2593) 23.0%, rgb(var(--ink-rgb) / 0.1562) 24.75%, rgb(var(--ink-rgb) / 0.0741) 26.5%, rgb(var(--ink-rgb) / 0.0197) 28.25%, rgb(var(--ink-rgb) / 0.0) 30.0%)}
.hero-fade{opacity:1}

/* Stacked, the copy rides up onto the photograph instead of sitting under it.
   The pull is 8% of the frame's width, which is 12% of its height: exactly
   the overlay, so the title starts where the overlay does. */
.hero-copy{max-width:min(100%,760px);padding:0 var(--gut) clamp(44px,5.5vw,76px);
  margin-top:-8%;position:relative;z-index:1}
/* The client set the headline in caps. It lives in the content files in
   sentence case and is shouted here, so switching back is one line.

   Caps costs width: measured, the set runs 13.9 times its own size at the
   widest line against 11.0 in sentence case, a quarter wider. The hero's h1
   therefore carries its own size here rather than taking the global h1's --
   6.2vw, which is what keeps each half on one line down to 360px, gutters
   counted. The measure
   goes with it: at 22ch the box was narrower than the longest line even when
   the column was not. */
.hero h1{color:#fff;max-width:26ch;margin-bottom:.4em;
  text-transform:uppercase;letter-spacing:-.012em;
  font-size:clamp(1.35rem,6.2vw,3rem)}
/* The two halves of the title are its own lines, not whatever the measure
   happens to give: the break is the point of the phrasing. Each half opts out
   of the balanced wrapping the other headings use -- balance would split a
   two-word line down the middle even with room to spare. */
.hero h1 > span{display:block;text-wrap:wrap}
.hero h1 em{font-style:normal;color:var(--hi)}
.hero .lead{font-size:clamp(1.02rem,1.4vw,1.18rem);color:rgba(245,243,240,.76);max-width:52ch;margin-bottom:1.9em}
.hero-cta{display:flex;flex-wrap:wrap;gap:12px}

/* The headline is what decides whether this layout can exist: in a narrow
   column it wraps to five or six lines and the copy outgrows the photograph,
   which is what forced the breakpoint up to 1360 and put the whole split
   layout out of reach of an ordinary laptop window. Scaling the headline with
   the column instead lets the split start at 1180 and still fit the frame. */
@media (min-width:1180px){
  /* Centred as one block with symmetric margins, on a measure wider than the
     standard wrap so the photograph keeps some size in half the width. */
  .hero-grid{
    grid-template-columns:minmax(0,.78fr) minmax(0,1.22fr);
    grid-template-areas:"copy shot";
    align-items:center;
    gap:0 clamp(18px,1.8vw,30px);
    max-width:1440px;margin-inline:auto;padding-inline:var(--gut);
  }
  .hero-copy{padding:0;max-width:none;margin-top:0}
  /* Each half of the title is one line here; the 15ch measure that keeps it
     from running wide when it sits above the photograph would break both. */
  /* Side by side the copy column is narrow -- 418px at 1180 against 760 when
     stacked -- so the split layout needs its own, smaller ramp. */
  .hero h1{font-size:clamp(1.5rem,2.5vw,2.3rem);max-width:none}
  .hero-frame{max-width:none;aspect-ratio:auto}
  .hero-photo{height:auto;object-fit:fill}
  /* left edge blends into the copy, right edge into the page margin, so the
     photo has no hard vertical line on either side */
  /* Side by side the photo spans the full hero height: its top meets the
     header and its bottom the hazard stripe, so there is no ground above or
     below to dissolve into. Only the sides fade. */
  .hero-fade{background:
    linear-gradient(to right, var(--ink) 0, rgb(var(--ink-rgb) / 0.972) calc(var(--fade-l) * 0.1), rgb(var(--ink-rgb) / 0.896) calc(var(--fade-l) * 0.2), rgb(var(--ink-rgb) / 0.784) calc(var(--fade-l) * 0.3), rgb(var(--ink-rgb) / 0.648) calc(var(--fade-l) * 0.4), rgb(var(--ink-rgb) / 0.5) calc(var(--fade-l) * 0.5), rgb(var(--ink-rgb) / 0.352) calc(var(--fade-l) * 0.6), rgb(var(--ink-rgb) / 0.216) calc(var(--fade-l) * 0.7), rgb(var(--ink-rgb) / 0.104) calc(var(--fade-l) * 0.8), rgb(var(--ink-rgb) / 0.028) calc(var(--fade-l) * 0.9), rgb(var(--ink-rgb) / 0) var(--fade-l)),
    linear-gradient(to left, var(--ink) 0, rgb(var(--ink-rgb) / 0.972) calc(var(--fade-r) * 0.1), rgb(var(--ink-rgb) / 0.896) calc(var(--fade-r) * 0.2), rgb(var(--ink-rgb) / 0.784) calc(var(--fade-r) * 0.3), rgb(var(--ink-rgb) / 0.648) calc(var(--fade-r) * 0.4), rgb(var(--ink-rgb) / 0.5) calc(var(--fade-r) * 0.5), rgb(var(--ink-rgb) / 0.352) calc(var(--fade-r) * 0.6), rgb(var(--ink-rgb) / 0.216) calc(var(--fade-r) * 0.7), rgb(var(--ink-rgb) / 0.104) calc(var(--fade-r) * 0.8), rgb(var(--ink-rgb) / 0.028) calc(var(--fade-r) * 0.9), rgb(var(--ink-rgb) / 0) var(--fade-r))}

  /* the base rule centres this with margin-inline:auto, which on a grid item
     also collapses it to shrink-to-fit — both have to go here */
}

.facilities{background:var(--hi);color:var(--ink)}
.facilities-in{display:flex;flex-wrap:wrap;align-items:center;gap:12px 34px;padding-block:16px}
.facilities-label{margin:0;font-family:var(--mono);font-size:.73rem;letter-spacing:.11em;
  text-transform:uppercase;color:rgb(var(--ink-rgb) / .72)}
.facilities-list{display:flex;flex-wrap:wrap;gap:8px 26px;margin-left:auto}
.facilities-list li{font-weight:700;font-size:.95rem;color:var(--ink);letter-spacing:-.01em}

/* a 47-character sentence is prose, not a label: it reads in the display
   face and in sentence case, and stays distinct by colour and weight */
/* The strap is three sentences now: measured, so it breaks rather than
   running to 92 characters on a tablet. */
.hero-strap{font-weight:600;font-size:clamp(1rem,1.3vw,1.14rem);letter-spacing:-.012em;
  color:var(--hi);margin:0 0 1.4em;max-width:56ch}

/* ---------- manpower, now inside the hero on its dark ground ---------- */
.mp{padding-block:clamp(52px,6.5vw,92px)}
.mp .sec-head h2{color:#fff}
/* the grid collapses to one column below 1040, where the prose would
   otherwise run the full width — well past a readable measure */
.mp .prose p{color:rgba(245,243,240,.78);max-width:66ch}
.mp-scale p{max-width:70ch}
/* the pin number carries the link back to the photograph; the roles that are
   not in frame keep the check, so the list reads as one thing either way */
.mp-grid{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,.92fr);
  gap:clamp(32px,4.5vw,64px);align-items:start}
.mp-scale{margin-top:2em;padding:24px 26px;background:transparent;
  border:2px solid rgba(255,255,255,.16);border-radius:var(--r)}
.mp-scale h3{margin-bottom:.4em;color:#fff}
.mp-scale p{margin:0;color:rgba(245,243,240,.68);font-size:.96rem}
.mp-note{margin-top:1em !important;padding-top:1em;border-top:1px solid rgba(255,255,255,.16);
  font-size:.98rem;color:var(--hi) !important;font-weight:600}

.mp-roles{background:rgb(255 255 255 / .04);border:1px solid rgba(255,255,255,.14);
  border-radius:var(--r);padding:clamp(26px,3vw,34px)}
.mp-roles-title{font-family:var(--mono);font-weight:600;font-size:.75rem;letter-spacing:.1em;
  text-transform:uppercase;color:var(--hi);margin-bottom:1.2em}
.mp-roles ul{display:grid;grid-template-columns:repeat(auto-fit,minmax(210px,1fr));gap:0 26px}
.mp-roles li{display:flex;align-items:flex-start;gap:11px;padding:11px 0;
  border-top:1px solid rgba(255,255,255,.12);color:rgba(245,243,240,.88);
  font-size:.94rem;line-height:1.45}
.mp-roles li svg{color:var(--hi);margin-top:4px}

.mp-strap{margin:clamp(52px,6.5vw,84px) 0 0;padding-top:0;
  font-weight:800;letter-spacing:-.028em;
  font-size:clamp(1.25rem,2.3vw,1.85rem);line-height:1.32;color:#fff;
  text-wrap:balance;max-width:26ch}

/* ---------- sections ---------- */
.section{padding-block:var(--sec)}
/* One section in the middle of the run goes to ink. The light ground reads as
   a rhythm rather than a wash, and the plates in here become panels set out
   on a dark surface instead of cards on a page. Only the type changes: the
   plates keep their own material. */
.section-dark{background:var(--ink);color:rgba(245,243,240,.8)}
.section-dark .sec-head h2,.section-dark h3.other-title{color:#fff}
.section-dark .sec-intro{color:rgba(245,243,240,.72)}
/* The plates carry an ink border, which on ink is no border at all: give them
   an edge so a card whose photograph is dark still reads as a panel. */
.section-dark .phase{border-color:rgba(255,255,255,.18)}
.section-dark .other-item{background:rgb(255 255 255 / .05);border-color:rgba(255,255,255,.16);
  color:rgba(245,243,240,.86)}
.section-dark .other-item:hover{border-color:var(--hi);color:#fff}
.section-dark .other-item svg{color:var(--hi)}
.section-soft{background-color:var(--band);background-image:var(--grain);
  background-size:var(--grain-size)}
.sec-head{max-width:820px;margin-bottom:clamp(34px,4.5vw,56px)}
.sec-head h2{margin-bottom:.3em}
.sec-intro{color:var(--muted);font-size:clamp(1rem,1.35vw,1.08rem);max-width:68ch;margin-bottom:0}
/* the section grids collapse to one column below 1040; without a cap the
   body copy then runs the full container width */
.prose p{color:var(--ink-2);margin-bottom:1.15em;max-width:68ch}
.prose p:last-child{margin-bottom:0}

.about-grid{display:grid;grid-template-columns:minmax(0,.78fr) minmax(0,1.22fr);
  gap:clamp(32px,5vw,64px);align-items:stretch}
.about-body{display:grid;gap:clamp(26px,3.5vw,40px)}
.pillars{display:grid;gap:0;border-top:2px solid var(--ink)}
.pillar{display:flex;gap:16px;padding:22px 0;border-bottom:1px solid var(--line-2);
  background:transparent;transition:none}
.pillar:hover{transform:none;box-shadow:none}
.pillar-ico{flex:none;width:42px;height:42px;display:grid;place-items:center;border-radius:var(--r);
  background:var(--hi);color:var(--ink)}
.pillar h3{margin-bottom:.25em}
.pillar p{margin:0;font-size:.93rem;color:var(--muted);line-height:1.6}

/* phases: boxed like a spec sheet */
.phases{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:20px;margin-bottom:clamp(46px,6vw,80px)}
.phase{position:relative;background:var(--plate);border:2px solid var(--ink);border-radius:var(--r);
  overflow:hidden;transition:transform .18s,box-shadow .18s}
.phase:hover{transform:translateY(-3px);box-shadow:6px 6px 0 var(--hi)}
.phase::before{display:none}
.phase-media{margin:0;aspect-ratio:4/3;background:var(--ink-2)}
.phase-media img{width:100%;height:100%;object-fit:cover}
.phase-body{padding:26px 24px 28px}
.phase h3{margin-bottom:.45em}
.phase p{margin:0;color:var(--muted);font-size:.93rem;line-height:1.6;max-width:68ch}

.other-title{font-size:1.05rem;margin-bottom:1em;color:var(--ink)}
.other-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:12px}
.other-item{display:flex;align-items:center;gap:11px;background:var(--plate);border:2px solid var(--line);
  border-radius:var(--r);padding:15px 17px;font-size:.93rem;font-weight:500;color:var(--ink-2);
  transition:border-color .15s,color .15s}
.other-item svg{color:var(--ink)}
.other-item:hover{border-color:var(--ink);color:var(--ink)}

/* one-time */
.onetime{display:grid;grid-template-columns:minmax(0,1.05fr) minmax(0,.95fr);gap:0;align-items:stretch;
  background:var(--plate);border:2px solid var(--ink);border-radius:var(--r);overflow:hidden}
.onetime-copy{padding:clamp(30px,4.2vw,52px)}
.onetime-copy .btn{margin-top:1.8em}
.onetime-media{border:0;border-radius:0;box-shadow:none}
.onetime-media img{min-height:300px}
.tags{display:flex;flex-wrap:wrap;gap:8px;margin-top:1.4em}
.tags li{font-family:var(--mono);font-size:.76rem;letter-spacing:.06em;text-transform:uppercase;
  color:var(--ink);background:var(--hi-soft);border:1px solid var(--hi);border-radius:var(--r);padding:.5em 1em}

/* multiservice */
.ms-grid{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,.85fr);
  gap:0 clamp(36px,5vw,72px);align-items:start}
.ms-media{grid-column:1/-1;aspect-ratio:21/9;margin-top:clamp(26px,4vw,44px)}
.ms-card{background:var(--ink);color:rgba(245,243,240,.78);border-radius:var(--r);padding:clamp(26px,3vw,34px)}
.ms-card-ico{display:grid;place-items:center;width:48px;height:48px;border-radius:var(--r);
  background:var(--hi);color:var(--ink);margin-bottom:1.1em}
.ms-card-title{font-weight:600;font-size:1rem;letter-spacing:-.01em;
  color:var(--hi);margin-bottom:1.1em}
.ticks{display:grid;gap:0}
.ticks li{display:flex;align-items:flex-start;gap:12px;padding:13px 0;
  border-top:1px solid rgba(255,255,255,.12);color:rgba(245,243,240,.86);font-size:.96rem}
.ticks li svg{color:var(--hi);margin-top:4px}

/* team: the whole crew wide, then three of the roles they fill */
.team-hero{aspect-ratio:16/10}
.team-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:clamp(16px,2.2vw,26px);
  margin-top:clamp(16px,2.2vw,26px)}
.team-item{display:grid;gap:10px;align-content:start}
.team-shot{aspect-ratio:4/3}
.team-role{margin:0;font-family:var(--mono);font-weight:600;font-size:.75rem;letter-spacing:.1em;
  text-transform:uppercase;color:rgb(var(--ink-rgb) / .72)}

/* media */
.media{margin:0;border-radius:var(--r);overflow:hidden;background:var(--ink-2);border:2px solid var(--ink)}
.media img{display:block;width:100%;height:100%;object-fit:cover}
.media-tall{min-height:460px}
/* the about photo is the crew standing low in the frame: keep them in when
   the box goes wide on narrow screens */
.about-grid .media img{object-position:50% 78%}

/* band */
.band{background:var(--hi);color:var(--ink)}
.band-in{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;
  gap:26px;padding-block:clamp(42px,5.5vw,70px)}
.band h2{color:var(--ink);margin-bottom:.25em;max-width:20ch}
.band p{margin:0;color:rgb(var(--ink-rgb) / .78);max-width:56ch}

/* contact */
.contact-grid{display:grid;grid-template-columns:minmax(0,.92fr) minmax(0,1.08fr);
  gap:clamp(28px,4vw,56px);align-items:start}
/* With the quote form off there is one column, and it is measured rather than
   stretched: the manager's card and the office block read as a block of
   details, not as a banner. */
.contact-grid-solo{grid-template-columns:minmax(0,1fr);max-width:660px}
.card{background:var(--plate);border:2px solid var(--ink);border-radius:var(--r);padding:26px 28px}
.card-label{font-family:var(--mono);font-weight:600;font-size:.72rem;letter-spacing:.11em;
  text-transform:uppercase;color:var(--muted);margin-bottom:.85em}
.card-label.mt{margin-top:2em}
.manager{background:var(--hi)}
.manager .card-label{color:rgb(var(--ink-rgb) / .7)}
.manager-name{font-weight:800;font-size:1.32rem;margin-bottom:.5em;letter-spacing:-.025em}
.row{display:flex;align-items:center;gap:.6em;padding:.42em 0;color:var(--ink-2);font-size:.96rem}
.row svg{color:var(--ink)}
.row:hover{color:var(--ink)}
.row strong{font-weight:700;font-size:1.04rem;color:var(--ink)}
.offices{display:grid;grid-template-columns:repeat(auto-fit,minmax(215px,1fr));gap:14px}
.office-city{display:flex;align-items:center;gap:.45em;font-weight:800;font-size:1.05rem;
  margin-bottom:.55em;letter-spacing:-.02em}
.office-city svg{color:var(--maple)}
.office address{color:var(--muted);font-size:.92rem;line-height:1.62;margin-bottom:.65em}
.depts li{display:flex;flex-wrap:wrap;justify-content:space-between;gap:6px 16px;
  padding:12px 0;border-top:1px solid var(--line-2);font-size:.94rem}
.depts li span{color:var(--muted)}
.depts li a{display:inline-flex;align-items:center;min-height:24px;padding-block:2px;
  font-weight:700;color:var(--ink);border-bottom:2px solid var(--hi)}
.depts li a:hover{background:var(--hi)}

/* form */
.form{padding:clamp(26px,3vw,36px)}
.form-title{font-size:1.3rem;margin-bottom:.25em}
.form-note{font-family:var(--mono);font-size:.78rem;color:var(--muted);margin-bottom:1.7em}
.field{margin-bottom:16px}
.field-row{display:grid;grid-template-columns:1fr 1fr;gap:16px}
.field label{display:block;font-size:.85rem;font-weight:600;color:var(--ink-2);margin-bottom:.4em}
.req{color:var(--maple)}
.field input,.field select,.field textarea{width:100%;font:inherit;font-size:.96rem;color:var(--ink);
  background:var(--concrete);border:2px solid var(--line);border-radius:var(--r);padding:.72em .85em;
  transition:border-color .15s,background .15s,box-shadow .15s}
.field textarea{resize:vertical;min-height:112px}
.field select{appearance:none;padding-right:2.4em;background-repeat:no-repeat;background-position:right .8em center;background-size:18px;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%236e6a64' stroke-width='2' stroke-linecap='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E")}
.field input:focus,.field select:focus,.field textarea:focus{
  outline:2px solid transparent;outline-offset:2px;background:var(--plate);
  border-color:var(--ink);box-shadow:0 0 0 3px var(--hi)}
.field [aria-invalid="true"]{border-color:var(--maple);box-shadow:0 0 0 3px rgba(163,22,33,.14)}
.hp{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}
.form .btn-block{margin-top:8px}
.form-status{margin:1em 0 0;font-size:.9rem;min-height:1.2em}
.form-status.ok{color:var(--ink);font-weight:700}
.form-status.err{color:var(--maple);font-weight:700}

/* footer */
.site-footer{background:var(--ink);color:rgba(245,243,240,.62)}
.site-footer .footer-in{padding-top:clamp(50px,6vw,78px)}
.footer-in{display:grid;grid-template-columns:1.7fr 1fr 1.2fr 1.3fr;gap:38px 30px;padding-bottom:clamp(38px,5vw,58px)}
.wm{display:block;color:#fff;margin-bottom:1em}
.wm .brand-logo{height:46px}
  text-transform:uppercase;color:rgba(245,243,240,.42);margin-top:.6em}
.footer-brand p{font-size:.92rem;max-width:34ch;line-height:1.6}
.lang-dark{border-color:rgba(255,255,255,.2);color:rgba(245,243,240,.82);margin-top:.6em}
.lang-dark:hover{border-color:var(--hi);color:var(--hi)}
.footer-title{font-family:var(--mono);font-weight:600;font-size:.72rem;letter-spacing:.11em;
  text-transform:uppercase;color:var(--hi);margin-bottom:1.05em}
.footer-col ul{display:grid;gap:10px}
.footer-col li{font-size:.91rem;line-height:1.5}
.footer-col a{display:inline-flex;align-items:center;min-height:24px}
.footer-col a:hover{color:#fff}
.footer-bottom{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;
  gap:14px;padding-block:22px;padding-bottom:max(22px,env(safe-area-inset-bottom));
  border-top:1px solid rgba(255,255,255,.12)}
.footer-bottom p{margin:0;font-family:var(--mono);font-size:.78rem;color:rgba(245,243,240,.6)}
.totop{display:grid;place-items:center;width:44px;height:44px;border-radius:var(--r);
  border:2px solid rgba(255,255,255,.2);color:rgba(245,243,240,.75);transition:all .15s}
.totop:hover{background:var(--hi);border-color:var(--hi);color:var(--ink)}

/* reveal */
/* Gated on .js, set by an inline script before first paint. Without
   JavaScript the reveal never fired and every section stayed at opacity 0 —
   the whole page rendered blank. Ungated, the content is simply visible. */
.js .reveal{opacity:0;transform:translateY(16px);
  /* Excluded from scroll anchoring: the browser chooses an anchor while these
     are still translated down, then compensates when the transform comes off
     on load, and the page arrives 16px lower than it was left. */
  overflow-anchor:none;
  transition:opacity .55s cubic-bezier(.2,.7,.3,1) var(--d,0s),transform .55s cubic-bezier(.2,.7,.3,1) var(--d,0s)}
.js .reveal.in{opacity:1;transform:none}

/* responsive */
@media (max-width:1040px){
  /* 26ch, same as the base: in caps the longest line is about 24ch wide, and
     a narrower measure clips it into two. */
  .hero h1{max-width:26ch}
  .about-grid,.ms-grid,.contact-grid,.mp-grid{grid-template-columns:1fr}
  .media-tall{min-height:0;aspect-ratio:16/10}
  .ms-grid{gap:clamp(28px,4vw,40px)}
  .ms-media{aspect-ratio:16/9;margin-top:0}
  .onetime{grid-template-columns:1fr}
  .onetime-media{order:-1;aspect-ratio:16/9}
  .onetime-media img{min-height:0}
  .phases{grid-template-columns:1fr;gap:16px}
  .footer-in{grid-template-columns:1fr 1fr}
}
@media (max-width:1080px){
  .burger{display:grid}
  .nav{position:fixed;inset:80px 0 auto;margin:0;display:block;background:var(--paper);
    border-bottom:2px solid var(--ink);padding:16px var(--gut) 24px;
    transform:translateY(-8px);opacity:0;visibility:hidden;pointer-events:none;
    transition:opacity .18s,transform .18s,visibility .18s;
    max-height:calc(100dvh - 80px);overflow-y:auto}
  .nav.open{transform:none;opacity:1;visibility:visible;pointer-events:auto}
  .nav-list{display:grid;gap:2px;margin-bottom:16px}
  .nav-list a{padding:.85em .5em;font-size:1.04rem;border-bottom:1px solid var(--line-2);border-radius:0}
  .nav-actions{flex-wrap:wrap}
  .nav-actions .btn,.nav-actions .lang{flex:1 1 auto;justify-content:center}
  .facilities-in{flex-direction:column;align-items:flex-start;gap:10px}
  .facilities-list{margin-left:0;gap:8px 20px}
  .band-in{flex-direction:column;align-items:flex-start}
}
@media (max-width:560px){
  body{font-size:16px}
  .field-row{grid-template-columns:1fr}
  .footer-in{grid-template-columns:1fr;gap:30px}
  .hero-cta{flex:1 1 100%}
  .hero-cta .btn{flex:1 1 100%}
  .team-grid{grid-template-columns:1fr}
}
/* Input method, not screen width: a touchscreen laptop needs the same
   comfortable target a phone does. env() keeps the rhythm from doubling. */
@media (pointer:coarse){
  .footer-col ul{gap:0}
  .footer-col a{min-height:44px}
  .depts li a{min-height:44px;padding-block:9px}
  .row{min-height:44px}
  .lang{min-height:44px}
  .logo{min-height:44px}
  .nav-list a{min-height:44px}
}

/* Reduced motion is about movement, not about feedback. Killing every
   transition globally also killed the hover and focus response, which is
   useful and causes nobody vestibular trouble. Movement goes; colour stays. */
@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  *,*::before,*::after{animation-duration:.01ms !important;animation-iteration-count:1 !important}
  .js .reveal{opacity:1;transform:none;transition:none}
  .phase:hover,.other-item:hover,.btn:hover{transform:none}
}
@media print{.site-header,.hero-bg,.band,.totop,.form,.hazard{display:none}body{font-size:12pt;color:#000}}
