/* The Landometer home page — `/` and `/en`. Everything below the bar.

   - Token names are bound to the `--lm-*` set in `nav/landometer-nav.css`
     rather than re-declared, so the theme toggle moves the bar and the page
     together. Names that set has none for are declared below from the v0.9.0
     kit.
   - Script routing is `:lang()`, not `html[lang]`: the page carries Latin terms
     inside Thai sentences and vice versa, so the face follows the element.

   Scoped under `.home`. The bar's own sheet shares this page, so no class here
   takes a name that sheet uses — the home's round utility button is
   `.homeUtilityCircle` for that reason. */

@layer tokens, fonts, base, layout, components, motion, responsive;

/* --------------------------------------------------------------------------
   Fonts. Same faces and unicode ranges as the reference.
   -------------------------------------------------------------------------- */

@font-face {
  font-family: "Material Symbols Rounded";
  src: url("/home/assets/fonts/material-symbols-rounded-rebuild02-r10.ttf")
    format("truetype");
  font-weight: 300;
  font-style: normal;
  /* `block`, not `swap`: a ligature name rendered as its own raw text while the
     face loads is a word in the middle of the layout, not a fallback glyph. */
  font-display: block;
}

@font-face {
  font-family: "Arvo";
  src: url("/home/assets/fonts/arvo-latin-700-normal.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-024F, U+1E00-1EFF;
}

@font-face {
  font-family: "IBM Plex Sans Thai Looped";
  src: url("/home/assets/fonts/ibm-plex-sans-thai-looped-thai-700-normal.woff2")
    format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
  ascent-override: 124%;
  descent-override: 54%;
  line-gap-override: 0%;
  unicode-range: U+0E00-0E7F;
}

@font-face {
  font-family: "IBM Plex Sans Thai Looped";
  src: url("/home/assets/fonts/ibm-plex-sans-thai-looped-latin-700-normal.woff2")
    format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
  ascent-override: 124%;
  descent-override: 54%;
  line-gap-override: 0%;
  unicode-range: U+0000-024F, U+1E00-1EFF;
}

@font-face {
  font-family: "Bai Jamjuree";
  src: url("/home/assets/fonts/bai-jamjuree-thai-400-normal.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0E00-0E7F;
}

@font-face {
  font-family: "Bai Jamjuree";
  src: url("/home/assets/fonts/bai-jamjuree-latin-400-normal.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-024F, U+1E00-1EFF;
}

@font-face {
  font-family: "Bai Jamjuree";
  src: url("/home/assets/fonts/bai-jamjuree-thai-600-normal.woff2") format("woff2");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0E00-0E7F;
}

@font-face {
  font-family: "Bai Jamjuree";
  src: url("/home/assets/fonts/bai-jamjuree-latin-600-normal.woff2") format("woff2");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-024F, U+1E00-1EFF;
}

@font-face {
  font-family: "JetBrains Mono";
  src: url("/home/assets/fonts/jetbrains-mono-latin-400-normal.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-024F, U+1E00-1EFF;
}

@layer tokens {
  .home {
    /* Surfaces, ink, borders and the interaction pair are the app's, so the
       page follows the bar's theme toggle. */
    --surface-canvas: var(--lm-surface-canvas);
    --surface-alt: var(--lm-surface-alt);
    --surface-card: var(--lm-surface-card);
    --surface-raised: var(--lm-surface-raised);
    --surface-soft: var(--lm-surface-soft);
    --surface-blue-tint: var(--lm-surface-blue-tint);
    --text-primary: var(--lm-text-primary);
    --text-secondary: var(--lm-text-secondary);
    --text-metadata: var(--lm-text-metadata);
    --border-hairline: var(--lm-border-hairline);
    --border-default: var(--lm-border-default);
    --interaction-accent: var(--lm-interaction-accent);
    --interaction-focus-ring: var(--lm-interaction-focus-ring);
    --brand-blue: var(--lm-brand-blue);
    --brand-beige: var(--lm-brand-beige);
    --energy-yellow: var(--lm-energy-yellow);
    --elevation-xs: var(--lm-elevation-xs);
    --overlay-glass: var(--lm-overlay-glass);
    --overlay-glass-ink: var(--lm-overlay-glass-ink);

    /* Names the app carries no token for, from the kit. */
    --surface-beige-tint: #f2f1df;
    --border-emphasis: #7d877f;
    --energy-sky: #59d2fe;
    --energy-mint: #0ad69c;
    --energy-coral: #ff5a5f;
    --overlay-glass-ink2: #f1f4ef;
    --overlay-glass-border: rgba(241, 244, 239, 0.24);
    --elevation-md: 0 12px 32px rgba(30, 34, 48, 0.14);

    /* Foreground contracts. A fixed surface owns its whole foreground: page ink
       is the wrong answer on an atmosphere gradient in either theme. */
    --fg-on-deep-primary: #ffffff;
    --fg-on-deep-secondary: #f1f4ef;
    --fg-on-light-primary: #182327;
    --fg-on-light-secondary: #293337;
    --fg-interactive-surface: #ffffff;
    --fg-interactive-ink: #182327;

    /* Atmosphere recipes, exact stops from the kit's A4 block. The four are
       recipes, not surfaces: the alias below picks which one a scene gets, and
       the theme picks the alias. */
    --atmosphere-measure-deep: linear-gradient(
      135deg,
      #1d4497 0%,
      #176b82 54%,
      #08756f 100%
    );
    --atmosphere-measure-luminous: linear-gradient(
      135deg,
      #89cef6 0%,
      #5ecad6 50%,
      #6cd5b3 100%
    );
    --atmosphere-cultivate-glow: linear-gradient(
      135deg,
      #eb8182 0%,
      #f5a06f 50%,
      #ebc573 100%
    );
    --atmosphere-cultivate-mist: linear-gradient(
      135deg,
      #f7cbc7 0%,
      #fbd1b6 50%,
      #f1e0b4 100%
    );

    /* The theme-resolved aliases, and the foreground each rendition takes.
       `measure` is the only one that changes field: deep takes white, luminous
       takes near-black. Both cultivate renditions are light fields. */
    --surface-atmosphere-measure: var(--atmosphere-measure-deep);
    --on-atmosphere-measure: var(--fg-on-deep-primary);
    --on-atmosphere-measure-2: var(--fg-on-deep-secondary);
    --surface-atmosphere-cultivate: var(--atmosphere-cultivate-glow);
    --on-atmosphere-cultivate: var(--fg-on-light-primary);
    --on-atmosphere-cultivate-2: var(--fg-on-light-secondary);

    /* Type. Roles, not families: which face a heading takes is decided by the
       script it is written in, further down. */
    --font-body: "Bai Jamjuree", "Noto Sans Thai", "Leelawadee UI", Tahoma,
      sans-serif;
    --font-display-en: "Arvo", Georgia, Cambria, "Times New Roman", serif;
    --font-display-th: "IBM Plex Sans Thai Looped", "Noto Sans Thai Looped",
      "Leelawadee UI", Tahoma, sans-serif;
    --font-ui-heading-en: var(--font-display-en);
    --font-ui-heading-th: var(--font-display-th);
    --font-technical: "JetBrains Mono", "IBM Plex Sans Thai", "SFMono-Regular",
      Consolas, monospace;
    --font-number: var(--font-technical);

    --type-body: 1rem;
    --type-body-lg: 1.125rem;
    --type-body-sm: 0.875rem;
    --type-label: 0.8125rem;
    --type-caption: 0.75rem;
    --type-h2: clamp(2rem, 4vw, 3.25rem);
    --type-h3: 1.375rem;

    --leading-body: 1.6;
    --leading-display-en: 1.02;
    --leading-display-th: 1.4;
    --leading-ui-heading-en: 1.22;
    --leading-ui-heading-th: 1.45;
    --tracking-eyebrow: 0.08em;

    --space-1: 4px;
    --space-2: 8px;
    --space-3: 12px;
    --space-4: 16px;
    --space-5: 24px;
    --space-6: 32px;
    --space-7: 48px;

    --radius-sm: 10px;
    --radius-md: 16px;
    --radius-pill: 999px;

    --motion-duration-feedback: var(--lm-motion-duration-feedback);
    --motion-duration-state: var(--lm-motion-duration-state);
    --motion-duration-emphasis: var(--lm-motion-duration-emphasis);
    --motion-distance-feedback: 2px;
    --motion-ease-enter: cubic-bezier(0.16, 1, 0.3, 1);
    --motion-ease-press: var(--lm-motion-ease-press);
    --motion-ease-settle: cubic-bezier(0.2, 0.9, 0.25, 1.08);

    /* The header this page measures its first screen against is the app bar's
       tall state, not the reference's own 76px constant. */
    --site-header-height: var(--lm-nav-height);
    --z-modal: 500;
  }

  /* --------------------------------------------------------------------
     The dark theme, the same three things the reference kit resolves there.

     The atmosphere aliases move to the other rendition: `measure` becomes
     luminous and turns from a deep field into a light one, so its ink flips
     with it; `cultivate` becomes mist and stays light, so its ink does not.

     The beiges are fields rather than marks and neither followed the mode.
     `--surface-beige-tint` backs `.serviceRoute`, whose copy is page ink —
     that ink turns light here, so the surface has to turn dark with it.
     `--brand-beige` backs `.pillarLand` and the CityChat card, which own
     their foreground through `--fg-on-light-*`; those stay a light field,
     muted to the beige CityChat and CityWiki already use in dark.

     The media query covers the moment before the attribute is written; the
     `:not()` keeps an explicit light choice from being overridden.
     -------------------------------------------------------------------- */
  @media (prefers-color-scheme: dark) {
    :root:not([data-color-scheme="light"]) .home {
      --surface-atmosphere-measure: var(--atmosphere-measure-luminous);
      --on-atmosphere-measure: var(--fg-on-light-primary);
      --on-atmosphere-measure-2: var(--fg-on-light-secondary);
      --surface-atmosphere-cultivate: var(--atmosphere-cultivate-mist);
      --surface-beige-tint: #2c2a22;
      --brand-beige: #d8cfb2;
      --border-emphasis: #7c8a84;
    }
  }

  :root[data-color-scheme="dark"] .home {
    --surface-atmosphere-measure: var(--atmosphere-measure-luminous);
    --on-atmosphere-measure: var(--fg-on-light-primary);
    --on-atmosphere-measure-2: var(--fg-on-light-secondary);
    --surface-atmosphere-cultivate: var(--atmosphere-cultivate-mist);
    --surface-beige-tint: #2c2a22;
    --brand-beige: #d8cfb2;
    --border-emphasis: #7c8a84;
  }
}

@layer base {
  .home {
    background: var(--surface-canvas);
    color: var(--text-primary);
    font-family: var(--font-body);
    font-size: var(--type-body);
    line-height: var(--leading-body);
    /* The hero and the atmosphere sections bleed past the reading column; the
       page must not scroll sideways because of it. */
    overflow-x: clip;
  }

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

  .home img,
  .home video,
  .home svg {
    display: block;
    max-width: 100%;
    height: auto;
  }

  .home h1,
  .home h2,
  .home h3 {
    margin: 0 0 var(--space-4);
    font-weight: 700;
    letter-spacing: -0.02em;
    text-wrap: balance;
  }

  /* Script routing per element, not per document: a Latin product name inside a
     Thai sentence has to reach the Latin face and keep the Thai leading around
     it. */
  .home :is(h2, h3):lang(th) {
    font-family: var(--font-ui-heading-th);
    /* Not the -0.02em above: tightening the bases does not move the marks with
       them, so a stack ends up over the next letter. */
    letter-spacing: normal;
    line-height: var(--leading-ui-heading-th);
  }

  .home :is(h2, h3):lang(en) {
    font-family: var(--font-ui-heading-en);
    line-height: var(--leading-ui-heading-en);
  }

  .home h2 {
    font-size: var(--type-h2);
  }

  .home h3 {
    font-size: var(--type-h3);
  }

  .home p,
  .home li {
    margin-top: 0;
    text-wrap: pretty;
  }

  .home a {
    color: var(--interaction-accent);
    text-underline-offset: 0.18em;
    text-decoration-thickness: 1px;
  }

  .home a:hover {
    text-decoration-thickness: 2px;
  }

  .home a:active {
    color: var(--interaction-accent);
  }

  .home button,
  .home input,
  .home select,
  .home textarea {
    font: inherit;
    color: inherit;
  }

  .home :is(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
    outline: 3px solid var(--interaction-focus-ring);
    outline-offset: 2px;
  }

  .home ::selection {
    background: var(--energy-yellow);
    color: var(--fg-on-light-primary);
  }

  .meta {
    color: var(--text-metadata);
    font-size: var(--type-body-sm);
  }

  /* Tabular figures wherever a number is meant to be read as a measurement. */
  .number {
    font-family: var(--font-number);
    font-variant-numeric: tabular-nums lining-nums;
    font-feature-settings: "tnum" 1, "lnum" 1;
  }

  .eyebrow {
    font-family: var(--font-technical);
    font-size: var(--type-label);
    font-weight: 400;
    text-transform: uppercase;
    letter-spacing: var(--tracking-eyebrow);
    color: var(--text-metadata);
  }

  .iconSymbol {
    font-family: "Material Symbols Rounded";
    font-weight: normal;
    font-style: normal;
    /* Locked axes: outline, rounded joins, thin stroke. A filled cut is for a
       selected state, and nothing on this page has one. */
    font-variation-settings: "FILL" 0, "wght" 300, "GRAD" 0, "opsz" 24;
    font-size: 24px;
    line-height: 1;
    letter-spacing: normal;
    text-transform: none;
    text-decoration: none;
    display: inline-block;
    white-space: nowrap;
    direction: ltr;
    -webkit-font-smoothing: antialiased;
  }

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

@layer layout {
  .container {
    max-width: 1120px;
    margin-inline: auto;
    padding-inline: 24px;
  }

  .containerReading {
    max-width: 760px;
  }

  .containerWide {
    max-width: 1280px;
  }

  @media (min-width: 600px) {
    .container {
      padding-inline: 32px;
    }
  }

  .sectionShell {
    padding: clamp(56px, 8vh, 96px) 0;
  }

  /* Not laid out until near the viewport. `hashJump` suspends that: a section
     with no layout has no position to jump to. */
  .lazySection {
    content-visibility: auto;
    contain-intrinsic-size: auto 860px;
  }

  .hashJump .lazySection {
    content-visibility: visible;
    contain-intrinsic-size: none;
  }

  .home section[tabindex="-1"]:focus-visible {
    outline-offset: -3px;
  }

  .sectionIntro {
    max-width: 68ch;
    margin-bottom: var(--space-6);
  }

  .sectionIntro .eyebrow {
    margin: 0 0 var(--space-3);
  }

  .sectionTitle {
    margin: 0 0 var(--space-3);
    color: var(--text-primary);
    font-size: var(--type-h2);
    text-wrap: balance;
  }

  /* Thai section headings take the UI-heading leading, not the display leading.
     That is the kit's own `h2:lang(th)` rule, which outranks a bare class and so
     wins over `.section-title` on the reference; stated here because this module
     has no element layer to be outranked by. Thai marks need the extra 0.16. */
  .sectionTitle:lang(th) {
    font-family: var(--font-display-th);
    line-height: var(--leading-ui-heading-th);
  }

  .sectionTitle:lang(en) {
    font-family: var(--font-display-en);
    letter-spacing: -0.02em;
    line-height: 1.08;
  }

  .subsectionTitle {
    margin: 0 0 var(--space-5);
    color: var(--text-primary);
    font-size: 1.5rem;
  }

  .sectionLede {
    max-width: 62ch;
    margin: 0;
    color: var(--text-secondary);
    font-size: var(--type-body-lg);
  }

  /* Surface and local foreground contract travel together: setting one without
     the other is what produces white text on a light gradient. */
  .sceneAtmosphere {
    color: var(--on-atmosphere, var(--fg-on-deep-primary));
  }

  .sceneMeasure {
    background-image: var(--surface-atmosphere-measure);
    --on-atmosphere: var(--on-atmosphere-measure);
    --on-atmosphere-2: var(--on-atmosphere-measure-2);
  }

  .sceneCultivate {
    background-image: var(--surface-atmosphere-cultivate);
    --on-atmosphere: var(--on-atmosphere-cultivate);
    --on-atmosphere-2: var(--on-atmosphere-cultivate-2);
  }

  .sceneAtmosphere .meta {
    color: var(--on-atmosphere-2);
  }

  .sceneAtmosphere :is(a, button, [tabindex]):focus-visible {
    outline-color: var(--on-atmosphere);
  }

  .sceneAtmosphere a:not(.btn):not(.showcaseTile):active {
    color: var(--on-atmosphere);
  }
}

@layer components {
  /* ------------------------------------------------------------------------
     First viewport
     ------------------------------------------------------------------------ */

  .hero {
    height: calc(100svh - var(--site-header-height));
    min-height: 0;
    display: grid;
    grid-template-columns: minmax(0, 1.03fr) minmax(0, 0.97fr);
    overflow: hidden;
  }

  .heroCopy {
    min-width: 0;
    min-height: 0;
    display: flex;
    flex-direction: column;
    justify-content: center;
    overflow-y: auto;
    padding: clamp(24px, 4vw, 56px);
    /* Holds the copy to the same left edge as the sections below once the
       viewport is wider than the reading column. */
    padding-left: max(clamp(24px, 4vw, 56px), calc((100vw - 1280px) / 2));
  }

  .heroEyebrow {
    margin: 0 0 var(--space-3);
    color: var(--on-atmosphere-2);
  }

  .hero h1 {
    max-width: 15ch;
    margin: 0 0 var(--space-3);
    color: var(--on-atmosphere);
    font-family: var(--font-display-en);
    font-size: clamp(2.2rem, 4.3vw, 4.5rem);
    font-weight: 700;
    letter-spacing: -0.02em;
    line-height: var(--leading-display-en);
    text-wrap: balance;
  }

  .heroSubheadline {
    margin: 0 0 var(--space-3);
    color: var(--on-atmosphere);
    font-family: var(--font-display-th);
    font-size: clamp(1.05rem, 2.1vw, 1.75rem);
    font-weight: 700;
    letter-spacing: normal;
    line-height: var(--leading-display-th);
  }

  .heroSubheadline:lang(en) {
    font-family: var(--font-display-en);
    letter-spacing: -0.01em;
  }

  .heroCopyLine {
    display: block;
  }

  .heroDescription {
    max-width: 54ch;
    margin: 0 0 var(--space-4);
    color: var(--on-atmosphere-2);
    font-size: clamp(0.9375rem, 1.1vw, 1.0625rem);
    line-height: 1.55;
  }

  .heroLink {
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    color: var(--on-atmosphere);
    font-size: var(--type-body-lg);
    font-weight: 600;
    text-decoration: none;
  }

  .heroLinkLabel {
    text-decoration: underline;
    text-decoration-thickness: 1px;
    text-underline-offset: 0.22em;
  }

  /* Positioned, and its own stacking context: the mark sits over the
     photograph and must not reach any further up the page than that. */
  .heroMedia {
    --hero-parallax-y: 0px;
    position: relative;
    isolation: isolate;
    min-width: 0;
    min-height: 0;
    margin: 0;
    overflow: hidden;
    background: var(--surface-soft);
  }

  /* Overscanned top and bottom so the parallax offset never exposes an edge. */
  .heroMedia picture {
    position: relative;
    top: -24px;
    display: block;
    width: 100%;
    height: calc(100% + 48px);
    transform: translate3d(0, var(--hero-parallax-y), 0);
    will-change: transform;
  }

  .heroMedia img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: 50% 62%;
    transform-origin: center;
    animation: home-hero-pan 32s ease-in-out infinite alternate;
    will-change: transform;
  }

  /* ------------------------------------------------------------------------
     Proof band
     ------------------------------------------------------------------------ */

  .proofBand {
    padding: clamp(28px, 4vw, 48px) 0;
    background: var(--surface-canvas);
  }

  .proofGrid {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: var(--space-3);
  }

  .proofCard {
    min-width: 0;
    min-height: 108px;
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-4);
    border: 1px solid var(--border-default);
    border-radius: var(--radius-md);
    background: var(--surface-card);
    color: var(--text-primary);
    text-decoration: none;
  }

  .proofCard:hover,
  .proofCard:focus-visible {
    border-color: var(--interaction-accent);
  }

  .proofValue {
    color: var(--interaction-accent);
    font-family: var(--font-number);
    font-variant-numeric: tabular-nums lining-nums;
    font-size: clamp(2rem, 3vw, 3rem);
    line-height: 1;
  }

  .proofLabel {
    display: block;
    font-weight: 600;
    line-height: 1.35;
  }

  .proofCard time {
    display: block;
    margin-top: 3px;
    color: var(--text-metadata);
    font-size: var(--type-caption);
  }

  /* ------------------------------------------------------------------------
     Land · Location · Living
     ------------------------------------------------------------------------ */

  .pillar {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    align-items: stretch;
  }

  .pillarCopy {
    min-width: 0;
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: var(--space-2);
    padding: clamp(36px, 5vw, 72px);
  }

  .pillarCopyLeft {
    padding-left: max(clamp(36px, 5vw, 72px), calc((100vw - 1280px) / 2));
  }

  .pillarCopyRight {
    padding-right: max(clamp(36px, 5vw, 72px), calc((100vw - 1280px) / 2));
  }

  .pillarCopy :is(.eyebrow, h2, p) {
    margin: 0;
  }

  .pillarCopy h2 {
    font-family: var(--font-display-th);
    font-size: clamp(1.75rem, 2.8vw, 2.5rem);
    line-height: var(--leading-display-th);
    text-wrap: balance;
  }

  .pillarCopy h2:lang(en) {
    font-family: var(--font-display-en);
    letter-spacing: -0.02em;
    line-height: 1.08;
  }

  .pillarLand {
    background: var(--brand-beige);
    color: var(--fg-on-light-primary);
  }

  .pillarLand :is(.pillarCopy p, .eyebrow) {
    color: var(--fg-on-light-secondary);
  }

  .pillarLand .mediaFigure img {
    object-position: 100% 50%;
  }

  .pillarLocation .mediaFigure img {
    object-position: 52% 57%;
  }

  .pillarLocation .pillarCopy,
  .pillarLocation .pillarCopy h2 {
    color: var(--on-atmosphere);
  }

  .pillarLocation :is(.pillarCopy p, .eyebrow) {
    color: var(--on-atmosphere-2);
  }

  .pillarLiving {
    background: var(--surface-alt);
    color: var(--text-primary);
  }

  .pillarLiving :is(.pillarCopy p, .eyebrow) {
    color: var(--text-secondary);
  }

  /* An eyebrow with its glyph on the same baseline. */
  .iconLine {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
  }

  .iconLine .iconSymbol {
    font-size: 18px;
    font-variation-settings: "FILL" 0, "wght" 300, "GRAD" 0, "opsz" 20;
  }

  .mediaFigure {
    position: relative;
    min-width: 0;
    margin: 0;
    overflow: hidden;
    background: var(--surface-soft);
  }

  .mediaFigure picture,
  .mediaFigure .mediaCanvas {
    display: block;
    width: 100%;
    aspect-ratio: 4 / 3;
    overflow: hidden;
    background: var(--surface-soft);
  }

  .mediaFigure :is(img, video) {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
  }

  .mediaCaption {
    margin: 0;
    padding: var(--space-2) var(--space-3);
    border-top: 1px solid var(--border-default);
    background: var(--surface-card);
    color: var(--text-secondary);
    font-size: var(--type-caption);
  }

  .livingVideo {
    background: var(--surface-soft);
    object-position: 50% 14%;
  }

  .pillarResolution {
    padding: clamp(48px, 8vh, 88px) 0;
    text-align: center;
  }

  .pillarResolution h2 {
    max-width: 30ch;
    margin: 0 auto;
    font-family: var(--font-display-th);
    font-size: clamp(1.6rem, 2.8vw, 2.4rem);
    line-height: var(--leading-display-th);
    text-wrap: balance;
  }

  .pillarResolution h2:lang(en) {
    font-family: var(--font-display-en);
    line-height: 1.12;
  }
}

@layer motion {
  @keyframes home-hero-pan {
    from {
      transform: translate3d(0, -2%, 0) scale(1.08);
    }
    to {
      transform: translate3d(0, 2%, 0) scale(1.08);
    }
  }
}

@layer components {
  /* ------------------------------------------------------------------------
     Buttons and links. The kit's `.btn` is one capsule with no third shape;
     `.pressable` is the page's own 2px press, applied to anything that takes a
     click and is not already a button.
     ------------------------------------------------------------------------ */

  .btn {
    max-width: 100%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    min-height: 44px;
    padding: 10px var(--space-5);
    border: 2px solid var(--interaction-accent);
    border-radius: var(--radius-pill);
    background: transparent;
    color: var(--interaction-accent);
    font: 600 var(--type-body) / 1.2 var(--font-body);
    text-decoration: none;
    white-space: nowrap;
    cursor: pointer;
    transition:
      background-color var(--motion-duration-feedback) var(--motion-ease-press),
      transform var(--motion-duration-feedback) var(--motion-ease-press);
  }

  /* The primary action in each group. It keeps the governed capsule geometry
     and gains a solid field, so the sweep underneath its label has something to
     sit on. Both are lost to `.sceneAtmosphere .btn` and `.btn:hover`, which
     are more specific — same as the reference, where the atmosphere contract
     and the hover state still win. */
  .btnPrimary {
    position: relative;
    isolation: isolate;
    overflow: hidden;
    background: var(--surface-card);
    box-shadow: var(--elevation-xs);
  }

  /* The sweep: a highlighter drawn under the label on the way in. Feedback
     only — it never runs on its own. */
  .btnPrimary::before {
    content: "";
    position: absolute;
    right: var(--space-4);
    bottom: 0.58em;
    left: var(--space-4);
    height: 3px;
    border-radius: var(--radius-pill);
    background: var(--energy-yellow);
    transform: scaleX(0);
    transform-origin: left center;
    transition: transform var(--motion-duration-emphasis)
      var(--motion-ease-enter);
    pointer-events: none;
  }

  .btnPrimary:hover::before,
  .btnPrimary:focus-visible::before {
    transform: scaleX(1);
  }

  .btn:hover {
    background: var(--surface-blue-tint);
  }

  .btn:active {
    background: var(--surface-soft);
    transform: translateY(var(--motion-distance-feedback));
  }

  .btn:disabled,
  .btn[aria-disabled="true"] {
    border-color: var(--border-hairline);
    color: var(--text-metadata);
    cursor: not-allowed;
    transform: none;
  }

  .btn[aria-busy="true"] {
    cursor: progress;
  }

  /* On an atmosphere surface the contract's interactive pair applies: the page
     ink would vanish into the gradient. */
  .sceneAtmosphere .btn {
    background: var(--fg-interactive-surface);
    color: var(--fg-interactive-ink);
    border-color: transparent;
  }

  .pressable {
    transition: transform var(--motion-duration-feedback)
      var(--motion-ease-press);
  }

  .pressable:active {
    transform: translateY(var(--motion-distance-feedback));
  }

  .card {
    background: var(--surface-card);
    border: 1px solid var(--border-default);
    border-radius: var(--radius-md);
    padding: var(--space-5);
  }

  .textLink {
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    color: var(--interaction-accent);
    font-weight: 600;
    text-decoration: none;
  }

  .textLinkLabel {
    text-decoration: underline;
    text-decoration-thickness: 1px;
    text-underline-offset: 0.22em;
  }

  .textLink:hover .textLinkLabel,
  .textLink:focus-visible .textLinkLabel {
    text-decoration-thickness: 2px;
  }

  /* The ↗ / ↓ that says where a link goes. Never underlined — it is a cue, not
     part of the label. */
  .textLinkCue {
    flex: none;
    font-family: var(--font-technical);
    font-weight: 500;
    line-height: 1;
    text-decoration: none;
  }

  .homeUtilityCircle {
    width: 44px;
    height: 44px;
    min-width: 44px;
    display: inline-grid;
    place-items: center;
    padding: 0;
    border: 1px solid var(--border-default);
    border-radius: var(--radius-pill);
    background: transparent;
    color: var(--interaction-accent);
    cursor: pointer;
    transition:
      background-color var(--motion-duration-feedback) var(--motion-ease-press),
      transform var(--motion-duration-feedback) var(--motion-ease-press);
  }

  .homeUtilityCircle:hover,
  .homeUtilityCircle:focus-visible {
    background: var(--surface-blue-tint);
  }

  .homeUtilityCircle:active {
    background: var(--surface-soft);
    transform: translateY(2px);
  }

  /* ------------------------------------------------------------------------
     Products and services
     ------------------------------------------------------------------------ */

  .productsSection {
    background: var(--surface-alt);
  }

  .productsSection .sectionIntro {
    max-width: 76ch;
  }

  .solutionsGrid {
    display: grid;
    /* Six columns so a featured card can take three and a standard one two —
       two sizes on one grid, without a second grid definition. */
    grid-template-columns: repeat(6, minmax(0, 1fr));
    gap: var(--space-4);
  }

  .solutionCardFeatured {
    grid-column: span 3;
  }

  .solutionCardStandard {
    grid-column: span 2;
  }

  .solutionCard {
    min-width: 0;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    border: 1px solid var(--border-default);
    border-radius: var(--radius-md);
    background: var(--surface-card);
  }

  .solutionCardMedia {
    position: relative;
    width: 100%;
    margin: 0;
    overflow: hidden;
    aspect-ratio: 3 / 2;
    background: var(--surface-soft);
  }

  .solutionCardStandard .solutionCardMedia {
    aspect-ratio: 4 / 3;
  }

  .solutionCardMedia picture,
  .solutionCardMedia img {
    display: block;
    width: 100%;
    height: 100%;
  }

  .solutionCardMedia img {
    object-fit: cover;
    object-position: var(--media-x, 50%) var(--media-y, 50%);
    transition: transform 920ms var(--motion-ease-settle);
  }

  .solutionCard:hover .solutionCardMedia:not(.staticParallax) img {
    transform: scale(1.025);
  }

  /* Credit and provenance sit on the image they describe, in the one glass
     treatment the kit allows over media. */
  .solutionCardMediaNote {
    position: absolute;
    right: 10px;
    bottom: 10px;
    left: 10px;
    z-index: 1;
    width: fit-content;
    max-width: calc(100% - 20px);
    padding: 5px 8px;
    border-radius: var(--radius-sm);
    background: var(--overlay-glass);
    color: var(--overlay-glass-ink2);
    font-size: clamp(0.68rem, 1.1vw, 0.76rem);
    line-height: 1.35;
  }

  .solutionCardMediaNote a {
    color: inherit;
    text-decoration-color: currentColor;
    text-underline-offset: 0.16em;
  }

  .solutionCardMediaNote a:focus-visible {
    outline-color: var(--overlay-glass-ink);
  }

  .solutionCardContent {
    min-height: 0;
    display: flex;
    flex: 1;
    flex-direction: column;
    gap: var(--space-3);
    padding: clamp(24px, 3vw, 36px);
  }

  .solutionCardBrand {
    min-height: 64px;
    display: flex;
    align-items: center;
    gap: 12px;
  }

  .solutionCardBrandCitychat {
    width: 230px;
    max-width: 100%;
    min-height: 64px;
  }

  .solutionCardLogo {
    display: block;
    width: auto;
    max-width: 100%;
    height: auto;
    object-fit: contain;
  }

  .solutionCardLogoLandometer {
    width: 58px;
    height: 58px;
  }

  .solutionCardWordmark {
    min-width: 0;
    color: var(--text-primary);
    font-family: var(--font-display-en);
    font-size: 23px;
    font-weight: 700;
    letter-spacing: -0.02em;
    line-height: 1.02;
    white-space: nowrap;
  }

  .solutionCardWordmarkLong {
    max-width: 18ch;
    font-size: clamp(18px, 1.6vw, 23px);
    line-height: 1.12;
    white-space: normal;
    text-wrap: balance;
  }

  .solutionCard :is(h3, p) {
    margin: 0;
  }

  .solutionCard h3 {
    font-size: 1.25rem;
  }

  .solutionCard p {
    color: var(--text-secondary);
  }

  .solutionCardFit {
    padding: var(--space-3);
    border-radius: var(--radius-sm);
    background: var(--surface-soft);
    color: var(--text-primary);
  }

  .solutionCardFit strong {
    display: block;
    margin-bottom: var(--space-1);
    color: var(--interaction-accent);
    font-size: var(--type-label);
  }

  /* The CityChat card sets its own beige field, so it also sets its own
     interactive pair: the page accent is unreadable on it. */
  .solutionCardCitychat .solutionCardContent {
    background: var(--brand-beige);
    color: var(--fg-on-light-primary);
    --interaction-accent: var(--fg-on-light-primary);
    --interaction-focus-ring: var(--fg-on-light-primary);
  }

  .solutionCardCitychat .solutionCardContent > p {
    color: var(--fg-on-light-secondary);
  }

  .solutionCardCitychat .solutionCardFit {
    background: color-mix(in srgb, var(--brand-beige) 76%, white);
    color: var(--fg-on-light-primary);
  }

  .solutionCardCitychat .solutionCardFit strong {
    color: var(--fg-on-light-primary);
  }

  .solutionCardCitychat .solutionCardActions .btn {
    border-color: var(--fg-on-light-primary);
    background: transparent;
    color: var(--fg-on-light-primary);
  }

  .solutionCardCitychat .solutionCardActions .btn:hover {
    background: var(--fg-interactive-surface);
    color: var(--fg-interactive-ink);
  }

  .solutionCardCitychat .solutionCardActions .btn:focus-visible {
    outline-color: var(--fg-on-light-primary);
  }

  .solutionCardActions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-3);
    /* Pins the row to the bottom so cards of different heights still line their
       actions up. */
    margin-top: auto;
    padding-top: var(--space-3);
  }

  .solutionCardActions .btn {
    justify-content: center;
  }

  /* ------------------------------------------------------------------------
     Projects and partnerships
     ------------------------------------------------------------------------ */

  .serviceRoute {
    display: grid;
    grid-template-columns: minmax(0, 1.02fr) minmax(0, 0.98fr);
    align-items: stretch;
    gap: 0;
    overflow: hidden;
    margin-top: var(--space-5);
    border-radius: var(--radius-md);
    background: var(--surface-beige-tint);
  }

  .serviceRouteMedia {
    min-width: 0;
    min-height: 100%;
    margin: 0;
    overflow: hidden;
    background: var(--surface-soft);
  }

  .serviceRouteMedia picture,
  .serviceRouteMedia img {
    display: block;
    width: 100%;
    height: 100%;
  }

  .serviceRouteMedia img {
    min-height: 420px;
    object-fit: cover;
    object-position: 50% 46%;
  }

  .serviceRouteContent {
    display: grid;
    align-content: center;
    gap: var(--space-4);
    padding: clamp(28px, 4vw, 52px);
  }

  .serviceRouteIcon {
    width: 64px;
    height: 64px;
    display: grid;
    place-items: center;
    border-radius: var(--radius-pill);
    background: var(--surface-card);
    color: var(--interaction-accent);
    font-size: 30px;
  }

  .serviceRouteCopy :is(.eyebrow, h3, p) {
    margin: 0;
  }

  .serviceRouteCopy .eyebrow {
    margin-bottom: var(--space-2);
  }

  .serviceRouteCopy h3 {
    margin-bottom: var(--space-2);
    font-size: clamp(1.25rem, 2vw, 1.6rem);
  }

  .serviceRouteCopy p {
    max-width: 66ch;
    color: var(--text-secondary);
  }

  .serviceRouteAction {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: var(--space-2);
  }
}

@layer components {
  /* ------------------------------------------------------------------------
     Location intelligence
     ------------------------------------------------------------------------ */

  .locationIntelligence {
    background: var(--surface-alt);
  }

  .locationIntelligence .sectionIntro {
    max-width: 920px;
  }

  /* Both horizontal rails on the page — the questions and the testimonials —
     share this shape: one row that scrolls, snapping to card starts. The
     looping is done in `useLoopRail`, which wraps the scroll position when you
     pass either end. */
  .loopRail {
    display: grid;
    grid-auto-flow: column;
    grid-template-columns: none;
    grid-auto-columns: minmax(300px, 34%);
    gap: var(--space-4);
    overflow-x: auto;
    overscroll-behavior-inline: contain;
    padding: 2px 2px var(--space-4);
    scroll-padding-inline: 2px;
    scroll-snap-type: x mandatory;
    /* No scrollbar: the ‹ › buttons below the rail are the control now. A bar
       measures a row three times longer than the reader is being shown and
       jumps under the thumb every time the offset wraps, so it read as a fault.
       Wheel, trackpad, touch and the arrow keys all still move the rail. */
    scrollbar-width: none;
    /* The browser must not try to hold a reading position in a row whose
       scroll offset this page rewrites. */
    overflow-anchor: none;
  }

  .loopRail::-webkit-scrollbar {
    display: none;
  }

  .loopRail:focus-visible {
    outline: 3px solid var(--interaction-focus-ring);
    outline-offset: 2px;
  }

  /* The buttons ride the rail's two edges — 16px of each in the page gutter,
     the rest over the first and last card. Columns of their own would have
     taken 100px of card width on every screen, phones included. */
  .loopRailShell {
    position: relative;
  }

  .loopRailButton {
    position: absolute;
    z-index: 1;
    /* Centred on the cards rather than on the rail's box — the box keeps room
       under them for the reveal lift. Both edges plus a fixed height and auto
       margins is what centres it in that band. */
    top: 2px;
    bottom: var(--space-4);
    margin-block: auto;
    width: 44px;
    height: 44px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    border: 2px solid var(--interaction-accent);
    border-radius: var(--radius-pill);
    /* Opaque, and lifted: it stands over photographs. */
    background: var(--surface-card);
    box-shadow: var(--elevation-md);
    color: var(--interaction-accent);
    cursor: pointer;
    /* A tap otherwise flashes the platform's rectangle over a round button.
       The press is still shown — `:active` fills it and drops it 2px. */
    -webkit-tap-highlight-color: transparent;
    transition:
      background-color var(--motion-duration-feedback) var(--motion-ease-press),
      transform var(--motion-duration-feedback) var(--motion-ease-press);
  }

  .loopRailPrevious {
    inset-inline-start: calc(var(--space-4) * -1);
  }

  .loopRailNext {
    inset-inline-end: calc(var(--space-4) * -1);
  }

  .loopRailButton:hover {
    background: var(--surface-blue-tint);
  }

  .loopRailButton:active {
    background: var(--surface-soft);
    transform: translateY(var(--motion-distance-feedback));
  }

  .loopRailButton:focus-visible {
    outline: 3px solid var(--interaction-focus-ring);
    outline-offset: 2px;
  }

  .loopRailButton svg {
    width: 22px;
    height: 22px;
  }

  /* While the rail is being wrapped from one end to the other, the jump must
     not animate and must not snap — either would show the seam. */
  .loopRailResetting {
    scroll-behavior: auto;
    scroll-snap-type: none;
  }

  /* The copies either side of the real row. Present for the eye only: they are
     `inert` and `aria-hidden` in the markup, and take no pointer either. */
  .loopClone {
    pointer-events: none;
    user-select: none;
  }

  .locationQuestionGrid {
    margin-top: var(--space-7);
  }

  .locationQuestion {
    min-width: 0;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    border: 1px solid var(--border-default);
    border-radius: var(--radius-md);
    background: var(--surface-card);
    scroll-snap-align: start;
  }

  .locationQuestionMedia {
    width: 100%;
    margin: 0;
    overflow: hidden;
    aspect-ratio: 4 / 3;
    background: var(--surface-soft);
  }

  .locationQuestionMedia picture,
  .locationQuestionMedia img {
    display: block;
    width: 100%;
    height: 100%;
  }

  .locationQuestionMedia img {
    object-fit: cover;
    object-position: var(--media-x, 50%) var(--media-y, 50%);
    transition: transform 920ms var(--motion-ease-settle);
  }

  .locationQuestion:hover .locationQuestionMedia:not(.staticParallax) img {
    transform: scale(1.025);
  }

  .locationQuestionBody {
    min-height: 0;
    display: flex;
    flex: 1;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-3);
    padding: clamp(22px, 2.5vw, 32px);
  }

  .locationQuestionBody > .iconSymbol {
    color: var(--interaction-accent);
    font-size: 30px;
  }

  .locationQuestion :is(h3, p) {
    margin: 0;
  }

  .locationQuestion h3 {
    font-size: clamp(1.08rem, 1.8vw, 1.3rem);
    line-height: 1.3;
  }

  .locationQuestion p {
    color: var(--text-secondary);
  }

  .locationQuestionCta {
    justify-content: center;
    max-width: 100%;
    margin-top: auto;
    padding-inline: clamp(14px, 2vw, 24px);
    font-size: clamp(0.82rem, 1.2vw, 0.96rem);
    white-space: nowrap;
    text-align: center;
  }

  .locationClose {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4) var(--space-6);
    margin-top: var(--space-6);
    padding-top: var(--space-5);
    border-top: 1px solid var(--border-hairline);
  }

  .locationClose > p {
    max-width: 48ch;
    margin: 0;
    font-family: var(--font-ui-heading-th);
    font-size: clamp(1.1rem, 2vw, 1.35rem);
    font-weight: 600;
  }

  .locationClose > p:lang(en) {
    font-family: var(--font-ui-heading-en);
  }

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

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

  .testimonialSection {
    margin-top: clamp(56px, 8vh, 96px);
  }

  .subsectionTitle {
    margin: 0 0 var(--space-4);
    font-family: var(--font-ui-heading-th);
    font-size: 1.35rem;
    line-height: var(--leading-ui-heading-th);
  }

  .subsectionTitle:lang(en) {
    font-family: var(--font-ui-heading-en);
    line-height: var(--leading-ui-heading-en);
  }

  .testimonialCard {
    min-height: 100%;
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    scroll-snap-align: start;
  }

  .testimonialCard p {
    margin: 0;
  }

  .testimonialPerson {
    display: grid;
    grid-template-columns: 72px minmax(0, 1fr);
    align-items: center;
    gap: var(--space-3);
  }

  .testimonialPicture,
  .testimonialPortrait {
    display: block;
    width: 72px;
    height: 72px;
  }

  .testimonialPicture {
    overflow: hidden;
    border-radius: var(--radius-pill);
    background: var(--surface-soft);
  }

  .testimonialPortrait {
    object-fit: cover;
  }

  .testimonialName {
    font-weight: 600;
  }

  .testimonialOrg {
    color: var(--text-metadata);
    font-size: var(--type-label);
  }

  .testimonialCompany {
    width: auto;
    max-width: 132px;
    height: 44px;
    /* Pinned to the bottom so logos of different heights sit on one line
       across the row. */
    margin-top: auto;
    object-fit: contain;
    object-position: left center;
  }
}

