/* ==========================================================================
   Brandora — design system

   Polished black with deep metallic purple. The material reference is obsidian:
   smooth, dark, catching one soft highlight — not glitter, not neon.

   Dark is the primary mode (§6) and light is a real second mode (§7), so every
   colour is a token defined twice rather than a dark theme with a few overrides.
   The tokens carry *roles* — surface, raised, ink, muted — so a component never
   names a colour and the two modes cannot drift.
   ========================================================================== */

/* --- Fonts (self-hosted: no CDN, no third-party request, no render block) -- */

@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url('../fonts/inter-var-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 300 700;
  font-display: swap;
  src: url('../fonts/inter-var-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* --- Palette -------------------------------------------------------------- */

:root {
  /* The brand's fixed colours. These do not change between modes — they are the
     brand. What changes is which of them does which job. */
  --deep-black: #050507;
  --near-black: #0B0A0F;
  --metallic-purple: #35105C;
  --rich-purple: #4B167A;
  --soft-purple: #7650A5;
  --silver: #B9B7C2;
  --off-white: #F5F3F7;

  /* Type */
  --font: 'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;

  /* Rhythm. One scale, so spacing never becomes a series of magic numbers. */
  --s1: 0.25rem;
  --s2: 0.5rem;
  --s3: 0.75rem;
  --s4: 1rem;
  --s5: 1.5rem;
  --s6: 2rem;
  --s7: 3rem;
  --s8: 4.5rem;
  --s9: 7rem;

  --radius: 14px;
  --radius-sm: 9px;
  --measure: 62ch;
  --page: 1180px;

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

/* Dark — the primary experience. */
:root,
[data-theme='dark'] {
  color-scheme: dark;

  --surface: var(--deep-black);
  --surface-raised: var(--near-black);
  --surface-sunken: #030304;
  --border: #1E1B26;
  --border-strong: #2E2839;

  --ink: var(--off-white);
  --ink-muted: var(--silver);
  --ink-faint: #6E6B7A;

  --accent: var(--soft-purple);
  --accent-strong: var(--rich-purple);
  --accent-deep: var(--metallic-purple);
  --on-accent: var(--off-white);

  /*
   * Amber, not red. This marks a figure that is incomplete or a decision worth
   * a second look — a supplier flagged for lateness, a total missing its
   * freight. Red would read as an error, and none of these are errors; they
   * are things a buyer needs to have noticed. Checked against the near-black
   * field for contrast at small sizes.
   */
  --warn: #E0A25A;

  /* The highlight that makes the black look polished rather than flat. */
  --sheen: linear-gradient(135deg, rgba(118, 80, 165, 0.22) 0%, rgba(118, 80, 165, 0) 42%);
  --shadow: 0 18px 48px rgba(0, 0, 0, 0.55);
}

/* Light — ivory field, deep purple type, metallic purple accents (§7). */
[data-theme='light'] {
  color-scheme: light;

  --surface: #FBFAFC;
  --surface-raised: #FFFFFF;
  --surface-sunken: #F1EEF5;
  --border: #E3DEEA;
  --border-strong: #CFC7DB;

  --ink: #14111B;
  --ink-muted: #57506A;
  --ink-faint: #857D96;

  --accent: var(--rich-purple);
  --accent-strong: var(--metallic-purple);
  --accent-deep: var(--metallic-purple);
  --on-accent: #FFFFFF;

  /* Darker on ivory, for the same reason: readable at 0.7rem. */
  --warn: #9A5B12;

  --sheen: linear-gradient(135deg, rgba(75, 22, 122, 0.07) 0%, rgba(75, 22, 122, 0) 45%);
  --shadow: 0 14px 38px rgba(20, 17, 27, 0.1);
}

/* --- Reset ---------------------------------------------------------------- */

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

/*
 * `hidden` must actually hide.
 *
 * The attribute is `display: none` in the UA stylesheet, which any author
 * `display` rule outranks — so `.control { display: inline-flex }` silently
 * un-hides every `<button class="control" hidden>`. The bug looks like broken
 * JavaScript and is not, so it is fixed once, here, rather than guessed at
 * wherever it next surfaces.
 */
[hidden] { display: none !important; }

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;
  background: var(--surface);
  color: var(--ink);
  font-family: var(--font);
  font-size: 1rem;
  line-height: 1.65;
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
  /* Theme changes should feel like a light moving across a surface, not a flash. */
  transition: background-color 0.4s var(--ease), color 0.4s var(--ease);
}

img, svg { max-width: 100%; height: auto; display: block; }
h1, h2, h3, h4 { line-height: 1.15; margin: 0 0 var(--s4); font-weight: 500; letter-spacing: -0.02em; }
p { margin: 0 0 var(--s4); max-width: var(--measure); }
a { color: var(--accent); text-decoration-thickness: 1px; text-underline-offset: 3px; }

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 4px;
}

.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;
}

.skip-link {
  position: absolute; left: var(--s4); top: -4rem; z-index: 100;
  padding: var(--s3) var(--s4); background: var(--accent); color: var(--on-accent);
  border-radius: var(--radius-sm); transition: top 0.2s var(--ease);
}
.skip-link:focus { top: var(--s4); }

/* --- Layout --------------------------------------------------------------- */

.wrap { width: min(100% - 2.5rem, var(--page)); margin-inline: auto; }
.section { padding-block: var(--s8); }
.section--tight { padding-block: var(--s7); }

.eyebrow {
  font-size: 0.75rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin-bottom: var(--s3);
}

.lede { font-size: 1.15rem; color: var(--ink-muted); }

/* --- Header --------------------------------------------------------------- */

.site-header {
  position: sticky; top: 0; z-index: 50;
  background: color-mix(in srgb, var(--surface) 86%, transparent);
  backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--border);
}

.site-header__inner {
  display: flex; align-items: center; gap: var(--s5);
  padding-block: var(--s3);
}

.brand-lockup { display: flex; align-items: center; gap: var(--s3); color: var(--ink); text-decoration: none; }
.brand-lockup img { width: 20px; height: 26px; }

/*
 * The stacked wordmark: BRANDORA with UNION beneath it.
 *
 * A column rather than two separate elements, so the mark stays vertically
 * centred against the B whatever the two lines measure. `align-items: center`
 * centres the boxes; the negative right margins below are what centre the
 * *ink*, which is not the same thing when both lines are letterspaced.
 */
.brand-lockup__stack { display: flex; flex-direction: column; align-items: center; }

/* The wordmark is set in a serif to match the letterform of the mark. Using the
   sans here would make the lockup read as two different brands stood together. */
.brand-lockup__word {
  font-family: Georgia, 'Times New Roman', serif;
  font-weight: 400;
  letter-spacing: 0.26em;
  font-size: 0.88rem;
  /*
   * Letter-spacing is added *after* every letter, including the last, so the
   * element is one tracking-width wider than the ink it contains. Without this
   * the word sits half a tracking-width left of where it looks like it should,
   * and UNION — tracked differently — would visibly disagree with it.
   */
  margin-right: -0.26em;
}

