/* ============================================================================
   Flora Logistics — site stylesheet
   ----------------------------------------------------------------------------
   The palette and the surface/border/shadow tokens are lifted from the Flolog
   admin app (web-admin/src/style.css and src/plugins/vuetify.ts) so the public
   site and the customer-facing app read as one product family. Names are kept
   identical to the app's (`--flg-*`) on purpose: a value changed there can be
   pasted straight in here.

   Everything paints through a token. Nothing takes a literal hex inside a
   `@media (prefers-color-scheme)` or `[data-theme]` block, so every component
   is correct in light, dark, and the un-stamped "system" state.
   ========================================================================== */

/* ── Tokens: light ──────────────────────────────────────────────────────── */
:root {
  /* Brand. --flg-brand is the Flolog admin's `primary`; the deep/bright pair is
     the logo leaf's own gradient, as declared in the Flutter app's AppTheme. */
  --flg-brand: #088940;
  --flg-brand-deep: #026333;
  --flg-brand-bright: #52b748;
  --flg-brand-accent: #34d399;
  /* The serif "LOGISTICS" in the wordmark is a warm sienna, and it is the only
     colour in the identity that is not green. Spent sparingly — eyebrows and
     the rule under a section label — it keeps the site tied to the printed
     logo instead of reading as generic corporate green. */
  --flg-sienna: #7a3115;

  --flg-bg: #f3f6fa;
  --flg-bg-accent: #e9f0f7;
  --flg-bg-glow-1: #ffffff;
  --flg-bg-glow-2: #e8eef8;
  --flg-surface: #ffffff;
  --flg-surface-2: #f8fafc;
  --flg-surface-3: #f1f5f9;

  --flg-text: #1f2937;
  --flg-text-muted: #64748b;
  --flg-text-subtle: #94a3b8;
  /* Text that sits on a brand-green fill, in either theme. */
  --flg-on-brand: #ffffff;

  --flg-border: #dbe3ea;
  --flg-border-strong: #cbd5e1;
  --flg-shadow: 0 10px 30px rgba(17, 24, 39, 0.08);
  --flg-shadow-soft: 0 4px 12px rgba(17, 24, 39, 0.06);
  --flg-shadow-lift: 0 18px 40px rgba(15, 23, 42, 0.12);

  /* Header glass. Separate from --flg-surface because it is composited over
     scrolling content and needs an alpha the opaque surface token can't carry. */
  --flg-header-bg: rgba(255, 255, 255, 0.82);
  /* The tint behind a hero photo. Two stops of the leaf gradient at low alpha,
     so the photography stays readable but the green still reads as brand. */
  --flg-scrim-1: rgba(2, 99, 51, 0.8);
  --flg-scrim-2: rgba(2, 99, 51, 0.46);
  /* A washed green plate: the quote blocks and the contact panel sit on it. */
  --flg-tint-brand: #eef6f1;
  --flg-tint-brand-border: #cfe6d9;
  /* The app's danger wash, for the contact form's failure message. */
  --flg-tint-danger: #fef2f2;
  --flg-tint-danger-border: #fecaca;

  --flg-focus: #088940;

  /* Type. Mulish stands in for the app's Avenir Next (nearest humanist sans on
     Google Fonts); Archivo's width axis gives headlines the wide, signage feel
     of a warehouse wayfinding sign; IBM Plex Mono carries every measurement. */
  --font-display: 'Archivo', 'Avenir Next', 'Segoe UI', Helvetica, Arial, sans-serif;
  --font-body: 'Mulish', 'Avenir Next', 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
  --font-mono: 'IBM Plex Mono', ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  /* Layout */
  --measure: 66ch;
  --gutter: clamp(20px, 5vw, 64px);
  --shell: 1200px;
}