@layer components {
  /* ------------------------------------------------------------------------
     Showcases
     ------------------------------------------------------------------------ */

  .showcaseSection,
  .showcaseSection .sectionTitle {
    color: var(--on-atmosphere);
  }

  .showcaseSection :is(.sectionLede, .eyebrow, .showcaseDate) {
    color: var(--on-atmosphere-2);
  }

  .showcaseDate {
    margin: var(--space-2) 0 0;
    font-size: var(--type-label);
  }

  .showcaseHero {
    position: relative;
    isolation: isolate;
    display: flex;
    flex-direction: column;
    margin: 0 0 var(--space-5);
    overflow: hidden;
    /* The outer hairline is the contract's second ink, not a page border: the
       section is a gradient and a page border would disappear into it. */
    border: 1px solid var(--on-atmosphere-2);
    border-radius: var(--radius-md);
    background: var(--surface-soft);
  }

  .showcaseHero picture {
    position: relative;
    z-index: 0;
    display: block;
    flex: none;
    aspect-ratio: 16 / 9;
    overflow: hidden;
    background: var(--surface-soft);
  }

  .showcaseHero img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
  }

  /* The caption is the figure's own foot — a card surface with card ink, not
     the atmosphere contract. It is inside the frame, so it does not read
     against the gradient. */
  .showcaseHero figcaption {
    position: relative;
    z-index: 2;
    flex: none;
    padding: var(--space-2) var(--space-3);
    border-top: 1px solid var(--border-emphasis);
    background: var(--surface-card);
    color: var(--text-secondary);
    font-size: var(--type-caption);
  }

  .showcaseGrid {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: var(--space-4);
  }

  .showcaseTile {
    min-width: 0;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    border-radius: var(--radius-md);
    background: var(--surface-card);
    color: var(--text-primary);
    text-decoration: none;
  }

  .showcaseTile picture {
    display: block;
    aspect-ratio: 4 / 3;
    overflow: hidden;
    background: var(--surface-soft);
  }

  .showcaseTile img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
  }

  .showcaseLabel {
    min-height: 66px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    background: var(--surface-card);
    color: var(--text-primary);
    font-weight: 600;
    line-height: 1.35;
  }

  .showcaseActions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-4);
    margin-top: var(--space-5);
    padding: 0;
  }

  .showcaseActions .textLink {
    color: var(--on-atmosphere);
  }

  .showcaseActionPrimary {
    gap: var(--space-2);
  }

  /* The second action must not take the atmosphere's filled interactive
     surface: two filled capsules side by side read as two primaries. */
  .showcaseSection.sceneAtmosphere .showcaseActionSecondary {
    border-color: var(--overlay-glass-border);
    background-color: transparent;
    background-image: none;
    color: var(--on-atmosphere);
  }

  .showcaseSection.sceneAtmosphere .showcaseActionSecondary:hover,
  .showcaseSection.sceneAtmosphere .showcaseActionSecondary:focus-visible {
    background: color-mix(in srgb, var(--on-atmosphere) 10%, transparent);
  }

  .showcaseSection .showcaseActionUtility {
    border-color: var(--overlay-glass-border);
    color: var(--on-atmosphere);
  }

  .showcaseSection .showcaseActionUtility:hover,
  .showcaseSection .showcaseActionUtility:focus-visible {
    background: color-mix(in srgb, var(--on-atmosphere) 10%, transparent);
  }

  /* ------------------------------------------------------------------------
     CityWiki and Landom — one two-column shape, two sections
     ------------------------------------------------------------------------ */

  .featureGrid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    align-items: center;
    gap: clamp(32px, 5vw, 72px);
  }

  .featureCopy {
    min-width: 0;
  }

  .featureCopy :is(.eyebrow, h2, p) {
    margin-top: 0;
  }

  .featureProof {
    display: flex;
    align-items: baseline;
    gap: var(--space-3);
    margin-block: var(--space-4);
  }

  .featureProof .number {
    color: var(--interaction-accent);
    font-size: clamp(2.4rem, 5vw, 4rem);
    line-height: 1;
  }

  .featureProof small {
    display: block;
    color: var(--text-metadata);
  }

  .chipList {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin-block: var(--space-4);
  }

  .chip {
    min-height: 40px;
    display: inline-flex;
    align-items: center;
    padding: var(--space-1) var(--space-3);
    border: 1px solid var(--border-default);
    border-radius: var(--radius-pill);
    background: var(--surface-card);
    color: var(--text-primary);
    font-size: var(--type-body-sm);
    font-weight: 600;
  }

  .citywikiMapNote {
    margin: var(--space-3) 0 0;
  }

  .landomSection,
  .landomSection :is(.sectionTitle, .featureCopy) {
    color: var(--on-atmosphere);
  }

  .landomSection :is(.sectionLede, .eyebrow, .featureProof small) {
    color: var(--on-atmosphere-2);
  }

  .landomSection .featureProof .number,
  .landomSection .textLink {
    color: var(--on-atmosphere);
  }

  .landomPaths {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-2);
    margin-top: var(--space-5);
  }

  .landomPath {
    min-height: 56px;
    min-width: 0;
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-3);
    border: 1px solid var(--overlay-glass-border);
    border-radius: var(--radius-sm);
    color: var(--on-atmosphere);
    font-weight: 600;
    line-height: 1.3;
    text-decoration: none;
  }

  .landomPathPrimary {
    border-color: transparent;
    background: var(--fg-interactive-surface);
    color: var(--fg-interactive-ink);
  }

  .landomPath:hover,
  .landomPath:focus-visible {
    background: color-mix(in srgb, var(--on-atmosphere) 10%, transparent);
  }

  /* The hover stays inside the contract's interactive pair. A theme surface
     here would be the page's dark blue under the pair's fixed dark ink. */
  .landomPathPrimary:hover,
  .landomPathPrimary:focus-visible {
    background: color-mix(
      in srgb,
      var(--fg-interactive-ink) 10%,
      var(--fg-interactive-surface)
    );
    color: var(--fg-interactive-ink);
  }

  .landomPathIndex {
    color: currentColor;
    font-family: var(--font-technical);
    font-size: var(--type-caption);
    font-weight: 400;
    opacity: 0.68;
  }

  /* ------------------------------------------------------------------------
     Our story
     ------------------------------------------------------------------------ */

  .storySignature {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    margin-bottom: var(--space-3);
  }

  .storySignature .eyebrow {
    margin: 0;
  }

  /* Two renditions of the approved mark stacked in one grid cell, one shown per
     theme. Neither is recoloured: the cream cut is its own approved asset, not
     a filter over the colour one. */
  .storyMark {
    width: 68px;
    height: 68px;
    display: grid;
    flex: none;
    place-items: center;
  }

  .storyMark img {
    grid-area: 1 / 1;
    width: 100%;
    height: 100%;
    object-fit: contain;
  }

  .storyMarkDark {
    display: none;
  }

  .storyList {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--space-4);
    padding: 0;
    margin: var(--space-6) 0;
    list-style: none;
  }

  .storyList li {
    display: grid;
    grid-template-columns: 28px minmax(0, 1fr);
    gap: var(--space-3);
    align-items: start;
  }

  .storyList .iconSymbol {
    color: var(--interaction-accent);
  }

  .storyDisclosure {
    margin: 0 0 var(--space-6);
    border-block: 1px solid var(--border-hairline);
  }

  .storyDisclosure summary {
    min-height: 56px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
    color: var(--text-primary);
    font-weight: 600;
    cursor: pointer;
    list-style: none;
  }

  .storyDisclosure summary::-webkit-details-marker {
    display: none;
  }

  /* A plus that becomes a cross when the section opens — the state is in the
     rotation, so there is no second glyph to keep in step. */
  .storyDisclosurePlus {
    position: relative;
    width: 22px;
    height: 22px;
    flex: none;
    transition: transform 260ms var(--motion-ease-settle);
  }

  .storyDisclosurePlus::before,
  .storyDisclosurePlus::after {
    content: "";
    position: absolute;
    top: 10px;
    left: 3px;
    width: 16px;
    height: 2px;
    border-radius: var(--radius-pill);
    background: currentColor;
  }

  .storyDisclosurePlus::after {
    transform: rotate(90deg);
  }

  .storyDisclosure[open] .storyDisclosurePlus {
    transform: rotate(45deg);
  }

  .storyDisclosureContent {
    padding: 0 0 var(--space-5);
  }

  .storyDisclosureContent p {
    margin: 0 0 var(--space-4);
  }

  .storyDisclosureContent p:last-child {
    margin-bottom: 0;
  }

  .storyRally {
    position: relative;
    width: fit-content;
    display: flex;
    flex-wrap: wrap;
    gap: 0.08em 0.34em;
    color: var(--interaction-accent);
    font-family: var(--font-display-en);
    font-size: clamp(1.25rem, 2.6vw, 1.75rem);
    font-weight: 700;
    line-height: 1.2;
  }

  .storyRally::after {
    content: "";
    position: absolute;
    right: 0;
    bottom: -0.28em;
    left: 0;
    height: 5px;
    border-radius: var(--radius-pill);
    background: linear-gradient(
      90deg,
      var(--energy-coral),
      var(--energy-yellow),
      var(--energy-mint),
      var(--energy-sky)
    );
    transform-origin: left;
  }

  /* ------------------------------------------------------------------------
     Stories and work in motion
     ------------------------------------------------------------------------ */

  .newsSection {
    background: var(--surface-alt);
  }

  .socialIcon {
    width: 22px;
    height: 22px;
    flex: none;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.65;
    stroke-linecap: round;
    stroke-linejoin: round;
  }

  .socialFeedGrid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    align-items: start;
    gap: var(--space-5);
    width: min(100%, 1180px);
    margin-inline: auto;
  }

  .socialFeedCard {
    width: 100%;
    min-width: 0;
    margin: 0;
    overflow: hidden;
    border: 1px solid var(--border-default);
    border-radius: var(--radius-md);
    background: var(--surface-card);
  }

  /* The two tall embeds take the full row; the two square ones pair. */
  .socialFeedCardTiktok,
  .socialFeedCardLinkedin {
    grid-column: 1 / -1;
  }

  .socialFeedCardHeader {
    min-height: 60px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    padding: var(--space-2) var(--space-3) var(--space-2) var(--space-4);
    border-bottom: 1px solid var(--border-hairline);
    font-weight: 600;
  }

  .socialFeedCardHeader > span,
  .socialFeedCardHeader > a {
    display: inline-flex;
    align-items: center;
  }

  .socialFeedCardHeader > span {
    min-width: 0;
    gap: var(--space-2);
  }

  .socialFeedCardHeader > a {
    width: 44px;
    height: 44px;
    flex: none;
    justify-content: center;
    border-radius: var(--radius-pill);
    color: var(--text-primary);
    text-decoration: none;
  }

  .socialFeedCardHeader > a:hover,
  .socialFeedCardHeader > a:focus-visible {
    background: var(--surface-soft);
  }

  .socialEmbed {
    display: grid;
    place-items: start center;
    background: linear-gradient(135deg, var(--surface-soft), var(--surface-card));
    /* The embedded documents pick their own theme from this; the page cannot
       style inside them. */
    color-scheme: light dark;
  }

  .socialEmbed iframe {
    width: 100%;
    display: block;
    border: 0;
    background: var(--surface-card);
    color-scheme: inherit;
  }

  /* Each network's embed reports a different intrinsic height and none of them
     resize, so the box is fixed per network rather than shared. */
  .socialEmbedFacebook,
  .socialEmbedFacebook iframe {
    min-height: 680px;
    height: 680px;
  }

  .socialEmbedFacebook iframe {
    width: 100%;
    max-width: 500px;
  }

  .socialEmbedInstagram {
    min-height: 0;
  }

  .socialEmbedInstagram iframe {
    min-height: 0;
    height: auto;
    aspect-ratio: 1 / 1.14;
  }

  .socialEmbedLinkedin,
  .socialEmbedLinkedin iframe {
    min-height: 1100px;
    height: 1100px;
  }

  .socialEmbedTiktok {
    min-height: 0;
    align-items: start;
    padding: var(--space-3);
  }

  /* TikTok's script replaces the blockquote with its own player and writes the
     width and margin it wants as inline style, so the constraint has to reach a
     class this module does not own and has to outrank an inline declaration. */
  .socialEmbedTiktok iframe,
  .socialEmbedTiktok .tiktok-embed {
    width: 100% !important;
    min-width: 288px;
    max-width: 720px !important;
    margin: 0 auto !important;
  }
}