/*
 * UNION: a designation, not a second wordmark.
 *
 * Set in the sans rather than the serif. At this size Georgia's serifs close up
 * and the word reads as a smudge; a grotesque holds its shape down to 8px. It
 * does not read as a second brand because nothing about it competes — it is
 * roughly half the size, tracked much wider, and sits underneath. That is the
 * shape of an institutional line (MAISON / PARIS), not of a lockup with two
 * names in it.
 *
 * The colour is `--ink`, which is near-black on the ivory theme and off-white
 * on the near-black one. Hierarchy here comes from size and tracking, which is
 * what keeps it working when the theme flips.
 */
.brand-lockup__union {
  font-family: inherit;
  font-weight: 500;
  font-size: 0.52rem;
  letter-spacing: 0.42em;
  margin-right: -0.42em;
  line-height: 1.5;
  color: var(--ink);
  /* Never wraps. A two-line UNION is a broken logo, not a small one. */
  white-space: nowrap;
}

.site-nav { display: none; gap: var(--s5); margin-inline-start: auto; }
.site-nav a { color: var(--ink-muted); text-decoration: none; font-size: 0.92rem; }
.site-nav a:hover, .site-nav a[aria-current='page'] { color: var(--ink); }

.header-tools { display: flex; align-items: center; gap: var(--s2); margin-inline-start: auto; }

@media (min-width: 62rem) {
  .site-nav { display: flex; }
  .header-tools { margin-inline-start: 0; }
}

/* --- Controls ------------------------------------------------------------- */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--s2);
  padding: 0.8rem 1.4rem;
  border: 1px solid transparent;
  border-radius: 999px;
  font: inherit; font-size: 0.95rem; font-weight: 500;
  cursor: pointer; text-decoration: none;
  /* 44px minimum target — this is a phone-first product (§63). */
  min-height: 44px;
  /*
   * A button is as wide as its label.
   *
   * Without this, "Log in" in the crowded header broke across three lines
   * inside its own pill — measured at 55px wide and 61px tall on a 1440px
   * desktop. Predates the UNION lockup; found while photographing the header
   * for it, and fixed here because a label wrapping inside a pill is a defect
   * at any width.
   */
  white-space: nowrap;
  transition: transform 0.18s var(--ease), background-color 0.18s var(--ease), border-color 0.18s var(--ease);
}
.btn:active { transform: translateY(1px); }

.btn--primary { background: var(--accent-strong); color: var(--on-accent); }
.btn--primary:hover { background: var(--accent); }

.btn--ghost { background: transparent; color: var(--ink); border-color: var(--border-strong); }
.btn--ghost:hover { border-color: var(--accent); color: var(--accent); }

.btn--quiet { background: transparent; color: var(--ink-muted); padding-inline: var(--s3); }
.btn--quiet:hover { color: var(--ink); }

.btn--small { padding: 0.45rem 0.9rem; font-size: 0.85rem; min-height: 36px; }

.control {
  display: inline-flex; align-items: center; gap: var(--s2);
  height: 38px; padding-inline: var(--s3);
  background: var(--surface-raised);
  border: 1px solid var(--border);
  border-radius: 999px;
  color: var(--ink-muted);
  font: inherit; font-size: 0.85rem;
  cursor: pointer;
}
.control:hover { color: var(--ink); border-color: var(--border-strong); }

/* A two-word control must stay on one line; "Log / out" reads as a broken button. */
.control { white-space: nowrap; }

select.control { padding-inline-end: var(--s2); appearance: none; }

/* --- Surfaces ------------------------------------------------------------- */

.card {
  position: relative;
  background: var(--surface-raised);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: var(--s5);
  overflow: hidden;
}

/* The obsidian sheen: one soft highlight raking across the top-left corner. */
.card::before {
  content: '';
  position: absolute; inset: 0;
  background: var(--sheen);
  pointer-events: none;
}
.card > * { position: relative; }

.card--flat::before { display: none; }

/* The sticky header is ~62px tall, and the builder moves focus to its result
   when the interview finishes. Without this the heading lands underneath the
   header and the founder's first sight of their brand is a cut-off word. */
[tabindex='-1'], [id] { scroll-margin-top: 5.5rem; }

.grid { display: grid; gap: var(--s4); }

/* Cards in a row share a height and hang their action off the bottom, so a
   column of "Add to Brand Package" buttons reads as one row of choices rather
   than a ragged staircase. */
