/* ==========================================================================
   MAINERMEDIA theme tokens
   --------------------------------------------------------------------------
   One source of truth for every surface, text, line and accent color.

   The site ships one register: the 2026 brand palette (guidelines v3),
   white and Mist with black type and Mainer Green as the one accent. Light is
   the default; a dark mode returns on the visitor's choice (see below). The dark register and its
   toggle were removed 2026-09-20 on Dylan's call. Every token resolves on
   :root; there is no per-scheme override and no data-theme attribute.
   ========================================================================== */

:root {
  color-scheme: light;

  /* Surfaces, deepest to most raised. Neutral: white and light gray with
     forest green as the one accent (Nate's 9/14 brief), a hair warm so it
     is not clinical (the 9/10 "not sterile" note). The 2026-09-08 ivory and
     sage register is retired here; the tokens keep their names. */
  /* 2026 brand guidelines (pp.13-15): white and Mist carry the page, black type, green as the accent. */
  --surface-0: #f4f5f6; /* Mist band */
  --surface-1: #ffffff; /* default section, white */
  --surface-2: #f8f9f9; /* cards, raised panels */
  --surface-3: #eceeef; /* wells, inset areas */

  /* An inverted block: the deep green band the concept uses to change register
     without going dark for the whole page. */
  --surface-invert: #185a35; /* Forest (guidelines p.19: Forest overlay, white type) */
  --text-on-invert: #ffffff;

  /* Text. Neutral near-black and grays; the green lives in the accent only. */
  --text-primary: #000000;
  --text-secondary: #2e3130;
  --text-muted: #585c5b; /* Charcoal */
  --text-dim: #6b6f6e;
  --text-on-accent: #ffffff;

  /* Lines */
  --line: #e3e5e7;
  --line-strong: #c9ccce;
  --hairline: rgba(0, 0, 0, 0.10);
  --hairline-soft: rgba(0, 0, 0, 0.06);
  --hairline-faint: rgba(0, 0, 0, 0.03);

  /* Brand accent. Forest green, not the dark build's emerald: the emerald
     was tuned to glow on near-black and turns acidic on ivory. */
  --accent: #177548;        /* Mainer Green, 5.7:1 on white */
  --accent-strong: #185a35; /* Forest */
  --accent-quiet: #449050;  /* Trail: graphics and large text only (3.9:1) */
  --accent-05: rgba(23, 117, 72, 0.05);
  --accent-10: rgba(23, 117, 72, 0.10);
  --accent-15: rgba(23, 117, 72, 0.15);
  --accent-20: rgba(23, 117, 72, 0.20);
  --accent-30: rgba(23, 117, 72, 0.30);
  --accent-40: rgba(23, 117, 72, 0.40);
  --accent-50: rgba(23, 117, 72, 0.50);

  /* Scrims: the wash laid over photography so type stays legible */
  --scrim-1: rgba(255, 255, 255, 0.74);
  --scrim-2: rgba(244, 245, 246, 0.86);

  /* Photographic texture. The frames were graded to sit under white type on
     near-black. On ivory the same frame reads as a grey stain, so the light
     register scales each placement's opacity down and lifts the black point
     hard. --texture-scale multiplies the per-placement opacity the markup
     already carries, so the art direction of each section is preserved and
     only its weight changes. */
  --hero-scrim: linear-gradient(180deg, rgba(255, 255, 255, 0.88) 0%, rgba(255, 255, 255, 0.80) 45%, rgba(244, 245, 246, 0.94) 100%);
  --hero-texture-scale: 0.34;
  --texture-scale: 0.5;
  --texture-filter: brightness(1.45) contrast(0.7) saturate(0.85);
  --texture-blend: normal;

  /* Status */
  --danger: #a33528;
  --warning: #8a5a00;

  /* Elevation */
  --shadow-1: 0 1px 2px rgba(0, 0, 0, 0.05), 0 1px 3px rgba(0, 0, 0, 0.07);
  --shadow-2: 0 4px 14px rgba(0, 0, 0, 0.07), 0 2px 4px rgba(0, 0, 0, 0.05);
  /* ---- Tailwind palette bridge -------------------------------------------
  Tailwind utilities (text-white, text-gray-400, bg-green-500 and 3,300 more
  already in the markup) resolve through these channel triplets, so the whole
  utility layer follows the theme without touching a single class name.
  Stored as "R G B" because Tailwind needs raw channels to honor the /alpha
  modifier in classes like bg-white/5.
  Semantics, not literal colors: gray-900 means "the ground opposite the
  accent", which is ink on dark and ivory on light. That is what makes
  text-gray-900 on a green button stay legible in both registers. */
  --c-surface-0: 244 245 246;
  --c-surface-1: 255 255 255;
  --c-surface-2: 248 249 249;
  --c-white: 0 0 0;
  --c-black: 255 255 255;
  --c-gray-300: 46 49 48;
  --c-gray-400: 88 92 91;
  --c-gray-500: 98 102 101;
  --c-gray-600: 98 102 101;
  --c-gray-700: 201 204 206;
  --c-gray-800: 227 229 231;
  --c-gray-900: 244 245 246;
  /* greens are used as text 400+ times, so every step used for type passes 4.5:1 on white */
  --c-green-300: 23 117 72;   /* Mainer Green */
  --c-green-400: 24 90 53;    /* Forest; distinct from 500 so hover:bg-green-400 is visible */
  --c-green-500: 23 117 72;   /* Mainer Green */
  --c-green-600: 24 90 53;    /* Forest */
  --c-green-700: 24 90 53;
  --c-on-accent: 255 255 255; /* text on a solid green fill; text-white is ink in this register */
  --c-red-400: 163 53 40;
  --c-amber-400: 138 90 0;
}

