/* ==========================================================================
   Froggies Lab, design tokens
   ========================================================================== */

:root {
  /* THEME, every color used anywhere on the site is defined here, once.
     To restyle the whole page, this is the only block that should need
     to change (the hero illustration is inlined in index.html precisely
     so it can reference these same variables instead of its own hex). */

  /* Brand surface hue (blue-green, H178°): near-black for dark surfaces
     through to the light neutral background. */
  --teal-950: #0e1b1b;
  --teal-900: #162c2b;
  --teal-850: #264a49;
  --teal-800: #264a49;
  --teal-700: #326260;
  --teal-600: #3f7b79;
  --teal-400: #89c3c1;

  --paper: #f1f3f4;
  --paper-dim: #e6ebea;
  --paper-line: #d6dedd;
  --paper-line-strong: #458785;
  --teal-line-strong: #89c3c1;

  --ink: #0e1b1b;
  --ink-soft: #326260;

  /* Accent hue (blue, H218°): the same blue as the hero illustration's
     analytics curve, reused site-wide as the one accent color. */
  --accent-deep: #164598;
  --accent: #2066df;
  --accent-vivid: #6c9aea;

  /* Reserved strictly for form validation feedback, never decorative. */
  --error: #c0392b;
  --error-bg-tint: color-mix(in srgb, var(--error) 8%, transparent);

  /* Semantic roles */
  --bg-dark: var(--teal-950);
  --bg-dark-raised: var(--teal-900);
  --border-dark: var(--teal-850);
  --text-on-dark: var(--paper);
  --text-on-dark-soft: var(--teal-400);

  --bg-light: var(--paper);
  --bg-light-raised: var(--paper-dim);
  --border-light: var(--paper-line);
  --text-on-light: var(--ink);
  --text-on-light-soft: var(--ink-soft);

  --accent-on-dark: var(--accent-vivid);
  --accent-on-light: var(--accent-deep);
  --accent-fill: var(--accent);
  --accent-fill-text: var(--paper);

  --brand-on-dark: var(--teal-400);
  --brand-on-light: var(--teal-600);

  --shadow-color: 178, 40%, 5%;
  --shadow-sm: 0 2px 10px -2px hsla(var(--shadow-color), 0.18);
  --shadow-md: 0 12px 28px -10px hsla(var(--shadow-color), 0.28);
  --shadow-lg: 0 24px 48px -16px hsla(var(--shadow-color), 0.32);

  --focus-ring: var(--accent);
  --focus-ring-on-dark: var(--accent-vivid);

  /* Ambient section textures, dot grids and glow blobs, derived from the
     same brand hues so they read as "studio" rather than decoration. */
  --texture-grid-line-on-light: color-mix(in srgb, var(--ink) 7%, transparent);
  --texture-glow-a: color-mix(in srgb, var(--accent) 32%, transparent);
  --texture-glow-b: color-mix(in srgb, var(--teal-400) 26%, transparent);
  --texture-glow-a-soft: color-mix(in srgb, var(--accent) 18%, transparent);
  --texture-glow-b-soft: color-mix(in srgb, var(--teal-600) 18%, transparent);

  /* Type */
  --font-display: 'Bricolage Grotesque', 'Arial Narrow', sans-serif;
  --font-body: 'Public Sans', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-mono: 'IBM Plex Mono', ui-monospace, 'SFMono-Regular', Menlo, monospace;

  --step-000: clamp(0.8rem, 0.78rem + 0.1vw, 0.86rem);
  --step-00: clamp(0.9rem, 0.88rem + 0.1vw, 0.98rem);
  --step-0: clamp(1rem, 0.97rem + 0.15vw, 1.1rem);
  --step-1: clamp(1.2rem, 1.13rem + 0.35vw, 1.4rem);
  --step-2: clamp(1.5rem, 1.35rem + 0.75vw, 1.95rem);
  --step-3: clamp(1.95rem, 1.65rem + 1.5vw, 2.8rem);
  --step-4: clamp(2.6rem, 2.05rem + 2.75vw, 4.2rem);
  --step-5: clamp(3.4rem, 2.5rem + 4.5vw, 6.2rem);

  /* Space */
  --space-1: 0.4rem;
  --space-2: 0.7rem;
  --space-3: 1.1rem;
  --space-4: 1.7rem;
  --space-5: 2.6rem;
  --space-6: 4rem;
  --space-7: 6rem;
  --space-8: 9rem;

  --radius-sm: 10px;
  --radius: 14px;
  --radius-lg: 24px;
  --radius-pill: 999px;
  --border-w: 1.5px;
  --wrap: 74rem;

  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
}

/* ==========================================================================
   Reset
   ========================================================================== */

*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; scroll-padding-top: 77px; }

body {
  font-family: var(--font-body);
  font-size: var(--step-0);
  line-height: 1.55;
  color: var(--text-on-light);
  background: var(--bg-light);
  min-height: 100vh;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
}

img, svg { display: block; max-width: 100%; }
button, input, textarea, select { font: inherit; color: inherit; }
button { cursor: pointer; }
a { color: inherit; }
ul { list-style: none; padding: 0; }

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

/* Focus visibility, never remove without replacing */
:focus { outline: none; }
:focus-visible {
  outline: 3px solid var(--focus-ring);
  outline-offset: 2px;
}
.bg-dark :focus-visible { outline-color: var(--focus-ring-on-dark); }