.grid > .card { display: flex; flex-direction: column; }
.grid > .card > :last-child { margin-top: auto; }
.grid > .card > .btn { align-self: flex-start; margin-top: auto; }
@media (min-width: 40rem) { .grid--2 { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 55rem) { .grid--3 { grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 62rem) { .grid--4 { grid-template-columns: repeat(4, 1fr); } }

/* --- Film hero (§9) ------------------------------------------------------- */

/*
 * The opening film, full-bleed.
 *
 * It breaks out of `.wrap` deliberately — this is the one element on the site
 * that should touch both edges of any screen, because a letterboxed cinematic
 * open is not a cinematic open.
 *
 * `100svh` rather than `100vh`: on a phone, `vh` is measured against the
 * viewport with the browser chrome hidden, so a `100vh` hero is taller than the
 * screen and pushes its own caption under the address bar.
 */
.film {
  position: relative;
  width: 100%;
  min-height: min(100svh, 46rem);
  display: grid;
  place-items: center;
  overflow: hidden;
  background: var(--deep-black);
  isolation: isolate;
}

.film__media {
  position: absolute; inset: 0; z-index: -2;
  width: 100%; height: 100%;
  object-fit: cover;
  /* The film is authored on black; letting it sit on the light-mode ivory would
     put a hard black rectangle in the middle of a pale page, so the stage stays
     black in both modes and the scrim below carries the transition. */
  background: var(--deep-black);
}

/* Fades the foot of the film into the page so the headline underneath is not
   fighting whatever frame happens to be on screen when the loop wraps. */
.film__scrim {
  position: absolute; inset: 0; z-index: -1;
  background:
    linear-gradient(to bottom, rgba(5, 5, 7, 0.35) 0%, rgba(5, 5, 7, 0) 30%, rgba(5, 5, 7, 0) 62%, var(--surface) 100%);
  pointer-events: none;
}

.film__caption {
  text-align: center;
  padding: var(--s6) var(--s4) var(--s8);
  /* Sits at the foot of the frame, where the eye lands after the logo. */
  align-self: end;
}

.film__caption p {
  margin: 0 auto;
  color: var(--silver);
  font-size: clamp(0.8rem, 2.4vw, 1rem);
  letter-spacing: 0.18em;
  text-transform: uppercase;
}

.film__logo { width: min(62vw, 22rem); margin: 0 auto var(--s5); }

/* Playback control. Autoplaying video needs a visible way to stop it — muted
   autoplay is still motion, and motion someone cannot stop is a trap. */
.film__toggle {
  position: absolute; right: var(--s4); bottom: var(--s4); z-index: 2;
  background: rgba(11, 10, 15, 0.7);
  border: 1px solid var(--border-strong);
  color: var(--off-white);
}

/* --- Hero ----------------------------------------------------------------- */

.hero { position: relative; padding-block: var(--s9) var(--s8); overflow: hidden; }

.hero::after {
  /* A pool of purple light on a black surface. Sits behind everything and is
     purely decorative, so it is hidden from assistive technology by being a
     pseudo-element with no content. */
  content: '';
  position: absolute; z-index: -1;
  inset-inline-start: 50%; top: -20%;
  width: min(90rem, 160%); aspect-ratio: 2 / 1;
  transform: translateX(-50%);
  background: radial-gradient(ellipse at center, color-mix(in srgb, var(--accent) 26%, transparent) 0%, transparent 62%);
  opacity: 0.75;
  pointer-events: none;
}

.hero h1 {
  font-size: clamp(2.35rem, 7vw, 4.4rem);
  font-weight: 500;
  letter-spacing: -0.035em;
  max-width: 15ch;
}

.hero .lede { font-size: clamp(1.05rem, 2.2vw, 1.3rem); max-width: 48ch; }

.hero__actions { display: flex; flex-wrap: wrap; gap: var(--s3); margin-top: var(--s6); }

/* --- Steps ---------------------------------------------------------------- */

/* An <ol> because the order is meaningful, but the numbers are drawn by
   `.step__n` — the browser's own markers would render "1. 01". */
.steps { display: grid; gap: var(--s4); list-style: none; padding: 0; margin: 0; }
@media (min-width: 48rem) { .steps { grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 68rem) { .steps { grid-template-columns: repeat(6, 1fr); } }

.step { border-top: 1px solid var(--border); padding-top: var(--s4); }
.step__n {
  font-size: 0.75rem; letter-spacing: 0.16em; color: var(--accent);
  font-variant-numeric: tabular-nums; margin-bottom: var(--s2);
}
.step h3 { font-size: 1rem; margin: 0; font-weight: 500; }

/* --- Flow diagram --------------------------------------------------------- */

.flow { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s3); list-style: none; padding: 0; margin: 0; }
.flow li {
  padding: var(--s2) var(--s4);
  border: 1px solid var(--border-strong);
  border-radius: 999px;
  font-size: 0.88rem;
  color: var(--ink-muted);
}
.flow li:last-child { border-color: var(--accent); color: var(--ink); }
.flow__arrow { color: var(--ink-faint); }

/* --- Swatches ------------------------------------------------------------- */

.swatches { display: flex; flex-wrap: wrap; gap: var(--s3); list-style: none; padding: 0; margin: 0 0 var(--s4); }
.swatch { width: 82px; }
.swatch__chip {
  height: 60px; border-radius: var(--radius-sm);
  /* The stronger border matters: a customer's ink colour is nearly black, and
     on Brandora's own black surface the swatch would otherwise disappear. */
  border: 1px solid var(--border-strong);
}
.swatch__name { font-size: 0.72rem; color: var(--ink-muted); margin-top: var(--s2); }
.swatch__hex { font-size: 0.72rem; color: var(--ink-faint); font-variant-numeric: tabular-nums; }

/* --- Forms ---------------------------------------------------------------- */

.field { margin-bottom: var(--s5); }
.field > label { display: block; font-size: 0.9rem; margin-bottom: var(--s2); color: var(--ink); }
.field__why { font-size: 0.82rem; color: var(--ink-faint); margin: 0 0 var(--s3); }

input[type='text'], input[type='email'], input[type='tel'], input[type='number'], textarea, select {
  width: 100%;
  padding: 0.75rem var(--s4);
  background: var(--surface-sunken);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--ink);
  font: inherit; font-size: 1rem;
  min-height: 44px;
}
textarea { min-height: 7rem; resize: vertical; }
input:focus, textarea:focus, select:focus { border-color: var(--accent); }

.chips { display: flex; flex-wrap: wrap; gap: var(--s2); }
.chip {
  padding: 0.55rem 1rem;
  border: 1px solid var(--border-strong);
  border-radius: 999px;
  background: transparent;
  color: var(--ink-muted);
  font: inherit; font-size: 0.88rem;
  cursor: pointer; min-height: 40px;
}
.chip[aria-pressed='true'] {
  border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 16%, transparent);
  color: var(--ink);
}

.option {
  display: block; width: 100%; text-align: start;
  padding: var(--s4);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-sunken);
  color: var(--ink);
  font: inherit; cursor: pointer;
  margin-bottom: var(--s2);
}
.option:hover { border-color: var(--border-strong); }
.option[aria-pressed='true'] { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 12%, transparent); }
.option__hint { display: block; font-size: 0.84rem; color: var(--ink-muted); margin-top: 2px; }

.help-note {
  border-inline-start: 2px solid var(--accent);
  padding: var(--s3) var(--s4);
  background: color-mix(in srgb, var(--accent) 8%, transparent);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  margin-bottom: var(--s4);
}
.help-note p:last-child { margin-bottom: 0; }
.help-note ul { margin: var(--s2) 0 0; padding-inline-start: var(--s5); color: var(--ink-muted); font-size: 0.9rem; }

/* --- Progress ------------------------------------------------------------- */

.progress { display: flex; gap: var(--s1); margin-bottom: var(--s6); }
.progress__seg { height: 3px; flex: 1; background: var(--border); border-radius: 2px; }
.progress__seg[data-done='true'] { background: var(--accent); }

/* --- Product cards -------------------------------------------------------- */

.product__meta { font-size: 0.82rem; color: var(--ink-faint); margin: 0 0 var(--s2); }
.product__price { font-size: 1.05rem; font-weight: 500; font-variant-numeric: tabular-nums; }

.tag {
  display: inline-block;
  font-size: 0.72rem; letter-spacing: 0.05em;
  padding: 2px 9px; border-radius: 999px;
  border: 1px solid var(--border-strong); color: var(--ink-muted);
}
.tag--ok { border-color: color-mix(in srgb, var(--accent) 60%, transparent); color: var(--accent); }
.tag--unconfirmed { border-color: var(--border-strong); color: var(--ink-faint); }

/* --- Tables and totals ---------------------------------------------------- */

.totals { width: 100%; border-collapse: collapse; font-variant-numeric: tabular-nums; }
.totals th, .totals td { text-align: start; padding: var(--s3) 0; border-bottom: 1px solid var(--border); font-weight: 400; }
.totals td:last-child, .totals th:last-child { text-align: end; }
.totals tr:last-child th, .totals tr:last-child td { border-bottom: 0; font-weight: 500; font-size: 1.1rem; padding-top: var(--s4); }

.scroll-x { overflow-x: auto; }

/* --- Notices -------------------------------------------------------------- */

.notice {
  padding: var(--s3) var(--s4);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  font-size: 0.9rem;
  color: var(--ink-muted);
  margin-bottom: var(--s4);
}
.notice--accent { border-color: color-mix(in srgb, var(--accent) 50%, transparent); color: var(--ink); }

/* --- Reveal on scroll ----------------------------------------------------- */

[data-reveal] { opacity: 0; transform: translateY(14px); transition: opacity 0.6s var(--ease), transform 0.6s var(--ease); }
[data-reveal].is-visible { opacity: 1; transform: none; }
.no-js [data-reveal] { opacity: 1; transform: none; }

/* --- Footer --------------------------------------------------------------- */

.site-footer {
  border-top: 1px solid var(--border);
  padding-block: var(--s6);
  margin-top: var(--s8);
  color: var(--ink-faint);
  font-size: 0.88rem;
}
.site-footer a { color: var(--ink-muted); text-decoration: none; }
.site-footer a:hover { color: var(--ink); }
.site-footer__row { display: flex; flex-wrap: wrap; gap: var(--s5); align-items: center; }

