/* ============================================================
   Solstice Systems — solar forecasting and detection.
   Design system: palette, type scale, spacing and radii.
   ============================================================ */

:root {
  /* palette — change --accent alone to re-brand the whole page */
  --accent:  #0B7A5E;   /* logo, links, rules, focus rings */
  --band:    #8FCBB4;   /* the call-to-action block */
  --paper:   #F8FBF7;   /* page background */
  --panel:   #E8EFE9;   /* the vision block */
  --ink:     #16211C;   /* body type */
  --white:   #FFFFFF;
  --ink-60:  rgba(22, 33, 28, 0.60);
  --ink-10:  rgba(22, 33, 28, 0.10);
  --hair:    #CBD6CE;
  --white-70: rgba(255, 255, 255, 0.70);

  /* A blue identity instead: --accent #0F5C8C and --band #9CC9E4.
     Nothing else needs to change. */

  /* type */
  --sans: "Figtree", "Helvetica Neue", Helvetica, Arial, sans-serif;
  --mono: "Spline Sans Mono", ui-monospace, "SFMono-Regular", Menlo, monospace;
  --num:  "Outfit", "Figtree", Helvetica, Arial, sans-serif;

  --rail: 270px;         /* fixed left navigation column */
  --pad: 40px;           /* page gutter */
  --label: 458px;        /* width of the label column in the two-up grid */
  --r-lg: 10px;
  --r-sm: 6px;
  --ease: cubic-bezier(0.4, 0, 0.2, 1);
  --t: 0.15s;
}

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

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 16px;
  line-height: 1.5;
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

img { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
ul { margin: 0; padding: 0; list-style: none; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 4px; }

/* --------------------------------------------------------------- type ---- */
.t80, .t56, .t40, .t30, .t22 { margin: 0; }
.t80 { font-size: 80px; line-height: 84px; font-weight: 300; letter-spacing: -3.2px; }
.t56 { font-size: 56px; line-height: 67.2px; font-weight: 300; letter-spacing: -2.24px; }
.t40 { font-size: 40px; line-height: 48px; font-weight: 300; }
.t30 { font-size: 30px; line-height: 42px; font-weight: 400; }
.t22 { font-size: 25px; line-height: 35px; font-weight: 400; }
.t18 { font-size: 18px; line-height: 26.1px; font-weight: 400; margin: 0; }
.mono { font-family: var(--mono); font-size: 16px; line-height: 22.4px; font-weight: 500; margin: 0; }
.muted { color: var(--ink-60); }
.num {
  font-family: var(--num);
  font-size: 80px;
  line-height: 104.8px;
  font-weight: 400;
  color: var(--accent);
  margin: 0;
}

/* --------------------------------------------------------------- rail ---- */
.rail {
  position: fixed;
  inset: var(--pad) auto var(--pad) var(--pad);
  width: calc(var(--rail) - var(--pad));
  z-index: 40;
  display: flex;
  flex-direction: column;
}
.logo { display: block; color: var(--accent); }
.mark { width: 46px; height: 46px; display: block; }
.logo__word {
  display: block;
  margin-top: 14px;
  font-family: var(--mono);
  font-size: 16px;
  font-weight: 500;
  letter-spacing: -0.32px;
  color: var(--accent);
  transition: color var(--t) var(--ease);
}

/* while the dark hero art is still behind the rail (before it's scrolled out
   of view), swap the logo's accent colour for white so it stays legible
   over the photo instead of the paper background. main.js toggles this the
   same way it toggles .is-scrolled. */
body.on-hero .rail .logo,
body.on-hero .rail .logo__word { color: var(--white); }

.mbar { display: none; }

/* ------------------------------------------------------------ content ---- */
.content { margin-left: var(--rail); padding-right: var(--pad); }
main > .section:first-of-type { padding-top: 0; }

.section { padding-block: 120px; }
.section--rule { border-top: 1px solid var(--hair); padding-top: 64px; }
.grid { display: grid; grid-template-columns: var(--label) minmax(0, 1fr); }

.center { text-align: center; }

/* buttons: a separate round icon and a pill, side by side */
.action { display: inline-flex; align-items: center; gap: 8px; }
.action__icon {
  width: 40px;
  height: 40px;
  border-radius: 999px;
  display: grid;
  place-items: center;
  flex: none;
  transition: transform 0.3s var(--ease);
}
.action__pill {
  border-radius: 999px;
  padding: 9px 22px;
  font-family: var(--mono);
  font-size: 16px;
  line-height: 22.4px;
  font-weight: 500;
  white-space: nowrap;
}
.ico { width: 16px; height: 16px; }
.ico--wide { width: 20px; height: 16px; }
.action--dark .action__icon { background: var(--ink); color: var(--paper); }
.action--dark .action__pill { background: var(--ink); color: var(--paper); }
.action--light .action__icon { background: var(--white); color: var(--ink); }
.action--light .action__pill { background: var(--white); color: var(--ink); }
.action:hover .action__icon { transform: rotate(45deg); }

.tlink {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  font-family: var(--mono);
  font-size: 16px;
  font-weight: 500;
  color: var(--accent);
}
.tlink--ink { color: var(--ink); }
.tlink .ico { transition: transform 0.3s var(--ease); }
.tlink:hover .ico { transform: translateX(5px); }

/* horizontal rails and their progress bars */
.hrail { overflow-x: auto; scroll-snap-type: x proximity; scrollbar-width: none; }
.hrail::-webkit-scrollbar { display: none; }
.hrail__track { display: flex; gap: 40px; width: max-content; }
.railbar { height: 2px; background: var(--hair); margin-top: 22px; }
.hrail.is-static + .railbar { visibility: hidden; }
.railbar span { display: block; height: 100%; width: 25%; background: var(--accent); }

/* --------------------------------------------------------------- hero ---- */
.hero { padding-top: var(--pad); padding-bottom: 40px; }
.hero__art {
  position: relative;
  aspect-ratio: 1190 / 560;      /* as on the reference */
  border-radius: var(--r-lg);
  overflow: hidden;
  background: #0E3546;
}
.hero__media {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
/* a slow, continuous drift-and-zoom ("Ken Burns effect") that makes a still
   photo read as a video loop instead of a static image. .hero__art already
   clips overflow, so the scaled-up image never shows an edge. The global
   reduced-motion rule elsewhere collapses this to a near-instant no-op. */
/* a loop, not a wobble: the camera roams across the whole frame along a
   smooth elliptical path (24 evenly-spaced points on one full sweep)
   instead of a handful of widely-spaced corners. Linear interpolation
   between a few far-apart points causes a sharp, DVD-screensaver-style
   direction reversal right at each stop; sampling the ellipse densely
   keeps the direction change gradual at every step, so `linear` timing
   between points reads as continuous motion. Each point keeps its
   translate distance within its own scale's overscan margin so the edges
   of the source photo never show. Ends back at the 0% values so the loop
   is seamless — no snap-back, no need for `alternate`. */
@keyframes kenBurns {
  0%      { transform: scale(1.2400) translate(8.000%, 0.000%); }
  4.167%  { transform: scale(1.2245) translate(7.727%, 1.553%); }
  8.333%  { transform: scale(1.2100) translate(6.928%, 3.000%); }
  12.5%   { transform: scale(1.1976) translate(5.657%, 4.243%); }
  16.667% { transform: scale(1.1880) translate(4.000%, 5.196%); }
  20.833% { transform: scale(1.1820) translate(2.071%, 5.796%); }
  25%     { transform: scale(1.1800) translate(0.000%, 6.000%); }
  29.167% { transform: scale(1.1820) translate(-2.071%, 5.796%); }
  33.333% { transform: scale(1.1880) translate(-4.000%, 5.196%); }
  37.5%   { transform: scale(1.1976) translate(-5.657%, 4.243%); }
  41.667% { transform: scale(1.2100) translate(-6.928%, 3.000%); }
  45.833% { transform: scale(1.2245) translate(-7.727%, 1.553%); }
  50%     { transform: scale(1.2400) translate(-8.000%, 0.000%); }
  54.167% { transform: scale(1.2555) translate(-7.727%, -1.553%); }
  58.333% { transform: scale(1.2700) translate(-6.928%, -3.000%); }
  62.5%   { transform: scale(1.2824) translate(-5.657%, -4.243%); }
  66.667% { transform: scale(1.2920) translate(-4.000%, -5.196%); }
  70.833% { transform: scale(1.2980) translate(-2.071%, -5.796%); }
  75%     { transform: scale(1.3000) translate(-0.000%, -6.000%); }
  79.167% { transform: scale(1.2980) translate(2.071%, -5.796%); }
  83.333% { transform: scale(1.2920) translate(4.000%, -5.196%); }
  87.5%   { transform: scale(1.2824) translate(5.657%, -4.243%); }
  91.667% { transform: scale(1.2700) translate(6.928%, -3.000%); }
  95.833% { transform: scale(1.2555) translate(7.727%, -1.553%); }
  100%    { transform: scale(1.2400) translate(8.000%, -0.000%); }
}
.hero__media--kb {
  animation: kenBurns 48s linear infinite;
  transform-origin: 50% 50%;
  will-change: transform;
}
/* the poster sits under the canvas and shows until the field is painted,
   and stays put under reduced motion or with scripting off */
.hero__canvas { z-index: 1; opacity: 0; transition: opacity 0.6s var(--ease); }
.hero__canvas.is-live { opacity: 1; }
.hero__title { margin: 28px 0 0; max-width: 15ch; }
.hero__sub { margin-top: 32px; max-width: 42ch; }

/* hero--full: the art fills the viewport at the top of the page, edge to
   edge, and the title/lede sit on top of it as a scrim-protected overlay.
   Everything below (.hero__overlay, .hero__scroll) stays in normal flow so
   it still reads correctly with scripting or animation off. */
.hero.hero--full {
  /* the doubled-up selector (.hero.hero--full) beats the mobile media
     query's plain .hero rule further down regardless of source order */
  position: relative;
  height: 100vh;
  height: 100dvh;               /* accounts for mobile browser chrome */
  min-height: 560px;
  padding: 0;
  margin: 0 calc(var(--pad) * -1) 0 calc(var(--rail) * -1);  /* bleed to the viewport edge, same trick as .section--panel */
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  overflow: hidden;
}
.hero--full .hero__art {
  position: absolute;
  inset: 0;
  aspect-ratio: auto;
  border-radius: 0;
  z-index: 0;
}
/* bottom-weighted scrim: guarantees contrast for the overlay text no matter
   which part of the flow field ends up behind it (the bloom drifts warm/light
   in the top-right, so the risk is concentrated at the bottom-left instead —
   this darkens exactly that band). */
.hero__scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg,
    rgba(6, 32, 46, 0)    0%,
    rgba(6, 32, 46, 0.05) 42%,
    rgba(6, 32, 46, 0.55) 78%,
    rgba(6, 32, 46, 0.82) 100%);
  pointer-events: none;
}
.hero__overlay {
  position: relative;
  z-index: 2;
  padding: 0 var(--pad) 96px calc(var(--pad) + var(--rail));
}
.hero--full .hero__title {
  margin: 0;
  max-width: 17ch;
  color: var(--white);
  text-shadow: 0 2px 30px rgba(6, 32, 46, 0.3);
}
.hero--full .hero__sub {
  margin-top: 28px;
  color: var(--white-70);
  text-shadow: 0 1px 20px rgba(6, 32, 46, 0.3);
}