/* ── Tokens: dark ───────────────────────────────────────────────────────────
   The app's dark values, not a mechanical inversion of the light set: the
   accents are re-picked lighter so they hold the same contrast against a dark
   ground that the light theme holds against white.
   Declared twice — once for a dark OS that has not been overridden, once for an
   explicit toggle — so both directions of the toggle win over the OS. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme='light']) {
    --flg-brand: #34c26d;
    --flg-brand-deep: #026333;
    --flg-brand-bright: #52b748;
    --flg-brand-accent: #6ee7a0;
    --flg-sienna: #d98d68;

    --flg-bg: #0e1319;
    --flg-bg-accent: #121821;
    --flg-bg-glow-1: #1b2430;
    --flg-bg-glow-2: #16202b;
    --flg-surface: #161c24;
    --flg-surface-2: #1a212b;
    --flg-surface-3: #202834;

    --flg-text: #e2e8f0;
    --flg-text-muted: #94a3b8;
    --flg-text-subtle: #7c8798;
    --flg-on-brand: #062313;

    --flg-border: #2a3441;
    --flg-border-strong: #3a4656;
    --flg-shadow: 0 10px 30px rgba(0, 0, 0, 0.55);
    --flg-shadow-soft: 0 4px 12px rgba(0, 0, 0, 0.4);
    --flg-shadow-lift: 0 18px 40px rgba(0, 0, 0, 0.6);

    --flg-header-bg: rgba(14, 19, 25, 0.82);
    --flg-scrim-1: rgba(6, 22, 14, 0.9);
    --flg-scrim-2: rgba(6, 22, 14, 0.58);
    --flg-tint-brand: #12251c;
    --flg-tint-brand-border: #24483a;
    --flg-tint-danger: #2a1517;
    --flg-tint-danger-border: #5c2a2a;

    --flg-focus: #6ee7a0;
  }
}

:root[data-theme='dark'] {
  --flg-brand: #34c26d;
  --flg-brand-deep: #026333;
  --flg-brand-bright: #52b748;
  --flg-brand-accent: #6ee7a0;
  --flg-sienna: #d98d68;

  --flg-bg: #0e1319;
  --flg-bg-accent: #121821;
  --flg-bg-glow-1: #1b2430;
  --flg-bg-glow-2: #16202b;
  --flg-surface: #161c24;
  --flg-surface-2: #1a212b;
  --flg-surface-3: #202834;

  --flg-text: #e2e8f0;
  --flg-text-muted: #94a3b8;
  --flg-text-subtle: #7c8798;
  --flg-on-brand: #062313;

  --flg-border: #2a3441;
  --flg-border-strong: #3a4656;
  --flg-shadow: 0 10px 30px rgba(0, 0, 0, 0.55);
  --flg-shadow-soft: 0 4px 12px rgba(0, 0, 0, 0.4);
  --flg-shadow-lift: 0 18px 40px rgba(0, 0, 0, 0.6);

  --flg-header-bg: rgba(14, 19, 25, 0.82);
  --flg-scrim-1: rgba(6, 22, 14, 0.9);
  --flg-scrim-2: rgba(6, 22, 14, 0.58);
  --flg-tint-brand: #12251c;
  --flg-tint-brand-border: #24483a;
  --flg-tint-danger: #2a1517;
  --flg-tint-danger-border: #5c2a2a;

  --flg-focus: #6ee7a0;
}

/* ── Base ───────────────────────────────────────────────────────────────── */
*,
*::before,
*::after {
  box-sizing: border-box;
}

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

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

body {
  margin: 0;
  font-family: var(--font-body);
  font-size: 17px;
  line-height: 1.65;
  color: var(--flg-text);
  /* Same two-glow recipe as the admin app's body, so the two backgrounds are
     recognisably the same surface. */
  background:
    radial-gradient(circle at 10% 6%, var(--flg-bg-glow-1) 0%, transparent 42%),
    radial-gradient(circle at 92% 0%, var(--flg-bg-glow-2) 0%, transparent 34%),
    linear-gradient(180deg, var(--flg-bg-accent), var(--flg-bg));
  background-attachment: fixed;
  -webkit-font-smoothing: antialiased;
}

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

a {
  color: var(--flg-brand);
  text-underline-offset: 3px;
}

:where(a, button, summary, input, textarea, [tabindex]):focus-visible {
  outline: 2px solid var(--flg-focus);
  outline-offset: 3px;
  border-radius: 4px;
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 200;
  background: var(--flg-brand);
  color: var(--flg-on-brand);
  padding: 10px 16px;
  border-radius: 0 0 8px 0;
  font-weight: 700;
}

.skip-link:focus {
  left: 0;
}

/* ── Type scale ─────────────────────────────────────────────────────────── */
h1,
h2,
h3,
h4 {
  font-family: var(--font-display);
  /* Archivo is variable on both axes; the slight expansion is what gives the
     headings their signage character. */
  font-variation-settings: 'wdth' 108;
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.12;
  text-wrap: balance;
  margin: 0;
}

h1 {
  font-size: clamp(2.3rem, 1.4rem + 3.6vw, 4rem);
}

h2 {
  font-size: clamp(1.7rem, 1.2rem + 1.9vw, 2.6rem);
}

h3 {
  font-size: clamp(1.15rem, 1rem + 0.6vw, 1.4rem);
  font-variation-settings: 'wdth' 100;
  letter-spacing: -0.01em;
}

h4 {
  font-size: 1rem;
  font-variation-settings: 'wdth' 100;
  letter-spacing: 0;
}

p {
  margin: 0;
}

/* The small uppercase mono label above a section heading. It always names the
   section's role — never decoration. */
.eyebrow {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--flg-sienna);
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0;
}

.eyebrow::before {
  content: '';
  width: 22px;
  height: 2px;
  background: currentColor;
  flex: none;
}

.lede {
  font-size: clamp(1.05rem, 1rem + 0.35vw, 1.22rem);
  line-height: 1.6;
  color: var(--flg-text-muted);
  max-width: var(--measure);
}

