/* ============================================================
   BILLITON — Gloss & Motion layer
   ------------------------------------------------------------
   Loaded AFTER style.css. This file adds surface depth and
   movement to the existing design. It changes no layout, no
   spacing, no colour and no type — every rule here is either a
   shadow, a gradient sheen, a transition or a transform.

   Because it is additive, deleting this one file (and its <link>
   in includes/header.php) returns the site exactly to how it
   looked before.
   ============================================================ */

/* ------------------------------------------------------------
   1. ELEVATION
   The old shadows were a single soft blur, which reads as fog.
   Real objects cast two shadows: a tight contact shadow where
   they meet the surface, and a wider, softer cast. Redefining
   the two existing tokens upgrades every card on the site at
   once, without touching a single component rule.
   ------------------------------------------------------------ */
:root {
  --shadow-sm: 0 1px 2px rgba(27,42,74,.06), 0 3px 10px rgba(27,42,74,.06);
  --shadow:    0 2px 4px rgba(27,42,74,.07), 0 14px 34px rgba(27,42,74,.11);
  --shadow-lg: 0 4px 8px rgba(27,42,74,.08), 0 26px 60px rgba(27,42,74,.16);

  /* The sheen used across glossy surfaces. */
  --sheen-top: linear-gradient(180deg, rgba(255,255,255,.9), rgba(255,255,255,0) 60%);
  --ease-out:  cubic-bezier(.16, 1, .3, 1);
}

/* ------------------------------------------------------------
   2. GLOSSY SURFACES
   A card reads as glass when light catches its top edge. One
   hairline highlight does more than any amount of gradient.
   ------------------------------------------------------------ */
/* LIGHT cards only. Several cards on this site are dark by design — the navy
   contact panel, the Vision/Mission pair, the featured service card — and they
   carry white text. Painting a white gradient over those makes the text
   disappear, so they are excluded here and given their own treatment below. */