/* ==========================================================================
   Utility
   ========================================================================== */

.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: var(--space-4);
}

.bg-dark { background: var(--bg-dark); color: var(--text-on-dark); }
.bg-dark-raised { background: var(--bg-dark-raised); }
.bg-light { background: var(--bg-light); color: var(--text-on-light); }
.bg-light-raised { background: var(--bg-light-raised); color: var(--text-on-light); }

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

.eyebrow {
  font-family: var(--font-mono);
  font-size: var(--step-000);
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--accent-on-light);
  display: inline-flex;
  align-items: center;
  gap: 0.6em;
}
.bg-dark .eyebrow { color: var(--accent-on-dark); }

/* Viewfinder-bracket mark, the recurring signature motif (this is a camera/scan
   studio: every "identify" app is a viewfinder pointed at something) built from
   four background-image bars, no image asset needed. */
.eyebrow::before {
  content: '';
  width: 0.95em;
  height: 0.95em;
  flex: none;
  background-image:
    linear-gradient(currentColor, currentColor),
    linear-gradient(currentColor, currentColor),
    linear-gradient(currentColor, currentColor),
    linear-gradient(currentColor, currentColor);
  background-repeat: no-repeat;
  background-size: 1.5px 42%, 42% 1.5px, 1.5px 42%, 42% 1.5px;
  background-position: top left, top left, bottom right, bottom right;
}

h1, h2, h3 {
  font-family: var(--font-display);
  font-weight: 650;
  letter-spacing: -0.01em;
  line-height: 1.05;
}

.section-heading {
  font-size: var(--step-3);
  max-width: 22ch;
}

.section-intro {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-3);
  margin-bottom: var(--space-6);
}
@media (min-width: 62em) {
  .section-intro {
    grid-template-columns: 1.1fr 0.9fr;
    align-items: start;
  }
}
.section-intro .lede {
  font-size: var(--step-1);
  max-width: 42ch;
}
.bg-dark .section-intro .lede { color: var(--text-on-dark-soft); }
.bg-light .section-intro .lede { color: var(--text-on-light-soft); }

.section { padding-block: var(--space-7); border-block-end: var(--border-w) solid transparent; }
.section + .section { position: relative; }

.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.6em;
  font-family: var(--font-body);
  font-size: var(--step-00);
  font-weight: 600;
  letter-spacing: 0;
  padding: 0.9em 1.5em;
  border: var(--border-w) solid currentColor;
  border-radius: var(--radius-pill);
  text-decoration: none;
  transition: transform 0.15s var(--ease), background 0.15s var(--ease), color 0.15s var(--ease), box-shadow 0.15s var(--ease);
  white-space: nowrap;
}
.btn:hover { transform: translateY(-2px); }
.btn:active { transform: translateY(0); }

.btn-solid {
  background: var(--accent-fill);
  border-color: var(--accent-fill);
  color: var(--accent-fill-text);
  box-shadow: var(--shadow-sm);
}
.btn-solid:hover { background: var(--accent-deep); border-color: var(--accent-deep); box-shadow: var(--shadow-md); }

/* Tonal fill rather than a hairline stroke: a 1.5px border on a full pill
   radius anti-aliases visibly (looks "pixelated") at most zoom levels. */
.btn-outline {
  border-color: transparent;
  background: rgba(243, 250, 249, 0.16);
  box-shadow: var(--shadow-sm);
}
.bg-dark .btn-outline { color: var(--paper); }
.btn-outline:hover { background: rgba(243, 250, 249, 0.26); }

.btn-arrow { transition: transform 0.15s var(--ease); }
.btn:hover .btn-arrow { transform: translateX(3px); }

/* ==========================================================================
   Header / nav
   ========================================================================== */

.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  background: var(--teal-950);
  border-bottom: var(--border-w) solid transparent;
  transition: border-color 0.2s var(--ease), background 0.2s var(--ease);
}
.site-header.is-scrolled { border-bottom-color: var(--teal-800); }

.site-header .wrap {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding-block: var(--space-3);
}

.logo {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  font-size: var(--step-1);
  text-decoration: none;
  color: var(--paper);
}
/* Sized off the wordmark's own em (not a fixed px square): the SVG's viewBox
   is cropped to the actual ink, so 1em of height here reads as roughly the
   same visual weight as 1em of the adjacent text, instead of the guesswork
   a fixed px value needs when the source has a lot of built-in padding. */
.logo-mark { width: auto; height: 1.5em; flex: none; }
.logo-word {
  font-family: var(--font-display);
  font-weight: 650;
  font-size: 1em;
  letter-spacing: -0.01em;
}

.main-nav ul {
  display: flex;
  align-items: center;
  gap: var(--space-5);
}
.main-nav a {
  text-decoration: none;
  font-size: var(--step-00);
  color: var(--text-on-dark-soft);
  position: relative;
  padding-block: 0.2em;
}
.main-nav a:hover, .main-nav a.is-active { color: var(--paper); }
.main-nav a.is-active::after {
  content: '';
  position: absolute;
  left: 0; right: 0; bottom: -6px;
  height: 2px;
  background: var(--accent-on-dark);
}

.header-tools {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}