@layer components {
  /* ------------------------------------------------------------------------
     Direct contact
     ------------------------------------------------------------------------ */

  .contactFooter {
    padding: 0;
    color: var(--on-atmosphere);
  }

  /* The four energy colours as a measured rule across the top of the footer —
     the page's one decorative mark, and the only place the full set appears. */
  .measureLine {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    height: 8px;
  }

  .measureLine span:nth-child(1) {
    background: var(--energy-coral);
  }

  .measureLine span:nth-child(2) {
    background: var(--energy-yellow);
  }

  .measureLine span:nth-child(3) {
    background: var(--energy-mint);
  }

  .measureLine span:nth-child(4) {
    background: var(--energy-sky);
  }

  .contactGrid {
    display: grid;
    grid-template-columns: minmax(0, 1.12fr) minmax(280px, 0.88fr);
    gap: clamp(40px, 6vw, 88px);
    padding-top: clamp(52px, 8vh, 88px);
    padding-bottom: clamp(48px, 7vh, 72px);
  }

  .contactTitle {
    max-width: 15ch;
    margin: 0 0 var(--space-3);
    color: var(--on-atmosphere);
    font-family: var(--font-display-th);
    font-size: clamp(2rem, 4vw, 3.25rem);
    /* Same UI-heading leading as `.sectionTitle:lang(th)`: this is a section
       heading in Thai, at the same size. */
    line-height: var(--leading-ui-heading-th);
    text-wrap: balance;
  }

  .contactTitle:lang(en) {
    font-family: var(--font-display-en);
    letter-spacing: -0.02em;
    line-height: 1.08;
  }

  .contactLede {
    max-width: 52ch;
    margin: 0 0 var(--space-5);
    color: var(--on-atmosphere-2);
  }

  .contactForm {
    max-width: 600px;
    display: grid;
    gap: var(--space-4);
  }

  .formField {
    min-width: 0;
    display: grid;
    gap: 6px;
  }

  .formField label,
  .formFieldLabel {
    color: var(--on-atmosphere);
    font-size: var(--type-label);
    font-weight: 600;
  }

  .formRow {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-4);
  }

  /* Controls sit on the atmosphere gradient, so they take the contract's
     interactive pair rather than the page surface — a card surface here would
     be a different white in each theme against a fixed ground. */
  .fieldControl,
  .topicPickerButton {
    width: 100%;
    min-height: 48px;
    padding: 12px 14px;
    border: 1px solid var(--border-default);
    border-radius: var(--radius-sm);
    background: var(--fg-interactive-surface);
    color: var(--fg-interactive-ink);
    font: inherit;
  }

  textarea.fieldControl {
    min-height: 148px;
    resize: vertical;
  }

  .topicPicker {
    position: relative;
  }

  .topicPickerButton {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    text-align: left;
    cursor: pointer;
  }

  .topicPickerButton .iconSymbol {
    flex: none;
    transition: transform var(--motion-duration-state) var(--motion-ease-settle);
  }

  .topicPickerChevron {
    transform: rotate(0deg);
  }

  .topicPickerButton[aria-expanded="true"] .topicPickerChevron {
    transform: rotate(180deg);
  }

  .topicPickerList {
    position: absolute;
    top: calc(100% + 6px);
    left: 0;
    z-index: var(--z-modal);
    width: 100%;
    max-height: min(360px, 52vh);
    overflow-y: auto;
    padding: var(--space-1);
    margin: 0;
    border: 1px solid var(--border-default);
    border-radius: var(--radius-md);
    background: var(--surface-raised);
    box-shadow: var(--elevation-md);
    list-style: none;
  }

  .topicPickerOption {
    width: 100%;
    min-height: 46px;
    display: flex;
    align-items: center;
    padding: var(--space-2) var(--space-3);
    border: 0;
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--text-primary);
    font: inherit;
    font-weight: 600;
    text-align: left;
    cursor: pointer;
  }

  .topicPickerOption[aria-selected="true"] {
    background: var(--surface-raised);
    color: var(--text-primary);
    box-shadow: var(--elevation-xs);
  }

  .topicPickerOption:hover,
  .topicPickerOption:focus-visible {
    background: var(--surface-soft);
    color: var(--text-primary);
    box-shadow: none;
  }

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

  .contactForm button[type="submit"][disabled] {
    cursor: wait;
    opacity: 0.72;
  }

  /* Reserves its own line height so the row does not jump when the message
     appears. */
  .formStatus {
    min-height: 1.5em;
    margin: 0;
    color: var(--on-atmosphere);
    font-size: var(--type-label);
    font-weight: 600;
  }

  .contactDetails {
    display: flex;
    flex-direction: column;
    gap: var(--space-5);
  }

  .contactDetails p {
    margin: 0;
  }

  .contactCompany {
    font-weight: 600;
    color: var(--on-atmosphere);
    margin-bottom: var(--space-2);
  }

  .contactDetailsSecondary {
    color: var(--on-atmosphere-2);
  }

  .contactEmail {
    min-height: 44px;
    width: fit-content;
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    color: var(--on-atmosphere);
    font-weight: 600;
    text-decoration: none;
  }

  .contactEmailLabel {
    text-decoration: underline;
    text-decoration-thickness: 1px;
    text-underline-offset: 0.22em;
  }

  .contactEmail:hover,
  .contactEmail:focus-visible {
    color: var(--on-atmosphere);
  }

  .contactEmail:hover .contactEmailLabel,
  .contactEmail:focus-visible .contactEmailLabel {
    text-decoration-thickness: 2px;
  }

  .mapLink {
    min-height: 44px;
    width: fit-content;
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    margin-top: var(--space-3);
    padding-inline: var(--space-3);
    border: 1px solid var(--overlay-glass-border);
    border-radius: var(--radius-pill);
    color: var(--on-atmosphere);
    text-decoration: none;
  }

  .mapLink:hover,
  .mapLink:focus-visible {
    background: color-mix(in srgb, currentColor 10%, transparent);
  }

  .socialLinks {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
  }

  .socialLinks a,
  .footerLinks a {
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    color: var(--on-atmosphere);
  }

  .socialLinks a {
    width: 44px;
    min-width: 44px;
    height: 44px;
    justify-content: center;
    gap: 0;
    border: 1px solid var(--overlay-glass-border);
    border-radius: var(--radius-pill);
    text-decoration: none;
  }

  .socialLinks a:hover,
  .socialLinks a:focus-visible {
    background: color-mix(in srgb, currentColor 10%, transparent);
  }

  .footerLinks {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    padding-top: var(--space-4);
    border-top: 1px solid var(--overlay-glass-border);
  }

  /* Below the gradient again: the legal line belongs to the page, not to the
     atmosphere above it. */
  .footerBottom {
    border-top: 1px solid var(--border-hairline);
    background: var(--surface-canvas);
    color: var(--text-primary);
  }

  .footerBottomInner {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
    padding-top: var(--space-4);
    padding-bottom: var(--space-5);
  }

  .footerIdentity {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-3) var(--space-5);
    color: var(--text-secondary);
    font-size: var(--type-label);
  }

  .footerBrand {
    min-height: 54px;
    display: inline-flex;
    align-items: center;
    gap: 10px;
    text-decoration: none;
  }

  .footerBrand img {
    width: 54px;
    height: 54px;
    object-fit: contain;
  }

  /* The logo grey, which only ever appears inside an approved asset — here the
     wordmark set beside the symbol it belongs to. */
  .footerBrand span {
    color: #757575;
    font-family: var(--font-display-en);
    font-size: 23px;
    font-weight: 700;
    letter-spacing: -0.02em;
    line-height: 1;
  }
}