.prose {
  display: flex;
  flex-direction: column;
  gap: 18px;
  max-width: var(--measure);
  color: var(--flg-text-muted);
}

.prose strong {
  color: var(--flg-text);
  font-weight: 700;
}

/* ── Layout shell ───────────────────────────────────────────────────────── */
.shell {
  width: min(100% - (2 * var(--gutter)), var(--shell));
  margin-inline: auto;
}

.section {
  padding-block: clamp(56px, 8vw, 104px);
}

.section-head {
  display: flex;
  flex-direction: column;
  gap: 14px;
  margin-bottom: clamp(28px, 4vw, 48px);
  max-width: 760px;
}

/* ── Header ─────────────────────────────────────────────────────────────── */
.topbar {
  background: var(--flg-brand-deep);
  color: #eaf5ee;
  font-size: 0.82rem;
}

.topbar .shell {
  display: flex;
  align-items: center;
  gap: 8px 22px;
  flex-wrap: wrap;
  min-height: 38px;
  padding-block: 6px;
}

.topbar a {
  color: inherit;
  text-decoration: none;
  font-weight: 600;
}

.topbar a:hover {
  text-decoration: underline;
}

.topbar-status {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

/* A slow pulse on the "open" dot: the one place the site says 24/7 in motion
   rather than words. */
.pulse {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--flg-brand-bright);
  box-shadow: 0 0 0 0 rgba(82, 183, 72, 0.7);
  animation: pulse 2.6s ease-out infinite;
  flex: none;
}

@keyframes pulse {
  70% {
    box-shadow: 0 0 0 9px rgba(82, 183, 72, 0);
  }

  100% {
    box-shadow: 0 0 0 0 rgba(82, 183, 72, 0);
  }
}

.topbar-spacer {
  margin-left: auto;
}

.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  background: var(--flg-header-bg);
  backdrop-filter: saturate(1.6) blur(14px);
  -webkit-backdrop-filter: saturate(1.6) blur(14px);
  border-bottom: 1px solid var(--flg-border);
}

.site-header .shell {
  display: flex;
  align-items: center;
  gap: 20px;
  min-height: 74px;
}

/* The lockup is a vertical stack: wordmark, then the tagline as live text.
   The tagline is part of the printed logo, but the raster version of it is an
   illegible smudge at header size, so it is clipped off the artwork (see
   .logo-standard below) and set here instead, where it stays crisp at any size.
   aria-hidden because the img alt already carries the same words — this is the
   same phrase twice over, not two pieces of information. */
.brand {
  display: inline-flex;
  align-items: center;
  gap: 14px;
  text-decoration: none;
  color: inherit;
  margin-right: auto;
}

/* Set beside the wordmark behind a hairline rather than stacked under it: at
   header size the wordmark is only ~90px wide and this line is nearly 260px,
   so stacking hangs a caption three times the width of the thing it captions. */
.brand-tagline {
  padding-left: 14px;
  border-left: 1px solid var(--flg-border);
  font-family: var(--font-mono);
  font-size: 0.62rem;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--flg-text-subtle);
  white-space: nowrap;
}

/* The nav needs the width back before it collapses to the menu button, and the
   wordmark alone carries the brand from here down. The hero still states the
   tagline in full. */
@media (max-width: 1100px) {
  .brand-tagline {
    display: none;
  }
}

/* The wordmark ships as two fixed-colour pieces of artwork: the positive
   (green FLORA, sienna LOGISTICS, transparent ground) and the reverse (white
   and sienna on a solid green plate). The positive vanishes on a dark ground
   and no filter rescues it without wrecking the brand greens, so the theme
   swaps in whichever was drawn for the ground it is standing on. Both ship in
   the markup; the hidden one is display:none, so a screen reader announces the
   wordmark exactly once.

   Both also carry the tagline locked up underneath, and at header size that
   line degrades into an illegible smudge — so it is clipped off here and the
   hero carries the tagline as real text instead. The two crops differ because
   the source files are cropped differently: the tagline is the bottom 13% of
   the positive and 14% of the reverse. Trim by the wrong amount and you either
   leave a smear of tagline behind or bite into "LOGISTICS". The negative margin
   on the mark takes back the space the clipped strip still occupies, so it
   stays optically centred in the flex row. */
.logo-standard {
  clip-path: inset(0 0 13% 0);
}

.logo-reverse {
  display: none;
  clip-path: inset(0 0 14% 0);
  border-radius: 6px;
}

.brand img {
  height: 46px;
  width: auto;
  /* Discounts the clipped tagline strip, which still occupies layout height,
     so the wordmark sits optically centred in the row rather than high. */
  margin-bottom: -6px;
}

:root[data-theme='dark'] .logo-standard {
  display: none;
}

:root[data-theme='dark'] .logo-reverse {
  display: block;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme='light']) .logo-standard {
    display: none;
  }

  :root:not([data-theme='light']) .logo-reverse {
    display: block;
  }
}