.lang-switch {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 2px;
  background: var(--teal-900);
  border: var(--border-w) solid var(--teal-850);
  border-radius: var(--radius-pill);
  padding: 3px;
}
/* The white active-state pill is a separate element that slides between the
   two buttons, rather than a background toggled per-button, that's what
   makes it read as one shape travelling, not two buttons swapping colors.
   Its left/right edges transition with a slight offset (one edge starts
   moving immediately, the other after a short delay) so the pill stretches
   toward the destination before catching up and settling, like a blob
   morphing rather than a rigid slab sliding on rails. */
.lang-switch-thumb {
  position: absolute;
  top: 3px;
  bottom: 3px;
  left: 3px;
  right: calc(50% + 1px);
  background: var(--paper);
  border-radius: var(--radius-pill);
  transition: left 0.32s var(--ease) 0.05s, right 0.32s var(--ease);
  z-index: 0;
}
.lang-switch[data-active="fr"] .lang-switch-thumb {
  left: calc(50% + 1px);
  right: 3px;
  transition: left 0.32s var(--ease), right 0.32s var(--ease) 0.05s;
}
.lang-option {
  position: relative;
  z-index: 1;
  flex: 1 1 0;
  text-align: center;
  text-decoration: none;
  font-family: var(--font-body);
  font-size: var(--step-000);
  font-weight: 600;
  background: transparent;
  border: none;
  border-radius: var(--radius-pill);
  color: var(--text-on-dark-soft);
  padding: 0.4em 0.85em;
  transition: color 0.15s var(--ease);
}
.lang-option:hover:not(.is-active) { color: var(--paper); }
.lang-option.is-active { color: var(--ink); }

.nav-toggle {
  display: none;
  background: transparent;
  border: var(--border-w) solid var(--teal-line-strong);
  border-radius: var(--radius);
  width: 40px;
  height: 40px;
  align-items: center;
  justify-content: center;
  color: var(--paper);
}
.nav-toggle svg { width: 18px; height: 18px; }

@media (max-width: 56em) {
  .main-nav {
    position: fixed;
    inset: 64px 0 0 0;
    background: var(--teal-950);
    transform: translateY(-8px);
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.2s var(--ease), transform 0.2s var(--ease), visibility 0.2s;
    overflow-y: auto;
  }
  .main-nav.is-open { opacity: 1; visibility: visible; transform: translateY(0); }
  .main-nav ul {
    flex-direction: column;
    align-items: flex-start;
    gap: 0;
    padding: var(--space-4);
  }
  .main-nav li { width: 100%; border-bottom: var(--border-w) solid var(--teal-900); }
  .main-nav a { display: block; padding-block: var(--space-3); font-size: var(--step-1); }
  .main-nav a.is-active::after { display: none; }
  .nav-toggle { display: inline-flex; }
}

/* ==========================================================================
   Hero
   ========================================================================== */

.hero {
  padding-block: var(--space-8) var(--space-7);
  position: relative;
  overflow: hidden;
}
.hero .wrap { position: relative; }

.hero-grid {
  display: grid;
  gap: var(--space-6);
}
@media (min-width: 62em) {
  .hero-grid { grid-template-columns: 1.3fr 0.9fr; align-items: start; }
}

.hero-eyebrow { margin-bottom: var(--space-4); }

.hero h1 {
  font-size: var(--step-5);
  margin-bottom: var(--space-4);
}
.hero-title-row {
  display: inline-flex;
  align-items: center;
  gap: 0.08em;
}
/* Height-only, width auto: same cropped-viewBox logic as the header mark
   (see .logo-mark). 0.72em lands close to the display font's cap-height
   rather than its full em-box, so the icon sits level with the letters
   instead of visibly overshooting them top and bottom. */
.hero-logo-mark {
  width: auto;
  height: 0.72em;
  flex: none;
}

.hero-lede {
  font-size: var(--step-1);
  max-width: 46ch;
  color: var(--text-on-dark-soft);
  margin-bottom: var(--space-5);
}
.hero-lede strong { color: var(--paper); font-weight: 600; }

.hero-ctas { display: flex; flex-wrap: wrap; gap: var(--space-3); }

.hero-illustration {
  display: flex;
  justify-content: center;
  filter: drop-shadow(0 24px 40px hsla(var(--shadow-color), 0.35));
}
.hero-illustration svg { width: 100%; max-width: 380px; height: auto; }
@media (max-width: 62em) { .hero-illustration { max-width: 320px; margin-inline: auto; } }

/* Hero illustration color roles, kept as classes (not inline hex) so the
   illustration follows the theme tokens above instead of its own palette. */
.hi-screen-stop-1 { stop-color: var(--teal-900); }
.hi-screen-stop-2 { stop-color: var(--teal-950); }
.hi-phone-stop-1 { stop-color: var(--teal-700); }
.hi-phone-stop-2 { stop-color: var(--teal-900); }
.hi-line { stroke: var(--teal-400); }
.hi-notch { fill: var(--teal-400); }
.hi-bar { fill: var(--teal-700); }
.hi-chart-line { stroke: var(--accent-vivid); }
.hi-chart-dot { fill: var(--accent-vivid); }
.hi-badge-bg { fill: var(--paper); }
.hi-badge-border { stroke: var(--paper-line); }
.hi-badge-icon { stroke: var(--ink); }