/*
 * The company block.
 *
 * The footer used to carry the word "Brandora" and nothing else. This is where
 * the reader is looking for who they are actually dealing with, so it is the
 * one place on every page that names the company in full, says what it does in
 * six words, and gives an address and a number that reach a person.
 */
.site-footer__identity { margin-bottom: var(--s5); }
.site-footer__name {
  font-family: Georgia, 'Times New Roman', serif;
  letter-spacing: 0.12em;
  color: var(--ink);
  margin: 0;
}
.site-footer__tagline { color: var(--ink-muted); font-size: 0.9rem; margin: 2px 0 0; }
.site-footer__contact { margin: var(--s3) 0 0; font-size: 0.9rem; display: flex; flex-wrap: wrap; gap: var(--s2); }
/* The separator is decoration; it must not sit alone on a line when the
   address and the number wrap on a narrow phone. */
.site-footer__contact span { color: var(--ink-faint); }

/* ==========================================================================
   The connected product: account, brand book, package lines, dashboards.

   The brand book is the one place on the site that is deliberately *not* in
   Brandora's colours. It paints itself in the customer's palette, because a
   brand book showing Brandora's purple is a document about Brandora.
   ========================================================================== */

.wrap--narrow { width: min(100% - 2.5rem, 44rem); margin-inline: auto; }

/* --- Forms ---------------------------------------------------------------- */

.input,
.field textarea,
.field input,
.field select {
  width: 100%;
  padding: 0.7rem 0.85rem;
  font: inherit;
  color: var(--ink);
  background: var(--surface-raised);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  min-height: 44px;
}

.input:focus, .field textarea:focus, .field input:focus, .field select:focus { border-color: var(--accent); }
.input--compact { width: 6rem; min-height: 40px; padding: 0.4rem 0.6rem; }
.field textarea { min-height: 7rem; resize: vertical; }
.field__optional { color: var(--ink-faint); font-weight: 400; }

.auth-panel { width: min(100% - 2.5rem, 27rem); margin-inline: auto; }
.auth-alt { color: var(--ink-muted); font-size: 0.92rem; margin-top: var(--s5); }

/* --- The brand book ------------------------------------------------------- */

/*
 * Every colour below is a custom property set from the customer's stored
 * palette by brand.js. The fallbacks exist only so the layout is inspectable
 * with no data — they are never what a customer sees.
 */
[data-book] {
  --brand-primary: var(--accent-strong);
  --brand-surface: var(--surface-raised);
  --brand-ink: var(--ink);
  --brand-accent: var(--accent);
  --brand-muted: var(--ink-muted);
  --brand-heading-font: var(--font);
  --brand-body-font: var(--font);
}

.book-cover {
  background: var(--brand-surface);
  color: var(--brand-ink);
  padding-block: clamp(4rem, 14vw, 9rem);
  border-bottom: 1px solid var(--border);
}

.book-cover__eyebrow {
  font-size: 0.78rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--brand-accent);
  margin-bottom: var(--s5);
}

.book-cover__name {
  font-family: var(--brand-heading-font);
  font-size: clamp(2.6rem, 9vw, 6rem);
  font-weight: 500;
  letter-spacing: -0.035em;
  margin: 0 0 var(--s4);
  color: var(--brand-ink);
}

.book-cover__slogan {
  font-family: var(--brand-body-font);
  font-size: clamp(1.1rem, 3vw, 1.6rem);
  color: var(--brand-ink);
  opacity: 0.82;
  max-width: 34ch;
}

/* A single hairline in the brand's primary. The whole cover's only ornament. */
.book-cover__rule {
  width: 4.5rem;
  height: 2px;
  background: var(--brand-primary);
  margin: var(--s6) 0 var(--s5);
}

.book-cover__meta {
  font-size: 0.9rem;
  color: var(--brand-ink);
  opacity: 0.6;
  text-transform: lowercase;
}

/* Label in the margin, content in the column — the shape of a printed manual. */
.book-grid { display: grid; gap: var(--s5); align-items: start; }
@media (min-width: 55rem) {
  .book-grid { grid-template-columns: 14rem 1fr; gap: var(--s7); }
}
.book-grid__label h2 { font-size: 1.1rem; letter-spacing: 0.01em; margin-bottom: var(--s2); }
.book-grid__body { min-width: 0; }

.book-lead { font-size: 1.2rem; line-height: 1.55; color: var(--ink); }

.book-defs { display: grid; gap: var(--s3) var(--s5); margin: var(--s5) 0; }
@media (min-width: 40rem) { .book-defs { grid-template-columns: 9rem 1fr; } }
.book-defs dt {
  font-size: 0.76rem; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--ink-faint); padding-top: 0.25rem;
}
.book-defs dd { margin: 0; color: var(--ink); }
.book-defs--tight { gap: var(--s2) var(--s4); margin: var(--s4) 0 0; }

.book-brief {
  border-inline-start: 2px solid var(--brand-primary);
  padding-inline-start: var(--s4);
  color: var(--ink-muted);
}

.book-actions { display: flex; flex-wrap: wrap; gap: var(--s3); }

.chips--static { list-style: none; padding: 0; margin: var(--s5) 0 0; }
.chip--static { cursor: default; }

/* --- Palette -------------------------------------------------------------- */

.palette-strip { list-style: none; padding: 0; margin: 0; display: grid; gap: var(--s4); }
@media (min-width: 48rem) { .palette-strip { grid-template-columns: repeat(2, 1fr); } }

.palette-strip__item { display: flex; gap: var(--s4); align-items: flex-start; }
.palette-strip__chip {
  width: 4.5rem; height: 4.5rem; flex: none;
  border-radius: var(--radius-sm); border: 1px solid var(--border);
}
.palette-strip__text { min-width: 0; }
.palette-strip__name { margin: 0; font-weight: 500; }
.palette-strip__hex {
  margin: 0; font-size: 0.8rem; color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
}
.palette-strip__why { margin: var(--s2) 0 0; font-size: 0.88rem; color: var(--ink-muted); }

.swatches--tight { gap: var(--s2); margin-bottom: var(--s3); }
.swatch--mini { width: 1.6rem; }
.swatch--mini .swatch__chip { height: 1.6rem; }

/* --- Typography specimen -------------------------------------------------- */

.specimen {
  font-family: var(--brand-heading-font);
  font-size: clamp(2.2rem, 7vw, 4rem);
  line-height: 1.05;
  letter-spacing: -0.03em;
  margin-bottom: var(--s3);
}
.specimen__scale { font-size: 0.9rem; color: var(--ink-faint); }

/* --- The mark ------------------------------------------------------------- */