.nav {
  display: flex;
  align-items: center;
  gap: 4px;
}

.nav a {
  display: block;
  padding: 9px 14px;
  border-radius: 8px;
  text-decoration: none;
  color: var(--flg-text-muted);
  font-weight: 600;
  font-size: 0.95rem;
  transition: background 140ms ease, color 140ms ease;
}

.nav a:hover {
  background: var(--flg-surface-3);
  color: var(--flg-text);
}

.nav a[aria-current='page'] {
  color: var(--flg-brand);
  background: var(--flg-tint-brand);
}

.header-tools {
  display: flex;
  align-items: center;
  gap: 8px;
}

.icon-btn {
  width: 40px;
  height: 40px;
  display: grid;
  place-items: center;
  border-radius: 10px;
  border: 1px solid var(--flg-border);
  background: var(--flg-surface);
  color: var(--flg-text-muted);
  cursor: pointer;
  padding: 0;
  transition: background 140ms ease, color 140ms ease;
}

.icon-btn:hover {
  background: var(--flg-surface-3);
  color: var(--flg-text);
}

.icon-btn svg {
  width: 20px;
  height: 20px;
}

.nav-toggle {
  display: none;
}

/* The theme toggle swaps which glyph is shown; both ship in the button. */
.icon-sun {
  display: none;
}

:root[data-theme='dark'] .icon-sun {
  display: block;
}

:root[data-theme='dark'] .icon-moon {
  display: none;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme='light']) .icon-sun {
    display: block;
  }

  :root:not([data-theme='light']) .icon-moon {
    display: none;
  }
}

@media (max-width: 900px) {
  .nav-toggle {
    display: grid;
  }

  .nav {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    flex-direction: column;
    align-items: stretch;
    gap: 2px;
    padding: 12px var(--gutter) 18px;
    background: var(--flg-surface);
    border-bottom: 1px solid var(--flg-border);
    box-shadow: var(--flg-shadow);
  }

  .nav[hidden] {
    display: none;
  }

  .nav a {
    padding: 12px 14px;
    font-size: 1rem;
  }
}

/* ── Buttons ────────────────────────────────────────────────────────────── */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  /* Matches the app's ElevatedButton: 8px radius, 24/12 padding, no elevation. */
  padding: 13px 24px;
  border-radius: 8px;
  border: 1px solid transparent;
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 0.98rem;
  text-decoration: none;
  cursor: pointer;
  transition: transform 140ms ease, box-shadow 140ms ease, background 140ms ease;
}

.btn svg {
  width: 18px;
  height: 18px;
  flex: none;
}

.btn-primary {
  background: linear-gradient(100deg, var(--flg-brand-bright), var(--flg-brand));
  color: #ffffff;
  box-shadow: var(--flg-shadow-soft);
}

.btn-primary:hover {
  transform: translateY(-1px);
  box-shadow: var(--flg-shadow);
}

.btn-ghost {
  background: var(--flg-surface);
  border-color: var(--flg-border-strong);
  color: var(--flg-text);
}

.btn-ghost:hover {
  background: var(--flg-surface-3);
}

/* On the hero's photographic scrim the ghost button has no surface to sit on,
   so it borrows the glass treatment instead. */
.btn-on-dark {
  background: rgba(255, 255, 255, 0.12);
  border-color: rgba(255, 255, 255, 0.42);
  color: #ffffff;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}

.btn-on-dark:hover {
  background: rgba(255, 255, 255, 0.2);
}

.btn-row {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}

/* ── Hero ───────────────────────────────────────────────────────────────── */
.hero {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  background: var(--flg-brand-deep);
  color: #ffffff;
}

.hero-media {
  position: absolute;
  inset: 0;
  z-index: -2;
}

.hero-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.hero::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(104deg, var(--flg-scrim-1) 0%, var(--flg-scrim-1) 24%, var(--flg-scrim-2) 100%);
}

.hero .shell {
  /* Sized to its content, not to the viewport, so the section under it is
     already in the first frame. */
  padding-block: clamp(64px, 10vw, 124px);
}

.hero-inner {
  display: flex;
  flex-direction: column;
  gap: 24px;
  max-width: 720px;
}

.hero .eyebrow {
  color: var(--flg-brand-bright);
}

.hero h1 {
  color: #ffffff;
}

.hero-lede {
  font-size: clamp(1.05rem, 1rem + 0.4vw, 1.25rem);
  line-height: 1.6;
  color: rgba(255, 255, 255, 0.88);
  max-width: 58ch;
}

/* The tagline off the printed logo, set in the mono face so it reads as a
   stamped mark rather than a second headline. */
.hero-tagline {
  font-family: var(--font-mono);
  font-size: 0.78rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.78);
}

/* The short banner at the top of an interior page. */
.page-hero {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  background: var(--flg-brand-deep);
  color: #ffffff;
}

.page-hero-media {
  position: absolute;
  inset: 0;
  z-index: -2;
}