/* ==========================================================================
   404 page, same hero treatment, centered single-column content
   ========================================================================== */

.error-section {
  /* 77px matches the sticky header height accounted for elsewhere
     (see `scroll-padding-top` above). */
  min-height: calc(100svh - 77px);
  display: flex;
  align-items: center;
  padding-block: var(--space-7);
  position: relative;
  overflow: hidden;
}
.error-section .wrap { position: relative; max-width: 54ch; }

.error-code {
  font-family: var(--font-display);
  font-size: var(--step-5);
  font-weight: 650;
  line-height: 1;
  color: var(--brand-on-dark);
  margin-bottom: var(--space-3);
}

.error-section h1 {
  font-size: var(--step-3);
  margin-bottom: var(--space-4);
}

.error-lede {
  font-size: var(--step-1);
  max-width: 46ch;
  color: var(--text-on-dark-soft);
  margin-bottom: var(--space-5);
}

/* ==========================================================================
   Product tiles, signature element

   Compact horizontal rows (icon · name+tagline · CTA chip) rather than tall
   centered cards. Two things this fixes structurally, not by patching: the
   chip's position no longer depends on how many lines the tagline wraps to
   (it's a sibling flex item pinned to the row's far end, not stacked below
   variable-height text), and the footprint per app is smaller, so more of
   the catalog is visible without scrolling.
   ========================================================================== */

.product-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-3);
}
@media (min-width: 40em) {
  .product-grid { grid-template-columns: repeat(2, 1fr); gap: var(--space-4); }
}

.product-tile {
  container-type: inline-size;
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--space-4);
  text-align: left;
  background: var(--bg-light-raised);
  border-radius: var(--radius);
  padding: var(--space-4);
  text-decoration: none;
  color: inherit;
  box-shadow: var(--shadow-sm);
  transition: background 0.2s var(--ease), box-shadow 0.2s var(--ease);
}
.product-tile:hover, .product-tile:focus-visible {
  background: color-mix(in srgb, var(--bg-light-raised) 90%, var(--accent) 10%);
  box-shadow: var(--shadow-md);
}

.product-icon {
  width: 48px;
  height: 48px;
  border-radius: var(--radius-sm);
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
}

.product-tile-body { flex: 1 1 auto; min-width: 0; }
.product-name {
  font-family: var(--font-display);
  font-weight: 650;
  font-size: var(--step-1);
}
.product-tagline {
  font-size: var(--step-00);
  color: var(--text-on-light-soft);
  margin-top: 0.15em;
}

.product-desc {
  font-size: var(--step-00);
  color: var(--text-on-light-soft);
  margin-bottom: var(--space-4);
  flex: 1;
}

/* Real app-icon image (App Store artwork), already fully designed and in
   color, so it just needs a frame, not extra background or glow. */
.product-icon-img {
  width: 48px;
  height: 48px;
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-sm);
  flex: none;
  transition: transform 0.2s var(--ease);
}
.product-tile:hover .product-icon-img,
.product-tile:focus-visible .product-icon-img {
  transform: scale(1.06);
}

/* CTA chip, a sibling of the text block, not stacked under it, so its
   position is fixed (far end of the row, vertically centered) no matter how
   long the name or tagline run. */
.product-tile-link {
  display: inline-flex;
  align-items: center;
  gap: 0.35em;
  flex: none;
  margin-left: auto;
  padding: 0.5em 0.4em 0.5em 1em;
  border-radius: var(--radius-pill);
  background: color-mix(in srgb, var(--accent) 10%, transparent);
  font-family: var(--font-body);
  font-size: var(--step-000);
  font-weight: 600;
  color: var(--accent-on-light);
  transition: background 0.2s var(--ease);
}
.product-tile-link svg {
  width: 22px;
  height: 22px;
  padding: 5px;
  border-radius: 50%;
  background: color-mix(in srgb, var(--accent) 16%, transparent);
  transition: transform 0.2s var(--ease), background 0.2s var(--ease);
}
.product-tile:hover .product-tile-link,
.product-tile:focus-visible .product-tile-link {
  background: color-mix(in srgb, var(--accent) 16%, transparent);
}
.product-tile:hover .product-tile-link svg,
.product-tile:focus-visible .product-tile-link svg {
  transform: translate(1px, -1px);
  background: var(--accent);
  color: var(--paper);
}

/* Text CTA hides below the width where icon + name + chip start fighting for
   room; the chip becomes an icon-only round button instead (still the same
   element, same accessible text, just visually collapsed). A container
   query on `.product-tile` itself, not a viewport media query: the grid
   goes to 2 columns at 40em viewport width, which makes each tile narrower
   than a single-column mobile tile ever gets, a media query keyed to the
   viewport never caught that case, so the CTA text and the wrapped tagline
   used to collide at exactly those in-between viewport widths. */
@container (max-width: 26em) {
  .product-tile-link { padding: 0; background: none; }
  /* Visually collapsed to an icon-only button, but the text stays in the
     accessible tree (same clip technique as `.visually-hidden`), a plain
     `display: none` here would drop "View on the App Store" from the
     link's accessible name entirely, not just from the screen. */
  .product-tile-link > span:first-child {
    position: absolute;
    width: 1px; height: 1px;
    padding: 0; margin: -1px;
    overflow: hidden;
    clip: rect(0,0,0,0);
    white-space: nowrap;
    border: 0;
  }
  .product-tile-link svg { width: 30px; height: 30px; padding: 7px; background: color-mix(in srgb, var(--accent) 16%, transparent); }
}