/* entrance animation: title first, sub a beat behind. `both` keeps them
   invisible before the delay elapses so there's no flash of unstyled text;
   the global reduced-motion rule collapses the duration to ~0 for anyone
   who's asked for less motion. */
@keyframes heroRise {
  from { opacity: 0; transform: translateY(28px); }
  to   { opacity: 1; transform: translateY(0); }
}
.hero__title--in { animation: heroRise 900ms var(--ease) 150ms both; }
.hero__sub--in   { animation: heroRise 900ms var(--ease) 380ms both; }

.hero__scroll {
  position: absolute;
  z-index: 2;
  left: calc(var(--pad) + var(--rail));
  bottom: 40px;
  display: flex;
  align-items: center;
  gap: 10px;
  color: var(--white-70);
  transition: color var(--t) var(--ease), opacity 0.4s var(--ease);
  animation: heroRise 900ms var(--ease) 600ms both;
}
.hero__scroll:hover { color: var(--white); }
.hero__scroll-line { width: 1px; height: 28px; background: currentColor; }
.hero__scroll-label { font-size: 13px; letter-spacing: 0.06em; text-transform: uppercase; }
/* !important: the entrance animation above also touches opacity, and a
   running/held CSS animation otherwise wins over a plain cascade rule for
   the same property — this is the one declaration that needs to beat it */