.page-hero-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.page-hero::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(100deg, var(--flg-scrim-1) 0%, var(--flg-scrim-1) 28%, var(--flg-scrim-2) 100%);
}

.page-hero .shell {
  padding-block: clamp(44px, 6vw, 76px);
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.page-hero h1 {
  color: #ffffff;
}

.page-hero .eyebrow {
  color: var(--flg-brand-bright);
}

.page-hero p {
  color: rgba(255, 255, 255, 0.88);
  max-width: 62ch;
  font-size: 1.05rem;
}

/* ── Spec band ──────────────────────────────────────────────────────────────
   The facility's real measurements, set in the mono face with their units, on
   hairline rules rather than in cards. These are readings off a spec sheet —
   drawing them as six rounded tiles would say "feature grid" instead. */
.specs {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 1px;
  background: var(--flg-border);
  border-block: 1px solid var(--flg-border);
}

.spec {
  background: var(--flg-surface);
  padding: 26px clamp(16px, 2vw, 26px);
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.spec-value {
  font-family: var(--font-mono);
  font-size: clamp(1.5rem, 1.2rem + 1.1vw, 2rem);
  font-weight: 500;
  line-height: 1;
  letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
  color: var(--flg-text);
}

.spec-unit {
  font-size: 0.62em;
  color: var(--flg-text-subtle);
  letter-spacing: 0;
  margin-left: 2px;
}

.spec-label {
  font-size: 0.86rem;
  color: var(--flg-text-muted);
  line-height: 1.4;
}

/* Sitting directly under the hero, the band overlaps it slightly so the two
   read as one masthead. */
.specs-inset {
  position: relative;
  z-index: 2;
}

/* ── Panels & cards ─────────────────────────────────────────────────────── */
.grid {
  display: grid;
  gap: clamp(16px, 2vw, 24px);
}

.grid-3 {
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
}

.grid-2 {
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
}

/* The app's .panel, verbatim: surface→surface-2 gradient, 1px border, 16px
   radius, soft shadow. */
.panel {
  background: linear-gradient(180deg, var(--flg-surface), var(--flg-surface-2));
  border: 1px solid var(--flg-border);
  border-radius: 16px;
  box-shadow: var(--flg-shadow-soft);
  padding: clamp(22px, 3vw, 32px);
  display: flex;
  flex-direction: column;
  gap: 14px;
}

/* Only the three navigational cards on the home page lift on hover — they are
   the page's only card-shaped links. */
.card-link {
  text-decoration: none;
  color: inherit;
  transition: transform 180ms ease, box-shadow 180ms ease, border-color 180ms ease;
  overflow: hidden;
  padding: 0;
}

.card-link:hover {
  transform: translateY(-3px);
  box-shadow: var(--flg-shadow-lift);
  border-color: var(--flg-border-strong);
}

.card-media {
  aspect-ratio: 16 / 9;
  overflow: hidden;
  background: var(--flg-surface-3);
}

.card-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 420ms ease;
}

.card-link:hover .card-media img {
  transform: scale(1.04);
}

.card-body {
  padding: 22px clamp(20px, 2.4vw, 26px) 26px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.card-body p {
  color: var(--flg-text-muted);
  font-size: 0.96rem;
}

.card-more {
  margin-top: auto;
  padding-top: 4px;
  color: var(--flg-brand);
  font-weight: 700;
  font-size: 0.92rem;
  display: inline-flex;
  align-items: center;
  gap: 7px;
}

.card-link:hover .card-more svg {
  transform: translateX(3px);
}

.card-more svg {
  width: 15px;
  height: 15px;
  transition: transform 180ms ease;
}

/* ── Feature lists ──────────────────────────────────────────────────────────
   The capability lists are inventories, not steps, so they get hairline rules
   and a leaf tick — no numbers. */
.spec-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
}

.spec-list li {
  display: grid;
  grid-template-columns: 18px 1fr;
  gap: 12px;
  align-items: start;
  padding: 11px 0;
  border-bottom: 1px solid var(--flg-border);
  font-size: 0.96rem;
  color: var(--flg-text-muted);
}

.spec-list li:last-child {
  border-bottom: 0;
}

.spec-list li::before {
  content: '';
  width: 9px;
  height: 9px;
  margin-top: 8px;
  border-radius: 50% 0 50% 50%;
  background: linear-gradient(135deg, var(--flg-brand-bright), var(--flg-brand));
  transform: rotate(45deg);
}

/* Two columns once there is room; the list is alphabetically meaningless, so
   column order does not matter. */
.spec-list-2col {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  column-gap: clamp(20px, 3vw, 44px);
}

/* ── Services ───────────────────────────────────────────────────────────── */
.service {
  scroll-margin-top: 120px;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(24px, 4vw, 56px);
  align-items: center;
  padding-block: clamp(36px, 5vw, 60px);
  border-top: 1px solid var(--flg-border);
}

.service:first-of-type {
  border-top: 0;
}

.service-body {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.service-figure {
  border-radius: 16px;
  overflow: hidden;
  border: 1px solid var(--flg-border);
  box-shadow: var(--flg-shadow-soft);
  aspect-ratio: 4 / 3;
}

.service-figure img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Alternate which side the photograph falls on, so the page has a rhythm
   rather than a single repeated row. */
.service:nth-of-type(even) .service-figure {
  order: -1;
}

@media (max-width: 820px) {
  .service {
    grid-template-columns: 1fr;
  }

  .service:nth-of-type(even) .service-figure {
    order: 0;
  }
}

/* The jump-list at the top of the Services page. */
.chip-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.chip {
  display: inline-block;
  padding: 8px 15px;
  border-radius: 999px;
  border: 1px solid var(--flg-border-strong);
  background: var(--flg-surface);
  color: var(--flg-text-muted);
  font-size: 0.88rem;
  font-weight: 600;
  text-decoration: none;
  transition: background 140ms ease, color 140ms ease, border-color 140ms ease;
}

.chip:hover {
  background: var(--flg-tint-brand);
  border-color: var(--flg-tint-brand-border);
  color: var(--flg-brand);
}

/* ── Quotes ─────────────────────────────────────────────────────────────── */
.quote {
  background: var(--flg-tint-brand);
  border: 1px solid var(--flg-tint-brand-border);
  border-radius: 16px;
  padding: clamp(24px, 3vw, 34px);
  display: flex;
  flex-direction: column;
  gap: 18px;
  margin: 0;
}

.quote blockquote {
  margin: 0;
  font-size: 1.02rem;
  line-height: 1.62;
  color: var(--flg-text);
}

.quote blockquote p + p {
  margin-top: 12px;
}

.quote figcaption {
  display: flex;
  flex-direction: column;
  gap: 2px;
  border-top: 1px solid var(--flg-tint-brand-border);
  padding-top: 16px;
  margin-top: auto;
}

.quote-name {
  font-weight: 700;
  color: var(--flg-text);
  font-size: 0.95rem;
}

.quote-org {
  font-family: var(--font-mono);
  font-size: 0.74rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--flg-text-muted);
}

/* ── Gallery ────────────────────────────────────────────────────────────── */
.gallery {
  columns: 3 280px;
  column-gap: 16px;
}

.gallery button {
  display: block;
  width: 100%;
  padding: 0;
  margin: 0 0 16px;
  border: 1px solid var(--flg-border);
  border-radius: 12px;
  overflow: hidden;
  background: var(--flg-surface-3);
  cursor: zoom-in;
  break-inside: avoid;
  transition: box-shadow 180ms ease, border-color 180ms ease;
}

.gallery button:hover {
  box-shadow: var(--flg-shadow-lift);
  border-color: var(--flg-brand);
}

.gallery img {
  width: 100%;
  height: auto;
  transition: transform 420ms ease;
}

.gallery button:hover img {
  transform: scale(1.03);
}

.lightbox {
  position: fixed;
  inset: 0;
  z-index: 300;
  border: 0;
  padding: 0;
  max-width: 100%;
  max-height: 100%;
  width: 100%;
  height: 100%;
  background: transparent;
}

.lightbox::backdrop {
  background: rgba(8, 14, 12, 0.88);
  backdrop-filter: blur(4px);
}

.lightbox-inner {
  width: 100%;
  height: 100%;
  display: grid;
  place-items: center;
  padding: clamp(16px, 4vw, 48px);
}

.lightbox img {
  max-width: 100%;
  max-height: 82vh;
  width: auto;
  border-radius: 12px;
  box-shadow: 0 30px 70px rgba(0, 0, 0, 0.6);
}

.lightbox-caption {
  margin-top: 14px;
  text-align: center;
  color: rgba(255, 255, 255, 0.82);
  font-family: var(--font-mono);
  font-size: 0.78rem;
  letter-spacing: 0.08em;
}

.lightbox-close {
  position: absolute;
  top: clamp(12px, 3vw, 24px);
  right: clamp(12px, 3vw, 24px);
  width: 44px;
  height: 44px;
  border-radius: 10px;
  border: 1px solid rgba(255, 255, 255, 0.32);
  background: rgba(255, 255, 255, 0.12);
  color: #ffffff;
  cursor: pointer;
  display: grid;
  place-items: center;
}

.lightbox-close svg {
  width: 20px;
  height: 20px;
}

/* ── Contact ────────────────────────────────────────────────────────────── */
.contact-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.1fr) minmax(0, 0.9fr);
  gap: clamp(20px, 3vw, 36px);
  align-items: start;
}