.mark-row { display: flex; flex-wrap: wrap; gap: var(--s4); margin-bottom: var(--s5); }
.mark-tile {
  width: 8.5rem; height: 8.5rem;
  display: grid; place-items: center;
  border-radius: var(--radius);
  background: var(--brand-primary);
  color: #fff;
  font-family: var(--brand-heading-font);
  font-size: 3rem;
  letter-spacing: -0.04em;
}
.mark-tile--light { background: #fff; color: var(--brand-primary); border: 1px solid var(--border); }

/* --- Applications ---------------------------------------------------------- */

/*
 * Drawn, not photographed. A photograph of a cup nobody has printed is a
 * picture of a promise; these are honestly the palette and the letterforms
 * applied to the silhouettes of catalogue products.
 */
/*
 * A fixed row height rather than a fixed cell width.
 *
 * The silhouettes have different proportions on purpose — a business card is
 * not a sticker — so sizing them by cell width left every row ragged and the
 * captions on five different baselines. Sizing by height lines the row up and
 * lets each shape keep its own proportion, which is the thing being shown.
 */
.applications {
  display: grid;
  gap: var(--s5) var(--s4);
  /* 7rem fitted the old CSS silhouettes; a photograph of a printed box at that
     size is a smudge. Wide enough now to actually read the material. */
  grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));
}

.application { margin: 0; display: grid; justify-items: center; align-content: start; }

/*
 * The brand, on a real product.
 *
 * The photograph is the ground and the mark sits on a plate above it. A plate
 * rather than a free-floating word because a brand name in the customer's own
 * colour, laid straight over a photograph of a printed box, is illegible about
 * half the time — and the half where it happens to work is the half that
 * flatters the palette. The plate makes every palette legible on every
 * material, which is the point: this section exists to answer "does my green
 * work on kraft", and it cannot answer that if the answer depends on luck.
 */