body.is-scrolled .hero__scroll { opacity: 0 !important; pointer-events: none; }

/* --------------------------------------------------------------- work ---- */
.wcard { scroll-snap-align: start; }
/* clip to the card's own rounded box so the hover zoom below scales inside
   it instead of bulging past it — without this the scaled image pokes out
   past .wcard__scrim (which stays pinned to the unscaled box), exposing a
   sliver of un-darkened photo around the edges on hover */
.wcard a { position: relative; display: block; width: 440px; overflow: hidden; border-radius: var(--r-lg); }
.wcard img { width: 100%; height: 500px; object-fit: cover; border-radius: var(--r-lg); }
/* the artwork used to bake a dark gradient into the SVG itself; now that
   these are photos, this sits between the image and the text/pill to keep
   both readable regardless of how bright the photo is underneath */
.wcard__scrim {
  position: absolute;
  inset: 0;
  border-radius: var(--r-lg);
  background: linear-gradient(180deg,
    rgba(6, 15, 12, 0.72) 0%,
    rgba(6, 15, 12, 0.08) 38%,
    rgba(6, 15, 12, 0.05) 60%,
    rgba(6, 15, 12, 0.6)  100%);
  pointer-events: none;
}
.wcard__text {
  position: absolute;
  top: 30px;
  right: 26px;
  width: 200px;
  margin: 0;
  color: var(--white);
  /* a tight dark shadow for crisp edges, plus a wider soft one so the text
     holds contrast even against the brightest patch of sky or rooftop */
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.65), 0 2px 18px rgba(6, 15, 12, 0.6);
  font-size: 19px;
  line-height: 26.6px;
}
.wcard__foot { position: absolute; left: 22px; bottom: 22px; }
.wcard__foot .action__pill { letter-spacing: -0.32px; }
.wcard img { transition: transform 0.6s var(--ease); }
.wcard a:hover img { transform: scale(1.02); }
.hrail[data-rail="work"] { margin-top: 96px; }

/* ------------------------------------------------------------- vision ---- */
.section--panel {
  background: var(--panel);
  margin-left: calc(var(--rail) * -1);
  margin-right: calc(var(--pad) * -1);
  padding: 120px calc(var(--pad) + var(--rail));
}
.vision__statement { max-width: 22ch; margin-bottom: 72px; }

/* running prose: a stack of plain paragraphs (article-style copy) rather
   than the labelled rows above — used on the work/*.html detail pages */