/* "See more" tile, same row footprint but solid blue, so it reads as a
   different kind of entry (a catalog link, not a shipped app). Keeps the
   soft white halo behind its icon that the plain app rows dropped, it
   reads well here specifically because the tile is already a solid, bold
   color rather than a neutral card. */
.product-tile--more {
  position: relative;
  overflow: hidden;
  background: linear-gradient(155deg, var(--accent), var(--accent-deep));
  color: var(--paper);
}
.product-tile--more::before {
  content: '';
  position: absolute;
  top: 50%;
  left: 0;
  width: 160px;
  height: 160px;
  transform: translate(-38%, -50%);
  background: radial-gradient(circle, color-mix(in srgb, var(--paper) 35%, transparent), transparent 68%);
  opacity: 0.5;
  transition: opacity 0.3s var(--ease);
  pointer-events: none;
}
.product-tile--more:hover::before, .product-tile--more:focus-visible::before { opacity: 1; }
.product-tile--more:hover, .product-tile--more:focus-visible {
  background: linear-gradient(155deg, var(--accent), var(--accent-deep));
  box-shadow: 0 20px 36px -16px color-mix(in srgb, var(--accent) 55%, transparent), var(--shadow-sm);
}
.product-tile--more .product-tagline {
  color: color-mix(in srgb, var(--paper) 78%, transparent);
}
.product-tile--more .product-tile-link {
  color: var(--paper);
  background: color-mix(in srgb, var(--paper) 16%, transparent);
}
.product-tile--more .product-tile-link svg { background: color-mix(in srgb, var(--paper) 22%, transparent); }
.product-tile--more:hover .product-tile-link,
.product-tile--more:focus-visible .product-tile-link {
  background: color-mix(in srgb, var(--paper) 26%, transparent);
}
.product-tile--more:hover .product-tile-link svg,
.product-tile--more:focus-visible .product-tile-link svg {
  background: var(--paper);
  color: var(--accent-deep);
}
.product-icon--more {
  border-radius: 50%;
  border: 1.5px solid color-mix(in srgb, var(--paper) 35%, transparent);
  background: color-mix(in srgb, var(--paper) 14%, transparent);
  color: var(--paper);
}

/* CulminApp banner, full-width, own component (not part of the equal grid),
   kept as the larger "platform" showcase rather than folded into the row
   list below it. The real CulminApp mark is inlined directly (not a
   CSS-masked glyph) on its own plain badge, so it renders the same way the
   real App Store artwork does for every app tile. */
.product-featured {
  position: relative;
  overflow: hidden;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-5);
  background: var(--teal-900);
  color: var(--text-on-dark);
  border-radius: var(--radius-lg);
  padding: var(--space-5);
  margin-bottom: var(--space-3);
  text-decoration: none;
  box-shadow: var(--shadow-sm);
  transition: box-shadow 0.2s var(--ease), transform 0.2s var(--ease);
}
.product-featured::before {
  content: '';
  position: absolute;
  inset: 0;
  background: radial-gradient(46% 80% at 88% 8%, color-mix(in srgb, var(--accent) 30%, transparent), transparent 70%);
  pointer-events: none;
}
/* Same white halo as the "more" tile, behind the icon, subtle at rest,
   blooming on hover. */
.product-featured::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 0;
  width: 240px;
  height: 240px;
  transform: translate(-30%, -50%);
  background: radial-gradient(circle, color-mix(in srgb, var(--paper) 35%, transparent), transparent 68%);
  opacity: 0.5;
  transition: opacity 0.3s var(--ease);
  pointer-events: none;
}
.product-featured:hover::after, .product-featured:focus-visible::after { opacity: 1; }
.product-featured > * { position: relative; z-index: 1; }
.product-featured:hover, .product-featured:focus-visible {
  box-shadow: var(--shadow-md);
  transform: translateY(-2px);
}
.product-featured .product-icon {
  width: 72px;
  height: 72px;
  border-radius: var(--radius);
  background: var(--paper);
  box-shadow: 0 16px 28px -14px color-mix(in srgb, var(--accent-vivid) 55%, transparent);
}
.product-featured .product-icon-mark { width: 38px; height: 38px; color: var(--accent); }
.product-featured-body { flex: 1 1 320px; min-width: 0; }
.product-featured .product-name { font-size: var(--step-2); margin-bottom: var(--space-2); }
.product-featured .product-tagline {
  color: var(--accent-on-dark);
  font-weight: 600;
  margin-bottom: var(--space-3);
}
.product-featured .product-desc { color: var(--text-on-dark-soft); margin-bottom: 0; max-width: 56ch; }
.product-featured-cta { flex: none; }

/* ==========================================================================
   Stats band, results, not narrative
   ========================================================================== */

.stats-section { padding-block: var(--space-6); }
.stats-section .eyebrow { margin-bottom: var(--space-2); }
.stats-section .stats-heading {
  font-size: var(--step-2);
  margin-bottom: var(--space-5);
  max-width: 30ch;
}