/* --------------------------------------------------------------------------
   Theme-dependent rules, keyed to MUI's `colorSchemeSelector` like
   `globals.css`. The media query covers the moment before the attribute is
   written; the `:not()` keeps an explicit light choice from being overridden.
   -------------------------------------------------------------------------- */

@layer components {
  @media (prefers-color-scheme: dark) {
    :root:not([data-color-scheme="light"]) .storyMarkLight {
      display: none;
    }

    :root:not([data-color-scheme="light"]) .storyMarkDark {
      display: block;
    }

    :root:not([data-color-scheme="light"]) .socialEmbed {
      background: var(--surface-soft);
      color-scheme: dark;
    }

    :root:not([data-color-scheme="light"])
      .topicPickerOption[aria-selected="true"] {
      background: color-mix(
        in srgb,
        var(--interaction-accent) 16%,
        var(--surface-raised)
      );
      box-shadow: none;
    }

    :root:not([data-color-scheme="light"])
      .topicPickerOption:is(:hover, :focus-visible) {
      background: color-mix(
        in srgb,
        var(--interaction-accent) 34%,
        var(--surface-raised)
      );
      color: var(--text-primary);
    }
  }

  :root[data-color-scheme="dark"] .storyMarkLight {
    display: none;
  }

  :root[data-color-scheme="dark"] .storyMarkDark {
    display: block;
  }

  :root[data-color-scheme="dark"] .socialEmbed {
    background: var(--surface-soft);
    color-scheme: dark;
  }

  :root[data-color-scheme="dark"]
    .topicPickerOption[aria-selected="true"] {
    background: color-mix(
      in srgb,
      var(--interaction-accent) 16%,
      var(--surface-raised)
    );
    box-shadow: none;
  }

  :root[data-color-scheme="dark"]
    .topicPickerOption:is(:hover, :focus-visible) {
    background: color-mix(
      in srgb,
      var(--interaction-accent) 34%,
      var(--surface-raised)
    );
    color: var(--text-primary);
  }
}