.prose { max-width: 62ch; }
.prose p + p { margin-top: 24px; }
.vrow {
  display: grid;
  grid-template-columns: var(--label) minmax(0, 1fr);
  gap: 24px;
  padding: 40px 0;
  border-top: 1px solid var(--ink-10);
}
.vrow--cta { border-top: 0; padding-top: 48px; }
.vlist li { display: flex; gap: 14px; font-size: 22px; line-height: 30.8px; padding: 6px 0; }
.vchev { color: var(--accent); }

/* ---------------------------------------------------------------- cta ---- */
.section--cta {
  background: var(--band);
  margin-left: calc(var(--rail) * -1);
  margin-right: calc(var(--pad) * -1);
  padding: 150px calc(var(--pad) + var(--rail)) 160px;
}
.section--cta .action { margin-top: 56px; }
.cta__link { margin-top: 34px; }

/* ------------------------------------------------------------- footer ---- */
.foot { padding: 96px 0 40px; }
.foot__grid { display: grid; grid-template-columns: var(--label) minmax(0, 1fr); }
.foot__cols { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 40px; }
.fcol__title { margin-bottom: 18px; color: var(--ink-60); }
.fcol a {
  display: block;
  padding: 5px 0;
  font-family: var(--mono);
  font-size: 16px;
  font-weight: 500;
  transition: color var(--t) var(--ease);
}
.fcol a:hover { color: var(--accent); }
.foot__copy { color: var(--ink-60); max-width: 34ch; }
.foot__social { display: flex; gap: 16px; margin-top: 28px; }
.social {
  width: 32px;
  height: 32px;
  border-radius: 999px;
  border: 1px solid var(--hair);
  display: grid;
  place-items: center;
  font-family: var(--mono);
  font-size: 12px;
  color: var(--ink-60);
  transition: border-color var(--t) var(--ease), color var(--t) var(--ease);
}
.social:hover { border-color: var(--accent); color: var(--accent); }

/* --------------------------------------------------------- responsive ---- */
@media (max-width: 1240px) {
  :root { --label: 320px; }
  .t80 { font-size: 62px; line-height: 66px; letter-spacing: -2.4px; }
}

@media (max-width: 980px) {
  :root { --pad: 16px; --rail: 0px; --label: 0px; }
  .rail { display: none; }   /* the mobile top bar (.mbar) carries the logo instead */

  .mbar {
    position: sticky;
    top: 0;
    z-index: 50;
    display: flex;
    align-items: flex-start;
    padding: 14px var(--pad);
    background: var(--paper);
  }
  .logo--m { display: flex; align-items: flex-start; gap: 12px; }
  .logo--m .mark { width: 34px; height: 34px; }
  .logo--m .logo__word { margin: 0; line-height: 1.15; font-size: 14px; }

  .content { margin-left: 0; padding-inline: var(--pad); }
  .section { padding-block: 72px; }
  .grid, .vrow, .foot__grid { grid-template-columns: minmax(0, 1fr); gap: 22px; }
  .t80 { font-size: 40px; line-height: 44px; letter-spacing: -1.2px; }
  .t56 { font-size: 34px; line-height: 41px; letter-spacing: -1px; }
  .t40 { font-size: 28px; line-height: 34px; }
  .t30 { font-size: 22px; line-height: 31px; }
  .num { font-size: 46px; line-height: 60px; }

  .hero { padding-top: 8px; }
  .hero__art { aspect-ratio: 1 / 1; }
  .hero__sub { margin-top: 24px; max-width: none; }

  .wcard a { width: 320px; }
  .wcard img { height: 380px; }
  .hrail[data-rail="work"] { margin-top: 40px; }
  .hrail__track { gap: 24px; padding-right: 8vw; }
  .section--panel, .section--cta { margin-inline: calc(var(--pad) * -1); padding: 72px var(--pad); }
  .vision__statement { margin-bottom: 40px; }
  .foot__cols { grid-template-columns: minmax(0, 1fr); gap: 32px; }
  .foot__grid { gap: 48px; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}