.stats-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--space-5) var(--space-4);
}
@media (max-width: 56em) { .stats-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 30em) { .stats-grid { grid-template-columns: 1fr; } }

.stat-block {
  padding-left: var(--space-4);
  border-left: var(--border-w) solid var(--border-light);
}
.bg-dark .stat-block { border-left-color: var(--teal-800); }

.stat-value {
  display: block;
  font-family: var(--font-display);
  font-size: var(--step-4);
  font-weight: 650;
  color: var(--brand-on-light);
  line-height: 1;
  margin-bottom: var(--space-2);
}
.bg-dark .stat-value { color: var(--brand-on-dark); }

.stat-label {
  font-family: var(--font-mono);
  font-size: var(--step-00);
  color: var(--text-on-light-soft);
}
.bg-dark .stat-label { color: var(--text-on-dark-soft); }

/* ==========================================================================
   Team
   ========================================================================== */

.team-section { padding-block: var(--space-6); }
.team-section .eyebrow { margin-bottom: var(--space-3); }

/* Two side-by-side cards, one per founder, same visual language as the
   product tiles (raised surface, soft shadow, generous radius) instead of a
   bare divider, so the page reads as one consistent set of "tile" components
   rather than two different card idioms. Each founder keeps a color identity
   (teal / accent) carried through the avatar ring and the role pill. */
.team-list {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-5);
  padding-top: var(--space-6);
}
@media (min-width: 48em) {
  .team-list { grid-template-columns: 1fr 1fr; }
}

.team-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  background: var(--bg-light-raised);
  border-radius: var(--radius-lg);
  padding: var(--space-6) var(--space-5);
  box-shadow: var(--shadow-sm);
}

.team-avatar {
  display: block;
  width: 128px;
  height: 128px;
  margin-bottom: var(--space-4);
  border-radius: 50%;
  object-fit: cover;
  box-shadow: var(--shadow-sm);
  border: 3px solid var(--teal-600);
  flex: none;
}
.team-avatar--accent { border-color: var(--accent); }

.team-card-body { min-width: 0; }

.team-name {
  font-family: var(--font-display);
  font-size: var(--step-2);
  font-weight: 650;
}
.team-role {
  display: inline-flex;
  font-family: var(--font-mono);
  font-size: var(--step-000);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  padding: 0.35em 0.9em;
  border-radius: var(--radius-pill);
  margin-top: 0.6em;
  margin-bottom: var(--space-4);
}
.team-role--teal { background: color-mix(in srgb, var(--teal-600) 16%, transparent); color: var(--teal-700); }
.team-role--accent { background: color-mix(in srgb, var(--accent) 14%, transparent); color: var(--accent-on-light); }

.team-bio {
  font-size: var(--step-00);
  color: var(--text-on-light-soft);
  max-width: 42ch;
  margin-inline: auto;
  text-align: justify;
  text-align-last: left;
  hyphens: auto;
}
.bg-dark .team-bio { color: var(--text-on-dark-soft); }

/* Shared closing line, ties the two founder cards back to one thing they
   build together. A third gray box here would just repeat the two cards
   above it, so it drops the card treatment entirely and instead sits as
   open text, marked with the same viewfinder-bracket used by every eyebrow
   on the page, the section's own signature, not a new one invented here. */
.team-together {
  margin-top: var(--space-7);
  margin-inline: auto;
  max-width: 48rem;
  font-family: var(--font-display);
  font-size: var(--step-2);
  font-weight: 600;
  line-height: 1.3;
  text-align: center;
  color: var(--text-on-light-soft);
}
.team-together::before {
  content: '';
  display: block;
  width: 26px;
  height: 26px;
  margin: 0 auto var(--space-4);
  color: var(--accent-on-light);
  background-image:
    linear-gradient(currentColor, currentColor),
    linear-gradient(currentColor, currentColor),
    linear-gradient(currentColor, currentColor),
    linear-gradient(currentColor, currentColor);
  background-repeat: no-repeat;
  background-size: 2px 42%, 42% 2px, 2px 42%, 42% 2px;
  background-position: top left, top left, bottom right, bottom right;
}
.team-together strong { color: var(--accent-on-light); font-weight: 650; }
.bg-dark .team-together { color: var(--text-on-dark-soft); }
.bg-dark .team-together::before { color: var(--accent-on-dark); }
.bg-dark .team-together strong { color: var(--accent-on-dark); }

/* ==========================================================================
   Contact
   ========================================================================== */

.contact-grid {
  display: grid;
  gap: var(--space-6);
}
@media (min-width: 62em) {
  .contact-grid { grid-template-columns: 0.8fr 1.2fr; }
}
.contact-info .eyebrow { margin-bottom: var(--space-3); }
.contact-info .section-heading { margin-bottom: var(--space-3); }
.contact-info p:not(.eyebrow) { max-width: 40ch; color: var(--text-on-light-soft); margin-bottom: var(--space-4); }

