/* =============================================================
   HIRAMAR AND COSTA — MARINE LOGISTICS AND ENERGY SERVICES
   Palette sampled from the company logo:
     forest #005020 · emerald #08A848
   Brass accent drawn from ship fittings and buoy markers.
   ============================================================= */

:root {
  /* --- colour --- */
  --abyss:      #042315;   /* deep hull green-black */
  --abyss-2:    #06301D;
  --forest:     #005020;   /* logo dark green */
  --forest-dim: #0A3D22;
  --forest-deep:#0E582E;   /* core-services panels */
  --emerald:    #08A848;   /* logo bright green */
  --emerald-lt: #2ECC71;
  --brass:      #C6952F;   /* ship fittings, buoy markers */
  --brass-lt:   #E0B355;
  --mint:       #EAF5EE;   /* pale ground, matches logo field */
  --mint-deep:  #D8EADF;
  --paper:      #FFFFFF;
  --ink:        #0C1710;
  --ink-soft:   #40544A;
  --hairline:   rgba(0, 80, 32, .16);
  --hairline-d: rgba(255, 255, 255, .14);

  /* --- theme roles ------------------------------------------------
     The brand colours above are fixed: forest, emerald and brass are
     the company's, and they are the same colours in either theme.
     What changes between light and dark is not the palette but the
     *job* each colour is doing — which green can be read as type,
     which surface a card sits on, how dark the ground is.

     The tokens below name those jobs. In light they resolve to
     exactly the values the site has always used, so nothing about
     the light theme moves. The dark block at the foot of this file
     is the only place they are given different values, which makes
     it the only place the second theme is described.

     Brand fills — a forest panel, an emerald button, the capability
     strip — are deliberately NOT in here. They carry white type on a
     saturated ground and read the same either way, so they go on
     using the brand tokens directly.
     ---------------------------------------------------------------- */
  --green-ink:      var(--forest);       /* green set as type on the page ground */
  --green-ink-deep: var(--forest-deep);  /* the Core Services heading tone        */
  --green-mark:     var(--emerald);      /* rules, markers, eyebrows, small labels */
  --brass-ink:      var(--brass);        /* brass set as type or as an edge        */

  --masthead:   rgba(234, 245, 238, .82);  /* the bar's own translucent ground */
  --edge-firm:  rgba(0, 80, 32, .35);      /* ghost button border              */
  --edge-tint:  rgba(0, 80, 32, .06);      /* ghost button hover fill          */
  --code-tint:  rgba(0, 80, 32, .09);      /* inline code in the manager       */
  --brass-tint: rgba(198, 149, 47, .09);   /* the note beneath the listings    */
  --ok-tint:    rgba(8, 168, 72, .12);     /* the form's success message       */
  --focus:      var(--emerald);            /* the focus ring                   */

  --danger:      #C0453B;                  /* a field that is wrong            */
  --danger-ink:  #8E2E26;                  /* what it says                     */
  --danger-tint: rgba(192, 69, 59, .04);   /* the field's own fill             */
  --danger-tint2:rgba(192, 69, 59, .10);   /* the form's failure message       */

  /* Lift. On the pale ground a shadow is the hull green at low
     opacity; on the dark one it has to be near-black to register. */
  --lift-drawer: 0 24px 48px rgba(4, 35, 21, .14);
  --lift-panel:  0 22px 44px rgba(4, 35, 21, .11);
  --lift-card:   0 24px 46px rgba(4, 35, 21, .14);

  /* Tells the browser which way the page reads, so native furniture
     — scrollbars, select menus, the caret — comes out to match. */
  color-scheme: light;
  /* Checkboxes and radios are drawn by the browser, and the one colour
     it will take from us is this. Brand green rather than the system
     blue, in either theme. */
  accent-color: var(--green-mark);

  /* --- type --- */
  --display: 'Archivo', 'Helvetica Neue', Arial, sans-serif;
  --body:    'Source Serif 4', Georgia, 'Times New Roman', serif;
  --mono:    'IBM Plex Mono', ui-monospace, 'SF Mono', Menlo, monospace;

  /* --- metrics --- */
  --shell:   1240px;
  --gut:     clamp(20px, 5vw, 64px);
  --radius:  4px;
  --ease:    cubic-bezier(.22, .61, .36, 1);

  /* --- heading scale ---------------------------------------------
     One ladder for the whole site. Every heading on every page draws
     its size from these three tokens, so the run of sizes is set here
     and nowhere else.

       tier          mobile   tablet   desktop
       h1 hero         34       44       56
       h2 section      28       34       40
       h3 subsection   21       23       26

     Every band heading sits on the section step, the one a page opens
     with included — a page's opening heading is a section heading here,
     not a size of its own. Small labels and eyebrows are left at the
     size they were drawn; the brief was to bring headings down, and a
     label tier would only have pushed them up.

     The values below are the mobile end. Two media queries further
     down carry each token to its tablet reading at 768px and its
     desktop reading at 1200px, interpolating between the anchors so
     nothing jumps at a breakpoint.
     ---------------------------------------------------------------- */
  --fs-h1:    34px;
  --fs-h2:    28px;
  --fs-h3:    21px;

  --lh-h1:    1.08;
  --lh-h2:    1.2;
  --lh-h3:    1.25;
}

/* 480px -> 768px: mobile reading climbs to the tablet reading. */
@media (min-width: 480px) {
  :root {
    --fs-h1:    clamp(34px, 3.4722vw + 17.333px, 44px);
    --fs-h2:    clamp(28px, 2.0833vw + 18px,     34px);
    --fs-h3:    clamp(21px, 0.6944vw + 17.667px, 23px);
  }
}

/* 768px -> 1200px: tablet reading climbs to the desktop reading,
   then holds. */
@media (min-width: 768px) {
  :root {
    --fs-h1:    clamp(44px, 2.7778vw + 22.667px, 56px);
    --fs-h2:    clamp(34px, 1.3889vw + 23.333px, 40px);
    --fs-h3:    clamp(23px, 0.6944vw + 17.667px, 26px);
  }
}

/* ---------- reset / base ---------- */
*, *::before, *::after { box-sizing: border-box; }

html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--mint);
  color: var(--ink);
  font-family: var(--body);
  font-size: clamp(16px, .55vw + 14.5px, 18px);
  line-height: 1.65;
  font-variant-numeric: oldstyle-nums;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

img { max-width: 100%; display: block; }
a { color: inherit; }

h1, h2, h3, h4 {
  font-family: var(--display);
  font-weight: 800;
  line-height: var(--lh-h2);
  letter-spacing: -.005em;
  margin: 0;
  font-variant-numeric: lining-nums;
  /* Headings are the longest unbroken strings on the page, so they are
     the ones that push a layout sideways. Balance the lines, and let a
     word that is genuinely wider than its column break rather than
     overflow it. */
  text-wrap: balance;
  overflow-wrap: break-word;
}

/* Untiered headings still land on the ladder rather than on the
   browser default, so a heading added later is never off-scale. */
h1 { font-size: var(--fs-h1);   line-height: var(--lh-h1); }
h2 { font-size: var(--fs-h2);   line-height: var(--lh-h2); }
h3 { font-size: var(--fs-h3);   line-height: var(--lh-h3); }
h4 { font-size: var(--fs-h3);   line-height: var(--lh-h3); }