.application__object {
  position: relative;
  display: block;
  width: 100%;
  aspect-ratio: 1 / 1;
  border-radius: var(--radius, 12px);
  border: 1px solid var(--border);
  overflow: hidden;
  background: var(--surface, #f7f8f7);
}
.application__photo {
  width: 100%; height: 100%; object-fit: cover; display: block;
}
.application__plate {
  position: absolute;
  left: 50%; bottom: 8%;
  transform: translateX(-50%);
  display: grid;
  justify-items: center;
  gap: 0.15rem;
  padding: 0.55rem 0.9rem;
  max-width: 82%;
  background: var(--brand-primary);
  color: #fff;
  border-radius: 4px;
  /* Enough shadow to separate the plate from a busy photograph, not enough to
     look like a sticker floating in front of the screen. */
  box-shadow: 0 2px 10px rgb(0 0 0 / 0.28);
}
.application__mark {
  font-family: var(--brand-heading-font);
  font-size: 1.15rem;
  letter-spacing: -0.03em;
  line-height: 1;
}
.application__word {
  font-family: var(--brand-body-font);
  font-size: 0.5rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  opacity: 0.9;
  max-width: 100%;
  text-align: center;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.application__caption {
  font-size: 0.8rem; color: var(--ink-faint); margin-top: var(--s2); text-align: center;
}

/* --- Package lines --------------------------------------------------------- */

.line-controls { display: flex; align-items: center; gap: var(--s3); margin-top: var(--s3); }
.product__reason { font-size: 0.85rem; color: var(--accent); margin: 0 0 var(--s2); }

/* --- Timeline -------------------------------------------------------------- */

.timeline { list-style: none; padding: 0; margin: 0; }
.timeline__item {
  display: grid; gap: 0.15rem;
  padding: var(--s3) 0 var(--s3) var(--s5);
  border-inline-start: 1px solid var(--border);
  position: relative;
}
.timeline__item::before {
  content: ''; position: absolute; inset-inline-start: -4px; top: 1.35rem;
  width: 7px; height: 7px; border-radius: 50%; background: var(--accent);
}
.timeline__when { font-size: 0.78rem; color: var(--ink-faint); font-variant-numeric: tabular-nums; }
.timeline__what { color: var(--ink); }

/* --- Dashboards ------------------------------------------------------------ */

.stat__value {
  font-size: 2rem; font-weight: 500; margin: 0;
  font-variant-numeric: tabular-nums; letter-spacing: -0.02em;
}
.masked { font-variant-numeric: tabular-nums; letter-spacing: 0.06em; }

/* --- The scheduler ---------------------------------------------------------- */

/*
 * Calendly's own popup is not used: it injects an overlay whose focus handling
 * and close affordance cannot be corrected from here. The inline embed mounts
 * inside this dialog instead, so the close button, the escape key and the
 * scroll lock behave like everything else on the site.
 */
.scheduler {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: grid;
  place-items: center;
  padding: var(--s4);
  background: color-mix(in srgb, var(--deep-black) 78%, transparent);
}

.scheduler__panel {
  position: relative;
  width: min(100%, 46rem);
  height: min(90vh, 46rem);
  background: var(--surface-raised);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  overflow: hidden;
}

.scheduler__close {
  position: absolute;
  top: var(--s3);
  inset-inline-end: var(--s3);
  z-index: 1;
}

.scheduler__embed { width: 100%; height: 100%; }
.scheduler__embed .notice { margin: var(--s7) var(--s5); }

/* Full-bleed on a phone: a month grid in a letterboxed card leaves too little
   room for the dates and the times underneath them. */
@media (max-width: 40rem) {
  .scheduler { padding: 0; }
  .scheduler__panel { width: 100%; height: 100%; border-radius: 0; border: 0; }
}

/*
 * The header's booking control is a secondary action, and at 390px the header
 * already carries the lockup, the account control, the language select and the
 * theme toggle. Adding a fifth pushed the row 48px past the viewport.
 *
 * Hidden here rather than made smaller: shrinking it would give a 390px screen
 * five cramped controls instead of four legible ones. Booking is still offered
 * where someone actually decides they want it — the landing page's closing call
 * to action and the quote page, both of which show it at every width.
 */
@media (max-width: 48rem) {
  .header-tools [data-book-call] { display: none !important; }
}

/* --- Ask Brandora ----------------------------------------------------------- */

/*
 * Deliberately not a chat bubble UI. §12 rules out "generic chatbot visuals",
 * and the reason is more than taste: bubbles imply a conversation with a person
 * who knows things. This is a column of questions and considered answers, set
 * like a document, which is what it actually is.
 */
.thread { display: grid; gap: var(--s5); margin: var(--s6) 0; }

.turn { display: grid; gap: var(--s2); }

.turn__who {
  font-size: 0.72rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin: 0;
}

.turn__body { margin: 0; max-width: 60ch; white-space: pre-wrap; }

.turn--you .turn__body {
  color: var(--ink-muted);
  border-inline-start: 2px solid var(--border-strong);
  padding-inline-start: var(--s4);
}

.turn--brandora .turn__body {
  font-size: 1.05rem;
  line-height: 1.65;
  border-inline-start: 2px solid var(--accent);
  padding-inline-start: var(--s4);
}

/* A steady pulse, not a bouncing ellipsis. §12: controlled motion. */
.turn__body--waiting { color: var(--ink-faint); animation: brandora-waiting 1.6s ease-in-out infinite; }

@keyframes brandora-waiting {
  0%, 100% { opacity: 0.45; }
  50% { opacity: 0.9; }
}

.turn__meta { font-size: 0.82rem; color: var(--ink-faint); margin: 0; }

.suggested-grid { margin-top: var(--s3); }
.suggested { gap: var(--s2); }

.ask { display: grid; gap: var(--s3); }
@media (min-width: 40rem) {
  .ask { grid-template-columns: 1fr auto; align-items: end; }
}
.ask textarea { resize: vertical; min-height: 3.4rem; }

[data-suggestions] { list-style: none; padding: 0; margin: 0 0 var(--s4); }

/*
 * A pill inside a column card is a flex item, so it stretches to the card's
 * width and stops reading as a pill. It should be as wide as its words.
 */
.card > .tag,
.suggested > .tag { align-self: flex-start; }

/* --- Sourcing ------------------------------------------------------------- */

/*
 * The procurement screen.
 *
 * Two things here are load-bearing rather than decorative.
 *
 * The recommended option gets an accent edge and the cheapest option gets a
 * plain badge, so the two are visibly *different claims* — a screen where the
 * first row simply looks best invites the reader to assume it is also the
 * cheapest, which is the assumption the whole ranking exists to correct.
 *
 * `.notice--warn` is warmer than `.notice` and is used for exactly two things:
 * a total with an uncalculated component in it, and the sentence explaining
 * what the recommendation costs over the cheapest option. Both are moments
 * where reading past the text loses money.
 */

.notice--quiet { border-color: var(--border); color: var(--ink-faint); font-size: 0.85rem; }
.notice--warn {
  border-color: color-mix(in srgb, var(--warn, #d08a3a) 55%, transparent);
  color: var(--ink);
}

.panel {
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: var(--s4);
  margin-top: var(--s5);
}
.panel__title { font-size: 1rem; letter-spacing: 0.02em; margin-bottom: var(--s3); }
.panel__count { color: var(--ink-faint); font-size: 0.85rem; font-weight: 400; }

.spec { display: grid; grid-template-columns: auto 1fr; gap: var(--s2) var(--s4); margin: 0; }
.spec dt { color: var(--ink-faint); font-size: 0.85rem; }
.spec dd { margin: 0; font-variant-numeric: tabular-nums; }
.spec--tight { gap: 2px var(--s4); font-size: 0.9rem; }

.options { display: grid; gap: var(--s4); }

.option {
  border: 1px solid var(--border);
  border-left: 3px solid var(--border);
  border-radius: var(--radius-sm);
  padding: var(--s4);
  display: grid;
  gap: var(--s3);
}
.option--recommended { border-left-color: var(--accent); }

.option__head { display: flex; flex-wrap: wrap; gap: var(--s2); align-items: baseline; justify-content: space-between; }
.option__name { font-size: 1.05rem; margin: 0; }
.option__badges { display: flex; flex-wrap: wrap; gap: var(--s2); }
.option__where { color: var(--ink-faint); font-size: 0.85rem; margin: 0; }
.option__price { font-weight: 600; }
.option__why, .option__missed, .option__concerns { font-size: 0.85rem; color: var(--ink-muted); margin: 0; }
.option__unknowns { margin: 0; }

.badge {
  display: inline-block;
  font-size: 0.7rem; letter-spacing: 0.05em; text-transform: uppercase;
  padding: 2px 9px; border-radius: 999px;
  border: 1px solid var(--border-strong); color: var(--ink-faint);
  white-space: nowrap;
}
.badge--strong { border-color: var(--accent); color: var(--accent); }
.badge--exact { border-color: color-mix(in srgb, var(--accent) 60%, transparent); color: var(--accent); }
.badge--close { color: var(--ink-muted); }
.badge--partial, .badge--warn { border-color: color-mix(in srgb, var(--warn, #d08a3a) 60%, transparent); color: var(--warn, #d08a3a); }

.signals { list-style: none; padding: 0; margin: 0; display: grid; gap: 4px; font-size: 0.85rem; }
.signals__item { display: flex; gap: var(--s3); align-items: baseline; }
.signals__code {
  font-size: 0.7rem; letter-spacing: 0.05em; text-transform: uppercase;
  color: var(--warn, #d08a3a); min-width: 7ch;
}

.score { list-style: none; padding: 0; margin: 0; display: grid; gap: 3px; }
.score__part { display: grid; grid-template-columns: 7rem 1fr auto; gap: var(--s3); align-items: center; font-size: 0.8rem; }
.score__label { color: var(--ink-faint); }
.score__meter {
  height: 4px; border-radius: 999px;
  background: linear-gradient(to right, var(--accent) var(--fill, 0%), var(--border) var(--fill, 0%));
}
.score__value { color: var(--ink-faint); font-variant-numeric: tabular-nums; }

.notes { margin: var(--s3) 0; padding-left: var(--s4); font-size: 0.85rem; color: var(--ink-muted); }
.next-step { margin: 0; font-size: 0.9rem; }

/*
 * On a phone the score labels and the three-column spec both collapse. This
 * screen is used standing in a warehouse as often as at a desk.
 */
@media (max-width: 32rem) {
  .score__part { grid-template-columns: 5.5rem 1fr auto; }
  .spec { grid-template-columns: 1fr; gap: 0 0; }
  .spec dt { margin-top: var(--s2); }
}

/* --- The company line and the chain --------------------------------------- */

/*
 * The hero eyebrow, when it carries the company rather than a positioning line.
 *
 * Two parts on one line on a wide screen, stacked on a phone. The company name
 * is set in the wordmark's serif so it reads as the name and not as a label;
 * the tagline beside it stays in the interface sans, because it is a sentence.
 */
.eyebrow--brand { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--s3); }
.eyebrow__company {
  font-family: Georgia, 'Times New Roman', serif;
  letter-spacing: 0.16em;
  color: var(--ink);
}
.eyebrow__tagline { color: var(--ink-muted); letter-spacing: normal; text-transform: none; }

/*
 * The six links of the chain.
 *
 * A grid rather than a row of arrows: arrows imply a hand-off, and the whole
 * claim of this section is that there is no hand-off. Auto-fit means it is six
 * across on a desktop, three on a tablet and two on a phone without a single
 * breakpoint deciding it.
 */
.chain {
  list-style: none;
  padding: 0;
  margin: var(--s6) 0 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
  gap: var(--s3);
  counter-reset: none;
}
.chain__link {
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: var(--s4);
  display: flex;
  flex-direction: column;
  gap: var(--s2);
  font-size: 0.95rem;
  color: var(--ink);
  background: var(--sheen);
}
.chain__n {
  font-family: Georgia, 'Times New Roman', serif;
  font-size: 0.8rem;
  color: var(--accent);
  letter-spacing: 0.1em;
}

.chain__contact {
  margin-top: var(--s6);
  display: flex;
  flex-wrap: wrap;
  gap: var(--s2) var(--s5);
  align-items: baseline;
  font-size: 0.95rem;
  color: var(--ink-muted);
}
.chain__contact a { color: var(--ink); }

/* ==========================================================================
   The homepage sections
   ==========================================================================

   Five principles taken from the references and applied in Brandora Union's
   own palette, rather than any of their layouts.

   1. Generous vertical rhythm. The references breathe; sections are separated
      by space, not by rules and boxes. `--section-gap` below is the single
      value that controls it.
   2. One idea per band. Each section makes one claim and gives it room.
   3. A large, quiet display face against small, tightly-tracked labels. The
      contrast in *scale* carries the hierarchy, so the palette does not have
      to.
   4. Cards are surfaces, not containers with heavy borders — a one-pixel line
      and a whisper of the sheen already in the theme.
   5. Motion is a settling, never a performance: a short fade and a few pixels
      of travel, and nothing that repeats or loops.
*/

:root { --section-gap: clamp(4rem, 9vw, 7.5rem); }

.hero__headline {
  /* Two lines on a desktop by measure rather than by a <br>, which would have
     to live inside a translation string and would break at a different word in
     French. `balance` keeps the two lines close in length. */
  max-width: 18ch;
  text-wrap: balance;
}

.section__more { margin-top: var(--s6); }

/* An arrow that moves a little on hover. The whole interaction vocabulary of
   this site is this restrained. */
.link-arrow { color: var(--ink); text-decoration: none; border-bottom: 1px solid var(--border-strong); padding-bottom: 2px; }
.link-arrow::after { content: ' →'; display: inline-block; transition: transform 0.22s var(--ease); }
.link-arrow:hover::after { transform: translateX(4px); }

/* --- What can be sourced -------------------------------------------------- */

.catalogue-grid {
  margin-top: var(--s6);
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: var(--s4);
}
.catalogue-card {
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: var(--s5);
  background: var(--sheen);
  display: flex; flex-direction: column; gap: var(--s3);
  transition: border-color 0.24s var(--ease), transform 0.24s var(--ease);
}
.catalogue-card:hover { border-color: var(--border-strong); transform: translateY(-2px); }
.catalogue-card__name { font-size: 1.15rem; margin: 0; }
.catalogue-card__copy { color: var(--ink-muted); font-size: 0.9rem; margin: 0; }
.catalogue-card__list {
  list-style: none; padding: 0; margin: 0;
  display: flex; flex-wrap: wrap; gap: var(--s2);
  font-size: 0.82rem; color: var(--ink-faint);
}
.catalogue-card__list li {
  border: 1px solid var(--border); border-radius: 999px; padding: 2px 10px;
}
.catalogue-card__meta { margin: auto 0 0; font-size: 0.82rem; color: var(--accent); }

/* --- Ask Brandora --------------------------------------------------------- */

.ask-panel {
  display: grid;
  grid-template-columns: 1.1fr 1fr;
  gap: var(--s6);
  align-items: center;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: clamp(1.5rem, 4vw, 3rem);
  background: var(--sheen);
}
.ask-panel__grounding {
  font-size: 0.88rem; color: var(--ink-faint);
  border-left: 2px solid var(--accent); padding-left: var(--s4); margin: var(--s5) 0;
}
.ask-demo { display: grid; gap: var(--s3); }
.ask-demo__turn {
  margin: 0; padding: var(--s4);
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  font-size: 0.92rem; line-height: 1.55;
  display: grid; gap: 6px;
}
.ask-demo__turn--brandora { border-color: color-mix(in srgb, var(--accent) 45%, transparent); }
.ask-demo__who {
  font-size: 0.68rem; letter-spacing: 0.16em; text-transform: uppercase; color: var(--ink-faint);
}
.ask-demo__turn--brandora .ask-demo__who { color: var(--accent); }

/* --- The network ---------------------------------------------------------- */

.network {
  margin-top: var(--s6);
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  gap: var(--s5);
  align-items: center;
}
.network__side { display: grid; gap: var(--s2); }
.network__side--end { text-align: right; }
.network__label {
  margin: 0; font-family: Georgia, 'Times New Roman', serif;
  font-size: clamp(1.3rem, 3vw, 2rem); color: var(--ink);
}
.network__note { margin: 0; color: var(--ink-muted); font-size: 0.9rem; max-width: 26ch; }
.network__side--end .network__note { margin-left: auto; }

.network__bridge { display: flex; align-items: center; gap: var(--s2); }
.network__node { width: 7px; height: 7px; border-radius: 50%; background: var(--accent); }
.network__line { width: clamp(1.5rem, 5vw, 4rem); height: 1px; background: linear-gradient(to right, var(--accent), var(--border-strong)); }
.network__hub {
  width: 46px; height: 46px; border-radius: 50%;
  display: grid; place-items: center;
  border: 1px solid var(--accent); color: var(--accent);
  font-family: Georgia, 'Times New Roman', serif; font-size: 1.2rem;
  background: var(--surface-raised);
}

/* --- The founder ---------------------------------------------------------- */

.founder { display: grid; grid-template-columns: 0.8fr 1.2fr; gap: var(--s7, 3rem); align-items: start; }
.founder__portrait { position: sticky; top: 6rem; }
.founder__portrait picture { display: block; }
.founder__portrait img {
  width: 100%; height: auto; display: block;
  border-radius: var(--radius); border: 1px solid var(--border);
  /* The photograph's own ratio. Forcing 4:5 here would crop it, and what a
     crop takes off a portrait is the top of the head or the bottom of the
     shoulders — neither improves it. */
  aspect-ratio: 1023 / 1537;
  object-fit: cover;
}
.founder__name { margin: var(--s2) 0 0; }
.founder__role { color: var(--ink-muted); font-size: 0.92rem; margin: var(--s2) 0 var(--s5); }
.founder__story { display: grid; gap: var(--s4); max-width: 62ch; color: var(--ink-muted); line-height: 1.75; }
.founder__story p { margin: 0; }
/* The two sentences the story turns on, given the weight of the display face. */
.founder__pull {
  font-family: Georgia, 'Times New Roman', serif;
  font-size: clamp(1.1rem, 2.4vw, 1.4rem);
  color: var(--ink); line-height: 1.5;
  border-left: 2px solid var(--accent); padding-left: var(--s4);
}

/* --- Join ----------------------------------------------------------------- */

.join {
  display: grid; grid-template-columns: 1fr 1fr; gap: var(--s6); align-items: center;
  border: 1px solid var(--border); border-radius: var(--radius);
  padding: clamp(1.5rem, 4vw, 3rem);
  background: var(--sheen);
}
.join__copy h2 { margin-top: 0; }
.join__form { display: grid; gap: var(--s3); }
.join__form .input { width: 100%; }

/*
 * The optional half of the waiting-list form.
 *
 * Two columns on a wide screen and one on a narrow one — a recomposition, not
 * a shrink: four fields side by side would each be too small to type a business
 * name into on a phone. The optional note sits above them so it is read before
 * the fields rather than after, which is the difference between four questions
 * and four requirements.
 */
.join__optional {
  margin: 0; font-size: 0.85rem; color: var(--muted, inherit); opacity: 0.8;
}
.join__details { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s3); }
.join__details .input--narrow { max-width: 10rem; }

@media (max-width: 40rem) {
  .join__details { grid-template-columns: 1fr; }
  .join__details .input--narrow { max-width: none; }
}
.join__status { margin: 0; font-size: 0.88rem; }
.join__status--ok { color: var(--accent); }
.join__status--error { color: var(--warn); }

/* --- The full footer ------------------------------------------------------ */

.site-footer--full { padding-block: var(--s7, 3rem) var(--s5); }
.site-footer__grid {
  display: grid; grid-template-columns: 1.4fr 1fr 1fr; gap: var(--s6);
  align-items: start;
}
.brand-lockup--footer { margin-bottom: var(--s4); }
.site-footer__nav { display: grid; gap: var(--s3); align-content: start; }
.site-footer__heading {
  font-size: 0.7rem; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--ink-faint); margin: 0 0 var(--s2);
}
.site-footer__place { color: var(--ink-faint); font-size: 0.85rem; margin: var(--s2) 0 0; }
.site-footer__base {
  margin-top: var(--s6); padding-top: var(--s4);
  border-top: 1px solid var(--border);
}
.site-footer__legal { margin: 0; color: var(--ink-faint); font-size: 0.82rem; }

/* --- Recomposed for small screens ----------------------------------------- */

/*
 * Not a shrink. Each of these becomes a different composition: the ask panel
 * and the join block stack, the network turns from a horizontal bridge into a
 * vertical one, and the founder portrait stops being sticky because a sticky
 * element in a single column just covers the text it belongs to.
 */
@media (max-width: 60rem) {
  .ask-panel, .join, .founder { grid-template-columns: 1fr; }
  .founder__portrait { position: static; max-width: 22rem; }
  .site-footer__grid { grid-template-columns: 1fr 1fr; }
  .site-footer__identity { grid-column: 1 / -1; }
}

@media (max-width: 40rem) {
  .network { grid-template-columns: 1fr; justify-items: start; text-align: left; }
  .network__side--end { text-align: left; }
  .network__side--end .network__note { margin-left: 0; }
  /* The bridge rotates rather than being hidden: it is the illustration of the
     word UNION, and a phone should not be the one screen that loses it. */
  .network__bridge { flex-direction: column; }
  .network__line { width: 1px; height: 2rem; background: linear-gradient(to bottom, var(--accent), var(--border-strong)); }
  .site-footer__grid { grid-template-columns: 1fr; }
}

/* --- Stagger -------------------------------------------------------------- */

/*
 * Children settle one after another rather than all at once.
 *
 * The delay is capped at six steps: past that a visitor is watching a queue
 * instead of reading a page, and the last card in a long grid would still be
 * animating after they had scrolled away from it. The whole effect is 260ms
 * and eight pixels — a settling, not a performance.
 *
 * `prefers-reduced-motion` already collapses every transition to 0.01ms at the
 * top of this file, so nothing here needs its own escape hatch. The elements
 * still become visible; they simply arrive rather than travel.
 */
[data-stagger] > * {
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 0.42s var(--ease), transform 0.42s var(--ease);
}
[data-stagger].is-visible > * { opacity: 1; transform: none; }
[data-stagger].is-visible > *:nth-child(1) { transition-delay: 0ms; }
[data-stagger].is-visible > *:nth-child(2) { transition-delay: 65ms; }
[data-stagger].is-visible > *:nth-child(3) { transition-delay: 130ms; }
[data-stagger].is-visible > *:nth-child(4) { transition-delay: 195ms; }
[data-stagger].is-visible > *:nth-child(n + 5) { transition-delay: 260ms; }
.no-js [data-stagger] > * { opacity: 1; transform: none; }

/* --- The globe ------------------------------------------------------------ */

.globe-panel {
  margin-top: var(--s6);
  display: grid; grid-template-columns: 0.9fr 1.1fr; gap: var(--s6);
  align-items: center;
}
.globe-panel__stage { display: grid; gap: var(--s3); justify-items: center; }
.globe {
  width: 100%; max-width: 24rem; display: block;
  /* The glow behind the sphere. Painted by the element rather than the canvas
     so it survives the canvas being cleared sixty times a second. */
  filter: drop-shadow(0 0 40px color-mix(in srgb, var(--accent) 22%, transparent));
}
.globe__status {
  margin: 0; text-align: center; font-size: 0.85rem; color: var(--ink-faint);
  max-width: 30ch;
}

.globe-stats { display: flex; gap: var(--s6); margin: 0 0 var(--s5); }
.globe-stats div { display: grid; gap: 2px; }
.globe-stats dt {
  font-size: 0.7rem; letter-spacing: 0.16em; text-transform: uppercase; color: var(--ink-faint);
}
.globe-stats dd {
  margin: 0; font-family: Georgia, 'Times New Roman', serif;
  font-size: clamp(1.6rem, 4vw, 2.4rem); color: var(--ink);
  font-variant-numeric: tabular-nums;
}

.network__pair { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s5); }

/* --- Testimonials --------------------------------------------------------- */

.words {
  margin-top: var(--s6);
  display: grid; grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr)); gap: var(--s4);
}
.word {
  margin: 0; padding: var(--s5);
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--sheen);
  display: grid; gap: var(--s4);
}
.word__quote { margin: 0; }
.word__quote p {
  margin: 0;
  font-family: Georgia, 'Times New Roman', serif;
  font-size: 1.05rem; line-height: 1.6; color: var(--ink);
}
/* The quote mark is decoration and belongs in CSS, not in the stored text —
   a quotation mark typed into the database would be doubled by any interface
   that adds its own. */
.word__quote p::before { content: '“'; color: var(--accent); margin-right: 2px; }
.word__quote p::after { content: '”'; color: var(--accent); margin-left: 2px; }
.word__by { display: grid; gap: 2px; font-size: 0.85rem; }
.word__name { color: var(--ink); }
.word__role, .word__where { color: var(--ink-faint); }

@media (max-width: 60rem) {
  .globe-panel { grid-template-columns: 1fr; }
  .globe { max-width: 18rem; }
}
@media (max-width: 40rem) {
  .network__pair { grid-template-columns: 1fr; }
  .globe-stats { gap: var(--s5); }
}

/* --- Language, before the dictionary arrives ------------------------------- */

/*
 * Translatable text is invisible until translated, and only until then.
 *
 * `visibility` rather than `display`, so the box keeps its size and the page
 * does not reflow when the words appear. The attribute is removed by app.js as
 * soon as the dictionary is applied, and by a 1.2s timeout in the head if the
 * fetch never lands — a page nobody can read is worse than a page in the wrong
 * language, so the failure mode is "shows English", not "shows nothing".
 */
html[data-i18n-pending] [data-i18n],
html[data-i18n-pending] [data-i18n-attr] {
  visibility: hidden;
}

/* Motion-averse and slow devices alike: no fade, no animation. It is either
   not yet readable or it is. */
@media (prefers-reduced-motion: reduce) {
  html[data-i18n-pending] [data-i18n] { visibility: hidden; }
}

/* --- Real packaging, from the factories ----------------------------------- */

/*
 * Four across on a desktop, two on a phone — two rather than one because these
 * are square product shots and a single column of them scrolls forever on the
 * device most of this audience is holding.
 *
 * `aspect-ratio` with `object-fit: cover` keeps the grid even without letting a
 * photograph distort: a squashed box is a box the customer will not receive.
 */
.samples { margin-top: var(--s6); }
.samples__grid {
  list-style: none; margin: var(--s4) 0 0; padding: 0;
  display: grid; gap: var(--s3);
  grid-template-columns: repeat(4, minmax(0, 1fr));
}
.samples__tile { margin: 0; }
.samples__tile img {
  width: 100%; height: auto; aspect-ratio: 1 / 1; object-fit: cover;
  display: block; border-radius: var(--radius, 12px);
  border: 1px solid var(--border);
  background: var(--surface, #f7f8f7);
}
.samples__note {
  margin: var(--s4) 0 0; max-width: 62ch;
  font-size: 0.9rem; color: var(--muted, inherit);
}

@media (max-width: 60rem) { .samples__grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 40rem) { .samples__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