.form-field { margin-bottom: var(--space-4); }
.form-field label {
  display: block;
  font-family: var(--font-body);
  font-weight: 600;
  font-size: var(--step-00);
  margin-bottom: var(--space-2);
  color: var(--ink);
}
.form-field .req { color: var(--accent-on-light); }
.form-field input,
.form-field textarea {
  width: 100%;
  background: var(--bg-light);
  border: var(--border-w) solid var(--paper-line-strong);
  border-radius: var(--radius);
  padding: 0.85em 1em;
  font-family: var(--font-body);
  font-size: var(--step-0);
  color: var(--ink);
  transition: border-color 0.15s var(--ease);
}
.form-field input:hover, .form-field textarea:hover { border-color: var(--ink-soft); }
.form-field input:focus, .form-field textarea:focus { border-color: var(--accent-on-light); }
.form-field textarea { resize: vertical; min-height: 9em; }
.field-error {
  display: none;
  font-family: var(--font-mono);
  font-size: var(--step-000);
  color: var(--error);
  margin-top: var(--space-2);
}
.form-field.has-error input,
.form-field.has-error textarea { border-color: var(--error); }
.form-field.has-error .field-error { display: block; }

.form-status {
  border: var(--border-w) solid var(--border-light);
  border-radius: var(--radius);
  padding: var(--space-3) var(--space-4);
  margin-bottom: var(--space-4);
  font-size: var(--step-00);
  display: none;
}
.form-status[data-state="success"] {
  display: block;
  border-color: var(--teal-700);
  color: var(--teal-700);
  background: color-mix(in srgb, var(--teal-700) 8%, transparent);
}
.form-status[data-state="error"] {
  display: block;
  border-color: var(--error);
  color: var(--error);
  background: var(--error-bg-tint);
}
.form-status[data-state="loading"] {
  display: block;
  color: var(--text-on-light-soft);
}

.js-only { display: none; }
.no-js .js-only { display: block; }
.no-js .hide-if-no-js { display: none; }
html:not(.no-js) .hide-if-js { display: none; }

/* ==========================================================================
   Section textures, one idea per section, four different techniques
   (points of light, a grid, two outlines, a glow), not one motif reused with
   small variations. All still derived from the same theme tokens so they
   read as one studio, not four unrelated ideas. Each rule targets the
   section's own `.wrap` so the decorative layer stays behind real content
   without extra markup.
   ========================================================================== */

.texture-sparkle, .texture-glow, .texture-tech, .texture-venn, .texture-contact-glow {
  position: relative;
  overflow: hidden;
}
.texture-sparkle > .wrap, .texture-glow > .wrap, .texture-tech > .wrap,
.texture-venn > .wrap, .texture-contact-glow > .wrap {
  position: relative;
  z-index: 1;
}

/* Hero, a light, soft glow in one corner (brought back after a client
   request, earlier rounds had removed it for being "just a halo", but a
   restrained one alongside the other elements is fine) plus a scatter of
   small fixed points and a handful of shooting-star streaks (`.hero-star`
   markup in index.html: a tapered gradient tail with a small bright head,
   no animation, the "petites étoiles filantes" brief, an example the
   client linked). A literal lightning-bolt clip-path shape was tried
   earlier and rejected as too illustrative; the tapered line + head reads
   as a point of light in motion instead. */
.texture-sparkle::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  opacity: 0.85;
  background-image:
    radial-gradient(1.8px 1.8px at 12% 20%, var(--paper), transparent),
    radial-gradient(1.5px 1.5px at 88% 14%, var(--accent-vivid), transparent),
    radial-gradient(2px 2px at 92% 48%, var(--paper), transparent),
    radial-gradient(1.5px 1.5px at 8% 64%, var(--paper), transparent),
    radial-gradient(1.8px 1.8px at 34% 86%, var(--paper), transparent),
    radial-gradient(1.5px 1.5px at 70% 92%, var(--accent-vivid), transparent),
    radial-gradient(1.4px 1.4px at 50% 10%, var(--paper), transparent),
    radial-gradient(1.7px 1.7px at 20% 42%, var(--paper), transparent),
    radial-gradient(1.5px 1.5px at 80% 68%, var(--paper), transparent);
}
.texture-sparkle::after {
  content: '';
  position: absolute;
  inset: -15% -10%;
  z-index: 0;
  pointer-events: none;
  opacity: 0.5;
  background: radial-gradient(36% 46% at 84% 10%, var(--texture-glow-a-soft), transparent 72%);
}

.hero-star {
  --star-color: var(--paper);
  position: absolute;
  z-index: 0;
  pointer-events: none;
  height: 2.5px;
  border-radius: 999px;
  background: linear-gradient(90deg, transparent, color-mix(in srgb, var(--star-color) 80%, transparent) 50%, var(--star-color) 100%);
}
.hero-star::after {
  content: '';
  position: absolute;
  top: 50%;
  right: -1px;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--star-color);
  transform: translateY(-50%);
  box-shadow: 0 0 10px 2px color-mix(in srgb, var(--star-color) 90%, transparent);
}
.hero-star--1 { top: 14%; left: 16%; width: 76px; transform: rotate(-36deg); opacity: 1; }
.hero-star--2 { top: 9%; left: 64%; width: 96px; transform: rotate(-30deg); opacity: 1; --star-color: var(--accent-vivid); }
.hero-star--3 { top: 34%; left: 82%; width: 60px; transform: rotate(-42deg); opacity: 1; }
.hero-star--4 { top: 58%; left: 4%; width: 68px; transform: rotate(-28deg); opacity: 1; --star-color: var(--accent-vivid); }
@media (max-width: 700px) {
  .hero-star--1 { top: 10%; }
  .hero-star--4, .hero-star--3 { display: none; }
}