/* Expanded width axis — hull lettering */
.u-hull {
  font-family: var(--display);
  font-variation-settings: 'wdth' 112, 'wght' 800;
  text-transform: uppercase;
  letter-spacing: .01em;
}

.u-mono {
  font-family: var(--mono);
  font-size: .72rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  font-variant-numeric: lining-nums tabular-nums;
}

.shell {
  width: 100%;
  max-width: var(--shell);
  margin-inline: auto;
  padding-inline: var(--gut);
}

/* The wide variant, used by the profile band on /about-us. That page is
   one long run of prose with nothing beside it, so it opens up: a 1400px
   outer bound rather than the 1240px shell, and page padding stated as a
   share of the viewport — 6% on the desktop, 4% on the tablet, a flat
   20px on the phone where a percentage would leave too little.

   The padding is inside the 1400px, box-sizing being border-box
   throughout, so the band can never be wider than the viewport and
   nothing here can start a sideways scroll. */
.shell--full {
  width: 100%;
  max-width: 1400px;
  margin-inline: auto;
  padding-inline: 20px;
}
@media (min-width: 768px)  { .shell--full { padding-inline: 4%; } }
@media (min-width: 1024px) { .shell--full { padding-inline: 6%; } }

.sr-only {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 3px;
  border-radius: 2px;
}

.skip-link {
  position: absolute; left: 12px; top: -60px; z-index: 200;
  background: var(--emerald); color: #fff;
  padding: 10px 18px; border-radius: var(--radius);
  font-family: var(--mono); font-size: .75rem; text-decoration: none;
  transition: top .2s var(--ease);
}
.skip-link:focus { top: 12px; }

/* =============================================================
   HEADER
   ============================================================= */
.masthead {
  position: sticky; top: 0; z-index: 90;
  background: var(--masthead);
  backdrop-filter: blur(14px) saturate(140%);
  -webkit-backdrop-filter: blur(14px) saturate(140%);
  border-bottom: 1px solid var(--hairline);
  transition: background .3s var(--ease), border-color .3s var(--ease);
}
.masthead__inner {
  display: flex; align-items: center; gap: 24px;
  min-height: 78px;
}
.brand {
  display: flex; align-items: center; gap: 12px;
  text-decoration: none; flex: 0 0 auto;
  margin-right: auto;                 /* pushes nav + CTA to the right */
  padding-right: 24px;                /* guaranteed gap, even when space is tight */
}
.masthead__inner > .nav { margin-right: clamp(16px, 2vw, 32px); }
/* The masthead carries the company logo itself — the horizontal lockup
   built from the original artwork, never retyped. */
.brand__logo { width: auto; height: 42px; display: block; }

.nav { display: none; align-items: center; gap: 28px; }
.nav__link {
  font-family: var(--display);
  font-variation-settings: 'wdth' 96, 'wght' 600;
  font-size: .82rem;
  text-transform: uppercase;
  letter-spacing: .07em;
  text-decoration: none;
  color: var(--green-ink);
  padding: 6px 0;
  position: relative;
  white-space: nowrap;
}
.nav__link::after {
  content: '';
  position: absolute; left: 0; bottom: 0;
  width: 0; height: 2px; background: var(--green-mark);
  transition: width .26s var(--ease);
}
.nav__link:hover::after, .nav__link.is-active::after { width: 100%; }
@media (min-width: 1120px) { .nav { display: flex; } }

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  font-family: var(--display);
  font-variation-settings: 'wdth' 100, 'wght' 700;
  font-size: .82rem;
  text-transform: uppercase;
  letter-spacing: .07em;
  text-decoration: none;
  padding: 14px 26px;
  border-radius: var(--radius);
  border: 1px solid transparent;
  cursor: pointer;
  transition: transform .2s var(--ease), background .25s var(--ease),
              color .25s var(--ease), border-color .25s var(--ease),
              box-shadow .25s var(--ease);
  white-space: nowrap;
}
.btn--solid {
  background: var(--emerald); color: #fff;
  box-shadow: 0 1px 0 rgba(0,0,0,.06);
}
.btn--solid:hover { background: var(--forest); transform: translateY(-2px); }
.btn--ghost {
  background: transparent; color: var(--green-ink);
  border-color: var(--edge-firm);
}
.btn--ghost:hover { border-color: var(--green-ink); background: var(--edge-tint); transform: translateY(-2px); }
.btn--onDark {
  background: transparent; color: #fff;
  border-color: rgba(255,255,255,.42);
}
.btn--onDark:hover { background: #fff; color: var(--abyss); transform: translateY(-2px); }
.btn--sm { padding: 10px 18px; font-size: .74rem; }
.masthead .btn { display: none; }
@media (min-width: 720px) { .masthead .btn { display: inline-flex; } }

/* hamburger */
.burger {
  display: inline-flex; flex-direction: column; justify-content: center; gap: 5px;
  width: 44px; height: 44px; padding: 0 10px;
  background: transparent; border: 1px solid var(--hairline);
  border-radius: var(--radius); cursor: pointer;
}
.burger span {
  display: block; height: 2px; width: 100%;
  background: var(--green-ink);
  transition: transform .3s var(--ease), opacity .2s var(--ease);
}
.burger[aria-expanded="true"] span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.burger[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.burger[aria-expanded="true"] span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }
@media (min-width: 1120px) { .burger { display: none; } }

/* ---------- light / dark ----------
   Sits beside the call to action, and is the one control in the bar
   that never goes away: on the phone the quote button is hidden and
   the nav folds into the drawer, but the switch stays out where it
   can be reached. Square, and the same 44px as the hamburger beside
   it, so the two read as a pair and both clear the minimum touch
   target.

   Both marks are in the button at once and cross over between them —
   the sun rises as the moon sets. Which one is showing says which
   theme is on; the aria-label, which theme.js rewrites on every
   switch, says what pressing it will do. */
.themetoggle {
  position: relative;
  display: inline-flex; align-items: center; justify-content: center;
  flex: 0 0 auto;
  width: 44px; height: 44px;
  padding: 0;
  background: transparent;
  border: 1px solid var(--hairline);
  border-radius: var(--radius);
  color: var(--green-ink);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: color .25s var(--ease), border-color .25s var(--ease),
              background .25s var(--ease);
}
.themetoggle:hover {
  border-color: var(--green-ink);
  background: var(--edge-tint);
}
/* The ring the rest of the site uses, stated here as well so it is
   never lost to the bar's overflow or to a later border rule. */
.themetoggle:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 3px;
}

/* The manager's bar is the deep hull green in either theme, so the
   switch standing in it is light-on-dark in either theme too. It also
   takes the height of the small buttons standing beside it rather than
   the 44px it uses in the site header — the manager's bar sizes itself
   to its tallest child, and two pixels of extra height there would push
   every page in the manager down by two pixels for no reason. */
.themetoggle--onDark {
  width: 42px; height: 42px;
  color: #fff;
  border-color: rgba(255, 255, 255, .42);
}
.themetoggle--onDark:hover {
  color: var(--abyss);
  background: #fff;
  border-color: #fff;
}