@media (max-width: 860px) {
  .contact-grid {
    grid-template-columns: 1fr;
  }
}

.field {
  display: flex;
  flex-direction: column;
  gap: 7px;
}

.field label {
  font-size: 0.86rem;
  font-weight: 700;
  color: var(--flg-text);
}

.field .req {
  color: var(--flg-text-subtle);
  font-weight: 500;
}

/* Matches the app's InputDecorationTheme: filled, borderless at rest, 8px
   radius, brand-green border only on focus. */
.field input,
.field textarea {
  font-family: inherit;
  font-size: 1rem;
  color: var(--flg-text);
  background: var(--flg-surface-3);
  border: 1px solid transparent;
  border-radius: 8px;
  padding: 12px 14px;
  width: 100%;
  transition: border-color 140ms ease, background 140ms ease;
}

.field textarea {
  min-height: 140px;
  resize: vertical;
}

.field input:focus,
.field textarea:focus {
  outline: none;
  border-color: var(--flg-brand);
  background: var(--flg-surface);
}

.form-grid {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.form-note {
  font-size: 0.86rem;
  color: var(--flg-text-subtle);
}

/* A definition list of contact facts: label left, value right, hairline ruled. */
.facts {
  margin: 0;
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0;
}

.facts dt {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--flg-text-subtle);
  padding: 13px 20px 13px 0;
  border-bottom: 1px solid var(--flg-border);
  white-space: nowrap;
}