/* Stats, a spotlight on the numbers, not a grid: results, not process. */
.texture-glow::before {
  content: '';
  position: absolute;
  inset: -15% -10%;
  z-index: 0;
  pointer-events: none;
  background:
    radial-gradient(38% 50% at 85% 15%, var(--texture-glow-a), transparent 70%),
    radial-gradient(32% 45% at 8% 90%, var(--texture-glow-b), transparent 70%);
}

/* Products, the one section that keeps the grid: it already renders its
   own literal grid of product tiles just below, so the background echoes
   the foreground instead of competing with CulminApp's own colored glow. */
.texture-tech::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background-image:
    linear-gradient(var(--texture-grid-line-on-light) 1px, transparent 1px),
    linear-gradient(90deg, var(--texture-grid-line-on-light) 1px, transparent 1px);
  background-size: 56px 56px;
  -webkit-mask-image: radial-gradient(ellipse 75% 65% at 50% 0%, black 35%, transparent 88%);
  mask-image: radial-gradient(ellipse 75% 65% at 50% 0%, black 35%, transparent 88%);
}

/* Team, two large overlapping rings, one per founder's identity color (the
   same teal/blue split as their avatar ring and role pill). Outline only,
   no fill: a fill made it read as another soft blob, too close to the
   glow sections; a pure ring stays "line art" even at a much bigger size.
   Sized to actually occupy real background space, not a token accent,
   revised after the first pass was judged "trop minimaliste, juste 2
   cercles". Anchored to the header band above the card row rather than
   mid-section: the founder cards below are opaque and nearly full-width,
   so a mid-section placement sits almost entirely behind them and is never
   actually seen. */
.texture-venn::before, .texture-venn::after {
  content: '';
  position: absolute;
  top: -170px;
  width: 520px;
  height: 520px;
  border-radius: 50%;
  z-index: 0;
  pointer-events: none;
}
.texture-venn::before {
  right: 300px;
  border: 3px solid color-mix(in srgb, var(--teal-600) 60%, transparent);
}
.texture-venn::after {
  right: -40px;
  border: 3px solid color-mix(in srgb, var(--accent) 55%, transparent);
}
@media (max-width: 700px) {
  .texture-venn::before, .texture-venn::after {
    top: -110px;
    width: 260px;
    height: 260px;
  }
  .texture-venn::before { right: 100px; }
  .texture-venn::after { right: -50px; }
}

/* Contact, a single soft accent glow: the last section is an invitation,
   not a spec sheet, so it stays the calmest one on the page. */
.texture-contact-glow::before {
  content: '';
  position: absolute;
  inset: -15% -10%;
  z-index: 0;
  pointer-events: none;
  background: radial-gradient(46% 55% at 88% 12%, var(--texture-glow-a-soft), transparent 72%);
}

/* ==========================================================================
   Footer
   ========================================================================== */

.site-footer { padding-block: var(--space-6) var(--space-5); }
.footer-grid {
  display: grid;
  gap: var(--space-5);
  padding-bottom: var(--space-5);
  border-bottom: var(--border-w) solid var(--teal-900);
  margin-bottom: var(--space-4);
}
@media (min-width: 48em) {
  .footer-grid { grid-template-columns: 1.3fr 1fr 1fr; }
}
.footer-brand .logo { margin-bottom: var(--space-3); }
.footer-brand p { color: var(--text-on-dark-soft); max-width: 34ch; font-size: var(--step-00); }

.footer-col-title {
  font-family: var(--font-mono);
  font-size: var(--step-000);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-on-dark-soft);
  margin-bottom: var(--space-3);
}
.footer-col a {
  display: block;
  text-decoration: none;
  color: var(--paper);
  padding-block: 0.35em;
  font-size: var(--step-00);
}
.footer-col a:hover { color: var(--accent-on-dark); }

.footer-bottom {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--space-3);
  font-family: var(--font-mono);
  font-size: var(--step-000);
  color: var(--text-on-dark-soft);
}
.footer-bottom .made-in {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
}

/* ==========================================================================
   Legal page + form privacy note
   ========================================================================== */

.legal { max-width: 70ch; }
.legal h1 { font-size: var(--step-4); margin-bottom: var(--space-5); }
.legal h2 { font-size: var(--step-2); margin: var(--space-5) 0 var(--space-3); }
.legal p, .legal ul { margin-bottom: var(--space-3); }
.legal ul { padding-left: 1.2em; list-style: disc; }
.legal a { color: var(--accent-on-light); text-decoration: underline; }
.legal mark { background: #fff3a8; color: var(--ink); padding: 0 0.2em; }

.form-note {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  margin: var(--space-1) 0 var(--space-4);
  font-size: var(--step-000);
  line-height: 1.5;
  color: var(--text-on-light-soft);
}
.form-note svg { flex: none; margin-top: 0.2em; }
.form-note a { color: var(--accent-on-light); text-decoration: underline; }

.footer-legal { display: flex; flex-wrap: wrap; gap: var(--space-3) var(--space-4); }
.footer-bottom a { color: inherit; }
.footer-bottom a:hover { text-decoration: underline; }