.themetoggle__icon {
  position: absolute;
  width: 21px; height: 21px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.9;
  stroke-linecap: round;
  stroke-linejoin: round;
  transition: opacity .3s var(--ease), transform .45s var(--ease);
}
/* Light is on: the sun is up. */
.themetoggle__icon--sun  { opacity: 1; transform: none; }
.themetoggle__icon--moon { opacity: 0; transform: rotate(-70deg) scale(.45); }
/* Dark is on: it has set, and the moon is out. */
[data-theme="dark"] .themetoggle__icon--sun  { opacity: 0; transform: rotate(70deg) scale(.45); }
[data-theme="dark"] .themetoggle__icon--moon { opacity: 1; transform: none; }

/* The two logos live in the bar together — the artwork as drawn, and
   the same lockup with the forest half lifted to mint so it reads on
   a dark ground. Only one is ever lit, and they cross over with the
   rest of the page rather than snapping. The pair is stacked rather
   than laid out side by side, so the bar's width is set by one logo,
   not two. */
.brand { position: relative; }
.brand__logo { transition: opacity .3s var(--ease); }
.brand__logo--dark {
  position: absolute; left: 0; top: 50%;
  transform: translateY(-50%);
  opacity: 0;
}
[data-theme="dark"] .brand__logo--light { opacity: 0; }
[data-theme="dark"] .brand__logo--dark  { opacity: 1; }

.drawer {
  position: fixed; inset: 78px 0 auto 0; z-index: 80;
  background: var(--paper);
  border-bottom: 1px solid var(--hairline);
  box-shadow: var(--lift-drawer);
  display: grid; gap: 2px;
  padding: 14px var(--gut) 24px;
  transform: translateY(-12px);
  opacity: 0; visibility: hidden;
  transition: opacity .25s var(--ease), transform .25s var(--ease), visibility .25s;
}
.drawer.is-open { opacity: 1; visibility: visible; transform: translateY(0); }
.drawer a {
  font-family: var(--display);
  font-variation-settings: 'wdth' 100, 'wght' 700;
  text-transform: uppercase; letter-spacing: .06em;
  font-size: 1rem; text-decoration: none; color: var(--green-ink);
  padding: 15px 4px; border-bottom: 1px solid var(--hairline);
}
.drawer a:last-child { border-bottom: 0; }
@media (min-width: 1120px) { .drawer { display: none; } }

/* =============================================================
   HERO
   ============================================================= */
.hero {
  position: relative;
  min-height: min(94svh, 860px);
  display: flex; align-items: flex-end;
  overflow: hidden;
  background: var(--abyss);
}
.hero__media { position: absolute; inset: 0; }
.hero__media img {
  width: 100%; height: 100%;
  object-fit: cover; object-position: 62% 58%;
  filter: saturate(1.06) contrast(1.08);
  transform: scale(1.06);
  animation: heroDrift 22s var(--ease) forwards;
}
@keyframes heroDrift { to { transform: scale(1); } }

.hero__scrim {
  position: absolute; inset: 0;
  background:
    linear-gradient(100deg, rgba(3,18,11,.95) 0%, rgba(3,18,11,.88) 25%,
                            rgba(3,18,11,.60) 48%, rgba(3,18,11,.18) 76%,
                            rgba(3,18,11,.04) 100%),
    linear-gradient(0deg, rgba(3,18,11,.80) 0%, rgba(3,18,11,0) 46%);
}

.hero__inner {
  position: relative; z-index: 2;
  width: 100%;
  /* The block stands on the floor of the hero. The section is
     bottom-aligned, so the second figure below is the gap between the
     buttons and the green capability strip that follows: 32px on a
     short desktop, 48px on a tall one, never outside that. The first
     figure keeps the headline clear of the masthead on the short,
     wide viewports where the content grows past the minimum height. */
  padding-block: clamp(72px, 14vh, 148px) clamp(32px, 4.2vh, 48px);
}

.hero__title {
  color: #fff;
  font-variation-settings: 'wdth' 112, 'wght' 800;
  text-transform: uppercase;
  font-size: var(--fs-h1);
  line-height: var(--lh-h1);
  letter-spacing: -.012em;
  max-width: 19ch;
  text-wrap: balance;
  text-shadow: 0 2px 26px rgba(3,18,11,.55);
}
.hero__title em {
  font-style: normal;
  display: block;
  color: var(--emerald-lt);
}
.hero__lede {
  color: rgba(255,255,255,.86);
  font-size: clamp(1.02rem, 1.5vw, 1.24rem);
  line-height: 1.6;
  max-width: 56ch;
  margin: clamp(20px, 3vh, 30px) 0 clamp(26px, 4vh, 38px);
}
.hero__cta { display: flex; flex-wrap: wrap; gap: 14px; }

/* animated entrance */
.hero__title, .hero__lede, .hero__cta {
  opacity: 0; transform: translateY(18px);
  animation: riseIn .9s var(--ease) forwards;
}
.hero__title { animation-delay: .10s; }
.hero__lede  { animation-delay: .20s; }
.hero__cta   { animation-delay: .30s; }
@keyframes riseIn { to { opacity: 1; transform: translateY(0); } }

/* =============================================================
   CAPABILITY STRIP
   An unbroken row travelling left to right, lit by a beam that runs
   the border. The row is one authored group of items that main.js
   repeats until it is wider than the screen; shifting the track by
   exactly one group width and starting over makes the seam invisible.
   ============================================================= */
.capstrip {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  background: var(--forest);
  color: #fff;
  border-block: 1px solid rgba(255,255,255,.14);
}

/* slow emerald and brass wash drifting behind the words */
.capstrip::before {
  content: '';
  position: absolute; inset: -50% -12%;
  z-index: -1;
  background:
    radial-gradient(36% 120% at 16% 50%, rgba(8,168,72,.42),   transparent 72%),
    radial-gradient(30% 110% at 55% 50%, rgba(198,149,47,.14), transparent 74%),
    radial-gradient(34% 120% at 88% 50%, rgba(46,204,113,.24), transparent 72%);
  filter: blur(14px);
  animation: capWash 19s ease-in-out infinite alternate;
}
@keyframes capWash {
  from { transform: translate3d(-7%, 0, 0) scale(1.04); opacity: .55; }
  to   { transform: translate3d( 7%, 0, 0) scale(1.20); opacity: .9;  }
}

/* the window the row runs through — both ends fade out */
.capstrip__viewport {
  overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 5%, #000 95%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 5%, #000 95%, transparent);
}

.capstrip__track {
  display: flex;
  width: max-content;
  will-change: transform;
}
/* main.js adds this once the group widths have been measured */
.capstrip__track.is-rolling {
  animation: capRoll var(--cap-dur, 30s) linear infinite;
}
@keyframes capRoll {
  from { transform: translate3d(calc(var(--cap-shift, 0px) * -1), 0, 0); }
  to   { transform: translate3d(0, 0, 0); }
}

.capstrip__group { display: flex; flex: 0 0 auto; }

.capstrip__item {
  flex: 0 0 auto;
  display: flex; align-items: center; gap: 12px;
  padding: 22px clamp(26px, 3.4vw, 52px);
  white-space: nowrap;
  border-right: 1px solid rgba(255,255,255,.13);
}
.capstrip__item span { color: rgba(255,255,255,.92); }
.capstrip__item i {
  font-style: normal; color: var(--brass-lt);
  font-family: var(--mono); font-size: .62rem;
}