/* Dark mode (2026-10-02, Dylan: "website should default to light mode", "and then we keep the dark mode").
   Light is the default for everyone; dark only when a visitor picks it with the toggle (stored as mm-theme
   and stamped on <html> before first paint). The OS preference is deliberately ignored. Brand dark grounds:
   black and near-black, white type, Summit green as the accent (guidelines: Summit on dark grounds only). */
:root[data-theme='dark'] {
  color-scheme: dark;

  --surface-0: #000000;
  --surface-1: #0b0c0c;
  --surface-2: #141616;
  --surface-3: #1c1e1e;
  --surface-invert: #185a35;
  --text-on-invert: #ffffff;

  --text-primary: #ffffff;
  --text-secondary: #d6d9d8;
  --text-muted: #a3a7a6;
  --text-dim: #8a8e8d;
  --text-on-accent: #000000;

  --line: #262828;
  --line-strong: #3a3d3c;
  --hairline: rgba(255, 255, 255, 0.10);
  --hairline-soft: rgba(255, 255, 255, 0.06);
  --hairline-faint: rgba(255, 255, 255, 0.03);

  --accent: #72c06f;
  --accent-strong: #449050;
  --accent-quiet: #9ed69b;
  --accent-05: rgba(114, 192, 111, 0.05);
  --accent-10: rgba(114, 192, 111, 0.10);
  --accent-15: rgba(114, 192, 111, 0.15);
  --accent-20: rgba(114, 192, 111, 0.20);
  --accent-30: rgba(114, 192, 111, 0.30);
  --accent-40: rgba(114, 192, 111, 0.40);
  --accent-50: rgba(114, 192, 111, 0.50);

  --scrim-1: rgba(0, 0, 0, 0.60);
  --scrim-2: rgba(11, 12, 12, 0.60);
  --hero-scrim: linear-gradient(180deg, rgba(0, 0, 0, 0.55) 0%, rgba(0, 0, 0, 0.35) 45%, rgba(11, 12, 12, 0.75) 100%);
  --hero-texture-scale: 1;
  --texture-scale: 1;
  --texture-filter: none;
  --texture-blend: normal;

  --danger: #ef4444;
  --warning: #f59e0b;

  --shadow-1: 0 1px 2px rgba(0, 0, 0, 0.30), 0 1px 3px rgba(0, 0, 0, 0.40);
  --shadow-2: 0 4px 12px rgba(0, 0, 0, 0.40), 0 2px 4px rgba(0, 0, 0, 0.30);

  --c-surface-0: 0 0 0;
  --c-surface-1: 11 12 12;
  --c-surface-2: 20 22 22;
  --c-white: 255 255 255;
  --c-black: 0 0 0;
  --c-gray-300: 214 217 216;
  --c-gray-400: 163 167 166;
  --c-gray-500: 138 142 141;
  --c-gray-600: 82 86 85;
  --c-gray-700: 58 61 60;
  --c-gray-800: 38 40 40;
  --c-gray-900: 17 19 19;
  --c-green-300: 158 214 155;
  --c-green-400: 158 214 155;  /* lighter than 500 so hover:bg-green-400 shows */
  --c-green-500: 114 192 111;  /* Summit */
  --c-green-600: 68 144 80;    /* Trail */
  --c-green-700: 23 117 72;    /* Mainer Green */
  --c-on-accent: 0 0 0;        /* black on Summit, 9.5:1 */
  --c-red-400: 248 113 113;
  --c-amber-400: 251 191 36;
}

/* Logo: full color on light, reversed (white type) on dark (guidelines p.9 color versions). */
.mm-lockup-rev { display: none; }
:root[data-theme='dark'] .mm-lockup-std { display: none; }
:root[data-theme='dark'] .mm-lockup-rev { display: inline-block; }

/* Homepage hero: the haze behind the copy goes dark with the theme so white type holds over the footage. */
:root[data-theme='dark'] .mm-hero-haze { background: radial-gradient(ellipse 62% 78% at 50% 48%, rgba(0,0,0,0.80) 0%, rgba(0,0,0,0.70) 45%, rgba(0,0,0,0.36) 78%, rgba(0,0,0,0.12) 100%) !important; }