.pillar,
.post-card,
.discipline-tile,
.service-card:not(.featured),
.job-card,
.contact-form {
  background-image: linear-gradient(180deg, #FFFFFF 0%, #FAFCFF 100%);
}

/* Transitions are safe on every card, dark or light. */
.pillar, .post-card, .discipline-tile, .service-card, .vm-card,
.team-card, .job-card, .contact-info-card, .contact-form, .gallery-item {
  transition: transform .38s var(--ease-out), box-shadow .38s var(--ease-out),
              border-color .38s var(--ease-out);
}

/* DARK cards get the same idea in reverse: a faint light wash from above,
   weak enough that white text stays at full contrast. */
.contact-info-card,
.vm-card,
.service-card.featured {
  background-image: linear-gradient(180deg, rgba(255,255,255,.07), rgba(255,255,255,0) 62%);
  box-shadow: var(--shadow);
}
/* .vm-card and .featured already use background-image for their gradient, so
   layer the sheen on top of it rather than replacing it. */
.vm-card.vision  { background-image: linear-gradient(180deg, rgba(255,255,255,.08), rgba(255,255,255,0) 60%), linear-gradient(135deg, var(--navy), #2a4070); }
.vm-card.mission { background-image: linear-gradient(180deg, rgba(255,255,255,.08), rgba(255,255,255,0) 60%), linear-gradient(135deg, #18753f, var(--green)); }
.service-card.featured { background-image: linear-gradient(180deg, rgba(255,255,255,.07), rgba(255,255,255,0) 58%), linear-gradient(135deg, var(--navy) 0%, #243a66 100%); }

/* The highlight along the top edge. Cards with a coloured bar on
   top (.pillar) already use ::before, so they are handled below. */
.post-card, .service-card, .job-card, .discipline-tile, .contact-info-card {
  position: relative;
}
.post-card::after, .service-card:not(.featured)::after,
.contact-info-card::after, .discipline-tile::after {
  content: "";
  position: absolute; inset: 0 0 auto 0; height: 1px;
  border-radius: var(--radius) var(--radius) 0 0;
  background: linear-gradient(90deg,
    rgba(255,255,255,0), rgba(255,255,255,.95) 20%,
    rgba(255,255,255,.95) 80%, rgba(255,255,255,0));
  pointer-events: none; z-index: 2;
}

/* The pillar's coloured top bar picks up a gradient and a glow,
   so it reads as lit rather than printed. */
.pillar::before { background-image: linear-gradient(90deg, rgba(255,255,255,.5), rgba(255,255,255,0)); }
.pillar.p-tech:hover::before { box-shadow: 0 0 18px rgba(91,141,217,.55); }
.pillar.p-hr:hover::before   { box-shadow: 0 0 18px rgba(240,180,41,.55); }
.pillar.p-con:hover::before  { box-shadow: 0 0 18px rgba(33,160,90,.55); }
.pillar.p-bat:hover::before  { box-shadow: 0 0 18px rgba(15,157,88,.55); }

/* Deeper lift on hover — same distance as before, better shadow. */
.pillar:hover, .post-card:hover, .service-card:hover, .team-card:hover { box-shadow: var(--shadow-lg); }

/* The icon tile inside a pillar gains depth and answers to hover. */
.pillar .p-icon {
  box-shadow: inset 0 1px 0 rgba(255,255,255,.7), 0 2px 8px rgba(27,42,74,.08);
  transition: transform .38s var(--ease-out), box-shadow .38s var(--ease-out);
}
.pillar:hover .p-icon { transform: translateY(-2px) scale(1.04); box-shadow: inset 0 1px 0 rgba(255,255,255,.8), 0 8px 20px rgba(27,42,74,.14); }

/* ------------------------------------------------------------
   3. BUTTONS
   Gloss goes in the background image rather than an overlay, so
   it can never wash out the label text.
   ------------------------------------------------------------ */
.btn {
  position: relative;
  background-image: var(--sheen-top);
  background-blend-mode: soft-light;
  transition: transform .2s var(--ease-out), box-shadow .25s var(--ease-out),
              background-color .2s, border-color .2s;
}
.btn-primary {
  background-image: linear-gradient(180deg, rgba(255,255,255,.16), rgba(255,255,255,0) 58%);
  box-shadow: var(--shadow-sm), inset 0 1px 0 rgba(255,255,255,.20);
}
.btn-primary:hover { box-shadow: var(--shadow), inset 0 1px 0 rgba(255,255,255,.26); }
.btn-ghost { background-image: linear-gradient(180deg, #FFFFFF, #F7FAFE); box-shadow: var(--shadow-sm); }
.btn-ghost:hover { box-shadow: var(--shadow); }
/* Press state: the button takes the tap. */
.btn:active { transform: translateY(1px) scale(.995); }

/* ------------------------------------------------------------
   4. HEADER
   Frosted while at the top, glossier once it lifts off the page.
   ------------------------------------------------------------ */
.site-header { transition: box-shadow .3s var(--ease-out), background-color .3s; }
.site-header.scrolled {
  background-color: rgba(255,255,255,.86);
  box-shadow: 0 1px 0 rgba(27,42,74,.06), 0 10px 30px rgba(27,42,74,.08);
}

/* ------------------------------------------------------------
   5. HERO
   A slow light bloom behind the headline. It drifts over half a
   minute, so it is felt rather than watched.
   ------------------------------------------------------------ */
.hero::after {
  content: "";
  position: absolute; inset: -25% -10% auto -10%; height: 130%;
  z-index: 0; pointer-events: none;
  background:
    radial-gradient(38% 42% at 20% 26%, rgba(91,141,217,.11), transparent 70%),
    radial-gradient(34% 38% at 80% 20%, rgba(240,180,41,.08), transparent 72%),
    radial-gradient(36% 40% at 64% 84%, rgba(33,160,90,.07), transparent 74%);
  animation: bt-bloom 32s ease-in-out infinite alternate;
}
/* Lift the real content above the bloom. Note this must NOT set `position`
   on every child — the floating dots are absolutely positioned, and forcing
   them to relative drops them out of place. */
.hero > .container { position: relative; z-index: 1; }
.hero .float-dot   { z-index: 2; }
@keyframes bt-bloom {
  0%   { transform: translate3d(0,0,0) scale(1); }
  50%  { transform: translate3d(-2%,1.5%,0) scale(1.05); }
  100% { transform: translate3d(1.5%,-2%,0) scale(1.02); }
}

/* The floating dots gain a soft halo. */
.float-dot { box-shadow: 0 0 22px currentColor; filter: saturate(1.15); }

/* ------------------------------------------------------------
   6. STATS STRIP
   Tabular figures so counting numbers do not jitter the layout
   as digits change width.
   ------------------------------------------------------------ */
.stats-strip { position: relative; overflow: hidden; }
.stats-strip::before {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(60% 120% at 50% 0%, rgba(255,255,255,.09), transparent 70%);
}
.stats-strip > * { position: relative; }
.stat-value { font-variant-numeric: tabular-nums; }

/* ------------------------------------------------------------
   7. MOTION — staggered reveals
   The reveal itself already exists. What was missing is rhythm:
   a row of four cards arriving together looks like a page
   repaint, while the same four arriving 80ms apart reads as
   deliberate. Done in CSS so no JavaScript changes are needed.
   ------------------------------------------------------------ */
html.js .reveal { transition: opacity .7s var(--ease-out), transform .7s var(--ease-out); }

html.js .pillars > .reveal:nth-child(2),
html.js .blog-grid > .reveal:nth-child(2),
html.js .service-grid > .reveal:nth-child(2),
html.js .team-grid > .reveal:nth-child(2),
html.js .gallery-grid > .reveal:nth-child(2),
html.js .vm-grid > .reveal:nth-child(2)      { transition-delay: .09s; }

html.js .pillars > .reveal:nth-child(3),
html.js .blog-grid > .reveal:nth-child(3),
html.js .service-grid > .reveal:nth-child(3),
html.js .team-grid > .reveal:nth-child(3),
html.js .gallery-grid > .reveal:nth-child(3) { transition-delay: .18s; }

html.js .pillars > .reveal:nth-child(4),
html.js .blog-grid > .reveal:nth-child(4),
html.js .service-grid > .reveal:nth-child(4),
html.js .team-grid > .reveal:nth-child(4),
html.js .gallery-grid > .reveal:nth-child(4) { transition-delay: .27s; }

html.js .gallery-grid > .reveal:nth-child(5),
html.js .team-grid > .reveal:nth-child(5)    { transition-delay: .36s; }
html.js .gallery-grid > .reveal:nth-child(6),
html.js .team-grid > .reveal:nth-child(6)    { transition-delay: .45s; }

/* ------------------------------------------------------------
   8. MOTION — micro-interactions
   ------------------------------------------------------------ */
.pillar .p-link svg,
.post-card .pc-link svg,
.service-card svg { transition: transform .3s var(--ease-out); }

.main-nav a::after { transition: width .3s var(--ease-out), background-color .3s; }

.discipline-tile:hover { box-shadow: var(--shadow); }
.discipline-tile .tile-dot { transition: transform .3s var(--ease-out), box-shadow .3s; }
.discipline-tile:hover .tile-dot { transform: scale(1.25); box-shadow: 0 0 14px currentColor; }

.gallery-item img { transition: transform .6s var(--ease-out); }
.gallery-item:hover img { transform: scale(1.045); }

.post-card .pc-img img { transition: transform .6s var(--ease-out); }
.post-card:hover .pc-img img { transform: scale(1.04); }

/* Form fields: recessed, with a clear focus ring. */
input[type=text], input[type=email], input[type=tel], input[type=url],
textarea, select {
  box-shadow: inset 0 1px 2px rgba(27,42,74,.05);
  transition: border-color .2s, box-shadow .2s;
}
input:focus, textarea:focus, select:focus {
  box-shadow: 0 0 0 3.5px rgba(91,141,217,.18), inset 0 1px 2px rgba(27,42,74,.04);
}

/* Keyboard users get a ring that is never removed. */
a:focus-visible, button:focus-visible, .btn:focus-visible {
  outline: 2px solid var(--blue); outline-offset: 3px; border-radius: 6px;
}

/* ------------------------------------------------------------
   9. REDUCED MOTION
   If the visitor's system asks for less movement, everything
   above becomes static. Gloss stays; motion goes.
   ------------------------------------------------------------ */
@media (prefers-reduced-motion: reduce) {
  .hero::after { animation: none; }
  .float-dot   { animation: none; }
  /* !important is deliberate: the stagger rules above are :nth-child
     selectors, so they outrank a plain selector here on specificity and
     the delay would survive the reduced-motion request. */
  html.js .reveal { transition-delay: 0s !important; }
  .pillar:hover, .post-card:hover, .service-card:hover,
  .team-card:hover, .discipline-tile:hover, .btn:hover { transform: none; }
  .gallery-item:hover img, .post-card:hover .pc-img img,
  .pillar:hover .p-icon, .discipline-tile:hover .tile-dot { transform: none; }
}

/* Printing: no shadows, no bloom. */
@media print {
  .hero::after, .stats-strip::before { display: none; }
  .pillar, .post-card, .service-card, .team-card { box-shadow: none; }
}

/* ============================================================
   FORM VALIDATION FEEDBACK
   The message sits next to the field it belongs to, because an
   error banner at the top of a form makes people hunt.
   ============================================================ */
.field-err {
  display: block; margin: -10px 0 14px;
  color: #A32218; font-size: .84rem; font-weight: 500;
}
.field-err::before { content: "▲ "; font-size: .7em; vertical-align: 1px; }
[aria-invalid="true"] {
  border-color: #D46B60 !important;
  box-shadow: 0 0 0 3.5px rgba(163,34,24,.12) !important;
}
[aria-invalid="true"]:focus { border-color: #A32218 !important; }

/* Legal links row in the footer. */
.footer-legal {
  display: flex; flex-wrap: wrap; gap: 8px 22px; justify-content: center;
  padding: 22px 0 4px; border-top: 1px solid rgba(255,255,255,.10);
  margin-top: 26px;
}
.footer-legal a {
  color: rgba(255,255,255,.62); font-size: .86rem; transition: color .2s;
}
.footer-legal a:hover { color: #fff; text-decoration: underline; }