/* ---------- border beam ----------
   Two lights chase each other around the edge of the strip. Browsers
   that understand motion paths send them round the whole rectangle;
   everywhere else they sweep the top and bottom rules instead. */
.capstrip__beam {
  position: absolute;
  top: 0; left: 0;
  width: clamp(110px, 13vw, 230px);
  height: 2px;
  border-radius: 999px;
  pointer-events: none;
  background: linear-gradient(90deg,
    rgba(8,168,72,0)     0%,
    rgba(46,204,113,.85) 28%,
    #F4FFF8              50%,
    rgba(224,179,85,.85) 72%,
    rgba(198,149,47,0)  100%);
  box-shadow: 0 0 6px rgba(46,204,113,.6), 0 0 15px rgba(46,204,113,.25);
}
.capstrip__beam--a { top: 0; animation: capBeamSweep 7s linear infinite; }
.capstrip__beam--b {
  top: auto; bottom: 0;
  animation: capBeamSweep 7s linear infinite reverse;
  animation-delay: -3.5s;
}
@keyframes capBeamSweep {
  from { transform: translate3d(-110%, 0, 0); }
  to   { transform: translate3d(calc(100vw + 10%), 0, 0); }
}

@supports (offset-path: rect(0 auto auto 0)) {
  .capstrip__beam {
    top: 0; bottom: auto;
    transform: none;
    offset-path: rect(2px calc(100% - 2px) calc(100% - 2px) 2px round 2px);
    offset-rotate: auto;
    offset-anchor: 50% 50%;
    animation: capBeamRing 9s linear infinite;
  }
  .capstrip__beam--b { animation-delay: -4.5s; }
  @keyframes capBeamRing {
    from { offset-distance: 0%;   }
    to   { offset-distance: 100%; }
  }
}

/* =============================================================
   GENERIC SECTION SHELL
   Padding lives on .band only, so nothing fights it later.
   ============================================================= */