/* The toggle: shows the icon for the mode you would switch TO. */
.theme-toggle { display: inline-flex; align-items: center; justify-content: center; width: 2.25rem; height: 2.25rem; border-radius: 0.5rem; border: 1px solid var(--hairline); background: transparent; color: var(--text-muted); cursor: pointer; transition: color .2s ease, border-color .2s ease, background-color .2s ease; }
.theme-toggle:hover { color: var(--text-primary); border-color: var(--line-strong); background: var(--hairline-faint); }
.theme-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.theme-toggle svg { width: 1.125rem; height: 1.125rem; }
.theme-toggle .icon-sun { display: none; }
.theme-toggle .icon-moon { display: block; }
:root[data-theme='dark'] .theme-toggle .icon-sun { display: block; }
:root[data-theme='dark'] .theme-toggle .icon-moon { display: none; }
@media (prefers-reduced-motion: reduce) { .theme-toggle { transition: none; } }

/* Text on solid green fills. In the light register `text-white` resolves to
   ink, which put near-black type on forest green (about 1.4:1) on every
   bg-green-600 button. Two-class selectors outrank the single utility, and
   the token follows the theme, so dark stays white. (Nate's 9/14 brief, A2.) */
.bg-green-500.text-white, .bg-green-600.text-white, .bg-green-700.text-white,
.bg-green-500.focus\:text-white:focus, .bg-green-600.focus\:text-white:focus,
.hover\:bg-green-600:hover, .hover\:bg-green-700:hover { color: rgb(var(--c-on-accent)); }



/* The page ground itself. The viewer paints behind the document, so this is
   set explicitly rather than inherited. */
html {
  background-color: var(--surface-1);
}

body {
  background-color: var(--surface-1);
  color: var(--text-primary);
}

/* Photographic texture layers. Each placement sets its own --tex-opacity in
   the markup (the art direction from the 2026-08-25 coverage pass); the theme
   scales and treats it. */
.section-texture {
  opacity: calc(var(--tex-opacity, 0.2) * var(--texture-scale));
  filter: var(--texture-filter);
  mix-blend-mode: var(--texture-blend);
}


/* The hero's wash over the Portland Head Light frame. It lifts the frame
   toward paper so dark type holds over it. */
.hero-scrim {
  background: var(--hero-scrim);
}

/* The hero frame gives up more of its weight than a section texture does. */
section:first-of-type .section-texture {
  opacity: calc(var(--tex-opacity, 0.2) * var(--hero-texture-scale));
}

/* ==========================================================================
   Wireframe terrain
   --------------------------------------------------------------------------
   Three rastered layers drifting at different rates to read as depth. Only
   `transform` is animated, so each layer is promoted to its own compositor
   layer and the main thread does no work per frame: no layout, no paint.
   Nothing here animates opacity, color or position, which would repaint.

   The layers are 120% wide and centered by the -10% inset, so the largest
   drift (3% of width) can never walk an edge into the section.
   ========================================================================== */
.terrain-ghost {
  /* the ink is baked into the raster; this is the one knob the markup sets */
  mix-blend-mode: multiply;
}

/* The <picture> is the positioned, animated box; the <img> just fills it.
   Positioning both collapses the picture to zero height, which silently
   doubles the effective width and zeroes any percentage vertical drift. */
.terrain-layer {
  position: absolute;
  bottom: 0;
  left: -10%;
  width: 120%;
}

.terrain-layer img {
  display: block;
  width: 100%;
  height: auto;
}

/* Phone: the section grows tall because the cards stack, and a ridge pinned
   to the bottom of it reads as noise under the copy instead of as landscape.
   Cover the band and frame on the ridge line so it stays a horizon. */
@media (max-width: 767px) {
  .terrain-layer {
    top: 0;
    bottom: 0;
  }

  .terrain-layer img {
    height: 100%;
    object-fit: cover;
    object-position: 50% 68%;
  }
}

.terrain-back {
  animation: terrain-drift-back 90s ease-in-out infinite alternate;
}

.terrain-front {
  animation: terrain-drift-front 61s ease-in-out infinite alternate;
}

.terrain-decoration {
  animation: terrain-drift-marks 47s ease-in-out infinite alternate;
}

/* Distant ridge: the least travel, as depth demands. */
@keyframes terrain-drift-back {
  from { transform: translate3d(-1.1%, 0, 0); }
  to   { transform: translate3d(1.1%, 0, 0); }
}

/* Near ridge: more travel and a breath of vertical, drifting against the
   back layer so the two open and close rather than sliding as one plate. */
@keyframes terrain-drift-front {
  from { transform: translate3d(2.4%, 0.5%, 0); }
  to   { transform: translate3d(-2.4%, -0.5%, 0); }
}

/* Registration marks: nearly still, just enough not to look pinned on. */
@keyframes terrain-drift-marks {
  from { transform: translate3d(0.6%, 0, 0); }
  to   { transform: translate3d(-0.6%, 0, 0); }
}

/* animations.css already zeroes every animation under this preference; this
   is the explicit statement of intent for anyone reading only this file. */
@media (prefers-reduced-motion: reduce) {
  .terrain-back,
  .terrain-front,
  .terrain-decoration {
    animation: none;
    transform: none;
  }
}