.facts dd {
  margin: 0;
  padding: 13px 0;
  border-bottom: 1px solid var(--flg-border);
  color: var(--flg-text);
  font-weight: 600;
}

.facts dd a {
  text-decoration: none;
  font-weight: 700;
}

.facts dd a:hover {
  text-decoration: underline;
}

/* ── Call to action ─────────────────────────────────────────────────────── */
.cta {
  background:
    radial-gradient(circle at 88% 12%, rgba(82, 183, 72, 0.42) 0%, transparent 52%),
    linear-gradient(102deg, var(--flg-brand-deep), #014a26);
  color: #ffffff;
  border-radius: 20px;
  padding: clamp(30px, 4.5vw, 56px);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
}

.cta h2 {
  color: #ffffff;
  max-width: 18ch;
}

.cta p {
  color: rgba(255, 255, 255, 0.84);
  max-width: 46ch;
  margin-top: 12px;
}

.cta-copy {
  min-width: 280px;
  flex: 1 1 380px;
}

/* ── Footer ─────────────────────────────────────────────────────────────── */
.site-footer {
  border-top: 1px solid var(--flg-border);
  background: var(--flg-surface);
  margin-top: clamp(48px, 7vw, 88px);
}

.footer-top {
  display: grid;
  grid-template-columns: minmax(0, 1.4fr) repeat(auto-fit, minmax(160px, 1fr));
  gap: clamp(24px, 4vw, 48px);
  padding-block: clamp(40px, 5vw, 64px);
}

.footer-brand {
  display: flex;
  flex-direction: column;
  gap: 16px;
  max-width: 42ch;
}

.footer-brand img {
  height: 50px;
  width: auto;
  margin-bottom: -7px;
}

.footer-brand p {
  color: var(--flg-text-muted);
  font-size: 0.94rem;
}

.footer-col {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.footer-col h4 {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--flg-text-subtle);
}

.footer-col a {
  color: var(--flg-text-muted);
  text-decoration: none;
  font-size: 0.94rem;
}

.footer-col a:hover {
  color: var(--flg-brand);
}

.footer-bottom {
  border-top: 1px solid var(--flg-border);
  padding-block: 20px;
  display: flex;
  flex-wrap: wrap;
  gap: 10px 22px;
  align-items: center;
  font-size: 0.85rem;
  color: var(--flg-text-subtle);
}

.footer-bottom a {
  color: var(--flg-text-muted);
  text-decoration: none;
}

.footer-bottom a:hover {
  color: var(--flg-brand);
}

.footer-bottom .spacer {
  margin-left: auto;
}

/* ── Entrance ───────────────────────────────────────────────────────────────
   The app's .slide-up, applied only to sections below the first screen. It
   animates FROM a visible resting state, so nothing is hidden if the animation
   never runs. */
@keyframes slide-up {
  from {
    opacity: 0;
    transform: translateY(8px);
  }

  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.slide-up {
  animation: slide-up 360ms ease both;
}

/* ── One-page sections ──────────────────────────────────────────────────────
   Home, Infrastructure and Services are three sections of one document rather
   than three pages. Everything that follows exists because of that. */

/* Anchor targets have to clear the sticky header, or a jump lands with the
   heading hidden underneath it. */
:where(section[id], article[id]) {
  scroll-margin-top: 96px;
}

/* The rule that separates one major section from the next. Sections carry their
   own top border instead of a shared divider element, so re-ordering them keeps
   the rhythm. */
.section-rule {
  border-top: 1px solid var(--flg-border);
}

/* The nav item for whatever section is currently under the header. Same
   treatment as aria-current on a real page nav — on a one-pager "which page am
   I on" and "which section am I in" are the same question. */
.nav a.is-current {
  color: var(--flg-brand);
  background: var(--flg-tint-brand);
}

/* The specs band as a panel inside the shell, rather than the full-bleed strip
   under the hero. Same grid, boxed. */
.specs-boxed {
  border: 1px solid var(--flg-border);
  border-radius: 16px;
  overflow: hidden;
  box-shadow: var(--flg-shadow-soft);
}

/* ── Contact modal ──────────────────────────────────────────────────────────
   The form is a dialog everywhere except contact.html, which is the same form
   as a page — the no-JS fallback and the URL worth sharing. */
.modal {
  width: min(100% - 32px, 940px);
  max-width: none;
  max-height: min(100% - 32px, 900px);
  padding: 0;
  border: 1px solid var(--flg-border);
  border-radius: 18px;
  background: var(--flg-surface);
  color: var(--flg-text);
  box-shadow: var(--flg-shadow-lift);
  overflow: visible;
}

.modal::backdrop {
  background: rgba(6, 22, 14, 0.62);
  backdrop-filter: blur(3px);
}

.modal-scroll {
  max-height: min(100vh - 32px, 900px);
  overflow-y: auto;
  border-radius: 18px;
  padding: clamp(22px, 3.4vw, 40px);
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr);
  gap: clamp(20px, 3vw, 36px);
  align-items: start;
}

@media (max-width: 800px) {
  .modal-scroll {
    grid-template-columns: 1fr;
  }
}

.modal-head {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin-bottom: 20px;
}

.modal-aside {
  display: flex;
  flex-direction: column;
  gap: 18px;
  background: var(--flg-surface-2);
  border: 1px solid var(--flg-border);
  border-radius: 14px;
  padding: clamp(18px, 2.4vw, 26px);
}

/* Floated just outside the dialog's corner rather than inside it: at the inside
   position it lands on top of the aside panel's own rounded corner. The dialog
   sets overflow:visible so this can hang off the edge, and the offset is smaller
   than the dialog's own viewport margin, so it never leaves the screen. */
.modal-close {
  position: absolute;
  top: -13px;
  right: -13px;
  z-index: 2;
  box-shadow: var(--flg-shadow-soft);
  width: 38px;
  height: 38px;
  display: grid;
  place-items: center;
  border-radius: 10px;
  border: 1px solid var(--flg-border);
  background: var(--flg-surface);
  color: var(--flg-text-muted);
  cursor: pointer;
  padding: 0;
}

.modal-close:hover {
  background: var(--flg-surface-3);
  color: var(--flg-text);
}

.modal-close svg {
  width: 18px;
  height: 18px;
}

/* ── Contact form ───────────────────────────────────────────────────────────
   Shared by the modal and contact.html. */

/* The honeypot. Off-screen rather than display:none — a bot that fills every
   field it can see in the DOM still trips it, and a person never reaches it:
   it is aria-hidden, out of the tab order, and has autocomplete off so no
   browser ever fills it in. */
.hp {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.form-status {
  margin: 0;
  font-size: 0.92rem;
  padding: 12px 14px;
  border-radius: 10px;
  border: 1px solid transparent;
}

.form-status:empty {
  display: none;
}

.form-status[data-state='sent'] {
  background: var(--flg-tint-brand);
  border-color: var(--flg-tint-brand-border);
  color: var(--flg-text);
}

.form-status[data-state='error'] {
  background: var(--flg-tint-danger);
  border-color: var(--flg-tint-danger-border);
  color: var(--flg-text);
}

/* ── Sent confirmation ──────────────────────────────────────────────────────
   After a successful send the form BECOMES its confirmation: `is-sent` hides
   every other child at once, so the inputs, the send button and the note all
   go together and what the sender typed is no longer sitting on screen behind
   a success message.

   One class on the <form> does the hiding rather than script touching each
   child, which means a field added to the form later is covered without
   anyone remembering to update this. */
.form-grid.is-sent > *:not(.form-sent) {
  display: none;
}

.form-sent {
  display: grid;
  justify-items: start;
  gap: 12px;
  padding: 24px;
  border-radius: 12px;
  background: var(--flg-tint-brand);
  border: 1px solid var(--flg-tint-brand-border);
}

/* Specificity has to beat the `display: grid` above, or the attribute that
   keeps this hidden until a send would do nothing. */
.form-sent[hidden] {
  display: none;
}

.form-sent h3 {
  margin: 0;
  font-size: 1.15rem;
}

.form-sent p {
  margin: 0;
  color: var(--flg-text-muted);
}

/* Focus lands here after a send, so it needs a ring like any other focus
   target — at that moment it is the only thing left in the panel. */
.form-sent:focus-visible {
  outline: 2px solid var(--flg-focus);
  outline-offset: 3px;
}

.form-sent-mark {
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  border-radius: 999px;
  background: var(--flg-brand);
  color: var(--flg-on-brand);
}

.form-sent-mark svg {
  width: 22px;
  height: 22px;
}

.btn[aria-busy='true'] {
  opacity: 0.72;
  pointer-events: none;
}