.band { padding-block: clamp(72px, 11vh, 132px); position: relative; }
.band--paper { background: var(--paper); }
.band--mint  { background: var(--mint); }
.band--dark  { background: var(--abyss); color: #fff; }
.band--forest{ background: var(--forest); color: #fff; }

/* The 62ch measure was set when the headings were large enough to need
   the same short line as the copy. At the sizes on the ladder they no
   longer do, and holding them to it broke short headings across two
   lines with one word stranded on the second. The head block opens up,
   and the reading measure moves down onto the copy where it belongs. */
.band__head { max-width: 80ch; margin-bottom: clamp(40px, 6vh, 68px); }
.band__eyebrow {
  display: flex; align-items: center; gap: 12px;
  color: var(--green-mark);
  margin-bottom: 20px;
}
.band__eyebrow::before {
  content: ''; width: 34px; height: 2px;
  background: var(--brass-ink); flex: 0 0 auto;
}
.band--dark .band__eyebrow, .band--forest .band__eyebrow { color: var(--brass-lt); }

.band__title {
  font-variation-settings: 'wdth' 106, 'wght' 800;
  text-transform: uppercase;
  font-size: var(--fs-h2);
  color: var(--green-ink);
  line-height: var(--lh-h2);
  text-wrap: balance;
}
.band--dark .band__title, .band--forest .band__title { color: #fff; }
/* Core Services carries its green in the panels, so the heading
   holds the same forest tone against the white ground. */
.band__title--forest { color: var(--green-ink-deep); }

.band__lede {
  margin-top: 18px;
  max-width: 62ch;
  font-size: 1.06rem;
  color: var(--ink-soft);
  line-height: 1.62;
}
.band--dark .band__lede, .band--forest .band__lede { color: rgba(255,255,255,.76); }

/* =============================================================
   LANDING-PAGE RHYTHM
   Every band on the home page is a short introduction now — an
   eyebrow, a heading, a line or two and the way through to the
   page that carries the detail. The padding they inherit was
   sized for bands that held their content, and at that measure
   Core Services, Equipment and Contact ended up drifting the
   better part of a screen apart. The home page takes its own,
   tighter rhythm.

   The figures below are half of each gap, because the band above
   and the band below both put their padding into it: the space
   between two sections comes to 96px on the desktop, 72px on the
   tablet and 50px on the phone. Nothing is pulled with a negative
   margin, so the bands cannot ride over one another.
   ============================================================= */
.page-home .band       { padding-block: 25px; }
.page-home .band__head { margin-bottom: 24px; }

/* The eyebrow is a <p>, and headings are the only elements the reset
   takes the margin off, so it still carried the browser's own 1em
   above it — fourteen pixels, sitting inside the band's top padding
   and quietly widening every gap on the page. The band opens on its
   padding and nothing else. */
.page-home .band__eyebrow { margin-top: 0; }

/* The row of buttons a band closes on. An inline-flex button sitting
   in a block wrapper still drags a line box along with it, and the
   leading under that line box added a dozen invisible pixels to every
   gap below. Laying the row out as flex drops the strut, so the space
   under a band is the padding and nothing else. */
.band__act { display: flex; flex-wrap: wrap; align-items: flex-start; gap: 14px; }


@media (min-width: 768px) {
  .page-home .band       { padding-block: 36px; }
  .page-home .band__head { margin-bottom: 28px; }
}

@media (min-width: 1024px) {
  .page-home .band       { padding-block: 48px; }
  .page-home .band__head { margin-bottom: 32px; }
}

/* =============================================================
   ABOUT
   ============================================================= */
/* --- the page's opening heading ---------------------------------
   The profile's title is the longest heading on the site, and on
   /about-us it was breaking across three lines with "and energy"
   stranded on the last of them. Two things were holding it there.

   The measure: .band__head is capped at 80ch, and ch is read off the
   element's own font — Source Serif at body size — so the cap came
   out around 720px. The heading is set in Archivo at heading size and
   needed a little over 740px to sit on two lines, so it missed by a
   hair. The cap is lifted altogether: the heading takes the same
   .shell--full measure the paragraphs take, and reaches as far right
   as they do.

   The size: the h2 step tops out at 40px, and this one heading comes
   down off it. It runs 26px on the phone to 34px by the tablet, then
   climbs again from 34px to the 48px ceiling only on displays wider
   than most desktops — so at an ordinary 1280-1600px window it reads
   between 36px and 40px, smaller than it was.

   Nothing forces a break. Below 1024px the wrap is left to
   text-wrap: balance, inherited from .band__title, which evens the
   lines out — the right thing on a phone, where there is no spare
   width to fill. From 1024px up there is spare width, and balance
   would leave it empty by holding both lines to the shorter of the
   two, so the heading wraps normally there and fills the measure.
   ---------------------------------------------------------------- */
.band__head--wide { max-width: none; }

.band__title--about {
  font-size: clamp(26px, 2.0833vw + 19.333px, 34px);
  line-height: 1.15;
}

/* The narrowest phones. The size is already sitting on its 26px floor
   here, so the only room left is on the width axis — the same lever
   the NARROW SCREENS block pulls for every other heading, taken one
   step further. Without it "Integrated" and "solutions" cannot share
   a line on a 320px screen and the heading runs to five. */
@media (max-width: 380px) {
  /* Compound on purpose: the NARROW SCREENS block further down sets
     'wdth' 98 on .band__title, and it comes later in the file. */
  .band__title.band__title--about { font-variation-settings: 'wdth' 88, 'wght' 800; }
}

/* 1024px and up. The curve is continuous at the breakpoint — it opens
   on the 34px the tablet finished at — and the 32px floor is there so
   the rule cannot land above its band if the query is ever widened. */
@media (min-width: 1024px) {
  .band__title--about {
    font-size: clamp(32px, 1.0174vw + 23.58px, 48px);
    text-wrap: wrap;
  }
}

/* The profile used to hold a 72ch reading measure, which left the
   right-hand half of the band empty. It runs the full width of
   .shell--full now — no cap of its own, no cap on the paragraphs —
   so the lines reach the same right edge as the heading above them.

   That is a long line to read: at the 1400px bound it comes out near
   150 characters, where 45 to 90 is the range prose is easiest to
   track along. The 1.7 line-height below is doing what it can about
   that, giving the eye a clear rail back to the start of the next
   line. Putting a max-width back on .about__prose is the one change
   that would undo it. */
.about__prose { max-width: none; }

/* One size for every paragraph, the opening one included, so the
   column reads evenly all the way down: 17px on the phone and the
   tablet, climbing to 18px by the time the shell reaches its bound. */
.about__prose p {
  margin: 0 0 1.15em;
  font-size: clamp(17px, 0.1582vw + 15.785px, 18px);
  line-height: 1.7;
}
.about__prose p:last-child { margin-bottom: 0; }
.about__prose strong { color: var(--green-ink); font-weight: 700; }
.about__prose .lead {
  color: var(--ink);
}
.about__prose .lead::first-letter {
  font-family: var(--display);
  font-variation-settings: 'wdth' 108, 'wght' 800;
  float: left;
  font-size: 3.5em;
  line-height: .78;
  padding: .06em .12em 0 0;
  color: var(--green-mark);
}

/* =============================================================
   MISSION & VISION
   ============================================================= */
.mv {
  display: grid; gap: 2px;
  grid-template-columns: 1fr;
  border: 1px solid var(--hairline-d);
}
@media (min-width: 860px) { .mv { grid-template-columns: 1fr 1fr; } }

.mv__cell {
  /* Trimmed from clamp(34px, 4.6vw, 56px): at laptop widths the old
     padding left the heading about ten pixels short of two lines, and
     it broke to three with one word on its own. */
  padding: clamp(30px, 3.4vw, 50px);
  background: var(--abyss-2);
  position: relative;
  overflow: hidden;
}
.mv__cell + .mv__cell { border-left: 1px solid var(--hairline-d); }
@media (max-width: 859px) {
  .mv__cell + .mv__cell { border-left: 0; border-top: 1px solid var(--hairline-d); }
}
.mv__glyph {
  position: absolute; right: -30px; bottom: -40px;
  width: 210px; opacity: .05;
  pointer-events: none;
}
.mv__k { color: var(--brass-lt); margin-bottom: 18px; display: block; }
.mv__h {
  font-variation-settings: 'wdth' 106, 'wght' 800;
  text-transform: uppercase;
  font-size: var(--fs-h3);
  line-height: var(--lh-h3);
  color: #fff; margin-bottom: 16px;
}
.mv__p { color: rgba(255,255,255,.8); margin: 0; position: relative; z-index: 1; }

/* =============================================================
   CORE SERVICES
   ============================================================= */
.svc {
  display: grid; gap: clamp(26px, 3vw, 34px);
  grid-template-columns: 1fr;
}
@media (min-width: 700px)  { .svc { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1080px) { .svc { grid-template-columns: repeat(4, 1fr); } }

.svc__col {
  background: var(--paper);
  border: 1px solid var(--hairline);
  border-top: 3px solid var(--emerald);
  border-radius: var(--radius);
  padding: 30px 26px;
  transition: transform .3s var(--ease), box-shadow .3s var(--ease),
              border-top-color .3s var(--ease);
}
.svc__col:hover {
  transform: translateY(-5px);
  box-shadow: var(--lift-panel);
  border-top-color: var(--brass);
}
.band--mint .svc__col { background: var(--paper); }

/* Four abreast is the narrowest the panels ever get — about 200px of
   text width. A little of the side padding comes back there, which is
   the difference between every heading holding to the two lines the
   rule beneath it is spaced for, and one of them running to three. */
@media (min-width: 1080px) { .svc__col { padding-inline: 18px; } }

.svc__h {
  font-variation-settings: 'wdth' 102, 'wght' 800;
  text-transform: uppercase;
  font-size: var(--fs-h3);
  line-height: var(--lh-h3);
  color: var(--green-ink);
  margin-bottom: 20px;
  padding-bottom: 16px;
  border-bottom: 1px solid var(--hairline);
  /* Four columns side by side, so the rules under the headings line up
     whether a heading takes one line or two. 2.5em is exactly two lines
     at this line-height. */
  min-height: 2.5em;
  display: flex; align-items: flex-end;
}
/* Stacked on one column, the four headings have nothing to line up
   with, so the reserved second line comes off. */
@media (max-width: 699px) { .svc__h { min-height: 0; } }

.svc__list { list-style: none; margin: 0; padding: 0; }
.svc__list li {
  position: relative;
  padding: 9px 0 9px 22px;
  font-size: .96rem;
  line-height: 1.45;
  color: var(--ink-soft);
}
.svc__list li::before {
  content: '';
  position: absolute; left: 0; top: 1.32em;
  width: 9px; height: 1px;
  background: var(--green-mark);
}

/* =============================================================
   EQUIPMENT FOR SALE
   ============================================================= */
.equip__bar {
  display: flex; flex-wrap: wrap; gap: 14px;
  align-items: center; justify-content: space-between;
  margin-bottom: 34px;
  padding-bottom: 18px;
  border-bottom: 1px solid var(--hairline);
}
.equip__count { color: var(--ink-soft); }
.equip__filters { display: flex; flex-wrap: wrap; gap: 8px; }
.chip {
  font-family: var(--mono);
  font-size: .66rem; letter-spacing: .12em; text-transform: uppercase;
  padding: 8px 14px;
  border: 1px solid var(--hairline);
  border-radius: 999px;
  background: transparent; color: var(--ink-soft);
  cursor: pointer;
  transition: background .22s var(--ease), color .22s var(--ease), border-color .22s var(--ease);
}
.chip:hover { border-color: var(--green-mark); color: var(--green-ink); }
.chip.is-on { background: var(--forest); border-color: var(--forest); color: #fff; }

.equip__grid {
  display: grid; gap: clamp(20px, 2.4vw, 28px);
  grid-template-columns: repeat(auto-fill, minmax(272px, 1fr));
}

.card {
  background: var(--paper);
  border: 1px solid var(--hairline);
  border-radius: var(--radius);
  overflow: hidden;
  display: flex; flex-direction: column;
  transition: transform .3s var(--ease), box-shadow .3s var(--ease);
}
.card:hover { transform: translateY(-5px); box-shadow: var(--lift-card); }

.card__media {
  position: relative;
  aspect-ratio: 4 / 3;
  background: var(--mint-deep);
  overflow: hidden;
}
.card__media img {
  width: 100%; height: 100%; object-fit: cover;
  transition: transform .6s var(--ease);
}
.card:hover .card__media img { transform: scale(1.05); }
.card__tag {
  position: absolute; left: 12px; top: 12px;
  background: rgba(4,35,21,.86);
  color: var(--brass-lt);
  font-family: var(--mono);
  font-size: .6rem; letter-spacing: .13em; text-transform: uppercase;
  padding: 6px 11px; border-radius: 2px;
  backdrop-filter: blur(6px);
}
/* 18px at the sides rather than 22px: in the three-up grid that is the
   difference between the title holding to two lines and running to
   three. The vertical rhythm is unchanged. */
.card__body { padding: 22px 18px 24px; display: flex; flex-direction: column; flex: 1; }
.card__title {
  font-variation-settings: 'wdth' 102, 'wght' 800;
  text-transform: uppercase;
  font-size: var(--fs-h3);
  line-height: var(--lh-h3);
  color: var(--green-ink);
  margin-bottom: 12px;
}
/* Optional description under a group heading, when one is written
   into the Content tab of the manager. */
.svc__blurb {
  font-size: .92rem;
  color: var(--ink-soft);
  margin: -8px 0 16px;
  line-height: 1.6;
}

/* A note attached to a single service. */
.svc__note {
  display: block;
  font-family: var(--mono);
  font-size: .66rem;
  letter-spacing: .05em;
  color: var(--ink-soft);
  margin-top: 3px;
}

/* Core services sit on white, so the green moves into the panels:
   four solid forest blocks, white type, brass on hover. */
.svc--forest .svc__col {
  background: var(--forest-deep);
  border: 1px solid var(--hairline-d);
  border-top: 3px solid var(--emerald);
  transition: transform .3s var(--ease), box-shadow .3s var(--ease),
              background .3s var(--ease), border-top-color .3s var(--ease);
}
/* The hover lift stays as it was; the fill lightens within the green
   rather than towards white, which on this ground would wash the panel
   out instead of lifting it. */
.svc--forest .svc__col:hover {
  background: #17683A;
  box-shadow: 0 22px 44px rgba(4,35,21,.20);
  border-top-color: var(--brass-lt);
}
.svc--forest .svc__h {
  color: #fff;
  border-bottom-color: var(--hairline-d);
}
.svc--forest .svc__list li { color: #fff; }
.svc--forest .svc__list li::before { background: var(--emerald-lt); }
.svc--forest .svc__blurb { color: #fff; }
.svc--forest .svc__note  { color: var(--brass-lt); }

/* Equipment description, between the title and the spec table. */
.card__blurb {
  font-size: .93rem;
  color: var(--ink-soft);
  line-height: 1.6;
  margin: -4px 0 14px;
}

.card__spec {
  list-style: none; margin: 0 0 18px; padding: 0;
  border-top: 1px solid var(--hairline);
}
.card__spec li {
  display: flex; justify-content: space-between; gap: 14px;
  padding: 8px 0;
  border-bottom: 1px solid var(--hairline);
  font-family: var(--mono);
  font-size: .68rem; letter-spacing: .04em;
  color: var(--ink-soft);
}
.card__spec b {
  color: var(--ink); font-weight: 600;
  text-align: right;
  font-variant-numeric: lining-nums tabular-nums;
}
.card__foot { margin-top: auto; display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.card__price {
  font-family: var(--display);
  font-variation-settings: 'wdth' 100, 'wght' 800;
  color: var(--brass-ink);
  font-size: 1.02rem;
  font-variant-numeric: lining-nums;
}

.equip__empty, .equip__loading {
  grid-column: 1 / -1;
  text-align: center;
  padding: 64px 24px;
  border: 1px dashed var(--hairline);
  border-radius: var(--radius);
  color: var(--ink-soft);
}
.equip__note {
  margin-top: 26px;
  padding: 16px 20px;
  border-left: 3px solid var(--brass-ink);
  background: var(--brass-tint);
  color: var(--ink-soft);
  font-size: .9rem;
}

/* =============================================================
   CONTACT
   ============================================================= */
.contact__grid {
  display: grid; gap: clamp(32px, 5vw, 60px);
  grid-template-columns: 1fr;
  align-items: start;
}
@media (min-width: 940px) { .contact__grid { grid-template-columns: 1.25fr .85fr; } }

.form { display: grid; gap: 20px; }
.form__row { display: grid; gap: 20px; grid-template-columns: 1fr; }
@media (min-width: 620px) { .form__row { grid-template-columns: 1fr 1fr; } }

.field { display: flex; flex-direction: column; gap: 8px; }
.field label {
  font-family: var(--mono);
  font-size: .66rem; letter-spacing: .14em; text-transform: uppercase;
  color: var(--green-ink);
}
.field label .req { color: var(--brass-ink); }
.field input, .field textarea, .field select {
  font-family: var(--body);
  font-size: 1rem;
  color: var(--ink);
  background: var(--paper);
  border: 1px solid var(--hairline);
  border-radius: var(--radius);
  padding: 14px 16px;
  width: 100%;
  transition: border-color .22s var(--ease), box-shadow .22s var(--ease);
}
.field textarea { resize: vertical; min-height: 150px; line-height: 1.55; }
.field input:focus, .field textarea:focus, .field select:focus {
  outline: none;
  border-color: var(--green-mark);
  box-shadow: 0 0 0 3px rgba(8,168,72,.16);
}
.field input:invalid:not(:placeholder-shown) { border-color: var(--danger); }

/* --- what the visitor is told when a field is wrong --- */
.field__err {
  margin: 0;
  font-family: var(--mono);
  font-size: .72rem;
  line-height: 1.45;
  color: var(--danger-ink);
  display: none;
}
.field.is-bad .field__err { display: block; }
.field.is-bad input,
.field.is-bad select,
.field.is-bad textarea { border-color: var(--danger); background: var(--danger-tint); }
.field.is-bad input:focus,
.field.is-bad select:focus,
.field.is-bad textarea:focus {
  border-color: var(--danger);
  box-shadow: 0 0 0 3px rgba(192,69,59,.16);
}

.form__status {
  padding: 14px 18px; border-radius: var(--radius);
  font-size: .92rem; display: none;
}
.form__status.is-shown { display: block; }
.form__status.is-ok  { background: var(--ok-tint); border-left: 3px solid var(--green-mark); color: var(--green-ink); }
.form__status.is-err { background: var(--danger-tint2); border-left: 3px solid var(--danger); color: var(--danger-ink); }

.contact__aside { display: grid; gap: 10px; }
.contact__item {
  background: var(--paper);
  border: 1px solid var(--hairline);
  padding: 22px 24px;
  border-radius: var(--radius);
}
.contact__k { color: var(--green-mark); display: block; margin-bottom: 8px; }
.contact__v {
  font-family: var(--display);
  font-variation-settings: 'wdth' 100, 'wght' 700;
  font-size: 1.02rem; color: var(--green-ink);
  text-decoration: none; word-break: break-word;
}
a.contact__v:hover { color: var(--green-mark); }

/* --- WhatsApp: the second way in, beside the form --- */
.contact__wa { display: grid; gap: 14px; justify-items: start; }
.contact__wa[hidden] { display: none; }
.contact__wa .contact__k { margin-bottom: 0; }
.contact__wa-note {
  margin: 0;
  font-size: .94rem;
  line-height: 1.5;
  color: var(--ink-soft);
}
.btn--wa {
  background: #25D366;
  color: #fff;
  box-shadow: 0 1px 0 rgba(0,0,0,.06);
}
.btn--wa:hover { background: var(--forest); transform: translateY(-2px); }
.btn--wa svg {
  width: 18px; height: 18px;
  fill: currentColor;
  flex: 0 0 auto;
}

/* =============================================================
   MAP — the registered office, on the contact page
   ============================================================= */
.map {
  border: 1px solid var(--hairline);
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--mint);
  line-height: 0;
}
.map__frame {
  display: block;
  width: 100%;
  height: clamp(280px, 46vw, 460px);
  border: 0;
}
.map__note { margin: 20px 0 0; }

/* =============================================================
   FOOTER
   ============================================================= */
.foot { background: var(--abyss); color: rgba(255,255,255,.7); }
.foot__top {
  display: grid; gap: 40px;
  grid-template-columns: 1fr;
  padding-block: clamp(52px, 7vh, 80px);
}
@media (min-width: 860px) { .foot__top { grid-template-columns: 1.4fr 1fr 1fr; } }
/* The footer carries the original company logo, full colour, on the pale
   ground it was drawn on — that field is part of the artwork, evenly
   margined, so nothing is added here but the corner radius the rest of the
   site uses. Width-driven, so it keeps its proportions as the column
   narrows. Dark green on the dark footer would all but vanish; on its own
   pale ground the wordmark and the anchor both read at this size. */
.foot__logo {
  display: block;
  width: 260px; max-width: 70%; height: auto;
  border-radius: var(--radius);
  margin-bottom: 26px;
}
.foot__blurb { max-width: 42ch; font-size: .95rem; line-height: 1.6; }
.foot__h {
  color: var(--brass-lt);
  margin-bottom: 18px; display: block;
}
.foot__list { list-style: none; margin: 0; padding: 0; display: grid; gap: 11px; }
.foot__list a {
  color: rgba(255,255,255,.76); text-decoration: none; font-size: .95rem;
  transition: color .2s var(--ease);
}
.foot__list a:hover { color: var(--emerald-lt); }
.foot__bar {
  border-top: 1px solid var(--hairline-d);
  padding-block: 24px;
  display: flex; flex-wrap: wrap; gap: 12px;
  align-items: center; justify-content: space-between;
  color: rgba(255,255,255,.5);
}

/* =============================================================
   SCROLL REVEAL
   ============================================================= */
.reveal { opacity: 0; transform: translateY(24px); }
.reveal.is-in {
  opacity: 1; transform: none;
  transition: opacity .7s var(--ease), transform .7s var(--ease);
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
  .reveal { opacity: 1; transform: none; }
  .hero__media img { animation: none; transform: none; }
  /* the strip stays full width but stands still, and the beam goes away */
  .capstrip__track.is-rolling { animation: none !important; transform: none; }
  .capstrip::before { animation: none !important; }
  .capstrip__beam { display: none; }
  .hero__title, .hero__lede, .hero__cta { opacity: 1; transform: none; }
}


/* =============================================================
   NARROW SCREENS
   The expanded display axis and wide mono tracking are luxuries
   that only fit on bigger viewports — pull both in.
   ============================================================= */
@media (max-width: 720px) {
  /* The width axis narrows so the headline still fits the column; the
     size itself now comes from --fs-h1 and is not restated here. */
  .hero__title {
    font-variation-settings: 'wdth' 92, 'wght' 800;
    max-width: none;
  }
  .capstrip__item .u-mono { font-size: .62rem; letter-spacing: .09em; }
  .band__title  { font-variation-settings: 'wdth' 98, 'wght' 800; }
  /* Not a set height any more. The bar has one more fixed-width
     control in it, so on the narrowest phones the lockup has to be
     able to give way — max-height with max-width, and the width and
     height both auto, scales it down in proportion rather than
     letting it overflow the bar or squash. */
  .brand__logo  { width: auto; height: auto; max-height: 34px; max-width: 100%; }
  .mv__h, .svc__h, .card__title { font-variation-settings: 'wdth' 96, 'wght' 800; }
  .card__spec li { font-size: .64rem; }
}

@media (max-width: 720px) {
  /* The quote button is hidden below 720px and the nav is in the
     drawer, so the bar is the lockup, the switch and the hamburger.
     The 24px gap was drawn for a bar with fewer things in it. */
  .masthead__inner { gap: 12px; }
  .brand { flex: 0 1 auto; min-width: 0; padding-right: 0; }
}

@media (max-width: 400px) {
  .btn { padding: 13px 20px; font-size: .76rem; }
  .masthead__inner { gap: 9px; }
  .themetoggle { width: 40px; height: 40px; }
  .themetoggle__icon { width: 19px; height: 19px; }
}


/* =============================================================
   HEADER AT LAPTOP WIDTHS
   Between the nav appearing and the layout reaching full width,
   the bar has to earn its space back.
   ============================================================= */
@media (min-width: 1120px) and (max-width: 1360px) {
  .nav { gap: clamp(15px, 1.7vw, 26px); }
  .nav__link { font-size: .77rem; letter-spacing: .05em; }
  .brand { margin-right: 22px; padding-right: 0; }
  .brand__logo { height: 38px; }
  .masthead .btn { padding: 12px 18px; font-size: .76rem; }
}

/* ============================================================
   ANIMATED BORDER BEAM
   A light travels the edge of a card. Pure CSS: a conic
   gradient is rotated by --beam-angle, then masked so only a
   1px ring of it shows. Used on Mission & Vision, Core
   Services and the Equipment cards.
   ============================================================ */

@property --beam-angle {
  syntax: '<angle>';
  initial-value: 0deg;
  inherits: false;
}

@keyframes beam-spin { to { --beam-angle: 1turn; } }

/* The ring itself — shared by all three placements. */
.mv--beam .mv__cell::after,
.svc--beam .svc__col::after,
.svc--beam .svc__col::before,
.card--beam::after {
  content: "";
  position: absolute;
  inset: 0;
  padding: 1px;                 /* ring thickness */
  border-radius: inherit;
  pointer-events: none;
  z-index: 3;
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
          mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
  animation: beam-spin 6s linear infinite;
}

/* These two are position:static by default; the ring needs a
   positioned parent to sit against. */
.svc--beam .svc__col,
.card--beam { position: relative; }

/* --- Mission & Vision: dark ground, so the beam runs bright --- */
.mv--beam .mv__cell::after {
  background: conic-gradient(from var(--beam-angle) at 50% 50%,
    transparent 0turn, transparent .62turn,
    var(--emerald) .78turn, var(--emerald-lt) .84turn,
    var(--brass-lt) .90turn, var(--brass) .95turn, transparent 1turn);
}
.mv--beam .mv__cell:nth-child(2)::after { animation-delay: -3s; }

/* --- Core Services ---
   These columns were pale when the beam was written, so it ran in
   --forest/--emerald/--brass to stay legible against white. The
   panels are now solid --forest-deep (#0E582E), which left a dark
   green beam on a dark green ground: present, but invisible. It
   now runs bright lemon so it reads against the block.

   The ring is pulled out to the border box (top -3px clears the
   3px emerald border, -1px clears the hairline on the other three
   sides) so the light travels the block's outer edge instead of
   hiding just inside it. Insets on an absolutely positioned
   pseudo-element cost no layout, so the blocks do not move. */
.svc--beam .svc__col {
  --svc-beam: conic-gradient(from var(--beam-angle) at 50% 50%,
    transparent 0turn, transparent .52turn,
    rgba(32,207,108,.32) .68turn,
    #20CF6C .82turn, #8CF7BC .90turn, #20CF6C .95turn,
    transparent 1turn);
}
.svc--beam .svc__col::after {
  background: var(--svc-beam);
  inset: -3px -1px -1px;
  padding: 3px;                 /* beam thickness */
  animation-duration: 3s;
}
/* The glow: the same travelling light on a wider band, blurred and
   held back in opacity. Masking happens after filtering, so the
   blur is contained by the band rather than spilling over the type
   — hence the band is wide enough to give the blur room to fall
   off. Sits under the crisp beam. */
.svc--beam .svc__col::before {
  background: var(--svc-beam);
  inset: -3px -1px -1px;
  padding: 11px;
  z-index: 2;
  opacity: .55;
  filter: blur(6px);
  animation-duration: 3s;
}
/* Stagger stays a quarter-cycle apart, rescaled to the 3s cycle. */
.svc--beam .svc__col:nth-child(2)::after,
.svc--beam .svc__col:nth-child(2)::before { animation-delay: -.75s; }
.svc--beam .svc__col:nth-child(3)::after,
.svc--beam .svc__col:nth-child(3)::before { animation-delay: -1.5s; }
.svc--beam .svc__col:nth-child(4)::after,
.svc--beam .svc__col:nth-child(4)::before { animation-delay: -2.25s; }

/* --- Equipment: beam waits for attention, then lights up.
       The grid can hold twenty listings; twenty rings turning
       at once is noise, and twenty repainting is a cost the
       page does not need to pay while nobody is looking. --- */
.card--beam::after {
  background: conic-gradient(from var(--beam-angle) at 50% 50%,
    transparent 0turn, transparent .60turn,
    var(--forest) .76turn, var(--emerald) .84turn,
    var(--brass) .92turn, transparent 1turn);
  opacity: 0;
  animation-play-state: paused;
  transition: opacity .35s var(--ease);
}
.card--beam:hover::after,
.card--beam:focus-within::after {
  opacity: 1;
  animation-play-state: running;
}

/* Motion is decorative here. If it is unwelcome, hold the beam
   still rather than removing the edge entirely. */
@media (prefers-reduced-motion: reduce) {
  .mv--beam .mv__cell::after,
  .svc--beam .svc__col::after,
  .svc--beam .svc__col::before,
  .card--beam::after {
    animation: none;
  }
  .card--beam:hover::after,
  .card--beam:focus-within::after { opacity: 1; }
}


/* =============================================================
   DARK THEME
   The whole of the second theme is here. theme.js puts
   data-theme="dark" on <html> before the body is parsed, and
   everything below follows from that one attribute.

   The brand does not move. Forest, emerald and brass are the
   company's colours and they are the same colours in the dark —
   what changes is which of them is doing which job. The forest
   green that sets headings on the pale ground is unreadable on a
   dark one, so the type role moves up to a light green while the
   fills — the quote button, the capability strip, the forest
   service panels — go on being brand forest and brand emerald
   with white type, exactly as before.

   The grounds are built out of the hull green the logo was
   sampled from rather than out of grey, so the dark theme is
   recognisably the same company: the page sits on #0A2617, cards
   and panels rise off it on #10301F, and the bands that are
   already dark in the light theme go deeper still so they keep
   reading as bands.
   ============================================================= */
[data-theme="dark"] {
  /* --- grounds and type --- */
  --mint:       #0A2617;   /* the page ground                    */
  --mint-deep:  #082013;   /* a well cut into it                 */
  --paper:      #10301F;   /* cards, panels, fields — raised     */
  --ink:        #E8F3EC;
  --ink-soft:   #A3BCAE;
  --hairline:   rgba(255, 255, 255, .13);

  --abyss:      #03150C;   /* footer and dark bands              */
  --abyss-2:    #061D11;

  /* --- the brand, doing its jobs on a dark ground --- */
  --green-ink:      #4FD98C;
  --green-ink-deep: #4FD98C;
  --green-mark:     var(--emerald-lt);
  --brass-ink:      var(--brass-lt);

  --masthead:   rgba(10, 38, 23, .82);
  --edge-firm:  rgba(255, 255, 255, .30);
  --edge-tint:  rgba(255, 255, 255, .07);
  --code-tint:  rgba(255, 255, 255, .08);
  --brass-tint: rgba(224, 179, 85, .11);
  --ok-tint:    rgba(46, 204, 113, .14);
  --focus:      var(--emerald-lt);

  --danger:      #E5695E;
  --danger-ink:  #FFA79C;
  --danger-tint: rgba(229, 105, 94, .10);
  --danger-tint2:rgba(229, 105, 94, .14);

  /* Hull green at low opacity disappears against a dark ground;
     lift has to be cut out of black here to register at all. */
  --lift-drawer: 0 24px 48px rgba(0, 0, 0, .55);
  --lift-panel:  0 22px 44px rgba(0, 0, 0, .45);
  --lift-card:   0 24px 46px rgba(0, 0, 0, .50);

  color-scheme: dark;
}

/* The service panels sit on the page ground rather than on white
   now, and 3% white is not enough to separate a card from it.
   The hairline they share with everything else does the work. */
[data-theme="dark"] .svc--forest .svc__col { border-color: var(--hairline); }

/* The equipment beam opened on forest, which on a dark card is the
   ground itself — the light appeared to start halfway along. It
   opens on the light green instead, so the full pass reads. */
[data-theme="dark"] .card--beam::after {
  background: conic-gradient(from var(--beam-angle) at 50% 50%,
    transparent 0turn, transparent .60turn,
    var(--emerald) .76turn, var(--emerald-lt) .84turn,
    var(--brass-lt) .92turn, transparent 1turn);
}

/* The photograph behind the hero is graded for a dark scrim and
   needs nothing; the map is a real map and stays a real map. Both
   are left alone deliberately. */


/* =============================================================
   THE SWITCH ITSELF
   Colour is spread across a few hundred declarations, and giving
   every one of them a standing transition would cost something on
   every hover and every scroll for the sake of one click.

   Instead the transition is lent to the page only while the switch
   is happening: theme.js puts .theme-switching on <html>, flips the
   attribute, and takes the class off again once the crossfade is
   done. At rest nothing here applies, so no existing transition on
   the site is touched.

   It is stated inside a no-preference query because the rule is
   more specific than the reduced-motion block further up and would
   otherwise beat it.
   ============================================================= */
@media (prefers-reduced-motion: no-preference) {
  .theme-switching,
  .theme-switching *,
  .theme-switching *::before,
  .theme-switching *::after {
    transition: background-color .4s var(--ease),
                border-color     .4s var(--ease),
                color            .4s var(--ease),
                fill             .4s var(--ease),
                stroke           .4s var(--ease),
                box-shadow       .4s var(--ease),
                opacity          .4s var(--ease),
                outline-color    .4s var(--ease) !important;
    transition-delay: 0s !important;
  }
  /* The sun and moon swap on transform, which the blanket rule
     above does not carry. More specific, so it wins it back. */
  .theme-switching .themetoggle__icon {
    transition: opacity .3s var(--ease), transform .45s var(--ease) !important;
  }
}