@layer motion {
  /* Everything is visible by default; `motionReady` is what hides what is
     about to be revealed, once the observer is running. */
  .reveal {
    opacity: 1;
    transform: none;
  }

  /* A marker `useReveal` reads, set on elements that are already a grid or a
     flex row. It has to appear here to reach the module's exports, so the one
     declaration is inert rather than something that could win over the layout
     rule underneath. */
  .revealGroup {
    --reveal-group: 1;
  }

  .motionReady .reveal:not(.isRevealed) {
    opacity: 0;
    transform: translateY(32px) scale(0.985);
  }

  .motionReady .revealFromLeft:not(.isRevealed) {
    transform: translateX(-36px);
  }

  .motionReady .revealFromRight:not(.isRevealed) {
    transform: translateX(36px);
  }

  .motionReady .reveal {
    transition:
      opacity 760ms var(--motion-ease-enter),
      transform 920ms var(--motion-ease-settle);
    transition-delay: var(--reveal-delay, 0ms);
  }

  .lazyMedia {
    opacity: 1;
  }

  .motionReady .lazyMedia:not(.isLoaded) {
    opacity: 0;
  }

  .motionReady .lazyMedia {
    transition: opacity 900ms var(--motion-ease-enter);
  }

  /* A slow drift on a still image, driven from the scroll position rather than
     a timer, so it only moves while the reader is moving. */
  .staticParallax {
    --static-parallax-y: 0px;
    --static-parallax-scale: 1.1;
  }

  .staticParallaxLayer {
    transform: translate3d(0, var(--static-parallax-y), 0)
      scale(var(--static-parallax-scale));
    transform-origin: center;
    transition: transform 180ms linear;
  }

  .staticParallax.isParallaxActive .staticParallaxLayer {
    will-change: transform;
  }

  .staticParallax:hover {
    --static-parallax-scale: 1.12;
  }

  .storyDisclosure[open] .storyStep {
    animation: home-story-step-in 820ms var(--motion-ease-enter) both;
  }

  .storyDisclosure[open] .storyStep:nth-child(1) {
    animation-delay: 80ms;
  }

  .storyDisclosure[open] .storyStep:nth-child(2) {
    animation-delay: 260ms;
  }

  .storyDisclosure[open] .storyStep:nth-child(3) {
    animation-delay: 480ms;
  }

  .storyDisclosure[open] .storyRally::after {
    animation: home-rally-line 900ms 940ms var(--motion-ease-enter) both;
  }

  .storyDisclosure[open] .storyRally span {
    animation: home-rally-word 760ms var(--motion-ease-settle) both;
  }

  .storyDisclosure[open] .storyRally span:nth-child(1) {
    animation-delay: 600ms;
  }

  .storyDisclosure[open] .storyRally span:nth-child(2) {
    animation-delay: 720ms;
  }

  .storyDisclosure[open] .storyRally span:nth-child(3) {
    animation-delay: 840ms;
  }

  .storyDisclosure[open] .storyRally span:nth-child(4) {
    animation-delay: 960ms;
  }

  @keyframes home-story-step-in {
    from {
      opacity: 0;
      transform: translateY(18px);
    }
    to {
      opacity: 1;
      transform: translateY(0);
    }
  }

  @keyframes home-rally-word {
    0% {
      opacity: 0;
      transform: translateY(18px) rotate(-2deg) scale(0.96);
    }
    70% {
      opacity: 1;
      transform: translateY(-2px) rotate(0.4deg) scale(1.02);
    }
    100% {
      opacity: 1;
      transform: none;
    }
  }

  @keyframes home-rally-line {
    from {
      opacity: 0;
      transform: scaleX(0);
    }
    to {
      opacity: 1;
      transform: scaleX(1);
    }
  }
}

@layer responsive {
  @media (max-width: 1080px) {
    .solutionsGrid {
      grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .solutionsGrid .solutionCardFeatured,
    .solutionsGrid .solutionCardStandard {
      grid-column: auto;
    }

    .solutionsGrid .solutionCard:last-child {
      grid-column: 1 / -1;
    }

    .showcaseGrid {
      grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .loopRail {
      grid-auto-columns: minmax(300px, 48%);
    }

    .socialFeedGrid {
      grid-template-columns: 1fr;
      gap: var(--space-4);
    }

    .socialFeedCardTiktok,
    .socialFeedCardLinkedin {
      grid-column: 1;
    }
  }

  @media (max-width: 700px) {
    .hero {
      grid-template-columns: 1fr;
      grid-template-rows: minmax(0, 56%) minmax(0, 44%);
    }

    .heroCopy {
      padding: 18px 20px;
    }

    .heroEyebrow {
      margin-bottom: var(--space-2);
      font-size: var(--type-caption);
    }

    .hero h1 {
      margin-bottom: var(--space-2);
      font-size: clamp(1.75rem, 8.5vw, 2.5rem);
    }

    .heroSubheadline {
      margin-bottom: var(--space-2);
      font-size: clamp(0.98rem, 4.8vw, 1.25rem);
    }

    .heroDescription {
      margin-bottom: var(--space-2);
      font-size: 0.875rem;
      line-height: 1.45;
    }

    .heroLink {
      min-height: 44px;
      font-size: var(--type-body-sm);
    }

    .proofGrid {
      grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .proofCard {
      min-height: 96px;
      padding: var(--space-3);
    }

    .pillar,
    .featureGrid,
    .contactGrid {
      grid-template-columns: 1fr;
    }

    .pillarCopy,
    .pillarCopyLeft,
    .pillarCopyRight {
      padding: 36px 24px;
    }

    /* Stacked, the copy comes first in every pillar — the mirrored order is a
       two-column device and reads as a mistake in one column. */
    .pillarLocation .mediaFigure {
      order: 2;
    }

    .pillarLocation .pillarCopy {
      order: 1;
    }

    .pillarLiving .mediaCanvas {
      aspect-ratio: 4 / 5;
    }

    .livingVideo {
      object-position: 50% 18%;
    }

    .solutionsGrid,
    .storyList,
    .landomPaths {
      grid-template-columns: 1fr;
    }

    .solutionsGrid .solutionCardFeatured,
    .solutionsGrid .solutionCardStandard,
    .solutionsGrid .solutionCard:last-child {
      grid-column: 1;
      min-height: 0;
    }

    .serviceRoute {
      grid-template-columns: 1fr;
    }

    .serviceRouteMedia img {
      min-height: 0;
      aspect-ratio: 4 / 3;
    }

    .serviceRouteAction {
      width: 100%;
    }

    .storyMark {
      width: 58px;
      height: 58px;
    }

    .loopRail {
      grid-auto-columns: minmax(280px, 88%);
    }

    /* The four tiles become a rail of their own at this width rather than a
       2×2 grid of thumbnails too small to read. */
    .showcaseGrid {
      display: grid;
      grid-auto-flow: column;
      grid-template-columns: none;
      grid-auto-columns: minmax(270px, 86%);
      overflow-x: auto;
      padding-bottom: var(--space-4);
      scroll-snap-type: x mandatory;
    }

    .showcaseTile {
      scroll-snap-align: start;
    }

    .formRow {
      grid-template-columns: 1fr;
    }

    .contactGrid {
      gap: var(--space-7);
    }
  }

  @media (max-width: 390px) {
    .heroDescription {
      display: none;
    }

    .hero {
      grid-template-rows: minmax(0, 52%) minmax(0, 48%);
    }

    .proofCard {
      grid-template-columns: 1fr;
      gap: var(--space-1);
    }

    .proofValue {
      font-size: 2rem;
    }
  }

  /* A short desktop window: the first screen keeps the headline and the link
     and drops what is repeated further down. */
  @media (max-height: 620px) and (min-width: 701px) {
    .heroEyebrow,
    .heroDescription {
      display: none;
    }

    .heroCopy {
      padding-block: 20px;
    }

    .hero h1 {
      font-size: clamp(2rem, 7vh, 3rem);
    }
  }

  @media (max-width: 700px) and (max-height: 700px) and (orientation: portrait) {
    .hero {
      grid-template-rows: minmax(0, 62%) minmax(0, 38%);
    }

    .heroEyebrow,
    .heroDescription {
      display: none;
    }

    .heroCopy {
      padding: 12px 18px;
    }

    .hero h1 {
      font-size: clamp(1.45rem, 7.5vw, 1.9rem);
    }

    .heroSubheadline {
      font-size: clamp(0.875rem, 4.2vw, 1.05rem);
    }
  }

  @media (max-width: 700px) and (orientation: landscape) {
    .hero {
      grid-template-columns: minmax(0, 1.08fr) minmax(0, 0.92fr);
      grid-template-rows: 1fr;
    }

    .heroEyebrow,
    .heroDescription {
      display: none;
    }

    .hero h1 {
      font-size: clamp(1.6rem, 7vh, 2.3rem);
    }

    .heroSubheadline {
      font-size: clamp(0.9rem, 4vh, 1.15rem);
    }
  }

  /* The kill switch. Arrival, parallax and the hero pan are decoration. */
  @media (prefers-reduced-motion: reduce) {
    .home *,
    .home *::before,
    .home *::after {
      animation-duration: 0.01ms;
      animation-iteration-count: 1;
      transition-duration: 0.01ms;
      transition-delay: 0ms;
    }

    .reveal,
    .motionReady .reveal,
    .motionReady .lazyMedia {
      opacity: 1;
      transform: none;
    }

    .heroMedia img,
    .heroMedia picture {
      animation: none;
      transform: none;
      will-change: auto;
    }

    .staticParallaxLayer,
    .staticParallax:hover .staticParallaxLayer {
      transform: none;
      will-change: auto;
    }

    .solutionCard:hover .solutionCardMedia img,
    .locationQuestion:hover .locationQuestionMedia img {
      transform: none;
    }
  }
}

/* ==========================================================================
   Motifs.

   One drawing per section in the mark's own vocabulary, the mark itself over
   the hero photograph, and the two product lockups that assemble themselves.

   Every one of them renders its FINISHED state, and `isPlaying` — set once,
   when the drawing arrives — is the only thing that starts it. So there is no
   reduced-motion kill switch here: reduced motion never sets the class, and
   the picture is already right.
   ========================================================================== */

@layer components {
  .motif {
    width: clamp(112px, 12vw, 156px);
    max-width: 100%;
    margin: 0 0 var(--space-3);
    color: var(--brand-blue);
    line-height: 0;

    /* The mark's priority wedge is not a token: it is derived from two of
       them, never a sampled hex. */
    --motif-wedge: color-mix(in lch, var(--energy-sky) 48%, var(--brand-blue));

    /* The character curve of the set — overshoots about 10% past the target,
       then settles. Not a design-system easing. */
    --motif-ease-pop: cubic-bezier(0.34, 1.56, 0.64, 1);
  }

  .motif svg {
    display: block;
    width: 100%;
    height: auto;
    aspect-ratio: 2 / 1;
  }

  /* A motif whose finale steps a piece outside its own box. */
  .motifStage {
    width: clamp(160px, 14vw, 180px);
    overflow: visible;
  }

  .motifTrail {
    margin: var(--space-3) 0 0 auto;
  }

  .motifProof {
    width: clamp(104px, 10vw, 136px);
  }

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

  .motifContact {
    width: clamp(120px, 13vw, 168px);
  }

  .motifResolution {
    margin: 0 auto var(--space-4);
  }

  /* The mark over the hero photograph. The pair of shadows is what holds it
     off the skyline: a hairline of page cream under the edge, then a soft
     drop. */
  .heroSkyLogo {
    position: absolute;
    z-index: 1;
    top: clamp(28px, 8%, 92px);
    left: 50%;
    width: min(78%, 720px);
    margin: 0;
    filter: drop-shadow(0 1px 1px rgba(252, 252, 250, 0.92))
      drop-shadow(0 10px 28px rgba(17, 25, 29, 0.2));
    transform: translateX(-50%);
    pointer-events: none;
  }

  /* ------------------------------------------------------------------------
     The two product lockups
     ------------------------------------------------------------------------ */

  .citychatLogoStage {
    display: grid;
    width: 100%;
    aspect-ratio: 494 / 106;
    line-height: 0;
  }

  /* The artwork and the bubbles drawn over it, in one cell. */
  .citychatLogoStage > * {
    grid-area: 1 / 1;
    display: block;
    width: 100%;
    height: 100%;
    object-fit: contain;
  }

  .ijjiLogoStage {
    flex: none;
    display: grid;
    place-items: center;
    width: 64px;
    height: 64px;
    max-width: 100%;
    aspect-ratio: 1;
    line-height: 0;
  }

  .ijjiLogoStage svg {
    display: block;
    width: 100%;
    height: auto;
    /* A head at full stretch reaches past the frame. */
    overflow: visible;
  }
}

@layer motion {
  /* The resting state of everything below lives in the markup; these rules
     only fix what its transform is measured against. */
  .motifStep {
    transform: translate(12px, -12px);
    transform-box: view-box;
    transform-origin: 300px 150px;
  }

  .motifDisc {
    transform-box: view-box;
    transform-origin: 300px 150px;
  }

  .motifSweep,
  .motifPulse {
    transform-box: view-box;
    transform-origin: 300px 200px;
  }

  .motifSway {
    transform-box: view-box;
  }

  .motifGrowX {
    transform-box: fill-box;
    transform-origin: left center;
  }

  .motifGrowXc {
    transform-box: fill-box;
    transform-origin: center;
  }

  .motifRadial {
    transform-box: view-box;
    transform-origin: 80px 260px;
  }

  .motifPin {
    transform-box: view-box;
    transform-origin: 300px 286px;
  }

  .motifPop,
  .motifWedge,
  .motifFocus {
    transform-box: view-box;
    transform-origin: 300px 143px;
  }

  .motif.isPlaying .motifDraw {
    animation: home-motif-draw 360ms var(--motion-ease-enter)
      var(--motif-delay, 0ms) both;
  }

  .motif.isPlaying .motifDraw.motifSweep {
    animation:
      home-motif-draw 360ms var(--motion-ease-enter) var(--motif-delay, 0ms)
        both,
      home-motif-sweep 520ms var(--motif-ease-pop) var(--motif-delay, 0ms) both;
  }

  .motif.isPlaying .motifGrowX {
    animation: home-motif-grow-x var(--motif-duration, 360ms)
      var(--motif-ease, var(--motion-ease-enter)) var(--motif-delay, 0ms) both;
  }

  .motif.isPlaying .motifGrowXc {
    animation: home-motif-grow-x 360ms var(--motion-ease-settle)
      var(--motif-delay, 0ms) both;
  }

  .motif.isPlaying .motifRadiate {
    animation: home-motif-radiate 760ms var(--motif-ease-pop)
      var(--motif-delay, 0ms) both;
  }

  .motif.isPlaying .motifStep {
    animation:
      home-motif-fade 760ms var(--motion-ease-enter) both,
      home-motif-wiggle 620ms var(--motion-ease-settle) 600ms both;
  }

  .motif.isPlaying .motifPulse {
    animation: home-motif-pulse 420ms var(--motion-ease-settle)
      var(--motif-delay, 0ms) both;
  }

  .motif.isPlaying .motifLand {
    animation: home-motif-land 560ms var(--motif-ease-pop)
      var(--motif-delay, 0ms) both;
  }

  .motif.isPlaying .motifSway {
    animation: home-motif-sway 760ms var(--motion-ease-settle)
      var(--motif-delay, 0ms) both;
  }

  .motif.isPlaying .motifDrop {
    animation: home-motif-drop 920ms linear var(--motif-delay, 120ms) both;
  }

  .motif.isPlaying .motifSettle {
    animation: home-motif-settle 760ms var(--motion-ease-enter) 700ms both;
  }

  .motif.isPlaying .motifPin {
    animation: home-motif-pin-fall 700ms linear both;
  }

  .motif.isPlaying .motifPop {
    animation: home-motif-lay 520ms var(--motif-ease-pop)
      var(--motif-delay, 0ms) both;
  }

  .motif.isPlaying .motifWedge {
    animation: home-motif-wedge-pop 600ms var(--motion-ease-settle)
      var(--motif-delay, 0ms) both;
  }

  .motif.isPlaying .motifFocus {
    animation: home-motif-focus-out 900ms var(--motion-ease-settle)
      var(--motif-delay, 0ms) both;
  }

  @keyframes home-motif-draw {
    from {
      stroke-dashoffset: 90;
    }
    to {
      stroke-dashoffset: 0;
    }
  }

  @keyframes home-motif-fade {
    from {
      opacity: 0;
    }
    to {
      opacity: 1;
    }
  }

  @keyframes home-motif-grow-x {
    from {
      transform: scaleX(0);
    }
    to {
      transform: scaleX(1);
    }
  }

  @keyframes home-motif-radiate {
    from {
      opacity: 0;
      transform: scale(0.82);
    }
    to {
      opacity: 1;
      transform: none;
    }
  }

  /* The priority slice wriggles free of the disc and steps out. */
  @keyframes home-motif-wiggle {
    0% {
      transform: translate(0, 0) rotate(0deg);
    }
    60% {
      transform: translate(14px, -14px) rotate(-5deg);
    }
    80% {
      transform: translate(12px, -12px) rotate(2deg);
    }
    100% {
      transform: translate(12px, -12px) rotate(0deg);
    }
  }

  /* The dial's needle, sweeping in under each arc as it draws. */
  @keyframes home-motif-sweep {
    from {
      transform: rotate(-12deg);
    }
    to {
      transform: none;
    }
  }

  @keyframes home-motif-pulse {
    0% {
      transform: none;
    }
    45% {
      transform: scale(1.06);
    }
    100% {
      transform: none;
    }
  }

  @keyframes home-motif-land {
    from {
      opacity: 0;
      transform: translateY(-30px);
    }
    to {
      opacity: 1;
      transform: none;
    }
  }

  @keyframes home-motif-sway {
    0% {
      transform: none;
    }
    30% {
      transform: rotate(3deg);
    }
    65% {
      transform: rotate(-2deg);
    }
    100% {
      transform: none;
    }
  }

  @keyframes home-motif-settle {
    from {
      opacity: 0;
      transform: translateY(-24px);
    }
    to {
      opacity: 1;
      transform: none;
    }
  }

  /* Squash and stretch: a seed falls, lands, bounces once. The fall and the
     rebound are different curves, so they sit on the frames rather than on
     the animation. */
  @keyframes home-motif-drop {
    0% {
      opacity: 0;
      transform: translateY(-56px);
      animation-timing-function: cubic-bezier(0.45, 0, 0.85, 0.5);
    }
    12% {
      opacity: 1;
    }
    52% {
      transform: translateY(0);
      animation-timing-function: cubic-bezier(0.2, 0.7, 0.4, 1);
    }
    72% {
      transform: translateY(-10px);
      animation-timing-function: cubic-bezier(0.5, 0, 0.8, 0.6);
    }
    100% {
      transform: none;
    }
  }

  /* The pin falls in from above the frame, lands on its tip, squashes, springs
     back. */
  @keyframes home-motif-pin-fall {
    0% {
      opacity: 0;
      transform: translateY(-210px);
      animation-timing-function: cubic-bezier(0.45, 0, 0.85, 0.5);
    }
    10% {
      opacity: 1;
    }
    55% {
      transform: translateY(0) scale(1, 1);
      animation-timing-function: cubic-bezier(0.2, 0.7, 0.4, 1);
    }
    68% {
      transform: scale(1.13, 0.86);
      animation-timing-function: cubic-bezier(0.4, 0, 0.6, 1);
    }
    84% {
      transform: scale(0.97, 1.05);
      animation-timing-function: cubic-bezier(0.4, 0, 0.6, 1);
    }
    100% {
      transform: none;
    }
  }

  /* A colour piece is laid down like a translucent sheet: it slides in along
     its own bisector, fades up, and settles with a small overshoot. */
  @keyframes home-motif-lay {
    0% {
      opacity: 0;
      transform: translate(var(--motif-dx, 0px), var(--motif-dy, -22px))
        scale(1.1);
    }
    100% {
      opacity: 1;
      transform: none;
    }
  }

  @keyframes home-motif-wedge-pop {
    0% {
      opacity: 0;
      transform: scale(0) rotate(-24deg);
    }
    55% {
      opacity: 1;
      transform: scale(1.16) rotate(5deg);
    }
    78% {
      transform: scale(0.96) rotate(-2deg);
    }
    100% {
      transform: none;
    }
  }

  /* The finale. Each sky layer steps forward along the 22.5° bisector by its
     own distance; only the wedge also swells and wiggles. They all settle
     back, and nothing else on the mark changes. */
  @keyframes home-motif-focus-out {
    0% {
      transform: none;
    }
    38% {
      transform: translate(var(--motif-fx, 33.26px), var(--motif-fy, -13.78px))
        scale(var(--motif-focus-scale, 1))
        rotate(var(--motif-focus-rotate, 0deg));
    }
    58% {
      transform: translate(var(--motif-fx, 33.26px), var(--motif-fy, -13.78px))
        scale(var(--motif-focus-scale, 1))
        rotate(calc(-1 * var(--motif-focus-rotate, 0deg)));
    }
    76% {
      transform: translate(var(--motif-fx, 33.26px), var(--motif-fy, -13.78px))
        scale(var(--motif-focus-scale, 1)) rotate(0deg);
    }
    100% {
      transform: none;
    }
  }

  /* ------------------------------------------------------------------------
     The CityChat bubbles. Each pops in off its own tail, then the three dots
     inside it hop in turn.
     ------------------------------------------------------------------------ */

  .citychatBubble {
    transform-box: fill-box;
    transform-origin: 20% 100%;
  }

  .citychatDots,
  .citychatDot {
    transform-box: fill-box;
    transform-origin: center;
  }

  .citychatLogoBubbles.isPlaying :is(.citychatBubble, .citychatDots) {
    animation: home-citychat-pop 420ms var(--motion-ease-settle)
      var(--motif-delay, 0ms) both;
  }

  .citychatLogoBubbles.isPlaying .citychatDot {
    animation: home-citychat-dot 360ms var(--motion-ease-settle)
      var(--motif-delay, 0ms) both;
  }

  @keyframes home-citychat-pop {
    0% {
      opacity: 0;
      transform: scale(0.3);
    }
    60% {
      opacity: 1;
      transform: scale(1.15);
    }
    100% {
      opacity: 1;
      transform: scale(1);
    }
  }

  @keyframes home-citychat-dot {
    0% {
      opacity: 0;
      transform: translateY(10px);
    }
    55% {
      opacity: 1;
      transform: translateY(-5px);
    }
    100% {
      opacity: 1;
      transform: none;
    }
  }
}

@layer responsive {
  @media (max-width: 700px) {
    .heroSkyLogo {
      top: clamp(16px, 6%, 34px);
      width: min(84%, 420px);
    }
  }
}
