/* ==========================================================================
   EU Gold Mining Inc. — site stylesheet
   --------------------------------------------------------------------------
   One stylesheet for every page. Load it from each page's <head>:

       <link rel="stylesheet" href="css/eugold.css">

   Conventions
   -----------
   Naming      ls-block__element--modifier, plus is-* for states set by JS
               or by the page (is-active, is-light, is-compact).
   Layers      Order is declared once, below. Later layers win regardless of
               where the rule sits in the file, so a page-scoped tweak never
               has to fight a component and nothing needs !important.
               `responsive` is last, so every breakpoint lives in one block at
               the foot of the file and always wins. One breakpoint carries
               the layout change: 900px, where the nav becomes a drawer and
               the article/aside pair stacks.
   Theming     Components that appear on both light and dark bands read their
               colours from custom properties set by a surface class, rather
               than duplicating the whole component per background.
   Values      Colours, type sizes and spacing come from the token block. Add
               a token before hard-coding a new value, so the palette stays
               countable.
   ========================================================================== */

@layer tokens, base, layout, components, pages, utilities, responsive, motion;

/* ==========================================================================
   TOKENS
   ========================================================================== */
@layer tokens {
  :root {
    /* --- Brand surfaces ------------------------------------------------- */
    --ls-abyss: #061c24;   /* deepest teal: footer, hero gradient tail      */
    --ls-deep: #08262f;    /* page backdrop, dark bands                     */
    --ls-teal: #0b3543;    /* mid dark band                                 */
    --ls-teal-mid: #0d4759;/* link hover on light, gradient head            */
    --ls-paper: #fbfaf6;   /* light band                                    */
    --ls-white: #ffffff;

    /* --- Brand gold ------------------------------------------------------ */
    --ls-gold: #e7cf8f;        /* accent on dark: headings, buttons, rules  */
    --ls-gold-deep: #cbaa5e;   /* kickers on dark, hairline rules           */
    --ls-gold-light: #f3e3b4;  /* hover lift on dark                        */
    --ls-gold-ink: #8a6e31;    /* the AA-safe gold for text on light        */

    /* --- Ink ------------------------------------------------------------- */
    --ls-ink: #182726;         /* body text on light                        */
    --ls-ink-soft: #4c5a58;
    --ls-cream: #f3eee2;       /* body text on dark                         */
    --ls-mute: #777463;

    /* Channel triplets, so alpha ramps below stay in one place. */
    --ls-ink-rgb: 24, 39, 38;
    --ls-cream-rgb: 243, 238, 226;
    --ls-teal-rgb: 13, 71, 89;
    --ls-gold-rgb: 231, 207, 143;
    --ls-gold-deep-rgb: 203, 170, 94;
    --ls-abyss-rgb: 6, 28, 36;

    /* --- Text alpha ramps ------------------------------------------------
       Three steps per channel, no more. Alpha never drops below .65: past
       that these stop clearing WCAG AA on their own backgrounds. Hierarchy
       comes from size and weight, not from fading text further. */
    --ls-ink-strong: rgba(var(--ls-ink-rgb), .80);
    --ls-ink-body: rgba(var(--ls-ink-rgb), .72);
    --ls-ink-meta: rgba(var(--ls-ink-rgb), .65);
    --ls-cream-strong: rgba(var(--ls-cream-rgb), .86);
    --ls-cream-body: rgba(var(--ls-cream-rgb), .72);
    --ls-cream-meta: rgba(var(--ls-cream-rgb), .65);

    /* --- Hairlines and washes -------------------------------------------- */
    --ls-rule-ink: rgba(var(--ls-ink-rgb), .12);
    --ls-rule-ink-soft: rgba(var(--ls-ink-rgb), .09);
    --ls-rule-teal: rgba(var(--ls-teal-rgb), .14);
    --ls-rule-gold: rgba(var(--ls-gold-rgb), .12);
    --ls-rule-gold-strong: rgba(var(--ls-gold-rgb), .25);
    --ls-wash-gold-hover: rgba(var(--ls-gold-deep-rgb), .2);

    /* --- Type ------------------------------------------------------------ */
    --ls-font-sans: 'Archivo', system-ui, sans-serif;
    --ls-font-serif: 'Libre Caslon Display', serif;
    --ls-font-mono: ui-monospace, monospace;

    /* Three reading steps, not six. The old ramp ran 15.5 / 14.5 / 14 / 13.5,
       four sizes inside two points, which reads as variance rather than
       hierarchy: at those deltas the reader cannot tell the ranks apart, so
       the distinctions cost legibility and bought nothing. Rank now comes
       from size, weight and colour together. The kicker step is separate
       because it is set in tracked capitals, where 11px is the intent.

       Every step is fluid, display and reading alike, and both ends of each
       clamp are load bearing. The floor is the size the step was designed at
       and holds from the phone up to ~1400px, so nothing below a large
       desktop moves. Above that the ramp steps up together — the slopes are
       ordered as the sizes are, so prose > prose-sm > meta at every width —
       and finishes at ~1570px, which is where --ls-wrap finishes growing to
       its 1440 ceiling, so type and column arrive at full size together.

       The ×1.12 here is deliberately less than the ×1.161 the column and every
       fixed width grow by, which is the whole difference between a large
       screen that is airier and one that is merely bigger. It costs about four
       per cent on the measure — a 104-character line becomes a 108-character
       one — which is inside the noise, and buys a page whose proportions a
       reader recognises as the same design at any size. */
    --ls-fs-h1: clamp(34px, 4.6vw, 67px);
    --ls-fs-h2: clamp(28px, 3.4vw, 49.5px);
    --ls-fs-h3: clamp(26px, 2.6vw, 40.5px);
    --ls-fs-lead: clamp(17px, 1.5vw, 22.5px);
    --ls-fs-prose: clamp(16.5px, 1.18vw, 18.5px);    /* body copy: the size text is read at      */
    --ls-fs-prose-sm: clamp(15px, 1.07vw, 16.5px);   /* dense copy: table cells, notes, captions */
    --ls-fs-meta: clamp(13.5px, .96vw, 15px);        /* timestamps, file sizes, footnotes        */
    --ls-fs-kicker: clamp(11px, .78vw, 12px);        /* tracked capitals only                    */

    /* --- Tracking ---------------------------------------------------------
       Small caps need tracking; body text does not. Seven steps, by role.
       Uppercase micro-labels all share one value, as do all section kickers:
       before this, near-identical labels carried five different values. */
    --ls-track-link: .04em;    /* nav and inline links                      */
    --ls-track-label: .06em;   /* small meta labels, card CTAs              */
    --ls-track-wide: .08em;    /* uppercase buttons and pills, tracked text */
    --ls-track-caps: .13em;    /* uppercase micro-labels, 10-12.5px         */
    --ls-track-tag: .16em;     /* tags and feature kickers                  */
    --ls-track-kicker: .22em;  /* section kickers                           */
    --ls-track-airy: .34em;    /* the home page's airy kicker               */

    --ls-lh-tight: 1.12;
    --ls-lh-snug: 1.5;
    --ls-lh-body: 1.65;
    --ls-lh-loose: 1.75;

    /* --- Shape and depth -------------------------------------------------- */
    /* Four radii, by the size of the thing being rounded. The house radius
       is nearly square: it is what makes the chips and buttons feel precise. */
    --ls-radius: 2px;      /* chips, buttons, badges, fields, menus         */
    --ls-radius-md: 8px;   /* cards and figures                            */
    --ls-radius-lg: 12px;  /* framed panels, callouts, embedded maps        */
    --ls-radius-xl: 18px;  /* full-width feature blocks                    */
    --ls-shadow-menu: 0 18px 40px rgba(var(--ls-teal-rgb), .16);
    --ls-shadow-card: 0 14px 34px rgba(var(--ls-teal-rgb), .13);
    --ls-shadow-lift: 0 24px 50px rgba(var(--ls-abyss-rgb), .28);

    /* --- Rhythm ------------------------------------------------------------ */
    /* The content measure. 92vw to 1440px, which it reaches at a 1565px
       viewport; past that the page grows its margins rather than its column.
       Nothing below 1348px moves, because 92vw is still the smaller term
       there — the widening happens entirely in the large-desktop range this
       ceiling was raised for.

       Anything that has to line up with the band edge reads this token rather
       than restating the expression: the nav, the footer, the page heroes and
       the home hero all did restate it, and a container width written in five
       places is a container width that will only be changed in four. */
    --ls-wrap: min(1440px, 92vw);

    /* One design pixel: a 1240th of the content measure, and never less than
       1px. Every fixed width in the file is written as calc(N * var(--ls-px))
       and so holds exactly N pixels up to 1348px — where --ls-wrap is still
       92vw and equals the 1240 it was designed against — then grows with the
       column, in step, reaching N × 1.161 at the same 1565px viewport the
       column stops at. Two consequences worth having: the interior of a band
       keeps the proportions it was drawn with at every width, so a column that
       ended 42px short of the band edge does not drift out to 156; and the
       ratio cannot fall out of step with the container, because it is derived
       from it rather than restated as a slope at each of the thirty sites.
       N stays legible at the use site, so ls-measure-640 still says what it
       is, and the type ramp deliberately grows a little less (×1.12) over the
       same band — large screens should get airier, not merely bigger. */
    --ls-px: max(1px, calc(var(--ls-wrap) / 1240));
    --ls-band-y: clamp(60px, 7.5vw, 111px);   /* section top/bottom padding  */
    --ls-head-gap: clamp(30px, 3.6vw, 56px); /* section head to its content */
    --ls-anchor-offset: 64px;                /* fixed nav clearance          */

    --ls-ease: .2s ease;
    --ls-ease-theme: .35s ease;

    /* --- Surface contract -------------------------------------------------
       Components that appear on both light and dark bands read this instead
       of hard-coding a colour. Every dark surface re-points it, so dropping a
       kicker into a new band needs no extra class. */
    --ls-accent-label: var(--ls-gold-ink);
  }

  /* Dark surfaces. Listed in one place so the set stays reviewable. */
  .ls-band--teal, .ls-band--deep, .ls-band--sink, .ls-band--sweep,
  .ls-pagehero, .ls-ctaband, .ls-statstrip, .ls-footer {
    --ls-accent-label: var(--ls-gold-deep);
  }
}

/* ==========================================================================
   BASE
   ========================================================================== */
@layer base {
  *, *::before, *::after { box-sizing: border-box; }

  html { scroll-behavior: smooth; }

  body {
    margin: 0;
    background: var(--ls-deep);
    color: var(--ls-ink);
    font-family: var(--ls-font-sans);
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
  }

  a { color: var(--ls-gold-ink); text-decoration: none; }
  a:hover { color: var(--ls-teal-mid); }

  ::selection { background: var(--ls-gold); color: var(--ls-deep); }

  input, button { font-family: var(--ls-font-sans); }

  /* One focus ring for the whole site. It is drawn in gold with a contrasting
     outer shadow so that it reads on the cream bands and on the deep teal
     ones without a per-surface variant, and :focus-visible keeps it off
     mouse clicks. Fields set outline: none, so without this they would have
     had only a faint border-colour shift to signal focus. */
  :focus-visible {
    outline: 2px solid var(--ls-gold);
    outline-offset: 2px;
    border-radius: 1px;
    box-shadow: 0 0 0 4px rgba(var(--ls-abyss-rgb), .35);
  }
  .ls-field:focus-visible { outline-offset: 1px; }

  @media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }
  }
}

/* ==========================================================================
   LAYOUT — the page skeleton: bands, the centred measure, section heads
   ========================================================================== */
@layer layout {

  /* The single content measure used by every band, nav and footer. */
  .ls-wrap { width: var(--ls-wrap); margin: 0 auto; }

  /* --- Bands ------------------------------------------------------------
     A band is a full-bleed horizontal stripe. The surface modifier sets both
     the background and the text colours the components inside it inherit. */
  .ls-band { padding: var(--ls-band-y) 0; }
  /* Only bands that are jump targets need to clear the fixed bar. */
  .ls-band--anchor { scroll-margin-top: var(--ls-anchor-offset); }
  .ls-band--flush-bottom { padding-bottom: 0; }
  /* An article band sits under a page hero, so it needs less lead-in above. */
  .ls-band--article { padding: clamp(56px, 7vw, 104px) 0 clamp(60px, 7.5vw, 111px); }
  .ls-band--rule-top { border-top: 1px solid var(--ls-rule-ink-soft); }
  .ls-band--rule-top-gold { border-top: 1px solid var(--ls-rule-gold); }

  .ls-band--paper { background: var(--ls-paper); color: var(--ls-ink); }
  .ls-band--white { background: var(--ls-white); color: var(--ls-ink); }
  .ls-band--teal { background: var(--ls-teal); color: var(--ls-cream); }
  .ls-band--deep { background: var(--ls-deep); color: var(--ls-cream); }
  .ls-band--sink {
    background: linear-gradient(160deg, var(--ls-teal) 0%, var(--ls-deep) 60%, var(--ls-abyss) 100%);
    color: var(--ls-cream);
  }
  .ls-band--sweep {
    background: linear-gradient(120deg, var(--ls-teal-mid), #0a3543 70%);
    color: var(--ls-cream);
  }

  /* --- Section head: kicker, title, and an optional trailing aside ------- */
  .ls-head { margin-bottom: var(--ls-head-gap); }
  .ls-head--split {
    display: flex;
    justify-content: space-between;
    align-items: flex-end;
    gap: 24px;
    flex-wrap: wrap;
  }
  .ls-head__title-col { max-width: calc(640 * var(--ls-px)); }

  /* --- Generic responsive grids ------------------------------------------
     Named for the minimum comfortable column, not for a column count, so the
     same class behaves at any wrap width. */
  .ls-grid { display: grid; gap: clamp(16px, 1.8vw, 26px); }
  /* Column minimum, then gap: two independent axes, so any pairing composes. */
  .ls-grid--170 { grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); }
  .ls-grid--220 { grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); }
  .ls-grid--240 { grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); }
  .ls-grid--250 { grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); }
  .ls-grid--260 { grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }
  .ls-grid--290 { grid-template-columns: repeat(auto-fit, minmax(290px, 1fr)); }
  .ls-grid--300 { grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); }
  .ls-grid--420 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 420px), 1fr)); }
  .ls-grid--one { grid-template-columns: 1fr; gap: 14px; }

  .ls-grid--gap-10 { gap: 10px; }
  .ls-grid--gap-14 { gap: 14px; }
  .ls-grid--gap-18 { gap: 18px; }
  .ls-grid--gap-40 { gap: clamp(24px, 3vw, 46px); }
  /* <figure> carries a 40px UA side margin, so this zeroes all sides. */
  .ls-grid--gap-b { margin: 0 0 20px; }
}

/* ==========================================================================
   COMPONENTS
   ========================================================================== */
@layer components {

  /* --- Typography -------------------------------------------------------
     Display type is the serif; everything else is the sans. These carry no
     colour, so they read correctly on whichever band they sit in. */
  .ls-display { font-family: var(--ls-font-serif); font-weight: 400; margin: 0; }
  .ls-h1 {
    font-family: var(--ls-font-serif); font-weight: 400; margin: 0;
    font-size: var(--ls-fs-h1); line-height: 1.08; letter-spacing: -0.01em;
  }
  .ls-h2 {
    font-family: var(--ls-font-serif); font-weight: 400; margin: 0;
    font-size: var(--ls-fs-h2); line-height: var(--ls-lh-tight); letter-spacing: -0.01em;
  }
  .ls-h3 {
    font-family: var(--ls-font-serif); font-weight: 400; margin: 0 0 18px;
    font-size: var(--ls-fs-h3); line-height: var(--ls-lh-tight);
  }
  .ls-subhead { margin: 0 0 10px; font-size: 18px; font-weight: 700; }

  /* Kicker: the letterspaced label above a title. Two steps are in use —
     the tighter .22em/.26em on section heads, the airier .34em on the home
     page bands. Colour follows the band. */
  .ls-kicker {
    display: block;
    font-size: var(--ls-fs-kicker); font-weight: 700;
    letter-spacing: var(--ls-track-kicker); text-transform: uppercase;
    color: var(--ls-accent-label);
    /* Margin is written long-hand so the class can be worn by a heading — the
       footer's group labels are <h2> — without the UA's top margin on h1-h6
       pushing it off the line its neighbours sit on. A no-op on the <div>s
       and <span>s that wear it everywhere else. */
    margin: 0 0 18px;
  }
  .ls-kicker--airy { font-size: var(--ls-fs-meta); font-weight: 600; letter-spacing: var(--ls-track-airy); }
  .ls-kicker--tight { letter-spacing: var(--ls-track-kicker); }
  .ls-kicker--wide { letter-spacing: var(--ls-track-tag); font-weight: 600; }
  .ls-kicker--gold { color: var(--ls-gold-deep); }
  .ls-kicker--flush { margin-bottom: 0; }
  .ls-kicker--gap-xs { margin-bottom: 12px; }
  .ls-kicker--gap-sm { margin-bottom: 16px; }
  .ls-kicker--gap-lg { margin-bottom: 20px; }

  /* Body copy scale. Each step is a size plus its leading; colour is set by
     the band or by an explicit tone class. */
  .ls-lead { margin: 0; font-size: var(--ls-fs-lead); line-height: 1.7; }
  .ls-copy { margin: 0 0 18px; font-size: var(--ls-fs-prose); line-height: var(--ls-lh-loose); text-wrap: pretty; }
  .ls-copy--gap-lg { margin-bottom: 22px; }
  .ls-copy--gap-xl { margin-bottom: 24px; }
  .ls-copy--flush { margin-bottom: 0; }
  .ls-prose { margin: 0; font-size: var(--ls-fs-prose); line-height: 1.7; }
  .ls-note { margin: 0; font-size: var(--ls-fs-prose-sm); line-height: var(--ls-lh-body); }
  .ls-fine { margin: 0; font-size: var(--ls-fs-kicker); line-height: 1.7; }

  .ls-t-body { color: var(--ls-ink-body); }
  .ls-t-meta { color: var(--ls-ink-meta); }
  .ls-t-strong { color: var(--ls-ink-strong); }
  .ls-t-on-dark { color: var(--ls-cream-body); }
  .ls-t-on-dark-meta { color: var(--ls-cream-meta); }
  .ls-t-gold { color: var(--ls-gold); }
  .ls-t-gold-ink { color: var(--ls-gold-ink); }
  .ls-t-teal { color: var(--ls-teal-mid); }
  .ls-t-ink-soft { color: var(--ls-ink-soft); }
  .ls-em-gold { font-style: italic; color: var(--ls-gold); }

  .ls-mono { font-family: var(--ls-font-mono); }
  .ls-mono--13 { font-size: 14px; color: var(--ls-mute); }
  .ls-mono--12 { font-size: 13px; color: var(--ls-mute); }

  /* Size and spacing modifiers on the copy scale. Each exists because a
     specific block needed it; they are named for the value so a future edit
     can see at a glance what is being overridden. */
  .ls-h2--gap { margin-bottom: 18px; }
  .ls-copy--gap-4 { margin-bottom: 4px; }
  .ls-copy--gap-20 { margin-bottom: 20px; }
  .ls-prose--sm { font-size: var(--ls-fs-prose-sm); }
  .ls-prose--15 { font-size: var(--ls-fs-prose); }
  .ls-prose--gap-12 { margin-bottom: 12px; }
  .ls-prose--gap-14 { margin-bottom: 14px; }
  .ls-lead--body { font-size: var(--ls-fs-prose); }
  .ls-note--gap { margin-bottom: 16px; }
  /* These two inherit their leading: their sources declared none, so they
     take it from whatever they sit inside. */
  .ls-note--11 { font-size: var(--ls-fs-kicker); line-height: inherit; color: var(--ls-ink-meta); }
  .ls-note--12 { font-size: var(--ls-fs-meta); line-height: inherit; }
  .ls-note--13 { font-size: var(--ls-fs-prose-sm); line-height: var(--ls-lh-snug); color: var(--ls-ink-meta); }
  .ls-fs-13 { font-size: var(--ls-fs-prose-sm); }
  .ls-ls-06 { letter-spacing: var(--ls-track-label); }
  .ls-mt-5 { margin-top: 5px; }
  .ls-col-128 { flex: 0 0 128px; }

  /* Photo focal points. object-position is a property of the picture, not of
     the layout, so each crop gets a name rather than an inline override. */
  .ls-focal-25 { object-position: center 25%; }
  .ls-focal-30 { object-position: center 30%; }
  .ls-focal-38 { object-position: center 38%; }
  .ls-focal-42 { object-position: center 42%; }
  .ls-focal-50 { object-position: center 50%; }
  .ls-focal-60 { object-position: center 60%; }
  .ls-focal-62 { object-position: center 62%; }

  /* A trailing legal or context note under a figure or table. */
  .ls-disclaimer { margin: 0; font-size: var(--ls-fs-meta); line-height: 1.6; color: var(--ls-ink-meta); max-width: calc(860 * var(--ls-px)); }
  /* "All news releases →" style link out of a section head. */
  .ls-morelink { color: var(--ls-gold-ink); font-size: var(--ls-fs-prose-sm); font-weight: 600; letter-spacing: var(--ls-track-link); }
  .ls-morelink:hover { color: var(--ls-teal-mid); }

  /* --- Arrow links -------------------------------------------------------
     The glyph is the affordance, so it travels the way it points. */
  .ls-arw { display: inline-block; transition: transform var(--ls-ease); }
  a:hover .ls-arw { transform: translateX(3px); }
  /* News rows carry "Read Release" in a <span> rather than a second <a>,
     because the headline link is stretched across the whole row. There is no
     ancestor anchor to hover, so the arrow answers the row instead, the same
     way the card CTAs below answer their card. */
  .ls-newsrow:hover .ls-arw { transform: translateX(3px); }
  @media (prefers-reduced-motion: reduce) {
    .ls-arw { transition: none; }
    a:hover .ls-arw,
    .ls-newsrow:hover .ls-arw { transform: none; }
  }

  /* Card CTAs: the whole card is the link, so its call-to-action answers the
     card hover rather than its own. */
  .ls-cta, .ls-cta-dk { transition: color var(--ls-ease); }
  a:hover .ls-cta { color: var(--ls-teal-mid); }
  a:hover .ls-cta-dk { color: var(--ls-gold-light); }

  /* ------------------------------------------------------------------------
     NAV
     Colours come from custom properties rather than duplicated rules, so the
     scrolled/hovered light state is one variable swap. Two independent states:
       is-light    the bar is over content (or hovered) and inverts
       is-compact  the page is scrolled, so the bar and logo shrink
     ---------------------------------------------------------------------- */
  .ls-nav {
    --nav-pad: 15px;
    --nav-logo-h: 36px;
    --nav-bg: rgba(8, 38, 47, .94);
    --nav-bd: var(--ls-rule-gold-strong);
    --nav-fg: var(--ls-cream-strong);
    --nav-accent: var(--ls-gold);
    --nav-logo-filter: brightness(0) invert(1);
    --pill-fg: var(--ls-gold);
    --pill-bd: rgba(var(--ls-gold-rgb), .55);
    --pill-hover-bg: var(--ls-gold);
    --pill-hover-fg: var(--ls-deep);

    position: fixed; top: 0; left: 0; right: 0; z-index: 100;
    background: var(--nav-bg);
    border-bottom: 1px solid var(--nav-bd);
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
    transition: background var(--ls-ease-theme), border-color var(--ls-ease-theme);
  }
  .ls-nav { --nav-bd: rgba(var(--ls-gold-rgb), .14); }

  .ls-nav.is-light {
    --nav-bg: rgba(251, 250, 246, .94);
    --nav-bd: rgba(var(--ls-teal-rgb), .12);
    --nav-fg: var(--ls-ink-strong);
    --nav-accent: var(--ls-gold-ink);
    --nav-logo-filter: none;
    --pill-fg: var(--ls-teal-mid);
    --pill-bd: rgba(var(--ls-teal-rgb), .4);
    --pill-hover-bg: var(--ls-teal-mid);
    --pill-hover-fg: var(--ls-cream);
  }
  .ls-nav.is-compact { --nav-pad: 10px; --nav-logo-h: 29px; }

  /* Home page: the bar floats over the hero photograph, so at rest it is a
     tint rather than a solid, and it carries no bottom rule. */
  .ls-nav--hero {
    --nav-bg: rgba(var(--ls-abyss-rgb), .38);
    --nav-bd: transparent;
    --nav-fg: var(--ls-cream-strong);
  }
  .ls-nav--hero.is-light { --nav-bg: rgba(251, 250, 246, .92); }
  /* Its pill keeps the gold hover in both states. */
  .ls-nav--hero.is-light { --pill-hover-bg: var(--ls-gold); --pill-hover-fg: var(--ls-deep); }

  .ls-nav__inner {
    width: var(--ls-wrap); margin: 0 auto;
    display: flex; align-items: center; gap: 22px; flex-wrap: wrap;
    padding: var(--nav-pad) 0;
    transition: padding .3s ease;
  }
  .ls-nav__logo {
    display: flex; align-items: center; margin-right: auto;
    transition: opacity var(--ls-ease);
  }
  .ls-nav__logo:hover { opacity: .7; }
  .ls-nav__logo-img {
    height: var(--nav-logo-h); display: block;
    filter: var(--nav-logo-filter);
    transition: filter var(--ls-ease-theme), height .3s ease;
  }

  .ls-nav__links {
    display: flex; gap: clamp(16px, 2.4vw, 35px);
    flex-wrap: wrap; align-items: center; align-self: stretch;
  }
  .ls-nav__link {
    color: var(--nav-fg);
    font-size: var(--ls-fs-prose-sm); font-weight: 500; letter-spacing: var(--ls-track-link);
    transition: color var(--ls-ease-theme);
  }
  .ls-nav__link:hover { color: var(--nav-accent); }
  .ls-nav__link.is-active { color: var(--nav-accent); font-weight: 600; }
  .ls-nav__link--parent { display: inline-flex; align-items: center; gap: 6px; }
  .ls-nav__caret { font-size: 8px; opacity: .75; }

  /* Dropdowns open on hover and on keyboard focus. The wrapper's top padding
     bridges the gap under the bar so the pointer can cross into the menu. */
  .ls-nav__item { position: relative; align-self: stretch; display: flex; align-items: center; }
  .ls-nav__dd {
    position: absolute; top: 100%; left: -16px; z-index: 110;
    padding-top: var(--nav-pad);
    display: none;
  }
  .ls-nav__item:hover > .ls-nav__dd,
  .ls-nav__item:focus-within > .ls-nav__dd { display: block; }

  .ls-nav__menu {
    background: var(--ls-paper);
    border: 1px solid var(--ls-rule-teal);
    border-radius: var(--ls-radius);
    box-shadow: var(--ls-shadow-menu);
    min-width: 210px;
    overflow: hidden;
  }
  .ls-nav__menu--wide { min-width: 230px; }
  .ls-nav__menu-link {
    display: block; padding: 10px 18px;
    color: var(--ls-ink-strong); font-size: var(--ls-fs-prose-sm);
  }
  /* The projects menu is eight items long, so it runs at the tighter step —
     all of it, rather than the first item at one padding and the rest at another. */
  .ls-nav__menu--wide .ls-nav__menu-link { padding: 9px 18px; }
  .ls-nav__menu-link:hover { background: var(--ls-wash-gold-hover); color: var(--ls-gold-ink); }
  .ls-nav__menu-link.is-active { color: var(--ls-gold-ink); font-weight: 600; }

  /* The drawer toggle. Present in the markup on every page but only shown
     below the nav breakpoint; it inherits --nav-fg so it inverts with the bar.
     The bars are drawn from borders so they animate to a cross without
     needing extra elements. */
  .ls-nav__toggle {
    display: none;
    width: 46px; height: 46px;
    margin-left: auto;
    padding: 0;
    background: none; border: 0;
    color: var(--nav-fg);
    cursor: pointer;
    align-items: center; justify-content: center;
    transition: color var(--ls-ease-theme);
  }
  .ls-nav__toggle:hover { color: var(--nav-accent); }
  .ls-nav__burger {
    position: relative;
    display: block; width: 22px; height: 2px;
    background: currentColor;
    transition: background var(--ls-ease);
  }
  .ls-nav__burger::before,
  .ls-nav__burger::after {
    content: ""; position: absolute; left: 0;
    width: 22px; height: 2px;
    background: currentColor;
    transition: transform var(--ls-ease), top var(--ls-ease);
  }
  .ls-nav__burger::before { top: -7px; }
  .ls-nav__burger::after  { top: 7px; }
  .ls-navopen .ls-nav__burger { background: transparent; }
  .ls-navopen .ls-nav__burger::before { top: 0; transform: rotate(45deg); }
  .ls-navopen .ls-nav__burger::after  { top: 0; transform: rotate(-45deg); }

  /* Skip link: off-screen until focused, then a solid chip over the bar. */
  .ls-skip {
    position: fixed; top: 8px; left: 8px; z-index: 200;
    transform: translateY(-160%);
    background: var(--ls-gold); color: var(--ls-deep);
    padding: 11px 18px; border-radius: var(--ls-radius);
    font-size: var(--ls-fs-prose-sm); font-weight: 700; letter-spacing: var(--ls-track-label);
    transition: transform var(--ls-ease);
  }
  .ls-skip:focus { transform: translateY(0); color: var(--ls-deep); }

  /* --- Buttons ----------------------------------------------------------- */
  .ls-btn {
    display: inline-block;
    border-radius: var(--ls-radius);
    font-size: var(--ls-fs-prose-sm); font-weight: 700;
    letter-spacing: var(--ls-track-label);
    padding: 15px 28px;
    transition: all var(--ls-ease);
    cursor: pointer;
  }
  /* The two hero buttons set their own leading so they match at every clamp step. */
  .ls-btn--gold, .ls-btn--ghost { line-height: 1.2; }
  .ls-btn--gold {
    background: var(--ls-gold-deep); border: 1px solid var(--ls-gold-deep); color: var(--ls-abyss);
  }
  .ls-btn--gold:hover {
    background: var(--ls-gold); border-color: var(--ls-gold); color: var(--ls-abyss);
    transform: translateY(-1px);
  }
  .ls-btn--ghost {
    color: var(--ls-cream);
    background: rgba(var(--ls-abyss-rgb), .34);
    border: 1px solid rgba(var(--ls-cream-rgb), .46);
    padding: 15px 24px; font-weight: 600;
  }
  .ls-btn--ghost:hover {
    border-color: var(--ls-gold); color: var(--ls-gold);
    background: rgba(var(--ls-abyss-rgb), .55);
    transform: translateY(-1px);
  }
  /* Home-page submit: sentence case, sized to sit beside the roomier field. */
  .ls-btn--solid {
    background: var(--ls-gold); color: var(--ls-deep); border: 0;
    padding: 15px 30px; transition: background var(--ls-ease);
  }
  .ls-btn--solid:hover { background: var(--ls-gold-light); }
  /* CTA-band submit: the uppercase form used on every interior page. */
  .ls-btn--submit {
    background: var(--ls-gold); color: var(--ls-deep); border: none;
    padding: 15px 30px;
    font-size: 13px; letter-spacing: var(--ls-track-wide); text-transform: uppercase;
    transition: background var(--ls-ease);
  }
  .ls-btn--submit:hover { background: var(--ls-gold-light); }

  /* The nav's outlined "Get updates" pill. */
  .ls-pill {
    color: var(--pill-fg);
    border: 1px solid var(--pill-bd);
    padding: 9px 18px;
    border-radius: var(--ls-radius);
    font-size: 12.5px; font-weight: 600; letter-spacing: var(--ls-track-wide); text-transform: uppercase;
    transition: all var(--ls-ease);
  }
  .ls-pill:hover { background: var(--pill-hover-bg); color: var(--pill-hover-fg); }

  /* --- Badges and chips ---------------------------------------------------
     Solid badge for status on any band; outlined chip for a quiet qualifier
     on dark. Gold on a photograph needs the solid form to stay legible. */
  /* Filled badge. Solid backing is what lets gold small-caps stay legible
     over a photograph, so this is the form to reach for on any image band. */
  .ls-badge {
    background: var(--ls-gold); color: var(--ls-deep);
    padding: 7px 14px; border-radius: var(--ls-radius);
    font-size: var(--ls-fs-kicker); font-weight: 700;
    letter-spacing: var(--ls-track-caps); text-transform: uppercase;
  }
  /* Outlined chip, for a quiet qualifier beside a heading. */
  .ls-chip {
    color: var(--ls-gold);
    border: 1px solid rgba(var(--ls-gold-rgb), .5);
    padding: 5px 10px; border-radius: var(--ls-radius);
    font-size: 10.5px; font-weight: 700;
    letter-spacing: var(--ls-track-caps); text-transform: uppercase;
    white-space: nowrap;
  }

  /* --- Stat pair: a serif figure over its label -------------------------- */
  .ls-stat__v { font-family: var(--ls-font-serif); font-size: 28px; color: var(--ls-gold); white-space: nowrap; }
  .ls-stat__l { font-size: var(--ls-fs-meta); letter-spacing: var(--ls-track-label); color: var(--ls-cream-meta); }
  .ls-stat-row { display: flex; gap: clamp(20px, 3vw, 51px); flex-wrap: wrap; }

  /* Inline "3 permits" pairing used inside cards. */
  .ls-figure { display: inline-flex; align-items: baseline; gap: 6px; white-space: nowrap; }
  .ls-figure__v { font-family: var(--ls-font-serif); font-size: 20px; color: var(--ls-gold); }
  .ls-figure__l { font-size: var(--ls-fs-meta); color: var(--ls-cream-meta); }

  /* --- Diamond bullet list ------------------------------------------------
     The rotated square is the site's bullet; it repeats down the project
     pages, so it is a component rather than a per-page flourish. */
  .ls-points { display: flex; flex-direction: column; gap: 12px; }
  .ls-points--gap-b { margin-bottom: 20px; }
  .ls-points--indent { padding-left: 16px; }
  .ls-point { display: flex; gap: 12px; align-items: flex-start; }
  .ls-point__mark {
    flex: none;
    width: 7px; height: 7px; margin-top: 6px;
    transform: rotate(45deg);
    background: var(--ls-gold-deep);
  }
  .ls-point__text { margin: 0; font-size: var(--ls-fs-prose); line-height: 1.62; color: var(--ls-ink-body); }
  .ls-band--teal .ls-point__text,
  .ls-band--deep .ls-point__text,
  .ls-band--sink .ls-point__text { color: var(--ls-cream-body); }

  /* --- Cards -------------------------------------------------------------- */
  .ls-card {
    display: flex; flex-direction: column;
    background: var(--ls-white);
    border: 1px solid var(--ls-rule-ink);
    border-radius: var(--ls-radius-md);
    padding: 28px;
    color: var(--ls-ink);
    transition: transform var(--ls-ease), box-shadow var(--ls-ease);
  }
  a.ls-card:hover {
    transform: translateY(-3px);
    box-shadow: var(--ls-shadow-card);
    color: var(--ls-ink);
  }
  .ls-card__date { font-family: var(--ls-font-mono); font-size: var(--ls-fs-meta); color: var(--ls-mute); margin-bottom: 30px; }
  .ls-card__title { font-family: var(--ls-font-serif); font-size: 23px; line-height: 1.22; margin-bottom: 22px; text-wrap: pretty; }
  .ls-card__cta { margin-top: auto; font-size: var(--ls-fs-meta); font-weight: 600; letter-spacing: var(--ls-track-label); color: var(--ls-gold-ink); }

  /* Panel: a bordered block on a dark band. */
  /* A column, so __foot can be pushed to the bottom: the three vehicles carry
     descriptions of different lengths, and without it the rule and figures
     follow the copy at three different heights and the row reads as three
     unrelated blocks. The grid already equalises the card heights. */
  .ls-panel {
    display: flex; flex-direction: column;
    border: 1px solid rgba(var(--ls-gold-rgb), .18);
    border-radius: var(--ls-radius);
    padding: clamp(20px, 2.4vw, 32px);
    background: rgba(var(--ls-abyss-rgb), .55);
  }
  .ls-panel__head { display: flex; justify-content: space-between; align-items: center; gap: 12px; margin-bottom: 14px; }
  .ls-panel__name { font-size: var(--ls-fs-prose); font-weight: 700; color: var(--ls-cream); }
  .ls-panel__foot {
    display: flex; gap: 24px;
    margin-top: auto;
    border-top: 1px solid rgba(var(--ls-gold-rgb), .14);
    padding-top: 14px;
  }

  /* --- Embedded portfolio map ---------------------------------------------
     Shared rather than page-scoped: the same frame carries the map on the
     projects page and on the home page. */
  .ls-mapframe {
    border: 1px solid var(--ls-rule-ink);
    border-radius: var(--ls-radius-xl);
    overflow: hidden;
    box-shadow: 0 24px 60px rgba(13,71,89,.14);
  }
  .ls-mapframe__frame { display: block; width: 100%; height: clamp(540px, 72vh, 700px); border: 0; }
  .ls-mapframe--short .ls-mapframe__frame { height: clamp(460px, 56vh, 580px); }

  /* --- Flagship strip -----------------------------------------------------
     A single dark panel giving one project the weight the rest of a listing
     cannot. Used on the home page to put the drill-ready asset above the
     fold-line of the portfolio section. */
  .ls-flagship {
    display: flex; flex-wrap: wrap; align-items: center;
    gap: clamp(24px, 3.4vw, 63px);
    margin-top: clamp(22px, 2.6vw, 37px);
    padding: clamp(26px, 3.2vw, 49px) clamp(24px, 3.2vw, 53px);
    background: linear-gradient(115deg, var(--ls-deep), var(--ls-teal));
    border-radius: var(--ls-radius-xl);
    color: var(--ls-cream);
  }
  .ls-flagship__body { flex: 1 1 420px; min-width: 0; }
  .ls-flagship__name {
    font-family: var(--ls-font-serif); font-weight: 400;
    font-size: clamp(27px, 2.8vw, 42.5px); line-height: 1.1;
    margin: 12px 0 0; color: var(--ls-cream);
  }
  .ls-flagship__lead {
    margin: 12px 0 0; max-width: 56ch;
    font-size: var(--ls-fs-prose); line-height: var(--ls-lh-body);
    color: var(--ls-cream-body);
  }
  .ls-flagship__figs {
    flex: 0 1 auto;
    display: grid; grid-template-columns: repeat(auto-fit, minmax(122px, 1fr)); gap: 1px;
    background: rgba(var(--ls-gold-rgb), .18);
    border: 1px solid rgba(var(--ls-gold-rgb), .18);
    border-radius: var(--ls-radius);
  }
  .ls-flagship__fig { background: var(--ls-deep); padding: 15px 18px; }
  .ls-flagship__v {
    font-family: var(--ls-font-serif); font-size: 21px; line-height: 1; color: var(--ls-gold);
    white-space: nowrap;
  }
  /* No two-line reservation here, unlike the stat strips: these figures stack
     rather than sitting in a row, so nothing has a baseline to keep. */
  .ls-flagship__l {
    margin-top: 7px;
    font-size: 10.5px; font-weight: 600; text-transform: uppercase;
    letter-spacing: var(--ls-track-caps); color: var(--ls-cream-meta);
    line-height: 1.35;
  }
  .ls-flagship__actions { display: flex; flex-wrap: wrap; gap: 12px; margin-top: clamp(20px, 2.2vw, 30px); }

  /* --- Field-photo band ---------------------------------------------------
     A full-bleed photograph with a caption row sitting in its lower scrim. */
  .ls-photoband { position: relative; overflow: hidden; }
  .ls-photoband__img {
    display: block; width: 100%;
    height: clamp(280px, 40vw, 534px);
    object-fit: cover;
  }
  .ls-photoband__scrim {
    position: absolute; inset: 0;
    background: linear-gradient(rgba(var(--ls-abyss-rgb), .05) 55%, rgba(var(--ls-abyss-rgb), .7));
  }
  .ls-photoband__caption { position: absolute; left: 0; right: 0; bottom: 0; }
  .ls-photoband__row {
    width: var(--ls-wrap); margin: 0 auto; padding-bottom: 24px;
    display: flex; justify-content: space-between; gap: 16px; flex-wrap: wrap; align-items: baseline;
  }
  .ls-photoband__label {
    font-size: 12.5px; font-weight: 600; letter-spacing: var(--ls-track-kicker);
    text-transform: uppercase; color: var(--ls-gold);
  }
  .ls-photoband__note { font-size: var(--ls-fs-prose-sm); color: var(--ls-cream-body); }

  /* --- Subscribe field ----------------------------------------------------
     A lifted well on the dark band rather than a hole punched through it. */
  .ls-field {
    background: rgba(var(--ls-cream-rgb), .1);
    border: 1px solid rgba(var(--ls-gold-rgb), .45);
    border-radius: var(--ls-radius);
    color: var(--ls-cream);
    outline: none;
    transition: background var(--ls-ease), border-color var(--ls-ease);
  }
  /* Two sizes: the roomier home-page form, and the tighter one in the CTA band. */
  .ls-field--home { flex: 1 1 240px; padding: 15px 22px; font-size: var(--ls-fs-prose); }
  .ls-field--band { flex: 1 1 230px; min-width: 0; padding: 15px 18px; font-size: var(--ls-fs-prose); }
  .ls-field::placeholder { color: var(--ls-cream-meta); }
  .ls-field:focus {
    border-color: var(--ls-gold);
    background: rgba(var(--ls-cream-rgb), .17);
  }


  /* Further kicker steps. The site uses four letterspacing values on small
     caps; they are kept apart here so the set is countable and easy to collapse. */
  .ls-kicker--20 { letter-spacing: var(--ls-track-kicker); }
  .ls-kicker--24 { letter-spacing: var(--ls-track-kicker); }
  .ls-kicker--gap-14 { margin-bottom: 14px; }
  .ls-subhead--17 { font-size: 17px; }
  .ls-yearhead__count--block { display: block; margin-bottom: 12px; }
  .ls-head--gap-44 { margin-bottom: clamp(30px, 3.6vw, 51px); }

  /* ------------------------------------------------------------------------
     PAGE HERO — the dark masthead that opens every interior page
     ---------------------------------------------------------------------- */
  .ls-pagehero {
    background: linear-gradient(160deg, var(--ls-teal) 0%, var(--ls-deep) 60%, var(--ls-abyss) 100%);
    color: var(--ls-cream);
    padding: clamp(140px, 18vh, 190px) 0 clamp(56px, 7vw, 97px);
    border-bottom: 1px solid rgba(var(--ls-gold-rgb), .1);
  }
  /* Short form, for pages whose hero runs straight into a stat strip. */
  .ls-pagehero--short { padding: clamp(140px, 18vh, 180px) 0 clamp(30px, 4vw, 51px); }
  /* Photo form: the image sits at low opacity under a matching scrim, so the
     gradient still carries the type contrast. */
  .ls-pagehero--photo {
    position: relative; overflow: hidden;
    padding: clamp(130px, 16vh, 175px) 0 0;
    border-bottom: 0;
  }
  .ls-pagehero__photo {
    position: absolute; inset: 0; width: 100%; height: 100%;
    object-fit: cover; object-position: center 55%;
    opacity: .2;
  }
  .ls-pagehero__scrim {
    position: absolute; inset: 0;
    background: linear-gradient(160deg, rgba(11, 53, 67, .86) 0%, rgba(8, 38, 47, .93) 60%, rgba(var(--ls-abyss-rgb), .97) 100%);
  }
  .ls-pagehero__inner {
    width: var(--ls-wrap); margin: 0 auto;
    padding-bottom: clamp(40px, 5vw, 65px);
    position: relative; z-index: 2;
  }
  .ls-pagehero__title {
    font-family: var(--ls-font-serif); font-weight: 400;
    margin: 0 0 22px;
    font-size: var(--ls-fs-h1); line-height: 1.08; letter-spacing: -0.01em;
    max-width: calc(820 * var(--ls-px));
  }
  .ls-pagehero__title--lead { margin-bottom: 14px; line-height: 1.06; }
  .ls-pagehero__lead {
    margin: 0;
    font-size: clamp(15px, 1.3vw, 19px); line-height: 1.7;
    color: var(--ls-cream-body);
    max-width: calc(680 * var(--ls-px)); text-wrap: pretty;
  }

  /* Breadcrumbs sit inside the hero, above the title. */
  .ls-crumbs {
    display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
    margin-bottom: 22px;
    font-size: var(--ls-fs-meta); letter-spacing: var(--ls-track-label);
  }
  .ls-crumbs__link { color: var(--ls-cream-meta); font-weight: 500; }
  .ls-crumbs__sep { color: var(--ls-cream-meta); }

  /* ------------------------------------------------------------------------
     STAT STRIP — the hairline-divided figures under a hero
     ---------------------------------------------------------------------- */
  .ls-statstrip {
    border-top: 1px solid rgba(var(--ls-gold-rgb), .16);
    background: rgba(var(--ls-abyss-rgb), .5);
    position: relative; z-index: 2;
  }
  .ls-statstrip__grid {
    width: var(--ls-wrap); margin: 0 auto;
    display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 1px;
  }
  .ls-statstrip__cell { padding: 24px 28px; border-left: 1px solid rgba(var(--ls-gold-rgb), .14); }
  /* Nothing to its left to divide — see .ls-home-hero__statcell:first-child. */
  .ls-statstrip__cell:first-child { border-left: 0; }
  .ls-statstrip__v {
    font-family: var(--ls-font-serif);
    font-size: clamp(24px, 2.2vw, 36px);
    color: var(--ls-gold); line-height: 1; white-space: nowrap;
  }
  .ls-statstrip__l {
    font-size: var(--ls-fs-kicker); font-weight: 600;
    letter-spacing: var(--ls-track-caps); text-transform: uppercase;
    color: var(--ls-cream-meta); margin-top: 8px;
    /* Two lines are always reserved. "km² licences and applications" wraps
       while its three neighbours do not, and a strip whose labels end on two
       different baselines reads as a mistake rather than as four equals. */
    line-height: 1.35; min-height: 2.7em;
  }

  /* ------------------------------------------------------------------------
     CTA BAND — the subscribe strip that closes most pages
     ---------------------------------------------------------------------- */
  .ls-ctaband {
    background: linear-gradient(160deg, var(--ls-teal) 0%, var(--ls-deep) 70%), var(--ls-deep);
    color: var(--ls-cream);
    padding: var(--ls-band-y) 0;
  }
  .ls-ctaband__inner {
    width: var(--ls-wrap); margin: 0 auto;
    display: flex; justify-content: space-between; align-items: center;
    gap: 28px; flex-wrap: wrap;
  }
  .ls-ctaband__title {
    margin: 0;
    font-family: var(--ls-font-serif); font-weight: 400;
    font-size: clamp(26px, 3vw, 45px); line-height: 1.15; letter-spacing: -0.01em;
    max-width: calc(560 * var(--ls-px)); text-wrap: balance;
  }
  .ls-ctaband__col { flex: 1 1 calc(380 * var(--ls-px)); max-width: calc(520 * var(--ls-px)); }

  .ls-formrow { display: flex; gap: 10px; flex-wrap: wrap; }
  .ls-formnote { margin: 12px 0 0; font-size: var(--ls-fs-meta); color: var(--ls-cream-meta); }

  /* Two fields share the row when a name is collected, so the email gives up
     some of its basis to make room before the pair wraps onto two lines.

     The name input carries both its size variant and --name, so --name is
     stated second: the two rules have equal specificity and source order is
     what separates them. The contact variant is sized in the pages layer,
     which outranks this one, so it repeats the pair there. */
  .ls-formrow--named .ls-field--band,
  .ls-formrow--named .ls-field--home { flex: 1 1 190px; }
  .ls-formrow--named .ls-field--name { flex: 1 1 150px; }

  /* --- Consent and errors -------------------------------------------------
     Both sit under the field row rather than inside it. The row is a flex line
     whose whole job is to keep the field and its button together at every
     width, and a checkbox or a sentence of error text wrapping into it would
     break that pairing.

     The checkbox follows the button in the document, which puts it after the
     button in the tab order. That is the trade for keeping the field and
     button on one line, and it costs nothing: the input is `required`, so
     submitting without it is refused by the browser, which then moves focus
     to the box and says why. */
  .ls-formconsent {
    display: flex; gap: 10px; align-items: flex-start;
    margin: 14px 0 0;
    font-size: var(--ls-fs-meta); color: var(--ls-cream-meta);
    max-width: calc(480 * var(--ls-px));
  }
  .ls-formconsent input { flex: none; margin-top: .15em; accent-color: var(--ls-gold); }
  .ls-formconsent a { color: var(--ls-gold); }

  /* Revealed by script when the server turns a sign-up away. Colour is not
     carrying the meaning here — the sentence states what happened and
     role="alert" announces it — so the gold reads as emphasis rather than as
     a status that has to be seen to be understood. */
  .ls-formerror { margin: 12px 0 0; font-size: var(--ls-fs-meta); color: var(--ls-gold); }

  /* Post-submit acknowledgement, in place of the form. */
  .ls-confirm {
    border: 1px solid rgba(var(--ls-gold-rgb), .4);
    border-radius: var(--ls-radius);
    background: rgba(var(--ls-gold-rgb), .08);
    padding: 20px 24px;
  }
  .ls-confirm__title { font-family: var(--ls-font-serif); font-size: 20px; color: var(--ls-gold); margin-bottom: 6px; }
  .ls-confirm__note { margin: 0; font-size: var(--ls-fs-prose-sm); color: var(--ls-cream-meta); }

  /* ------------------------------------------------------------------------
     SIDE NAV — the sticky in-page contents on long pages
     ---------------------------------------------------------------------- */
  .ls-withaside {
    width: var(--ls-wrap); margin: 0 auto;
    display: flex; gap: clamp(36px, 5vw, 84px); align-items: flex-start;
  }
  /* Wider gutter form, used where the aside is a list of sibling pages. */
  .ls-withaside--wide { gap: clamp(32px, 4vw, 74px); flex-wrap: wrap; }
  /* No max-width: the column runs to the band's right edge. It used to stop at
     860 (760 for the article form), which left 147px of the band unused at
     1280 and 263px once --ls-wrap reached 1440 — the aside was flush with one
     edge of the band and the article stopped short of the other, so the pair
     read as pushed left rather than as a two-column layout. The measure that
     costs is real and deliberate: body copy on these pages runs to ~120
     characters at 1920. Reinstating a cap is one declaration if it ever wants
     one back. */
  .ls-withaside__main { flex: 1 1 calc(560 * var(--ls-px)); min-width: 0; }

  .ls-sidenav { flex: 0 0 calc(212 * var(--ls-px)); position: sticky; top: 74px; }
  .ls-sidenav__label {
    font-size: 10.5px; font-weight: 700; letter-spacing: var(--ls-track-kicker); text-transform: uppercase;
    color: var(--ls-ink-meta); margin-bottom: 12px; padding-left: 15px;
  }
  .ls-sidenav__label--inset { padding-left: 16px; }
  .ls-sidenav__list { display: flex; flex-direction: column; border-left: 1px solid rgba(var(--ls-ink-rgb), .14); }
  .ls-sidenav__link {
    padding: 9px 15px;
    font-size: var(--ls-fs-prose-sm); font-weight: 500;
    color: var(--ls-ink-meta);
    border-left: 2px solid transparent;
    margin-left: -1px; line-height: 1.4;
    transition: color var(--ls-ease), border-color var(--ls-ease);
  }
  .ls-sidenav__link:hover { color: var(--ls-teal-mid); }
  .ls-sidenav__link--sub { padding: 7px 15px 7px 29px; font-size: var(--ls-fs-meta); }
  .ls-sidenav__link.is-active { color: var(--ls-ink); border-left-color: var(--ls-gold-deep); font-weight: 700; }
  .ls-sidenav__link--sub.is-active { font-weight: 600; }

  /* Project switcher: the same idea, sized for page titles rather than
     section headings. */
  .ls-projnav { flex: 0 1 calc(220 * var(--ls-px)); min-width: calc(190 * var(--ls-px)); position: sticky; top: 78px; }
  .ls-projnav__label {
    font-size: var(--ls-fs-kicker); font-weight: 700; letter-spacing: var(--ls-track-kicker); text-transform: uppercase;
    color: var(--ls-gold-ink); margin-bottom: 16px; padding-left: 16px;
  }
  .ls-projnav__link {
    display: block; padding: 11px 16px;
    border-left: 2px solid #e7e2d4;
    color: var(--ls-ink-soft); font-size: var(--ls-fs-prose); font-weight: 500;
  }
  .ls-projnav__link:hover { color: var(--ls-teal-mid); border-left-color: var(--ls-gold-deep); }
  .ls-projnav__link.is-active {
    border-left-color: var(--ls-gold-deep); color: var(--ls-teal-mid);
    font-weight: 700; background: rgba(var(--ls-gold-deep-rgb), .08);
  }

  /* A section within a long page: an anchor target with its own bottom gap. */
  .ls-subsection { scroll-margin-top: 78px; margin-bottom: var(--ls-head-gap); }

  /* ------------------------------------------------------------------------
     SPEC GRID — the hairline table of permit figures
     ---------------------------------------------------------------------- */
  .ls-specs {
    display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); gap: 1px;
    background: rgba(var(--ls-ink-rgb), .14);
    border: 1px solid rgba(var(--ls-ink-rgb), .14);
    margin-bottom: 8px;
  }
  .ls-specs__cell { background: var(--ls-white); padding: 18px 20px; }
  .ls-specs__v {
    font-family: var(--ls-font-serif); font-size: 21px;
    color: var(--ls-teal-mid); line-height: 1.1; white-space: nowrap;
  }
  .ls-specs__l {
    font-size: 10.5px; font-weight: 600; letter-spacing: var(--ls-track-caps); text-transform: uppercase;
    color: var(--ls-ink-meta); margin-top: 6px;
  }

  /* ------------------------------------------------------------------------
     FIGURES AND FRAMES
     ---------------------------------------------------------------------- */
  .ls-figframe {
    margin: 0 0 20px;
    background: var(--ls-white);
    border: 1px solid var(--ls-rule-ink);
    border-radius: var(--ls-radius-md);
    overflow: hidden;
  }
  .ls-img { display: block; width: 100%; height: auto; }
  .ls-caption { padding: 12px 16px; font-size: var(--ls-fs-meta); color: var(--ls-ink-meta); line-height: var(--ls-lh-snug); }

  .ls-mapframe {
    border: 1px solid rgba(var(--ls-ink-rgb), .16);
    border-radius: var(--ls-radius-lg); overflow: hidden;
    box-shadow: 0 18px 50px rgba(var(--ls-teal-rgb), .12);
  }
  .ls-mapframe__frame { display: block; width: 100%; height: clamp(400px, 52vh, 520px); border: 0; }

  /* A plain white card on a paper band. */
  .ls-tile {
    background: var(--ls-white);
    border: 1px solid #e7e2d4;
    border-radius: var(--ls-radius);
    padding: clamp(22px, 2.6vw, 35px);
  }

  /* --- Further chip variants ---------------------------------------------- */
  .ls-tag {
    font-size: var(--ls-fs-kicker); font-weight: 600;
    letter-spacing: var(--ls-track-tag); text-transform: uppercase;
    color: var(--ls-gold-deep);
  }
  .ls-tag--gold { color: var(--ls-gold); }
  .ls-chip--wide { font-size: var(--ls-fs-kicker); letter-spacing: var(--ls-track-tag); padding: 6px 12px; white-space: normal; }
  /* Filled status pill: the fill replaces the outline rather than sitting inside it. */
  .ls-chip--granted { background: #3f6b54; color: var(--ls-cream); border: 0; }
  .ls-chip--ink {
    font-size: 10.5px; letter-spacing: var(--ls-track-caps);
    color: var(--ls-ink-meta); border-color: rgba(var(--ls-ink-rgb), .18);
    padding: 4px 9px; white-space: normal;
  }
  /* Quiet chip: a file-type marker inside a link, so weight, case and colour
     all come from the link it sits in. */
  .ls-chip--quiet {
    border-color: rgba(156, 125, 56, .4);
    padding: 3px 7px; font-size: 10px; letter-spacing: var(--ls-track-wide);
    font-weight: inherit; text-transform: inherit; color: inherit; white-space: normal;
  }
  .ls-chip--quiet-sm { padding: 2px 6px; }

  /* ------------------------------------------------------------------------
     TIMELINE — a gold rule with dated entries hung off it
     ---------------------------------------------------------------------- */
  .ls-splitlayout {
    width: var(--ls-wrap); margin: 0 auto;
    display: flex; gap: clamp(32px, 5vw, 84px); flex-wrap: wrap; align-items: flex-start;
  }
  .ls-splitlayout__aside { flex: 0 1 400px; min-width: 260px; }
  .ls-timeline { flex: 1 1 520px; min-width: 0; display: flex; flex-direction: column; border-left: 2px solid var(--ls-gold-deep); }
  .ls-timeline__row { display: flex; gap: 6px 20px; flex-wrap: wrap; padding: 12px 0 12px 22px; align-items: baseline; }
  .ls-timeline__when {
    flex: 0 0 110px; font-family: var(--ls-font-serif); font-size: 17px;
    color: var(--ls-gold-ink); white-space: nowrap;
  }
  .ls-timeline__what { margin: 0; flex: 1 1 260px; font-size: var(--ls-fs-prose); line-height: var(--ls-lh-body); color: var(--ls-ink-body); }

  /* ------------------------------------------------------------------------
     NEWS INDEX — a year heading over hairline-separated release rows
     ---------------------------------------------------------------------- */
  /* --- News year bar ------------------------------------------------------
     Every year of releases in one wrapping row, at the top of the archive.
     This is the **mobile** form of the news navigation, and the only one: it
     is display:none here and turned on inside the 900px block, the same block
     that hides .ls-projnav. Above 900px the archive carries the same sticky
     year aside as the news detail pages, so arriving at a release and going
     back up to the index no longer swaps one navigation for another; below it
     the aside is gone and the row takes over. Declaring it off by default is
     what keeps every media query in the file a max-width one.

     A row rather than a stacked column because a column stops being scannable
     once there are ten years in it, and it wraps rather than scrolls, so the
     tenth year is as reachable as the first. Adding a year is one more link in
     both places rather than a layout decision. */
  .ls-yearbar { display: none; flex-wrap: wrap; gap: 8px; margin: 0 0 clamp(24px, 3vw, 39px); }
  .ls-yearbar__link {
    display: inline-flex; align-items: center; min-height: 38px;
    padding: 0 16px;
    border: 1px solid rgba(var(--ls-ink-rgb), .16);
    border-radius: var(--ls-radius);
    font-size: var(--ls-fs-prose-sm); font-weight: 600;
    letter-spacing: var(--ls-track-link);
    color: var(--ls-ink-body);
    transition: color var(--ls-ease), border-color var(--ls-ease), background var(--ls-ease);
  }
  .ls-yearbar__link:hover { color: var(--ls-teal-mid); border-color: rgba(var(--ls-teal-rgb), .4); }
  /* The current year takes the solid badge treatment, the site's strongest
     "this one" marker, so it reads at a glance in a row of ten. */
  .ls-yearbar__link.is-active,
  .ls-yearbar__link.is-active:hover {
    background: var(--ls-gold); border-color: var(--ls-gold);
    color: var(--ls-deep); font-weight: 700;
  }

  .ls-yearhead { display: flex; align-items: baseline; gap: 16px; margin-bottom: clamp(20px, 2.6vw, 35px); }
  .ls-yearhead__title {
    margin: 0; font-family: var(--ls-font-serif); font-weight: 400;
    font-size: clamp(30px, 3.4vw, 49.5px); line-height: 1.1; letter-spacing: -0.01em;
  }
  .ls-yearhead__count {
    font-size: 12.5px; font-weight: 600; letter-spacing: var(--ls-track-caps);
    text-transform: uppercase; color: var(--ls-ink-meta);
  }
  /* The whole row is the target, not just the headline. The headline link
     stretches an invisible ::after over the row, which keeps one link per
     release in the accessibility tree while giving the pointer a target the
     size of the row; the PDF link is lifted above it so it stays reachable.
     "Read Release" is a span rather than a second link to the same page —
     it is the at-rest affordance, and duplicating the destination only made
     a screen reader announce every release twice. */
  .ls-newsrow {
    position: relative;
    display: flex; gap: clamp(18px, 3vw, 51px); flex-wrap: wrap; align-items: baseline;
    /* The row is exactly its column: no side padding, no negative side margin.
       It used to pad 19px and bleed -16px back out, so the hover box and the
       hairline sat ~16px wider than the text on each side. That was invisible
       while the archive was capped at an 820px measure inside a 1240 wrap —
       there was empty column either side to bleed into. Now the column runs to
       the band edge, so the bleed put every hairline 16px past the edge every
       other band on the page aligns to, and put the row 2px past the viewport
       on a 375 phone. */
    padding: clamp(20px, 2.4vw, 30px) 0;
    margin: 0;
    border-top: 1px solid #e7e2d4;
    border-radius: var(--ls-radius);
    transition: background var(--ls-ease);
  }
  .ls-newsrow:hover { background: rgba(var(--ls-gold-deep-rgb), .08); }
  .ls-newsrow--tight { padding-top: clamp(16px, 1.9vw, 26px); padding-bottom: clamp(16px, 1.9vw, 26px); }
  .ls-newsrow__body { flex: 1 1 380px; min-width: 0; }
  .ls-newsrow__title { margin: 0 0 11px; font-size: 17.5px; font-weight: 650; line-height: 1.35; letter-spacing: -0.005em; }
  /* The underline only appears on hover, so the list reads as a list at rest. */
  .ls-newsrow__link {
    color: var(--ls-ink); transition: color var(--ls-ease);
    text-decoration-color: transparent; text-underline-offset: 3px; text-decoration-thickness: 1px;
  }
  .ls-newsrow__link::after { content: ""; position: absolute; inset: 0; border-radius: inherit; }
  .ls-newsrow:hover .ls-newsrow__link { color: var(--ls-teal-mid); text-decoration: underline; text-decoration-color: var(--ls-teal-mid); }
  .ls-newsrow__link:focus-visible { outline-offset: 3px; }
  .ls-newsrow__meta { font-size: var(--ls-fs-meta); font-weight: 600; letter-spacing: var(--ls-track-label); color: var(--ls-gold-ink); }
  .ls-newsrow:hover .ls-newsrow__meta { color: var(--ls-teal-mid); }
  .ls-newsrow__cta {
    position: relative; z-index: 1;   /* above the stretched headline link */
    display: inline-flex; align-items: center; gap: 8px;
    font-size: var(--ls-fs-meta); font-weight: 600; letter-spacing: var(--ls-track-label); color: var(--ls-gold-ink);
  }
  .ls-divider-v { position: relative; z-index: 1; }
  .ls-divider-v { width: 1px; height: 13px; background: #e7e2d4; }

  /* ------------------------------------------------------------------------
     NEWS RELEASE — the long-form article body
     ---------------------------------------------------------------------- */
  .ls-article__back {
    display: inline-block;
    font-size: var(--ls-fs-meta); font-weight: 600; letter-spacing: var(--ls-track-link);
    color: var(--ls-gold-deep); margin-bottom: 20px;
  }
  .ls-article__head {
    padding-bottom: clamp(20px, 2.4vw, 30px);
    border-bottom: 1px solid #e7e2d4;
    margin-bottom: clamp(26px, 3vw, 39px);
  }
  .ls-article__title {
    margin: 0 0 16px;
    font-family: var(--ls-font-serif); font-weight: 400;
    font-size: clamp(28px, 3.2vw, 47px); line-height: var(--ls-lh-tight); letter-spacing: -0.01em;
    color: var(--ls-ink);
  }
  .ls-article__h2 {
    margin: clamp(34px, 4vw, 53px) 0 16px;
    font-family: var(--ls-font-serif); font-weight: 400;
    font-size: clamp(22px, 2.2vw, 31.5px); line-height: 1.15; color: var(--ls-ink);
  }
  .ls-article__label {
    margin: 0 0 6px;
    font-size: var(--ls-fs-meta); font-weight: 700; letter-spacing: var(--ls-track-caps); text-transform: uppercase;
    color: var(--ls-ink-meta);
  }
  .ls-article__label--gold { margin-bottom: 8px; color: var(--ls-gold-ink); }
  .ls-article__foot { margin: clamp(30px, 3.5vw, 46px) 0 0; padding-top: 22px; border-top: 1px solid #e7e2d4; }
  .ls-article__foot--lg { padding-top: 24px; }
  .ls-article__box {
    margin: 22px 0 0; padding: 20px 24px;
    background: var(--ls-white); border: 1px solid #e7e2d4; border-radius: var(--ls-radius-md);
  }
  .ls-article__link {
    display: inline-flex; align-items: center; gap: 11px;
    font-size: var(--ls-fs-prose-sm); font-weight: 600; letter-spacing: var(--ls-track-link); color: var(--ls-gold-ink);
  }
  .ls-article__note { margin: 20px 0 12px; font-size: var(--ls-fs-meta); line-height: 1.7; color: var(--ls-ink-meta); }

  .ls-quote { margin: clamp(26px, 3vw, 39px) 0; padding: 4px 0 4px 26px; border-left: 2px solid var(--ls-gold-deep); }
  .ls-quote__text {
    margin: 0 0 12px;
    font-family: var(--ls-font-serif); font-size: clamp(18px, 1.9vw, 24.5px);
    line-height: var(--ls-lh-snug); color: var(--ls-teal-mid);
  }
  .ls-quote__by {
    font-size: 12.5px; font-weight: 600; letter-spacing: var(--ls-track-wide);
    text-transform: uppercase; color: var(--ls-gold-ink);
  }

  /* ------------------------------------------------------------------------
     CALLOUT — a teal block that lifts one finding out of the running text
     ---------------------------------------------------------------------- */
  .ls-callout {
    background: var(--ls-teal-mid); color: var(--ls-cream);
    border-radius: var(--ls-radius-lg); padding: clamp(22px, 2.8vw, 37px);
    margin-bottom: 20px;
  }
  .ls-callout__text { margin: 0; font-size: var(--ls-fs-prose); line-height: 1.7; color: rgba(var(--ls-cream-rgb), .85); }

  /* ------------------------------------------------------------------------
     DOCUMENT CARD — photo panel beside a copy panel, the whole card a link
     ---------------------------------------------------------------------- */
  .ls-doccard {
    overflow: hidden; display: flex;
    min-height: clamp(268px, 23vw, 369px);
    border-radius: var(--ls-radius-lg);
    background: var(--ls-deep); color: var(--ls-cream);
    transition: transform .25s ease, box-shadow .25s ease;
  }
  .ls-doccard:hover { transform: translateY(-4px); box-shadow: var(--ls-shadow-lift); color: var(--ls-cream); }
  .ls-doccard__visual {
    position: relative; flex: 0 0 38%;
    display: flex; align-items: center; justify-content: center;
    padding: clamp(14px, 1.4vw, 23px); overflow: hidden;
  }
  .ls-doccard__photo { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
  .ls-doccard__scrim { position: absolute; inset: 0; background: linear-gradient(150deg, rgba(var(--ls-abyss-rgb), .32), rgba(var(--ls-abyss-rgb), .58)); }
  /* The cover thumbnail reads as a printed sheet lying on the photograph. */
  .ls-doccard__sheet {
    position: relative; z-index: 1;
    width: min(100%, 214px); aspect-ratio: 16/9; overflow: hidden;
    background: var(--ls-white);
    border: 1px solid rgba(var(--ls-abyss-rgb), .3);
    box-shadow: 0 18px 40px rgba(3, 17, 22, .5), 0 3px 8px rgba(3, 17, 22, .32);
  }
  .ls-doccard__cover { display: block; width: 100%; height: 100%; object-fit: cover; }
  .ls-doccard__body {
    flex: 1; min-width: 0;
    display: flex; flex-direction: column; justify-content: center;
    padding: clamp(26px, 2.8vw, 42px);
    background: linear-gradient(158deg, #0e4a5d, #082a34);
    box-shadow: -26px 0 46px rgba(var(--ls-abyss-rgb), .45);
  }
  .ls-doccard__kicker {
    display: block;
    font-size: var(--ls-fs-kicker); font-weight: 700; letter-spacing: var(--ls-track-kicker); text-transform: uppercase;
    color: var(--ls-gold-deep);
  }
  .ls-doccard__title {
    display: block; font-family: var(--ls-font-serif);
    font-size: clamp(21px, 2vw, 30px); line-height: 1.16; margin-top: 12px; text-wrap: pretty;
  }
  .ls-doccard__date { display: block; font-family: var(--ls-font-mono); font-size: var(--ls-fs-meta); color: var(--ls-cream-meta); margin-top: 10px; }
  .ls-doccard__desc { display: block; font-size: var(--ls-fs-prose-sm); line-height: 1.62; color: var(--ls-cream-body); margin-top: 14px; text-wrap: pretty; }
  .ls-doccard__foot {
    display: flex; align-items: baseline; gap: 14px; flex-wrap: wrap;
    margin-top: 20px; padding-top: 18px;
    border-top: 1px solid rgba(var(--ls-gold-rgb), .16);
  }
  .ls-doccard__cta { font-size: var(--ls-fs-meta); font-weight: 700; letter-spacing: var(--ls-track-wide); text-transform: uppercase; color: var(--ls-gold); }
  .ls-doccard__size { font-family: var(--ls-font-mono); font-size: var(--ls-fs-meta); color: var(--ls-cream-meta); }

  /* Card variant that matches the paper-band tiles on the investors page. */
  .ls-card--tile { border-color: #e7e2d4; border-radius: var(--ls-radius); padding: clamp(22px, 2.6vw, 35px); }

  /* ------------------------------------------------------------------------
     FOOTER
     ---------------------------------------------------------------------- */
  .ls-footer {
    position: relative; overflow: hidden;
    background: var(--ls-abyss); color: var(--ls-cream);
    padding: clamp(56px, 7vw, 102px) 0 36px;
  }
  /* The mark sits whole in the corner rather than bleeding off it. A crop
     works for a shape that still reads when you only see part of it; this one
     is a 129x129 monogram of straight angular facets, so any partial view is
     just a run of parallelograms, and the eye keeps trying to resolve it as a
     logo and failing. That is what it did at the original -5vw/-6vw, where
     two thirds of it sat inside the content area clipped mid-shape, and
     pushing the crop further out only made a smaller fragment. Uncropped and
     small, it reads as the company's mark and as deliberate. Small enough not
     to compete with the logo lockup diagonally opposite it. Two runs sit over
     it — the second contact block and the build credit — and .05 white lifts
     the ground under them from #061c24 to #12272f, which costs those runs
     about half a point of contrast: 6.96 to 6.43 and 8.28 to 7.55, both worst
     case and both a long way clear of 4.5. Raising the opacity is what would
     put that at risk, not the position. */
  .ls-footer__mark {
    position: absolute;
    right: clamp(28px, 3vw, 64px);
    bottom: clamp(28px, 3vw, 64px);
    height: clamp(150px, 15vw, 220px); width: auto;
    opacity: .05;
    filter: brightness(0) invert(1);
    pointer-events: none; user-select: none;
  }
  .ls-footer__inner { width: var(--ls-wrap); margin: 0 auto; position: relative; z-index: 1; }
  /* Explicit tracks, not `repeat(auto-fit, minmax(220px, 1fr))`. auto-fit
     chose the column count by arithmetic: four 220px tracks plus their gaps
     do not fit until ~1100px, so every width from 790 to 1099 — iPad
     landscape, a half-width laptop window — fell to three columns and
     orphaned Contact onto a second row with a void beside it. The count is a
     design decision, so it is made at a breakpoint (below, in `responsive`)
     rather than derived. The brand and nav tracks are wider because their
     content is: a two-line blurb and a two-up link list against an address. */
  .ls-footer__cols {
    display: grid;
    grid-template-columns: 1.5fr 1.35fr 1fr 1fr;
    align-items: start;
    gap: clamp(32px, 4vw, 65px);
    padding-bottom: clamp(36px, 4vw, 65px);
    border-bottom: 1px solid var(--ls-rule-gold);
  }
  .ls-footer__brand { max-width: calc(340 * var(--ls-px)); padding-top: 4px; }
  .ls-footer__logo { display: inline-block; margin-bottom: 16px; transition: opacity var(--ls-ease); }
  .ls-footer__logo:hover { opacity: .7; }
  .ls-footer__logo-img { height: 40px; display: block; filter: brightness(0) invert(1); }
  .ls-footer__blurb { margin: 0; font-size: var(--ls-fs-prose-sm); line-height: var(--ls-lh-body); color: var(--ls-cream-meta); }
  .ls-footer__list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 11px; }
  /* The site nav runs two-up. Eight to ten links in a single column made a
     252px spike next to a 78px Contact block, and because grid rows size to
     the tallest item the other three columns each carried its dead space.
     Multi-column rather than a grid so the reading order stays top-to-bottom
     down column one, whatever number of links a given page's footer carries.
     Spacing is padding, not a row gap: a margin between items would also be
     applied at the top of column two and push it out of line with column one. */
  .ls-footer__list--nav { display: block; columns: 2; column-gap: 24px; }
  .ls-footer__list--nav li { break-inside: avoid; padding-bottom: 11px; }
  .ls-footer__link { color: var(--ls-cream-body); font-size: var(--ls-fs-prose-sm); }
  .ls-footer__link:hover { color: var(--ls-gold); }
  /* A phone number and an email address read as data, not as controls, and
     the footer's link colour is the same one the postal address beside them
     uses — so at every width above the 760px rule that underlines all of
     these, nothing but hover said the phone number was dialable. Scoped to
     tel:/mailto: so the nav links stay clean. */
  .ls-footer__link[href^="tel:"],
  .ls-footer__link[href^="mailto:"] {
    text-decoration: underline;
    text-decoration-color: rgba(var(--ls-cream-rgb), .28);
    text-underline-offset: 3px;
  }
  .ls-footer__link[href^="tel:"]:hover,
  .ls-footer__link[href^="mailto:"]:hover { text-decoration-color: currentColor; }
  /* Label above each contact point: a bare address or number gives no clue
     what it is for, or which one to reach for. */
  .ls-footer__contact { margin: 0 0 14px; font-size: var(--ls-fs-prose-sm); line-height: 1.7; color: var(--ls-cream-meta); }
  .ls-footer__contact:last-child { margin-bottom: 0; }
  .ls-footer__contact > a { display: block; color: var(--ls-cream-body); }
  .ls-footer__address { margin: 0 0 14px; font-size: var(--ls-fs-prose-sm); line-height: 1.7; color: var(--ls-cream-body); }
  /* Investor-fraud notice. Kept as its own unit above .ls-footer__legal
     rather than folded into it, because the two are different kinds of small
     print: the forward-looking paragraph qualifies what the page claims,
     this one asks the reader to act. So it is set a step larger than the
     legal run and on the body tier rather than the meta one — small print
     that has to actually be read. The gold edge marks it without the alarm
     colouring a red banner would bring to a page that is not reporting an
     incident; gold is already the footer's accent, so the rule reads as
     emphasis rather than as an error state. Width matches the legal run so
     the two share a measure. */
  .ls-footer__alert {
    margin: clamp(26px, 3vw, 38px) 0 0;
    padding-left: clamp(16px, 1.6vw, 22px);
    border-left: 2px solid rgba(var(--ls-gold-rgb), .42);
    max-width: calc(1020 * var(--ls-px));
  }
  .ls-footer__alert-body { margin: 0; font-size: var(--ls-fs-meta); line-height: 1.75; color: var(--ls-cream-body); }
  .ls-footer__legal { font-size: var(--ls-fs-kicker); line-height: 1.7; color: var(--ls-cream-meta); margin: 26px 0 0; max-width: calc(1020 * var(--ls-px)); }
  .ls-footer__bar { display: flex; justify-content: space-between; gap: 16px; flex-wrap: wrap; margin-top: 22px; }
  .ls-footer__copy { font-size: var(--ls-fs-meta); color: var(--ls-cream-meta); }
  /* Bottom bar: copyright and the legal links group at one end, the build
     credit at the other. The links sit one step above the meta tier the
     copyright uses, so they read as links without competing with the
     company's own footer navigation above. The gap is wider than the space
     between the two links themselves so the copyright sentence reads as its
     own item rather than as the first word of the link run. */
  .ls-footer__barleft { display: flex; gap: 20px; flex-wrap: wrap; align-items: baseline; }
  .ls-footer__barleft > .ls-footer__copy { margin-right: 12px; }
  .ls-footer__minilink { font-size: var(--ls-fs-meta); color: var(--ls-cream-body); }
  .ls-footer__minilink:hover { color: var(--ls-gold); }
}

/* ==========================================================================
   UTILITIES — single-purpose helpers, used sparingly
   ========================================================================== */
@layer utilities {
  /* The subscribe form and its confirmation swap with the `hidden` attribute.
     The browser's own rule for it is a UA declaration, so any class that sets
     a display beats it (.ls-formrow is display:flex, and would stay visible);
     restating it here puts it in a layer above the components. */
  [hidden] { display: none; }

  /* Read, not seen. ls-countup.js parks the finished figure in one of these
     for the length of the ramp, so a screen reader is never handed a number
     that is still moving. Removed again when the count lands. */
  .ls-sr-only {
    position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
    overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
  }

  .ls-m0 { margin: 0; }
  .ls-mt-30 { margin-top: 30px; }
  .ls-nowrap { white-space: nowrap; }
  .ls-balance { text-wrap: balance; }
  .ls-pretty { text-wrap: pretty; }
  .ls-strong { font-weight: 600; }
  .ls-rule-top { border-top: 1px solid #e7e2d4; }
  .ls-stack { display: flex; flex-direction: column; }
  .ls-row { display: flex; }
  .ls-row--wrap { flex-wrap: wrap; }
  .ls-row--center { align-items: center; }
  .ls-row--10 { gap: 10px; }
  .ls-row--14 { gap: 14px; }
  .ls-row--16 { gap: 16px; }
  .ls-row--gap-b { margin-bottom: 20px; }

  /* Reading measures. Numeric because these are layout constraints on one
     element, not a semantic role — the number is the clearest possible name. */
  .ls-measure-400 { max-width: calc(400 * var(--ls-px)); }
  .ls-measure-480 { max-width: calc(480 * var(--ls-px)); }
  .ls-measure-560 { max-width: calc(560 * var(--ls-px)); }
  .ls-measure-640 { max-width: calc(640 * var(--ls-px)); }
  .ls-measure-680 { max-width: calc(680 * var(--ls-px)); }
  .ls-measure-700 { max-width: calc(700 * var(--ls-px)); }
  .ls-measure-760 { max-width: calc(760 * var(--ls-px)); }
  .ls-measure-820 { max-width: calc(820 * var(--ls-px)); }
  .ls-measure-860 { max-width: calc(860 * var(--ls-px)); }
}

/* ==========================================================================
   PAGES — styling that belongs to one page or one page family.
   Anything that turns out to be reused belongs in the components layer above.
   ========================================================================== */
@layer pages {
  /* --- Shared layout ---------------------------------------------------- */
  /* Two even columns, vertically centred: the subscribe and contact bands */
  .ls-splitband {
    width:var(--ls-wrap);
    margin:0 auto;
    display:grid;
    grid-template-columns:repeat(auto-fit,minmax(300px,1fr));
    gap:clamp(32px,4vw,84px);
    align-items:center;
  }
  /* Top-aligned variant. Centring works when both columns carry similar
     weight, as on the home page; where one is a short address and the other a
     display heading over a form, centring floats the short column and the two
     kickers no longer share a line. */
  .ls-splitband--top { align-items:start; }

  /* --- HOME -------------------------------------------------------------- */
  /* The photographic masthead. Its scrims are tuned per viewport; see the media queries at the foot of this layer. */
  .ls-home-hero {
    position:relative;
    overflow:hidden;
    background:linear-gradient(160deg,#0b3543 0%,#08262f 55%,#061c24 100%);
    color:#f3eee2;
    min-height:clamp(620px,96vh,960px);
    display:flex;
    flex-direction:column;
  }
  .ls-home-hero__img {
    position:absolute;
    left:0;
    right:0;
    bottom:0;
    width:100%;
    height:100%;
    object-fit:cover;
    /* The photograph is 2115×1584 (4:3) and the box is the full width of the
       screen by at most 960px, so the wider the screen the more of the frame's
       height `cover` throws away: a third of it at 1920, half at 2560, nearly
       two thirds at 3440. `62%` takes that crop mostly off the top, and the
       top is where the crew are — their hard hats sit between 26% and 36% down
       the frame, so past about 2000px the hats start being cut off, which is
       the one thing this photograph cannot afford to lose.

       The second term is a ceiling on that top crop, not a second design
       value. 16.4vw is 22% of the displayed image height (the image is
       0.749 × its box width), so `max()` takes whichever offset hides less of
       the top: 62% everywhere it is the safer of the two, and a hard stop at
       22% of the frame beyond that, four points clear of the hats. Below a
       ~1980px viewport the percentage always wins and nothing moves; above it
       the picture pans up rather than losing the faces. Recompute both numbers
       if the photograph is ever replaced — they encode its aspect ratio and
       where the people are standing in it. */
    object-position:center max(-16.4vw, 62%);
  }
  /* Side scrim, masked to stop below the crew's faces at every crop */
  .ls-hero-side {
    position:absolute;
    inset:0;
    background:linear-gradient(97deg,rgba(6,28,36,.84) 0%,rgba(6,28,36,.72) 36%,rgba(6,28,36,.16) 54%,rgba(6,28,36,0) 63%);
    -webkit-mask-image:linear-gradient(to top,#000 340px,transparent 415px);
    mask-image:linear-gradient(to top,#000 340px,transparent 415px);
  }
  .ls-hero-veil {
    position:absolute;
    inset:auto 0 0 0;
    height:400px;
    max-height:100%;
    background:linear-gradient(to top,rgba(6,28,36,.9) 0px,rgba(6,28,36,.38) 150px,rgba(6,28,36,.08) 280px,rgba(6,28,36,0) 400px);
  }
  .ls-home-hero__topfade {
    position:absolute;
    inset:0 0 auto 0;
    height:150px;
    background:linear-gradient(rgba(6,28,36,.5),rgba(6,28,36,0));
  }
  .ls-home-hero__deco {
    position:absolute;
    right:-6%;
    top:52%;
    transform:translateY(-52%);
    width:min(720px,58vw);
    pointer-events:none;
    user-select:none;
  }
  .ls-home-hero__pulse { transform-origin:280px 255px; animation:lsPulse 2.6s ease-out infinite; }
  .ls-home-hero__decofade {
    position:absolute;
    inset:auto 0 0 0;
    height:30%;
    background:linear-gradient(rgba(6,28,36,0),rgba(6,28,36,.6));
    pointer-events:none;
  }
  .ls-hero-wrap {
    width:var(--ls-wrap);
    margin:0 auto;
    flex:1;
    display:flex;
    align-items:flex-end;
    position:relative;
    z-index:2;
    padding:150px 0 72px;
  }
  /* The copy block used to fade in as one; the `motion` layer now brings the
     headline and the buttons in separately, so it carries no animation. */
  .ls-home-hero__copy { max-width:calc(560 * var(--ls-px)); position:relative; z-index:0; }
  /* Soft panel travelling with the copy, so the side scrim never has to reach up into the crew's faces */
  .ls-home-hero__panel {
    position:absolute;
    z-index:-1;
    inset:-12px -70px -20px -60px;
    background:rgba(6,28,36,.46);
    border-radius:44px;   /* a blurred scrim shape, not a UI radius */
    filter:blur(28px);
    pointer-events:none;
  }
  /* Strengthens the headline's cap row. Every edge is feathered over at least 40px: anything steeper reads as a line drawn across the photograph. */
  .ls-home-hero__booster {
    position:absolute;
    z-index:-1;
    left:-40px;
    right:-50px;
    top:-34px;
    height:140px;
    background:linear-gradient(to bottom,rgba(6,28,36,0) 0,rgba(6,28,36,.34) 40px,rgba(6,28,36,.28) 70px,rgba(6,28,36,0) 140px);
    -webkit-mask-image:linear-gradient(90deg,transparent 0,#000 40px,#000 calc(100% - 70px),transparent 100%);
    mask-image:linear-gradient(90deg,transparent 0,#000 40px,#000 calc(100% - 70px),transparent 100%);
    pointer-events:none;
  }
  .ls-home-hero__title {
    font-family:'Libre Caslon Display',serif;
    font-weight:400;
    font-size:clamp(34px,4.4vw,65px);
    line-height:1.06;
    margin:0 0 22px;
    letter-spacing:-.01em;
    text-shadow:0 1px 3px rgba(6,28,36,.5),0 2px 28px rgba(6,28,36,.6);
  }
  .ls-home-hero__actions { display:flex; gap:14px; flex-wrap:wrap; align-items:center; margin-top:34px; }
  .ls-home-hero__stats {
    position:relative;
    z-index:2;
    border-top:1px solid rgba(231,207,143,.16);
    background:rgba(6,28,36,.35);
    backdrop-filter:blur(4px);
  }
  .ls-home-hero__statgrid {
    width:var(--ls-wrap);
    margin:0 auto;
    display:grid;
    grid-template-columns:repeat(auto-fit,minmax(180px,1fr));
    gap:1px;
    padding:0;
  }
  .ls-home-hero__statcell {
    padding:26px 28px 26px 0;
    border-left:1px solid rgba(231,207,143,.14);
    padding-left:28px;
  }
  /* The left rule is what divides one cell from the next, so on the first cell
     it has nothing to its left to divide and reads as a stray line down the
     edge of the band — the more so as there is no rule closing the strip on
     the right. Same reasoning already applied two-up at 760px; see
     .ls-statstrip__cell:nth-child(odd). */
  .ls-home-hero__statcell:first-child { border-left:0; }
  .ls-home-hero__statv {
    font-family:'Libre Caslon Display',serif;
    font-size:clamp(26px,2.4vw,40.5px);
    color:#e7cf8f;
    line-height:1;
  }
  .ls-home-hero__statl {
    font-size:11.5px;
    font-weight:600;
    letter-spacing: var(--ls-track-caps);
    text-transform:uppercase;
    color: var(--ls-cream-meta);
    margin-top:9px;
    line-height:1.35; min-height:2.7em;   /* see .ls-statstrip__l */
  }
  .ls-home-about { display:flex; flex-wrap:wrap; gap:clamp(30px,5vw,90px); align-items:flex-start; }
  .ls-home-about__head { flex:1 1 330px; min-width:0; }
  .ls-home-about__title {
    font-family:'Libre Caslon Display',serif;
    font-weight:400;
    font-size:clamp(28px,3vw,49.5px);
    line-height:1.14;
    margin:0;
    letter-spacing:-0.01em;
    text-wrap:pretty;
  }
  .ls-about-body {
    flex:1.3 1 430px;
    min-width:0;
    display:flex;
    flex-direction:column;
    gap:18px;
    border-left:1px solid rgba(var(--ls-ink-rgb), .12);
    padding-left:clamp(26px,3.4vw,60px);
  }
  /* .ls-home-about__title carries margin:0 because in #about it is a flex
     child of .ls-home-about, whose gap does the spacing. #portfolio reuses
     the class in a plain block, where that gap does not exist and the title
     sat hard against its lead. 14px matches .ls-home-sub__title, the page's
     other title-directly-above-a-lead. */
  .ls-home-about__title--gap-14 { margin-bottom: 14px; }
  .ls-home-about__lead {
    margin:0;
    font-size:clamp(16px,1.32vw,20.5px);
    line-height:1.72;
    color: var(--ls-ink-strong);
    text-wrap:pretty;
  }
  .ls-home-about__note {
    margin:0;
    font-size:clamp(14.5px,1.15vw,18px);
    line-height:1.75;
    color: var(--ls-ink-meta);
    text-wrap:pretty;
  }
  .ls-home-news__title {
    font-family:'Libre Caslon Display',serif;
    font-weight:400;
    font-size:clamp(32px,3.6vw,58px);
    line-height:1.1;
    margin:0;
  }
  .ls-home-docs__title {
    font-family:'Libre Caslon Display',serif;
    font-weight:400;
    font-size:clamp(30px,3.4vw,51.5px);
    line-height:1.1;
    margin:0;
    letter-spacing:-0.01em;
    text-wrap:pretty;
  }
  .ls-home-sub__title {
    font-family:'Libre Caslon Display',serif;
    font-weight:400;
    font-size:clamp(30px,3.2vw,51.5px);
    line-height:1.12;
    margin:0 0 14px;
    text-wrap:pretty;
  }
  .ls-home-sub__lead {
    font-size: var(--ls-fs-prose);
    line-height:1.65;
    color: var(--ls-cream-meta);
    margin:0;
    max-width:calc(480 * var(--ls-px));
    text-wrap:pretty;
  }
  .ls-home-sub__note { font-size: var(--ls-fs-meta); color: var(--ls-cream-meta); margin:14px 4px 0; }
  .ls-home-sub__confirm {
    border:1px solid rgba(231,207,143,.4);
    border-radius: var(--ls-radius-lg);
    padding:26px 28px;
    background:rgba(6,28,36,.35);
  }
  .ls-home-sub__confirm-title {
    font-family:'Libre Caslon Display',serif;
    font-size:24px;
    color:#e7cf8f;
    margin-bottom:8px;
  }
  .ls-home-sub__confirm-note { margin:0; font-size: var(--ls-fs-prose); line-height:1.6; color: var(--ls-cream-meta); }

  /* --- CORPORATE --------------------------------------------------------- */
  /* Numbered strategy column */
  .ls-corp-step { border-top:2px solid #cbaa5e; padding-top:22px; }
  .ls-corp-step__n {
    font-family:'Libre Caslon Display',serif;
    font-size: var(--ls-fs-prose);
    color:#8a6e31;
    margin-bottom:12px;
  }
  /* Parent-company row above the three subsidiary panels */
  .ls-corp-parent {
    border:1px solid rgba(231,207,143,.25);
    border-radius: var(--ls-radius);
    padding:clamp(20px,2.6vw,37px);
    display:flex;
    align-items:center;
    justify-content:space-between;
    gap:18px;
    flex-wrap:wrap;
    background:rgba(231,207,143,.05);
    margin-bottom:14px;
  }
  .ls-corp-parent__name {
    font-family:'Libre Caslon Display',serif;
    font-size:clamp(20px,2vw,29px);
    color:#f3eee2;
  }
  .ls-corp-parent__note { font-size: var(--ls-fs-prose-sm); color: var(--ls-cream-meta); margin-top:6px; }
  .ls-corp-jvnote { margin:18px 0 0; font-size: var(--ls-fs-meta); color: var(--ls-cream-meta); }
  .ls-btn--gold-flat {
    background:#cbaa5e;
    color:#08262f;
    padding:15px 26px;
    border-radius: var(--ls-radius);
    font-size:var(--ls-fs-meta);
    font-weight:700;
    letter-spacing: var(--ls-track-label);
    text-transform:uppercase;
  }
  .ls-btn--outline-gold {
    border:1px solid rgba(231,207,143,.55);
    color:#e7cf8f;
    padding:15px 26px;
    border-radius: var(--ls-radius);
    font-size:var(--ls-fs-meta);
    font-weight:700;
    letter-spacing: var(--ls-track-label);
    text-transform:uppercase;
  }

  /* --- MANAGEMENT -------------------------------------------------------- */
  .ls-mgmt-bio {
    background:#ffffff;
    border:1px solid #e7e2d4;
    border-left:3px solid #cbaa5e;
    border-radius: var(--ls-radius);
    padding:clamp(22px,2.6vw,35px);
    margin-bottom:14px;
  }
  .ls-mgmt-bio__name { font-size:20px; font-weight:700; letter-spacing:-0.01em; }
  .ls-mgmt-bio__role {
    font-size:12.5px;
    letter-spacing: var(--ls-track-wide);
    text-transform:uppercase;
    color:#8a6e31;
    margin:6px 0 14px;
  }
  .ls-mgmt-name { font-size:17px; font-weight:700; }
  .ls-mgmt-role {
    font-size:12.5px;
    letter-spacing: var(--ls-track-wide);
    text-transform:uppercase;
    color:#8a6e31;
    margin:5px 0 12px;
  }
  .ls-mgmt-name--sm { font-size: var(--ls-fs-prose); font-weight:700; }
  .ls-mgmt-role--sm {
    font-size:12px;
    letter-spacing: var(--ls-track-label);
    text-transform:uppercase;
    color:#8a6e31;
    margin:4px 0 0;
  }
  .ls-mgmt-intro {
    margin:0 0 14px;
    font-family:'Libre Caslon Display',serif;
    font-weight:400;
    font-size:clamp(26px,3vw,42.5px);
    line-height:1.12;
    letter-spacing:-0.01em;
  }
  .ls-head--gap-48 { margin-bottom:clamp(32px,4vw,56px); }
  .ls-col-560 { flex:1 1 560px; min-width:0; }
  .ls-row--wide { display:flex; gap:clamp(18px,4vw,65px); flex-wrap:wrap; }

  /* --- CONTACT ----------------------------------------------------------- */
  .ls-contact-card {
    background:#ffffff;
    border:1px solid #e7e2d4;
    border-radius: var(--ls-radius);
    padding:clamp(24px,3vw,39px);
  }
  /* `__body` is the boxed form; `.ls-contact-address` is the same block set
     loose on the band, with no card around it. */
  .ls-contact-card__body,
  .ls-contact-address { margin:0 0 18px; font-size: var(--ls-fs-prose); line-height:1.8; color:#4c5a58; }
  .ls-contact-list { display:flex; flex-direction:column; gap:7px; }
  .ls-contact-line { font-size: var(--ls-fs-prose); }
  .ls-contact-line--name { margin:0 0 2px; font-size: var(--ls-fs-prose); font-weight:700; color:#182726; }
  .ls-contact-sub__title {
    margin:0 0 14px;
    font-family:'Libre Caslon Display',serif;
    font-weight:400;
    font-size:clamp(26px,3vw,45px);
    line-height:1.15;
    letter-spacing:-0.01em;
  }
  .ls-contact-sub__lead {
    margin:0;
    font-size: var(--ls-fs-prose);
    line-height:1.7;
    color: var(--ls-cream-meta);
    max-width:calc(480 * var(--ls-px));
  }
  /* Sized here rather than in components because .ls-field--contact below
     sets its own basis, and the pages layer outranks components whatever the
     specificity. Same reason --name comes second as in the components layer. */
  .ls-formrow--named .ls-field--contact { flex: 1 1 200px; }
  .ls-formrow--named .ls-field--name { flex: 1 1 150px; }

  .ls-field--contact {
    flex:1 1 240px;
    background:rgba(243,238,226,.1);
    border:1px solid rgba(231,207,143,.45);
    border-radius: var(--ls-radius);
    color:#f3eee2;
    padding:15px 18px;
    font-size: var(--ls-fs-prose);
    outline:none;
  }
  .ls-btn--submit-deep {
    background:#cbaa5e;
    color:#08262f;
    border:none;
    border-radius: var(--ls-radius);
    padding:15px 26px;
    font-size:var(--ls-fs-meta);
    font-weight:700;
    letter-spacing: var(--ls-track-label);
    text-transform:uppercase;
    cursor:pointer;
    font-family:'Archivo',sans-serif;
  }
  .ls-confirm--lg {
    border:1px solid rgba(231,207,143,.4);
    border-radius: var(--ls-radius);
    background:rgba(231,207,143,.08);
    padding:26px 28px;
  }
  .ls-confirm__title--lg {
    font-family:'Libre Caslon Display',serif;
    font-size:22px;
    color:#e7cf8f;
    margin-bottom:8px;
  }
  .ls-confirm__note--lg { margin:0; font-size: var(--ls-fs-prose); color: var(--ls-cream-meta); }

  /* The subscribe block on a light band. Every form style in this system was
     built for dark surfaces — cream text on a translucent cream fill — because
     until the contact page put the form on paper, every form sat on one. This
     is the light counterpart, scoped to a single wrapper so the dark original
     is untouched everywhere else. It lives in `pages` on purpose: the rules it
     overrides are `.ls-field--contact` and friends in this same layer, so a
     `components`-layer rule would lose regardless of specificity.
     The gold submit button needs no variant — #cbaa5e carries its own contrast
     against both surfaces. */
  .ls-sub--light .ls-contact-sub__lead { color: var(--ls-ink-body); }
  .ls-sub--light .ls-field {
    background: var(--ls-white);
    border-color: #d9d3c2;
    color: var(--ls-ink);
  }
  .ls-sub--light .ls-field::placeholder { color: var(--ls-ink-meta); }
  .ls-sub--light .ls-field:focus {
    border-color: var(--ls-gold-ink);
    background: var(--ls-white);
  }
  .ls-sub--light .ls-formnote { color: var(--ls-ink-meta); }
  .ls-sub--light .ls-formconsent { color: var(--ls-ink-meta); }
  .ls-sub--light .ls-formconsent input { accent-color: var(--ls-gold-ink); }
  .ls-sub--light .ls-formconsent a,
  .ls-sub--light .ls-formerror { color: var(--ls-gold-ink); }
  /* Hold the form to the lead's measure. Left free it runs the full column —
     an email field twice the width of the sentence explaining it. */
  .ls-sub--light .ls-formrow,
  .ls-sub--light .ls-confirm { max-width: calc(480 * var(--ls-px)); }
  .ls-sub--light .ls-confirm__title { color: var(--ls-gold-ink); }
  .ls-sub--light .ls-confirm__note { color: var(--ls-ink-body); }

  /* --- INVESTORS --------------------------------------------------------- */
  .ls-inv-card {
    display:flex;
    flex-direction:column;
    background:#ffffff;
    border:1px solid #e7e2d4;
    border-radius: var(--ls-radius);
    padding:clamp(22px,2.6vw,35px);
    color:#182726;
    transition:border-color .2s ease,box-shadow .2s ease;
  }
  .ls-inv-card__title {
    font-family:'Libre Caslon Display',serif;
    font-size:clamp(19px,1.8vw,27px);
    line-height:1.2;
    margin-top:12px;
  }
  .ls-inv-card__desc { font-size: var(--ls-fs-prose-sm); line-height:1.62; color:#4c5a58; margin-top:12px; text-wrap:pretty; }
  .ls-inv-card__cta {
    font-size:12px;
    font-weight:700;
    letter-spacing: var(--ls-track-wide);
    text-transform:uppercase;
    color:#8a6e31;
    margin-top:16px;
  }
  .ls-inv-link {
    font-size: var(--ls-fs-prose);
    line-height:1.6;
    color:#182726;
    text-decoration:underline;
    text-underline-offset:3px;
  }
  .ls-inv-stats { display:flex; gap:22px; flex-wrap:wrap; margin-top:clamp(24px,3vw,42px); }
  .ls-inv-stat__note { font-size:var(--ls-fs-kicker); letter-spacing: var(--ls-track-link); color: var(--ls-cream-meta); margin-top:3px; }
  .ls-inv-foot { margin-top:clamp(24px,2.8vw,39px); padding-top:24px; border-top:1px solid #e7e2d4; }
  .ls-inv-foot__row { display:flex; gap:12px 34px; flex-wrap:wrap; }
  .ls-inv-cta__title {
    margin:0 0 14px;
    font-family:'Libre Caslon Display',serif;
    font-weight:400;
    font-size:clamp(26px,3vw,45px);
    line-height:1.15;
    letter-spacing:-0.01em;
    text-wrap:balance;
  }
  .ls-btn--mt-20 {
    display:inline-block;
    margin-top:20px;
    background:#cbaa5e;
    color:#08262f;
    padding:15px 26px;
    border-radius: var(--ls-radius);
    font-size:var(--ls-fs-meta);
    font-weight:700;
    letter-spacing: var(--ls-track-label);
    text-transform:uppercase;
  }

  /* --- FINANCIAL STATEMENTS ---------------------------------------------- */
  .ls-fs-link { min-width:0; color:#182726; transition:color .2s; }
  .ls-fs-link__title {
    display:block;
    font-size: var(--ls-fs-prose);
    font-weight:650;
    line-height:1.4;
    letter-spacing:-0.005em;
  }
  .ls-fs-link__note { display:block; margin-top:5px; font-size: var(--ls-fs-meta); line-height:1.5; color:#777463; }
  .ls-fs-meta { font-family:ui-monospace,monospace; font-size: var(--ls-fs-meta); }
  .ls-anchor-78 { scroll-margin-top:78px; }
  .ls-fs-title {
    margin:0 0 clamp(22px,2.8vw,37px);
    font-family:'Libre Caslon Display',serif;
    font-weight:400;
    font-size:clamp(30px,3.4vw,49.5px);
    line-height:1.1;
    letter-spacing:-0.01em;
  }
  .ls-fs-rowbody {
    flex:1 1 380px;
    min-width:0;
    display:grid;
    grid-template-columns:repeat(auto-fit,minmax(240px,1fr));
    gap:14px clamp(20px,2.8vw,42px);
  }
  .ls-fs-note { margin:16px 0 0; font-size: var(--ls-fs-prose-sm); line-height:1.65; color:#777463; }
  .ls-fs-sedar { margin-top:clamp(44px,5vw,74px); scroll-margin-top:78px; }
  .ls-fs-sedar__panel {
    background:#08262f;
    color:#f3eee2;
    border-radius: var(--ls-radius);
    padding:clamp(24px,3vw,42px);
    display:flex;
    justify-content:space-between;
    align-items:center;
    gap:24px;
    flex-wrap:wrap;
  }
  .ls-fs-sedar__title {
    margin:0 0 12px;
    font-family:'Libre Caslon Display',serif;
    font-weight:400;
    font-size:clamp(22px,2.4vw,33.5px);
    line-height:1.15;
    letter-spacing:-0.01em;
  }

  /* --- PROJECT PAGES ----------------------------------------------------- */
  .ls-proj-portrait {
    display:block;
    width:100%;
    aspect-ratio:238/276;
    object-fit:cover;
    background:#ffffff;
    border:1px solid rgba(var(--ls-ink-rgb), .12);
    border-radius: var(--ls-radius-md);
  }

  /* --- KIMOUKRO ---------------------------------------------------------- */
  .ls-kim-hero__photo {
    position:absolute;
    inset:0;
    width:100%;
    height:100%;
    object-fit:cover;
    object-position:center 60%;
    opacity:.22;
  }
  .ls-kim-hero__scrim {
    position:absolute;
    inset:0;
    background:linear-gradient(160deg,rgba(11,53,67,.85) 0%,rgba(8,38,47,.92) 60%,rgba(6,28,36,.96) 100%);
  }
  .ls-kim-specs {
    display:grid;
    grid-template-columns:repeat(auto-fit,minmax(160px,1fr));
    gap:1px;
    background:rgba(var(--ls-ink-rgb), .12);
    border:1px solid rgba(var(--ls-ink-rgb), .12);
  }
  .ls-kim-specs__v {
    font-family:'Libre Caslon Display',serif;
    font-size:clamp(20px,2vw,29px);
    color:#0d4759;
    white-space:nowrap;
  }
  .ls-kim-specs__l {
    font-size:10.5px;
    letter-spacing: var(--ls-track-caps);
    text-transform:uppercase;
    color: var(--ls-ink-meta);
    margin-top:4px;
  }
  .ls-kim-facts { display:flex; gap:clamp(20px,3vw,51px); flex-wrap:wrap; margin-top:26px; }
  .ls-kim-facts--gap-b { display:flex; gap:clamp(20px,3vw,51px); flex-wrap:wrap; margin-bottom:22px;
    margin-top: 0;
  }
  .ls-kim-fact { flex:1 1 240px; display:flex; gap:12px; align-items:flex-start; }
  .ls-kim-fact--220 { flex:1 1 220px; display:flex; gap:12px; align-items:flex-start; }
  .ls-kim-note { margin:22px 0 0; font-size: var(--ls-fs-prose-sm); line-height:1.65; color: var(--ls-ink-meta); }
  .ls-kim-history { display:flex; flex-direction:column; gap:0; border-left:2px solid #cbaa5e; }
  .ls-kim-history__row { display:flex; gap:18px; padding:10px 0 10px 20px; align-items:baseline; }
  .ls-kim-history__when {
    flex:0 0 96px;
    font-family:'Libre Caslon Display',serif;
    font-size:16px;
    color:#8a6e31;
    white-space:nowrap;
  }
  .ls-kim-history__what { margin:0; font-size: var(--ls-fs-prose); line-height:1.6; color: var(--ls-ink-body); }
  .ls-kim-steps { display:flex; flex-direction:column; gap:12px; margin-bottom:24px; }
  .ls-kim-step {
    display:flex;
    gap:14px;
    align-items:flex-start;
    background:#ffffff;
    border:1px solid rgba(var(--ls-ink-rgb), .09);
    border-radius: var(--ls-radius-md);
    padding:16px 18px;
  }
  .ls-kim-step__n {
    flex:0 0 84px;
    font-family:'Libre Caslon Display',serif;
    font-size:18px;
    color:#8a6e31;
  }
  .ls-kim-step__text { margin:0; font-size: var(--ls-fs-prose); line-height:1.6; color: var(--ls-ink-body); }
  .ls-kim-banner {
    background:#0d4759;
    color:#f3eee2;
    border-radius: var(--ls-radius-lg);
    padding:clamp(24px,3vw,39px);
    display:flex;
    gap:clamp(20px,3vw,46px);
    align-items:center;
    flex-wrap:wrap;
    margin-bottom:24px;
  }
  .ls-kim-banner__col { flex:1 1 300px; }
  .ls-kim-banner__kicker {
    font-size:10.5px;
    font-weight:700;
    letter-spacing: var(--ls-track-tag);
    text-transform:uppercase;
    color:#cbaa5e;
    margin-bottom:10px;
  }
  .ls-kim-banner__title {
    font-family:'Libre Caslon Display',serif;
    font-size:clamp(21px,2.2vw,31.5px);
    line-height:1.25;
    text-wrap:pretty;
  }
  .ls-kim-banner__note {
    flex:1 1 240px;
    margin:0;
    font-size: var(--ls-fs-prose-sm);
    line-height:1.65;
    color: var(--ls-cream-body);
  }
  .ls-kim-grid200 {
    display:grid;
    grid-template-columns:repeat(auto-fit,minmax(200px,1fr));
    gap:14px;
    margin-bottom:24px;
  }
  .ls-kim-aside {
    background:#f1ede0;
    border:1px solid rgba(var(--ls-ink-rgb), .12);
    border-radius: var(--ls-radius-md);
    padding:20px 24px;
    margin-bottom:22px;
  }
  .ls-kim-aside__text { margin:0; font-size: var(--ls-fs-prose); line-height:1.7; color: var(--ls-ink-body); }
  .ls-kim-media {
    display:flex;
    gap:clamp(18px,3vw,37px);
    flex-wrap:wrap;
    align-items:flex-start;
    margin-bottom:24px;
  }
  .ls-kim-media__fig {
    flex:1 1 300px;
    margin:0;
    background:#ffffff;
    border:1px solid rgba(var(--ls-ink-rgb), .12);
    border-radius: var(--ls-radius-md);
    overflow:hidden;
    max-width:calc(420 * var(--ls-px));
  }
  .ls-kim-media__side { flex:1 1 320px; display:flex; flex-direction:column; gap:12px; }
  .ls-kim-strip {
    display:flex;
    gap:0;
    flex-wrap:wrap;
    border:1px solid rgba(var(--ls-ink-rgb), .16);
    border-radius: var(--ls-radius-lg);
    overflow:hidden;
    background:#ffffff;
  }
  .ls-kim-strip__cell { flex:1 1 100px; padding:18px 20px; border-right:1px solid rgba(var(--ls-ink-rgb), .12); }
  .ls-kim-strip__cell--last { flex:1 1 100px; padding:18px 20px;
    border-right: 0;
  }
  .ls-kim-list { display:flex; flex-direction:column; gap:10px; }
  .ls-kim-list__text { margin:0; font-size: var(--ls-fs-prose-sm); line-height:1.6; color: var(--ls-ink-body); }
  .ls-kim-panel {
    background:#ffffff;
    border:1px solid rgba(var(--ls-ink-rgb), .12);
    border-radius: var(--ls-radius-md);
    padding:20px 22px;
  }
  .ls-kim-panel__v { font-family:'Libre Caslon Display',serif; font-size:26px; color:#0d4759; }
  .ls-kim-panel__note { margin:8px 0 0; font-size: var(--ls-fs-prose-sm); line-height:1.55; color: var(--ls-ink-meta); }
  .ls-figframe--flush {
    margin:0;
    background:#ffffff;
    border:1px solid rgba(var(--ls-ink-rgb), .12);
    border-radius: var(--ls-radius-md);
    overflow:hidden;
  }
  /* Tall figures — country maps, geology plates — are portrait and 1,100px+
     wide at source. Left to fill the content column they tower over the text
     they illustrate, so they are held to a plate width. Left aligned, not
     centred: they share a column with body copy, and a centred plate breaks
     the left edge every paragraph beside it holds. The full resolution is a
     click away; see .ls-figzoom. */
  .ls-figframe--inset {
    max-width: calc(520 * var(--ls-px));
    margin-left:0;
    margin-right:auto;
  }
  /* A figure set in a run of body copy is a change of medium, not the next
     sentence, so it needs more room than the 18px between two paragraphs.
     Worn by a single frame or by a row of them. NB .ls-figframe--flush
     zeroes the base margin outright — that modifier is for figures whose
     container already owns the spacing, and pairing it with prose is what
     left the copy sitting flush against the frame. */
  .ls-figblock { margin: clamp(20px, 2.2vw, 30px) 0; }

  /* Mount the image inside the frame instead of letting it bleed to the
     border, so its edge lines up with the caption's rather than sitting
     16px outside it. The caption loses its own side padding to match. */
  .ls-figframe--pad { padding: clamp(10px, 1.2vw, 16px); }
  .ls-figframe--pad > .ls-caption { padding: 12px 2px 2px; }

  /* The zoom affordance is the cursor plus the hint below; no overlay icon,
     which would sit on top of map detail. */
  .ls-figzoom { display:block; cursor:zoom-in; }
  .ls-figzoom:focus-visible { outline-offset:-2px; }
  .ls-caption__zoom { display:block; margin-top:4px; color: var(--ls-gold-ink); }

  /* Lightbox. A native <dialog>, so Esc, the focus trap and the top layer are
     the browser's job rather than ours; ls-lightbox.js only fills and opens
     it. Without JS the figure stays an ordinary link to the image file. */
  .ls-lightbox {
    border:0; padding:0; background:transparent;
    max-width:min(96vw, 1400px); max-height:96vh;
  }
  .ls-lightbox::backdrop { background: rgba(var(--ls-abyss-rgb), .88); }
  .ls-lightbox__img {
    display:block; max-width:100%; max-height:88vh;
    width:auto; height:auto; margin:0 auto;
    border-radius: var(--ls-radius-md); background:#ffffff;
  }
  .ls-lightbox__cap {
    margin:10px auto 0; max-width: calc(760 * var(--ls-px));
    font-size: var(--ls-fs-meta); line-height: var(--ls-lh-snug);
    color: var(--ls-cream-meta); text-align:center;
  }
  .ls-lightbox__close {
    position:absolute; top:calc(2vh + 4px); right:calc(2vw + 4px);
    width:40px; height:40px; padding:0;
    display:flex; align-items:center; justify-content:center;
    font-size:22px; line-height:1; cursor:pointer;
    color: var(--ls-cream); background: rgba(var(--ls-abyss-rgb), .6);
    border:1px solid rgba(var(--ls-gold-rgb), .35); border-radius: var(--ls-radius);
  }
  .ls-lightbox__close:hover { background: var(--ls-gold); color: var(--ls-deep); }
  .ls-img--43 { display:block; width:100%; aspect-ratio:4/3; object-fit:cover; }
  .ls-kim-doclink {
    display:inline-flex;
    align-items:center;
    gap:14px;
    background:#ffffff;
    border:1px solid rgba(var(--ls-ink-rgb), .16);
    border-radius: var(--ls-radius-md);
    padding:18px 24px;
    transition:box-shadow .2s,transform .2s;
  }
  .ls-kim-doclink__badge {
    flex:none;
    width:40px;
    height:40px;
    border-radius: var(--ls-radius-md);
    background:#0d4759;
    color:#e7cf8f;
    display:inline-flex;
    align-items:center;
    justify-content:center;
    font-size:var(--ls-fs-kicker);
    font-weight:700;
    letter-spacing: var(--ls-track-label);
  }
  .ls-kim-doclink__title { display:block; font-size: var(--ls-fs-prose); font-weight:700; color:#182726; }
  .ls-kim-doclink__note { display:block; font-size: var(--ls-fs-meta); color: var(--ls-ink-meta); margin-top:3px; }
  .ls-kim-doc-note { margin:16px 0 0; font-size: var(--ls-fs-prose-sm); line-height:1.65; color: var(--ls-ink-meta); }
  .ls-link-underline { color:#8a6e31; text-decoration:underline; }
  .ls-subsection--44 { scroll-margin-top:78px; margin-bottom:clamp(32px,4vw,51px); }

  /* --- KIMOUKRO — drill collar table ------------------------------------- */
  .ls-kim-table {
    border:1px solid rgba(var(--ls-ink-rgb), .12);
    border-radius: var(--ls-radius-md);
    background:#ffffff;
    overflow-x:auto;
  }
  .ls-kim-table__head {
    padding:18px 22px 4px;
    display:flex;
    justify-content:space-between;
    align-items:baseline;
    gap:16px;
    flex-wrap:wrap;
  }
  .ls-kim-table__title { font-family:'Libre Caslon Display',serif; font-weight:400; font-size:19px; margin:0; }
  .ls-kim-table__meta { font-size: var(--ls-fs-meta); color: var(--ls-ink-meta); }
  .ls-kim-table__el { width:100%; border-collapse:collapse; font-size: 14px; min-width:680px; }
  .ls-kim-table__th {
    text-align:left;
    padding:12px 10px 10px;
    font-size:10px;
    letter-spacing: var(--ls-track-caps);
    font-weight:700;
    text-transform:uppercase;
    color: var(--ls-ink-meta);
    border-bottom:1px solid rgba(var(--ls-ink-rgb), .16);
  }
  .ls-kim-table__th--first {
    text-align:left;
    padding:12px 10px 10px 22px;
    font-size:10px;
    letter-spacing: var(--ls-track-caps);
    font-weight:700;
    text-transform:uppercase;
    color: var(--ls-ink-meta);
    border-bottom:1px solid rgba(var(--ls-ink-rgb), .16);
  }
  .ls-kim-table__th--num {
    text-align:right;
    padding:12px 10px 10px;
    font-size:10px;
    letter-spacing: var(--ls-track-caps);
    font-weight:700;
    text-transform:uppercase;
    color: var(--ls-ink-meta);
    border-bottom:1px solid rgba(var(--ls-ink-rgb), .16);
  }
  .ls-kim-table__th--last {
    text-align:left;
    padding:12px 22px 10px 14px;
    font-size:10px;
    letter-spacing: var(--ls-track-caps);
    font-weight:700;
    text-transform:uppercase;
    color: var(--ls-ink-meta);
    border-bottom:1px solid rgba(var(--ls-ink-rgb), .16);
  }
  .ls-kim-table__td {
    padding:9px 10px;
    border-bottom:1px solid #eee9dc;
    font-size: var(--ls-fs-meta);
    color: var(--ls-ink-body);
  }
  .ls-kim-table__td--first {
    color: inherit;
    padding:9px 10px 9px 22px;
    border-bottom:1px solid #eee9dc;
    font-family:ui-monospace,monospace;
    font-size: var(--ls-fs-meta);
    font-weight:600;
    white-space:nowrap;
  }
  .ls-kim-table__td--num {
    padding:9px 10px;
    border-bottom:1px solid #eee9dc;
    text-align:right;
    font-family:ui-monospace,monospace;
    font-size: var(--ls-fs-meta);
      color: inherit;
  }
  .ls-kim-table__td--last {
    padding:9px 22px 9px 14px;
    border-bottom:1px solid #eee9dc;
    color: var(--ls-ink-body);
    font-size: inherit;
  }
  .ls-kim-table__note {
    margin:0;
    padding:12px 22px 16px;
    font-size: var(--ls-fs-meta);
    line-height:1.6;
    color: var(--ls-ink-meta);
  }

  /* --- PROJECTS ---------------------------------------------------------- */
  .ls-proj-hero {
    background:linear-gradient(160deg, var(--ls-teal) 0%, var(--ls-deep) 60%, var(--ls-abyss) 100%);
    color:var(--ls-cream);
    padding:clamp(140px,18vh,190px) 0 0;
  }
  /* flex-start, not center: the deco column is taller than the copy, and
     centring pushed the kicker 27px below the hero's top padding, so this
     page's heading started lower than every other .ls-pagehero. The deco
     keeps align-self:stretch, so it still spans the full height and centres
     its own artwork. */
  .ls-proj-hero__inner {
    width:var(--ls-wrap);
    margin:0 auto;
    display:flex;
    align-items:flex-start;
    gap:clamp(32px,5vw,93px);
    flex-wrap:wrap;
    padding-bottom:clamp(44px,5vw,74px);
  }
  .ls-proj-hero__copy { flex:1 1 480px; min-width:0; }
  .ls-proj-hero__kicker {
    font-size:var(--ls-fs-kicker);
    font-weight:700;
    letter-spacing: var(--ls-track-kicker);
    text-transform:uppercase;
    color:var(--ls-gold-deep);
  }
  .ls-proj-hero__lead {
    margin:0;
    font-size:clamp(15.5px,1.4vw,20px);
    line-height:1.7;
    color:var(--ls-cream-body);
    max-width:calc(660 * var(--ls-px));
    text-wrap:pretty;
  }
  .ls-proj-hero__deco { flex:0 1 320px; min-width:220px; align-self:stretch; display:flex; align-items:center; }
  .ls-proj-hero__pulse { transform-origin:215px 185px; animation:lsPulse 2.6s ease-out infinite; }
  .ls-proj-hero__decolbl {
    font-family:'Archivo';
    font-size:10px;
    letter-spacing: var(--ls-track-tag);
    text-transform:uppercase;
    fill: var(--ls-cream-meta);
  }
  .ls-proj-statstrip { border-top:1px solid rgba(231,207,143,.16); background:rgba(6,28,36,.35); }
  .ls-proj-statstrip__cell { padding:26px 28px 26px; border-left:1px solid rgba(231,207,143,.16); }
  /* Nothing to its left to divide — see .ls-home-hero__statcell:first-child. */
  .ls-proj-statstrip__cell:first-child { border-left:0; }
  .ls-proj-statstrip__v {
    font-family:'Libre Caslon Display',serif;
    font-size:clamp(26px,2.4vw,40.5px);
    color:var(--ls-gold);
    line-height:1;
  }
  .ls-proj-statstrip__l {
    line-height:1.35; min-height:2.7em;   /* see .ls-statstrip__l */
    font-size:11.5px;
    font-weight:600;
    letter-spacing: var(--ls-track-caps);
    text-transform:uppercase;
    color: var(--ls-cream-meta);
    margin-top:9px;
  }
  .ls-proj-why {
    display:grid;
    grid-template-columns:repeat(auto-fit,minmax(min(100%,420px),1fr));
    gap:clamp(20px,3vw,65px);
    align-items:end;
    margin-bottom:clamp(30px,3.6vw,56px);
  }
  .ls-proj-why__title {
    font-family:'Libre Caslon Display',serif;
    font-weight:400;
    font-size:clamp(32px,3.6vw,58px);
    line-height:1.1;
    margin:0;
    text-wrap:pretty;
  }
  .ls-proj-why__lead {
    font-size:clamp(15px,1.2vw,19px);
    line-height:1.72;
    color: var(--ls-ink-meta);
    margin:0;
    text-wrap:pretty;
  }
  .ls-proj-whygrid {
    display:grid;
    grid-template-columns:repeat(auto-fit,minmax(max(230px,29%),1fr));
    gap:1px;
    background:rgba(var(--ls-ink-rgb), .12);
    border:1px solid rgba(var(--ls-ink-rgb), .12);
    border-radius: var(--ls-radius-lg);
    overflow:hidden;
  }
  .ls-proj-whygrid__cell {
    background:#ffffff;
    padding:clamp(26px,2.5vw,39px) clamp(24px,2.4vw,37px);
    display:flex;
    flex-direction:column;
  }
  .ls-proj-whygrid__v {
    font-family:'Libre Caslon Display',serif;
    font-size:clamp(32px,2.9vw,49.5px);
    line-height:1;
    color:#0d4759;
    letter-spacing:-0.01em;
  }
  .ls-proj-whygrid__l { font-size: var(--ls-fs-prose-sm); font-weight:650; line-height:1.4; color:#182726; margin-top:15px; }
  .ls-proj-whygrid__note { font-size: var(--ls-fs-meta); line-height:1.5; color: var(--ls-ink-meta); margin-top:6px; }
  /* No rule above these: the stat grid is a fully bordered card, so its own
     bottom edge already closes the group, and a second hairline in the same
     1px rgba(ink,.12) 44px below it just read as a stray line. The gap now
     matches .ls-proj-why's margin-bottom, so the band is three evenly
     spaced blocks: intro, grid, points. */
  .ls-proj-whypoints {
    display:grid;
    grid-template-columns:repeat(auto-fit,minmax(min(100%,240px),1fr));
    gap:clamp(18px,2.4vw,42px);
    margin-top:clamp(30px,3.6vw,56px);
  }
  .ls-proj-whypoints__text {
    margin:0;
    font-size: var(--ls-fs-prose);
    line-height:1.62;
    color: var(--ls-ink-body);
    text-wrap:pretty;
  }
  .ls-proj-mapband {
    background:linear-gradient(#ffffff,#fbfaf6);
    color:#182726;
    padding:clamp(56px,7vw,104px) 0 clamp(48px,6vw,93px);
    scroll-margin-top:64px;
  }
  .ls-proj-maphead {
    display:flex;
    justify-content:space-between;
    align-items:flex-end;
    gap:24px;
    flex-wrap:wrap;
    margin-bottom:clamp(26px,3vw,46px);
  }
  .ls-proj-maphead__title {
    font-family:'Libre Caslon Display',serif;
    font-weight:400;
    font-size:clamp(30px,3.2vw,51.5px);
    line-height:1.1;
    margin:0 0 16px;
    text-wrap:pretty;
  }
  .ls-proj-maphead__lead {
    font-size: var(--ls-fs-prose);
    line-height:1.65;
    color:#4c5a58;
    margin:0;
    max-width:calc(560 * var(--ls-px));
    text-wrap:pretty;
  }
  .ls-proj-maplegend { display:flex; gap:26px; flex-wrap:wrap; }
  .ls-proj-mapnote {
    font-size: var(--ls-fs-meta);
    line-height:1.6;
    color: var(--ls-ink-meta);
    margin:18px 4px 0;
    max-width:calc(980 * var(--ls-px));
  }
  .ls-head--gap-52 {
    display:flex;
    justify-content:space-between;
    align-items:flex-end;
    gap:24px;
    flex-wrap:wrap;
    margin-bottom:clamp(32px,4vw,60px);
  }
  .ls-proj-listtitle {
    font-family:'Libre Caslon Display',serif;
    font-weight:400;
    font-size:clamp(30px,3.4vw,54px);
    line-height:1.1;
    margin:0;
  }

  /* --- PROJECTS — flagship panel ----------------------------------------- */
  .ls-proj-flag {
    background:#0d4759;
    color:#f3eee2;
    border-radius: var(--ls-radius-xl);
    overflow:hidden;
    display:grid;
    grid-template-columns:repeat(auto-fit,minmax(320px,1fr));
    margin-bottom:clamp(30px,3.6vw,56px);
  }
  .ls-proj-flag__body { padding:clamp(30px,3.6vw,63px); }
  .ls-proj-flag__kicker {
    font-size:var(--ls-fs-kicker);
    font-weight:600;
    letter-spacing: var(--ls-track-tag);
    text-transform:uppercase;
    color:#e7cf8f;
  }
  .ls-proj-flag__title {
    font-family:'Libre Caslon Display',serif;
    font-weight:400;
    font-size:clamp(30px,3vw,49.5px);
    margin:0 0 6px;
    line-height:1.05;
  }
  .ls-proj-flag__sub { font-size:13px; letter-spacing: var(--ls-track-wide); color: var(--ls-cream-meta); margin-bottom:20px; }
  .ls-proj-flag__lead {
    font-size: var(--ls-fs-prose);
    line-height:1.68;
    color: var(--ls-cream-strong);
    margin:0 0 28px;
    text-wrap:pretty;
  }
  .ls-proj-flag__specs {
    display:flex;
    gap:0;
    flex-wrap:wrap;
    border:1px solid rgba(231,207,143,.22);
    border-radius: var(--ls-radius-lg);
    overflow:hidden;
    margin-bottom:28px;
  }
  .ls-proj-flag__spec { flex:1 1 110px; padding:16px 18px; border-right:1px solid rgba(231,207,143,.22); }
  .ls-proj-flag__spec--last { flex:1 1 110px; padding:16px 18px;
    border-right: 0;
  }
  .ls-proj-flag__specv {
    font-family:'Libre Caslon Display',serif;
    font-size:clamp(19px,1.8vw,27px);
    color:#e7cf8f;
    white-space:nowrap;
  }
  .ls-proj-flag__specl {
    font-size:10.5px;
    letter-spacing: var(--ls-track-caps);
    text-transform:uppercase;
    color: var(--ls-cream-meta);
    margin-top:4px;
  }
  .ls-proj-flag__actions { display:flex; gap:12px; flex-wrap:wrap; align-items:center; }
  .ls-btn--gold-sm {
    background:#e7cf8f;
    color:#08262f;
    padding:13px 24px;
    border-radius: var(--ls-radius);
    font-size:12.5px;
    font-weight:700;
    letter-spacing: var(--ls-track-wide);
    text-transform:uppercase;
    transition:all .2s;
  }
  .ls-btn--ghost-sm {
    cursor:pointer;
    font-family:'Archivo';
    background:transparent;
    border:1px solid rgba(231,207,143,.55);
    color:#e7cf8f;
    padding:13px 24px;
    border-radius: var(--ls-radius);
    font-size:12.5px;
    font-weight:700;
    letter-spacing: var(--ls-track-wide);
    text-transform:uppercase;
    transition:all .2s;
  }
  .ls-proj-flag__visual {
    position:relative;
    min-height:320px;
    background:#0b3543;
    border-left:1px solid rgba(231,207,143,.16);
  }
  .ls-proj-flag__img {
    position:absolute;
    inset:0;
    width:100%;
    height:100%;
    object-fit:cover;
    object-position:center 30%;
  }
  .ls-proj-flag__cap {
    position:absolute;
    left:0;
    right:0;
    bottom:0;
    background:linear-gradient(rgba(6,28,36,0),rgba(6,28,36,.82));
    padding:38px 20px 14px;
    text-align:center;
  }
  .ls-proj-flag__caplbl {
    font-size:var(--ls-fs-kicker);
    letter-spacing: var(--ls-track-caps);
    text-transform:uppercase;
    color:#e7cf8f;
    font-weight:600;
  }

  /* --- PROJECTS — permit rows -------------------------------------------- */
  .ls-proj-group { margin-bottom:clamp(30px,3.6vw,56px); }
  .ls-proj-group__head {
    display:flex;
    justify-content:space-between;
    align-items:baseline;
    gap:16px;
    flex-wrap:wrap;
    border-bottom:1px solid rgba(var(--ls-ink-rgb), .16);
    padding-bottom:14px;
    margin-bottom:20px;
  }
  .ls-proj-group__names { display:flex; gap:14px; align-items:baseline; flex-wrap:wrap; }
  .ls-proj-group__title {
    font-family:'Libre Caslon Display',serif;
    font-weight:400;
    font-size:clamp(21px,2vw,30px);
    margin:0;
  }
  .ls-proj-group__holder {
    font-size:11.5px;
    font-weight:700;
    letter-spacing: var(--ls-track-caps);
    text-transform:uppercase;
    color:#8a6e31;
  }
  .ls-proj-group__meta { font-size: var(--ls-fs-prose-sm); color: var(--ls-ink-meta); }
  .ls-proj-rows { display:flex; flex-direction:column; gap:14px; }
  .ls-proj-row {
    display:flex;
    gap:clamp(18px,3vw,46px);
    flex-wrap:wrap;
    align-items:center;
    background: var(--ls-white);
    border: 1px solid var(--ls-rule-ink);
    border-radius: var(--ls-radius-md);
    padding:clamp(20px,2.4vw,32px) clamp(20px,2.6vw,35px);
    transition:background .3s,border-color .3s,box-shadow .2s;
  }
  .ls-proj-row__id { flex:0 0 128px; display:flex; flex-direction:column; gap:10px; align-items:flex-start; }
  .ls-proj-row__ref { font-size:11.5px; letter-spacing: var(--ls-track-wide); color: var(--ls-ink-meta); font-weight:600; }
  .ls-proj-row__status {
    font-size:10px;
    font-weight:700;
    letter-spacing: var(--ls-track-caps);
    text-transform:uppercase;
    background:#3f6b54;
    color:#f3eee2;
    padding:5px 11px;
    border-radius: var(--ls-radius);
    white-space:nowrap;
  }
  .ls-proj-row__status--pending {
    font-size:10px;
    font-weight:700;
    letter-spacing: var(--ls-track-caps);
    text-transform:uppercase;
    border:1px solid rgba(138,109,44,.45);
    color:#7d6428;
    padding:5px 11px;
    border-radius: var(--ls-radius);
    white-space:nowrap;
    background: transparent;
  }
  .ls-proj-row__body { flex:1 1 360px; min-width:0; }
  /* The row lifts when its permit is selected on the map. */
  .ls-proj-row.is-active { background: #fffbee; border-color: var(--ls-gold-deep); }
  .ls-proj-table__td--status.is-granted { color: #3f6b54; }
  .ls-proj-row__name {
    font-family:'Libre Caslon Display',serif;
    font-weight:400;
    font-size:25px;
    margin:0 0 4px;
    color:#182726;
  }
  .ls-proj-row__sub {
    font-size:12.5px;
    color:#8a6e31;
    font-weight:600;
    letter-spacing: var(--ls-track-label);
    margin-bottom:12px;
  }
  .ls-proj-row__note {
    margin:0;
    font-size: var(--ls-fs-prose-sm);
    line-height:1.62;
    color: var(--ls-ink-meta);
    max-width:calc(640 * var(--ls-px));
    text-wrap:pretty;
  }
  /* One button per row, not two. Seven rows each carrying a pair of equally
     weighted buttons gave the directory fourteen competing primary actions;
     "locate on map" is a convenience, so it reads as a link. */
  .ls-proj-row__actions { flex:0 0 auto; display:flex; flex-direction:column; gap:10px; align-items:stretch; }
  .ls-proj-row__locate {
    background:none; border:0; padding:0; cursor:pointer;
    font-size: var(--ls-fs-meta); font-weight:600; letter-spacing: var(--ls-track-label);
    color: var(--ls-gold-ink);
    transition: color var(--ls-ease);
  }
  .ls-proj-row__locate:hover { color: var(--ls-teal-mid); }
  /* A granted permit gets a gold edge; an application does not. The status
     chip alone did not survive being scanned down a column of seven. */
  .ls-proj-row.is-granted { border-left:3px solid var(--ls-gold-deep); }
  .ls-proj-row__note--ref { font-style:italic; }
  .ls-btn--teal-sm {
    text-align:center;
    background:#0d4759;
    border:1px solid #0d4759;
    color:#f3eee2;
    padding:11px 20px;
    border-radius: var(--ls-radius);
    font-size:11.5px;
    font-weight:700;
    letter-spacing: var(--ls-track-wide);
    text-transform:uppercase;
    transition:all .2s;
    white-space:nowrap;
  }
  .ls-btn--teal-ghost-sm {
    cursor:pointer;
    font-family:'Archivo';
    background:transparent;
    border:1px solid rgba(13,71,89,.35);
    color:#0d4759;
    padding:11px 20px;
    border-radius: var(--ls-radius);
    font-size:11.5px;
    font-weight:700;
    letter-spacing: var(--ls-track-wide);
    text-transform:uppercase;
    transition:all .2s;
    white-space:nowrap;
  }
  .ls-proj-row__desc {
    margin:0;
    font-size: var(--ls-fs-prose-sm);
    line-height:1.62;
    color: var(--ls-ink-meta);
    max-width:calc(640 * var(--ls-px));
    text-wrap:pretty;
  }

  /* --- PROJECTS — permit table ------------------------------------------- */
  .ls-proj-tableband {
    background:#fbfaf6;
    color:#182726;
    padding:0 0 clamp(60px,7.5vw,111px);
    scroll-margin-top:80px;
  }
  .ls-proj-table {
    border:1px solid rgba(var(--ls-ink-rgb), .12);
    border-radius: var(--ls-radius-md);
    background:#ffffff;
    overflow:hidden;
  }
  .ls-proj-table__scroll { overflow-x:auto; }
  .ls-proj-table__head {
    padding:24px 26px 6px;
    display:flex;
    justify-content:space-between;
    align-items:baseline;
    gap:16px;
    flex-wrap:wrap;
  }
  .ls-proj-table__title {
    font-family:'Libre Caslon Display',serif;
    font-weight:400;
    font-size:clamp(20px,2vw,29px);
    margin:0;
  }
  .ls-proj-table__el { width:100%; border-collapse:collapse; font-size: var(--ls-fs-prose-sm); min-width:760px; }
  .ls-proj-table__th {
    text-align:left;
    padding:16px 14px 12px;
    font-size:10.5px;
    letter-spacing: var(--ls-track-caps);
    font-weight:700;
    text-transform:uppercase;
    color: var(--ls-ink-meta);
    border-bottom:1px solid rgba(var(--ls-ink-rgb), .16);
  }
  .ls-proj-table__th--first {
    text-align:left;
    padding:16px 14px 12px 26px;
    font-size:10.5px;
    letter-spacing: var(--ls-track-caps);
    font-weight:700;
    text-transform:uppercase;
    color: var(--ls-ink-meta);
    border-bottom:1px solid rgba(var(--ls-ink-rgb), .16);
  }
  .ls-proj-table__th--num {
    text-align:right;
    padding:16px 14px 12px;
    font-size:10.5px;
    letter-spacing: var(--ls-track-caps);
    font-weight:700;
    text-transform:uppercase;
    color: var(--ls-ink-meta);
    border-bottom:1px solid rgba(var(--ls-ink-rgb), .16);
  }
  .ls-proj-table__th--last {
    text-align:left;
    padding:16px 26px 12px 14px;
    font-size:10.5px;
    letter-spacing: var(--ls-track-caps);
    font-weight:700;
    text-transform:uppercase;
    color: var(--ls-ink-meta);
    border-bottom:1px solid rgba(var(--ls-ink-rgb), .16);
  }
  .ls-proj-table__td { padding:13px 14px; border-bottom:1px solid #eee9dc; color: var(--ls-ink-body); }
  .ls-proj-table__td--first { padding:13px 14px 13px 26px; border-bottom:1px solid #eee9dc; font-weight:600;
    color: inherit;
  }
  .ls-proj-table__td--mono {
    padding:13px 14px;
    border-bottom:1px solid #eee9dc;
    font-family:ui-monospace,monospace;
    font-size: var(--ls-fs-meta);
    color: var(--ls-ink-meta);
  }
  .ls-proj-table__td--num {
    padding:13px 14px;
    border-bottom:1px solid #eee9dc;
    text-align:right;
    font-family:ui-monospace,monospace;
    font-size: var(--ls-fs-meta);
      color: inherit;
  }
  .ls-proj-table__td--status {
    padding:13px 26px 13px 14px;
    border-bottom:1px solid #eee9dc;
    font-size: var(--ls-fs-meta);
    font-weight:600;
    color: #7d6428;
  }
  .ls-proj-table__td--total-first { padding:15px 14px 17px 26px; font-weight:700;
    border-bottom: 0;
    color: inherit;
  }
  .ls-proj-table__td--total-num {
    padding:15px 14px 17px;
    text-align:right;
    font-family:ui-monospace,monospace;
    font-weight:700;
    border-bottom: 0;
    color: inherit;
  }
  .ls-proj-table__td--total-last { padding:15px 26px 17px 14px; font-size: var(--ls-fs-meta); color: var(--ls-ink-meta);
    border-bottom: 0;
  }
  .ls-proj-table__note {
    margin:0;
    padding:14px 26px 18px;
    font-size: var(--ls-fs-meta);
    line-height:1.6;
    color: var(--ls-ink-meta);
    border-top:1px solid #eee9dc;
  }
  .ls-row--gap-18 { display:flex; align-items:center; gap:14px; margin-bottom:18px; }

  /* --- PROJECTS — map legend --------------------------------------------- */
  .ls-proj-maplegend__v {
    font-family:'Libre Caslon Display',serif;
    font-size:30px;
    color:#0d4759;
    line-height:1;
  }
  .ls-proj-maplegend__l {
    font-size:10.5px;
    letter-spacing: var(--ls-track-caps);
    text-transform:uppercase;
    color: var(--ls-ink-meta);
    margin-top:6px;
  }
  .ls-article__list { margin:0 0 18px; padding-left:22px; display:flex; flex-direction:column; gap:9px; }
  .ls-kim-list__text--14 { margin:0; font-size: var(--ls-fs-prose); line-height:1.6; color: var(--ls-ink-body); }

  @keyframes lsPulse { 0% { transform: scale(.6); opacity: .55; } 100% { transform: scale(1.9); opacity: 0; } }

  /* --- Hover states ------------------------------------------------------ */
  /* Two link roles that recur across pages: gold-on-light darkens to teal,
     gold-on-dark lifts to the pale gold. */
  .ls-crumbs__link:hover { color: var(--ls-gold); }
  .ls-article__back:hover { color: var(--ls-gold-light); }
  .ls-article__link:hover { color: var(--ls-teal-mid); }
  .ls-contact-line:hover { color: var(--ls-teal-mid); }
  .ls-fs-link:hover { color: var(--ls-teal-mid); }
  .ls-inv-link:hover { color: var(--ls-teal-mid); }
  .ls-newsrow__cta:hover { color: var(--ls-teal-mid); }
  .ls-newsrow__meta:hover { color: var(--ls-teal-mid); }
  .ls-link-ink:hover { color: var(--ls-teal-mid); }
  .ls-link-ink-quiet:hover { color: var(--ls-gold-ink); }
  .ls-link-gold:hover { color: var(--ls-gold-light); }
  .ls-inv-card:hover { border-color: var(--ls-gold-deep); box-shadow: 0 14px 32px rgba(var(--ls-teal-rgb), .1); color: var(--ls-ink); }
  .ls-kim-doclink:hover { box-shadow: var(--ls-shadow-card); transform: translateY(-2px); }
  .ls-proj-row:hover { box-shadow: 0 14px 34px rgba(var(--ls-teal-rgb), .1); }
  .ls-btn--gold-flat:hover { background: var(--ls-gold); color: var(--ls-deep); }
  .ls-btn--outline-gold:hover { background: rgba(var(--ls-gold-rgb), .12); color: var(--ls-gold); }
  .ls-btn--submit-deep:hover { background: var(--ls-gold); }
  .ls-btn--gold-sm:hover { background: var(--ls-gold-light); color: var(--ls-deep); }
  .ls-btn--ghost-sm:hover { background: var(--ls-gold); color: var(--ls-deep); }
  .ls-btn--teal-sm:hover { background: #155c72; color: var(--ls-cream); }
  .ls-btn--teal-ghost-sm:hover { background: var(--ls-teal-mid); color: var(--ls-cream); }
}

/* ==========================================================================
   RESPONSIVE
   --------------------------------------------------------------------------
   Every breakpoint in the stylesheet lives here, largest first. The layer is
   declared last, so these always win and none of them need to out-specify the
   rule they are adjusting.

   900px is the structural breakpoint: the nav becomes a drawer and the
   article/aside pair stacks. The narrower steps below it are cosmetic.
   ========================================================================== */
@layer responsive {

  /* --- 1100px: the footer's column count ----------------------------------
     Four columns need roughly 1100px of viewport before the two text-heavy
     ones stop being cramped, so that is where the footer folds — to a 2x2,
     which keeps every group paired with a neighbour instead of leaving the
     last one alone on a row of its own. Chosen here rather than left to
     `auto-fit`, which used to pick the same number by arithmetic and land on
     three across the whole 790-1099 band. */
  @media (max-width: 1100px) {
    .ls-footer__cols { grid-template-columns: 1fr 1fr; }
    .ls-footer__brand { max-width: calc(420 * var(--ls-px)); }
  }

  /* --- Home hero ----------------------------------------------------------
     The copy is capped at 560 design pixels, which is ~45% of the column at
     every width from a 1280 laptop up — the cap grows with --ls-px, so the
     scrim tuned here does not have to be retuned for a wide screen. What it
     is tuned against is the narrow end: at 768 the copy is ~77% of the column,
     and between there and 1000 the side scrim has to reach further right to
     stay behind the headline. */
  @media (max-width: 1000px) {
    .ls-hero-side {
      background: linear-gradient(97deg, rgba(6,28,36,.84) 0%, rgba(6,28,36,.74) 42%, rgba(6,28,36,.26) 72%, rgba(6,28,36,0) 88%);
    }
  }

  /* --- 900px: the structural breakpoint ----------------------------------
     Above this the seven nav items sit on one row (they begin to wrap at
     ~830px) and the article keeps a workable measure beside its 212px aside.
     Below it, both have to change shape. */
  @media (max-width: 900px) {

    /* The bar keeps only the logo and the toggle. The toggle is 46px, which is
       taller than the logo at either size, so it is what sets the bar's
       height: 15 + 46 + 15 + 1 = 77px at rest, dropping to 67px when
       is-compact takes --nav-pad to 10. Ten pixels of a phone screen, and a
       jump on first scroll, for padding around an element that is already a
       comfortable target. Holding --nav-pad at the compact value makes the
       mobile bar a constant 67px, close to the 64px anchor offset. */
    .ls-nav { --nav-pad: 10px; }
    .ls-nav__toggle { display: flex; }
    .ls-nav__inner { flex-wrap: nowrap; gap: 12px; }
    .ls-nav__logo { margin-right: 0; }

    /* While the drawer is open the bar is the drawer's header, not a separate
       surface. Without this the bar keeps whatever state the scroll position
       left it in, so on any scrolled page a cream bar sat on top of a
       near-black panel and the two read as unrelated. The border goes
       transparent because .ls-nav__links draws the rule between them. */
    .ls-navopen .ls-nav {
      --nav-bg: var(--ls-abyss);
      --nav-bd: transparent;
      --nav-fg: var(--ls-cream-strong);
      --nav-accent: var(--ls-gold);
      --nav-logo-filter: brightness(0) invert(1);
    }

    /* Links and the pill become a drawer panel under the bar. It is laid out
       whether or not it is open so that opening only changes transform and
       opacity, which the compositor can animate.

       Positioned against the nav, not the viewport: .ls-nav carries a
       backdrop-filter, which makes it the containing block for fixed
       descendants too, so `position: fixed` here would size against the 64px
       bar instead of the screen. The nav is itself fixed at top: 0 and spans
       the viewport, so absolute offsets from it are screen coordinates. */
    .ls-nav { --ls-drawer-foot: 62px; }
    .ls-nav__links,
    .ls-nav .ls-pill {
      position: absolute; left: 0; right: 0;
      background: var(--ls-abyss);
      transform: translateY(-8px);
      opacity: 0; visibility: hidden;
      transition: opacity var(--ls-ease), transform var(--ls-ease), visibility var(--ls-ease);
    }
    .ls-nav__links {
      top: var(--ls-navbar-h, 64px);
      height: calc(100vh - var(--ls-navbar-h, 64px) - var(--ls-drawer-foot));
      height: calc(100dvh - var(--ls-navbar-h, 64px) - var(--ls-drawer-foot));
      display: block;
      overflow-y: auto;
      -webkit-overflow-scrolling: touch;
      padding: 10px 0 24px;
      border-top: 1px solid var(--ls-rule-gold);
    }
    /* The pill docks to the foot of the drawer rather than scrolling with it. */
    .ls-nav .ls-pill {
      top: calc(100vh - var(--ls-drawer-foot));
      top: calc(100dvh - var(--ls-drawer-foot));
      height: var(--ls-drawer-foot);
      display: flex; align-items: center; justify-content: center;
      margin: 0; padding: 0;
      color: var(--ls-gold);
      border: 0; border-top: 1px solid var(--ls-rule-gold);
      border-radius: 0;
    }
    .ls-navopen .ls-nav__links,
    .ls-navopen .ls-nav .ls-pill {
      transform: translateY(0);
      opacity: 1; visibility: visible;
    }

    /* Drawer rows. 48px minimum on the top level, 44px on sub-items, both
       past the 24px WCAG 2.5.8 floor and at the platform-guidance size. */
    .ls-nav__links > *,
    .ls-nav__item { display: block; width: var(--ls-wrap); margin: 0 auto; }
    .ls-nav__link {
      display: flex; align-items: center;
      min-height: 48px;
      font-size: 16px;
      color: var(--ls-cream-strong);
      border-bottom: 1px solid rgba(var(--ls-cream-rgb), .08);
    }
    .ls-nav__link:hover,
    .ls-nav__link.is-active { color: var(--ls-gold); }

    /* Sub-menus are always open inside the drawer. Hover and focus-within
       cannot be reached by touch, so every page in the menus would otherwise
       be unreachable from the bar. */
    .ls-nav__dd {
      position: static; display: block;
      padding-top: 0;
    }
    .ls-nav__menu,
    .ls-nav__menu--wide {
      background: none; border: 0; border-radius: 0; box-shadow: none;
      min-width: 0;
      padding: 2px 0 8px;
    }
    .ls-nav__menu-link,
    .ls-nav__menu--wide .ls-nav__menu-link {
      display: flex; align-items: center;
      min-height: 44px;
      padding: 0 0 0 18px;
      font-size: var(--ls-fs-prose-sm);
      color: var(--ls-cream-body);
    }
    .ls-nav__menu-link:hover,
    .ls-nav__menu-link.is-active { background: none; color: var(--ls-gold); }
    /* The caret is a pointer affordance for a menu that is now always open. */
    .ls-nav__caret { display: none; }

    /* While the drawer is open the page behind it must not scroll. */
    .ls-navopen, .ls-navopen body { overflow: hidden; }

    /* --- Article aside --------------------------------------------------
       The aside is dropped rather than reflowed. It is a desktop convenience:
       sibling pages, which the drawer already lists, plus in-page anchors,
       which are a short scroll on a phone. Stacked it was ~700px of links
       before the article started, and as a scrolling chip strip it read as a
       second navigation bar under the first.

       .ls-sidenav is flex: 0 0 212px and never shrinks, so the article has
       to be released from the row as well, or it keeps whatever width is
       left over. */
    .ls-sidenav, .ls-projnav { display: none; }
    .ls-withaside { flex-wrap: wrap; gap: 32px; }
    .ls-withaside__main { flex: 1 1 100%; }
    /* The one destination the aside carries that the drawer does not is the
       news year switch, so the archive's year bar comes on in the same breath
       as the aside goes off. Above this width it is the aside's job and the
       bar is display:none; the two are never both on screen. */
    .ls-yearbar { display: flex; }
  }

  /* --- 760px: utility -----------------------------------------------------
     Drop an element on a phone. Spelled out in the markup rather than keyed
     off whatever class an element happens to carry, so the intent survives a
     restyle: the home hero's secondary call to action is hidden by wearing
     this, not by being the one .ls-btn--ghost in the section. */
  @media (max-width: 760px) {
    .ls-hide-sm { display: none; }
  }

  /* --- 760px: home hero ---------------------------------------------------
     The hero becomes exactly one screenful: photograph, headline, buttons.
     It used to run 1.4-1.6x the viewport, and 44% of that was the stat row,
     which fell to a single column below ~414px and stacked four cells to
     476px. So the photograph and its veil are pinned to the first screen and
     the stat row is left to sit below them on the section's own gradient,
     where it costs the hero nothing and reads two-up.

     svh rather than dvh or vh: dvh reflows the whole hero as the URL bar
     collapses, and vh measures the bar-hidden viewport, so at 100vh the
     buttons start below the fold on first paint. */
  @media (max-width: 760px) {
    /* One number drives the photograph's height and where the copy starts, so
       the two cannot drift apart. */
    .ls-home-hero {
      /* Floors sized for a short viewport: a 375x667 handset with a URL bar
         and toolbar leaves ~520svh, and the buttons still have to clear it. */
      --hero-photo-h: clamp(240px, 52svh, 520px);
      --hero-photo-gap: clamp(22px, 4svh, 44px);
      min-height: 0;
    }
    /* The photograph takes the upper part of the screen rather than all of it,
       and the copy sits below it on the section's own gradient.

       Shortening the box is what widens the crop. A 4:3 source in a portrait
       box covers by height, so the shorter the box the less it has to scale,
       and the more of the frame's width survives: at 100svh on a 375 screen
       only 35% of the width was visible, about five of the crew; at 56svh it
       is 62%, and their heads rise from 33-40% of the screen to about 20%,
       just under the bar. (The vertical half of object-position stays inert
       either way, since the height is always the constrained axis.) */
    .ls-home-hero__img {
      top: 0; bottom: auto;
      height: var(--hero-photo-h);
      max-height: none;
      object-position: 50% center;
      /* Dissolve rather than cut. Fading the image out beats fading a colour
         over it: the veil colour (#061c24) is not the section gradient's
         colour at that point (#0a2f3c), so a scrim would leave a seam.
         White, not black: mask-mode is match-source, and the -webkit- path
         reads a gradient as luminance, where black is zero and silently
         masks the entire photograph away. White reads as opaque under both
         alpha and luminance, so it is the portable choice. */
      -webkit-mask-image: linear-gradient(to bottom, #fff 68%, rgba(255,255,255,.45) 87%, transparent 100%);
      mask-image: linear-gradient(to bottom, #fff 68%, rgba(255,255,255,.45) 87%, transparent 100%);
    }
    .ls-hero-side { display: none; }
    /* No longer needed: the copy is off the photograph entirely, so the only
       cover still required is the top fade behind the bar. */
    .ls-hero-veil { display: none; }
    /* Bottom-anchored within that screen (align-items: flex-end comes from
       the base rule), which is what keeps the copy clear of the crew at every
       handset aspect now that a fixed padding no longer has to do it. The
       padding only has to clear the fixed bar. */
    /* The copy hangs off the bottom of the photograph, not off the bottom of
       the screen. Bottom-anchoring it to 100svh while the photograph stopped
       at ~55% left the leftover 45% as a dark void between the two. */
    .ls-hero-wrap {
      min-height: 0;
      align-items: flex-start;
      padding: calc(var(--hero-photo-h) + var(--hero-photo-gap)) 0 clamp(24px, 5svh, 48px);
    }
    /* The copy now sits over the darkest part of the veil rather than over
       the crew, so the blurred panel and its top booster have no contrast
       left to add and only risk showing an edge over the hi-vis shirts. */
    .ls-home-hero__panel,
    .ls-home-hero__booster { display: none; }
    /* Dropped on a phone. Nothing is lost with it: every figure it carries
       appears again in the About copy immediately below (seven permits, three
       granted, 1,390 km2, and the ~2,500 m initial programme), so on a narrow
       screen it is a second telling that delays the first. It stays in the
       markup, so it is still there for crawlers and for wider screens. */
    .ls-home-hero__stats { display: none; }
  }

  /* --- 760px: numbered strategy steps -------------------------------------
     Three columns on a desktop, where a number stacked over its title reads
     as a column heading. In one column it read as four separate blocks under
     the rule, the number stranded on a line of its own. Setting it into a
     gutter beside the text makes each step a numbered item again and gives
     the title and its copy a shared left edge. */
  @media (max-width: 760px) {
    .ls-corp-step {
      display: grid;
      /* A set width, not auto: each step is its own grid, and the serif
         digits are not tabular, so an auto gutter sized itself per step and
         the titles did not line up down the list. */
      grid-template-columns: 30px 1fr;
      column-gap: 14px;
      align-items: baseline;
    }
    .ls-corp-step__n {
      grid-row: 1 / span 2;
      margin-bottom: 0;
      font-size: 20px;
    }
    .ls-corp-step > :not(.ls-corp-step__n) { grid-column: 2; }
  }

  /* --- 760px: stat strips -------------------------------------------------
     The grid's auto-fit minimum is 180px against a ~345px wrap, so on a phone
     all four cells drop into one column and the strip runs to ~510px for four
     figures. Two up halves that, and the cell padding comes in with it.
     Shared by projects.html and the seven project pages, which carry the same
     four-cell strip under their heroes. */
  @media (max-width: 760px) {
    .ls-statstrip__grid { grid-template-columns: 1fr 1fr; }
    .ls-statstrip__cell,
    .ls-proj-statstrip__cell { padding: 18px 14px; }
    /* Every cell carries a left rule, which is what divides them in a row of
       four. Two up, the first column's rule has nothing to its left to divide
       and reads as a stray line down the edge of the band. */
    .ls-statstrip__cell:nth-child(odd),
    .ls-proj-statstrip__cell:nth-child(odd) { border-left: 0; }
    /* The grid is a .ls-wrap, so the cells start on the 15px gutter and their
       own 14px padding puts the figures at 29px. In a row of four that inset
       is the cell's business, but two up the strip is a full-bleed dark band
       between two light ones, and its left column is read directly against
       the headings and copy above and below it, all of which sit at 15. So
       the outer edges of the pair lose their padding and the strip lines up
       with the page; the divider and the gutter between the columns are
       untouched, and the two text columns come out at 158 and 157px. */
    .ls-statstrip__cell:nth-child(odd),
    .ls-proj-statstrip__cell:nth-child(odd) { padding-left: 0; }
    .ls-statstrip__cell:nth-child(even),
    .ls-proj-statstrip__cell:nth-child(even) { padding-right: 0; }
  }

  /* --- 760px: subscribe row -----------------------------------------------
     The field is flex: 1 1 230px, so on a phone it takes the whole first line
     and the button wraps under it at its own text width, which reads as a
     ragged step rather than a pair. Full width matches the field above it. */
  @media (max-width: 760px) {
    .ls-formrow > .ls-btn { flex: 1 1 100%; }
  }

  /* --- 760px: stat rows ---------------------------------------------------
     The row wraps rather than aligns. Each item shrink-wraps to its label
     (52px, 154px and 175px on corporate.html), so two land on the first line
     at whatever widths they happen to be and the third drops below, none of
     them sharing a left edge with the heading above.

     Stacked, with the figure and its label on one line rather than over it,
     all three line up on the band's left edge, the same edge as the heading.
     It costs 13px on corporate.html and 28px on investors.html, where the
     longer labels wrap; the alignment is worth the line. A 2-up grid was the
     other option and would have been shorter, but the values carry
     white-space: nowrap and investors.html's widest needs more room than a
     half-column gives it, so it would have overflowed. */
  @media (max-width: 760px) {
    .ls-stat-row { flex-direction: column; gap: 14px; }
    .ls-stat-row > * {
      display: flex; flex-wrap: wrap; align-items: baseline; column-gap: 10px;
    }
    /* Qualifies the figure above it, so it takes its own line. */
    .ls-inv-stat__note { flex-basis: 100%; }
  }

  /* The column divider only makes sense while the two columns sit side by side. */
  @media (max-width: 820px) {
    .ls-about-body { border-left: 0; padding-left: 0; }
  }

  /* Document card: photo panel and copy panel stack once the card narrows. */
  @media (max-width: 640px) {
    .ls-doccard { flex-direction: column; }
    .ls-doccard__visual { flex: none; height: 196px; }
    .ls-doccard__body { box-shadow: none; }
  }

  /* --- 640px: "Why Côte d'Ivoire" figures ---------------------------------
     Same shape of problem as the stat strips, one size worse. The auto-fit
     minimum is max(230px, 29%), so the six cells hold three columns down to
     ~720px and two down to ~500px, and then all SIX drop into one column:
     885px for six figures, more than a phone screen, every cell identical at
     146px, nothing to scan. Two up is 522px.

     640px, not 760: at 760 the card is legitimately three across, and this
     rule would have taken it down to two. Between 500 and 640 auto-fit
     already gives two columns, so the rule only restates what is there and
     the phone range is what actually changes.

     The cells keep the type ramp (15px label, 13.5px note); only the padding
     comes in, which buys the text 123px -> 141px of measure and holds every
     label to two lines. The 1px gap that draws the dividers works at any
     column count, so unlike the stat strips there is no stray edge rule to
     clear here. */
  @media (max-width: 640px) {
    .ls-proj-whygrid { grid-template-columns: 1fr 1fr; }
    .ls-proj-whygrid__cell { padding: 20px 16px; }
    .ls-proj-whygrid__l { margin-top: 12px; }
  }

  /* --- 760px: section padding ---------------------------------------------
     --ls-band-y is clamp(60px, 7.5vw, 111px), and 7.5vw does not reach 60px
     until the viewport is 800 wide, so every phone sits on the clamp floor:
     60px top and bottom, 120px between any two sections, before whatever
     padding the last card inside the band contributes (measured 121-163px on
     index.html). Against a ~640px usable handset screen that is a fifth to a
     quarter of a screen of nothing at each boundary.

     48px takes the boundary to 96px. The intra-section step on a phone is
     30px (.ls-head--gap-44 and .ls-proj-why both bottom out there), so the
     ratio goes 4:1 -> 3.2:1, still clearly reading as a section break and
     still airy. --ls-band-y also drives .ls-ctaband, which wants the same
     treatment; .ls-band--article sets its own literal clamps and is brought
     with it so the article pages do not end up looser than everything else.
     The hero paddings are deliberately left alone — they have their own
     rhythm, measured separately. */
  @media (max-width: 760px) {
    :root { --ls-band-y: 48px; }
    .ls-band--article { padding-top: 48px; padding-bottom: 48px; }
    /* Its own literal clamps land on 56/48 at phone width; the 56 was the
       only top padding left out of step with its neighbours. */
    .ls-proj-mapband { padding-top: 48px; }
    /* The permit schedule band sets its bottom padding literally and was the
       one section on the site closing at 60 while the other 53 closed at 48. */
    .ls-proj-tableband { padding-bottom: 48px; }
  }

  /* --- 760px: page hero top padding ---------------------------------------
     Three hero families open the interior pages and each sets its own top
     padding: .ls-pagehero clamp(140px, 18vh, 190px), its --short form the
     same, and --photo clamp(130px, 16vh, 175px). Against a 67px bar that is
     63, 64 and 53px of clear space, and the vh term moves the first two again
     with the handset: 140 on a 667-tall screen, 146 on an 812. Four values
     for one relationship, none of which the reader can see a reason for.

     One number for all three. 120px leaves 53px under the bar, which is what
     the photo heroes already had and the tightest of the four, so nothing
     gets airier and the interior pages open the same way on every phone. The
     bottom paddings stay as they are: those differ by what follows the hero
     (a stat strip, an article head, a band) rather than by family. */
  @media (max-width: 760px) {
    .ls-pagehero,
    .ls-pagehero--short,
    .ls-pagehero--photo,
    .ls-proj-hero { padding-top: 120px; }
  }

  /* --- 760px: card padding ------------------------------------------------
     Every card is the full width of the wrap on a phone and they arrive in
     one column, so their inner left edges are read against each other and
     against the 15px gutter that every heading, kicker and paragraph sits on.
     The floors of the individual card paddings were each chosen for that
     card's desktop proportions and land on 20, 22, 24, 26 and 28, which puts
     card text at 35, 37, 39, 41 and 43px from the edge of the screen down a
     single scroll.

     One value. 22px is what most of them already use (.ls-tile, .ls-inv-card,
     .ls-mgmt-bio, .ls-callout and .ls-kim-panel between them account for
     nineteen instances), and it leaves a 301px measure, which is 3px more
     than the widest of them has now.

     Only cards that sit directly in the page column are listed. Components
     inside a card — spec cells, figure cells, the numbered steps — keep their
     own tighter scale, since they are read against their card rather than
     against the page. */
  @media (max-width: 760px) {
    .ls-card,
    .ls-panel,
    .ls-tile,
    .ls-callout,
    .ls-flagship,
    .ls-doccard__body,
    .ls-corp-parent,
    .ls-mgmt-bio,
    .ls-contact-card,
    .ls-inv-card,
    .ls-fs-sedar__panel,
    .ls-kim-banner,
    .ls-kim-aside,
    .ls-kim-panel,
    .ls-article__box,
    .ls-proj-row { padding: 22px; }
  }

  /* --- 760px: section headings --------------------------------------------
     The reading ramp is a token, --ls-fs-h2, whose floor is 28px. The five
     page-scoped section titles predate it and set their own clamps, whose
     floors are 30 and 32, and the CTA band's is 26. On a desktop those sit in
     separate sections at widths where a two-point difference is a fraction of
     the line; on a phone they arrive one after another in a single column and
     index.html alone runs 28, 28, 32, 30, 30 down the page.

     They all mean "section head", so on a phone they are all the token. The
     desktop clamps are untouched: the tops of those ramps are deliberate. */
  @media (max-width: 760px) {
    .ls-home-about__title,
    .ls-home-news__title,
    .ls-home-docs__title,
    .ls-home-sub__title,
    .ls-proj-why__title,
    .ls-proj-maphead__title,
    .ls-ctaband__title { font-size: var(--ls-fs-h2); }
  }

  /* --- 760px: the flagship card -------------------------------------------
     The card is a two-column flex row that wraps to one column on a phone,
     and neither of the two things that wrapped was told to fill it.

     The figures block is flex: 0 1 auto and sizes to its widest label, so it
     came out 217px inside a 297px content box: a bordered panel whose right
     edge lined up with nothing, 80px short of the copy above it. Full width,
     one column — auto-fit would give two at this width and leave the third
     figure alone on its row.

     The two buttons shrink-wrap to their own text, so they stacked at 185 and
     207px, a ragged step down the left edge. Full width matches the block
     above them and each other, and is what .ls-formrow already does with the
     subscribe button. */
  @media (max-width: 760px) {
    .ls-flagship__figs { flex: 1 1 100%; grid-template-columns: 1fr; }
    .ls-flagship__actions > .ls-btn { flex: 1 1 100%; }
    /* 10.5px is under the floor these labels can be read at on a handset, and
       the block is now wide enough that the extra tracking costs nothing. It
       joins the kicker step, which is the site's size for tracked capitals. */
    .ls-flagship__l { font-size: var(--ls-fs-kicker); }
  }

  /* --- 760px: standalone link targets -------------------------------------
     WCAG 2.5.8 asks for 24x24 CSS pixels, and exempts links that sit in a
     sentence. These do not: they are the footer's contact list and legal row,
     the breadcrumb, the news row's PDF link and the article's back link and
     source link, each of them a target on its own, and each 15 to 19px tall.

     The area is grown with a pseudo-element rather than with padding so that
     nothing moves. Padding on .ls-footer__link would open a gap between the
     phone number and the address lines above it, which are not links and
     would not get one. 24px, not 44px, because the footer's contact links are
     27px apart and a 44px box would have them overlapping. */
  @media (max-width: 760px) {
    .ls-footer__link,
    .ls-footer__minilink,
    .ls-crumbs__link,
    .ls-contact-line,
    .ls-newsrow__cta,
    .ls-article__back,
    .ls-article__link,
    .ls-morelink,
    a.ls-cta,
    .ls-inv-stats > a { position: relative; }
    .ls-footer__link::after,
    .ls-footer__minilink::after,
    .ls-crumbs__link::after,
    .ls-contact-line::after,
    .ls-newsrow__cta::after,
    .ls-article__back::after,
    .ls-article__link::after,
    .ls-morelink::after,
    a.ls-cta::after,
    .ls-inv-stats > a::after {
      content: "";
      position: absolute; left: 0; right: 0; top: 50%;
      height: 24px; transform: translateY(-50%);
    }

    /* The footer's phone number and two addresses are set in --ls-cream-body,
       which is exactly what the postal address beside them uses, so the only
       thing marking them as links was a hover colour that a touch screen never
       shows. Same for the legal row, which sits inside a copyright line of the
       same size and colour. A rule at low alpha reads as a link without
       pulling either group out of the footer's tone. */
    .ls-footer__link,
    .ls-footer__minilink {
      text-decoration: underline;
      text-decoration-color: rgba(var(--ls-cream-rgb), .3);
      text-underline-offset: 3px;
    }
  }

  /* --- 760px: horizontally scrolling tables -------------------------------
     The permit schedule is 760px of columns and the drill programme 680, in a
     343px box. Both scroll, but an overlay scrollbar only appears while the
     finger is moving, so at rest the last columns simply look absent: the
     schedule shows Project, Permit and Holder and gives no sign that Interest,
     Area and Status are to the right of them.

     The standard background-attachment pair: the two `local` gradients scroll
     with the content and cover the shadows when the table is at that end, the
     two `scroll` shadows stay pinned to the box. Cells declare no background
     of their own, so the container's shows through. */
  @media (max-width: 760px) {
    .ls-proj-table__scroll,
    .ls-kim-table {
      background:
        linear-gradient(to right, #fff 40%, rgba(255,255,255,0)) left center / 28px 100% no-repeat local,
        linear-gradient(to left,  #fff 40%, rgba(255,255,255,0)) right center / 28px 100% no-repeat local,
        radial-gradient(farthest-side at 0 50%, rgba(var(--ls-ink-rgb), .16), rgba(var(--ls-ink-rgb), 0)) left center / 13px 100% no-repeat scroll,
        radial-gradient(farthest-side at 100% 50%, rgba(var(--ls-ink-rgb), .16), rgba(var(--ls-ink-rgb), 0)) right center / 13px 100% no-repeat scroll,
        #fff;
    }
  }

  /* --- 600px: project directory rows --------------------------------------
     The row is three flex items — a 128px id rail, the body, the actions —
     and below ~610px all three are on their own line. Two of them are then
     stacked pairs that read better inline once they have the full width:

     - the id rail puts its permit number over its status chip, 44px of a
       two-word header; side by side it is one 21px line, and it reads as the
       card's header rather than as a rail that lost its column.
     - the actions column is align-items: stretch, so the locate button took
       the CTA's 158px width and centred its own text inside it — the one
       thing in the card not on the card's left edge. As a wrapping row it
       sits beside the CTA when it fits and drops to the left edge when it
       does not, which is what .ls-proj-flag__actions already does on the
       flagship card above.

     600px, not 640: at 620 the id rail and the body are still side by side,
     and full-width id would have broken that. The rules only apply where the
     row has already stacked of its own accord.

     The locate link's padding is a target-size fix, not spacing: 15px tall
     is under the 24px minimum, and it is a primary way into the map. */
  @media (max-width: 600px) {
    .ls-proj-row__id {
      flex: 1 1 100%;
      flex-direction: row;
      align-items: center;
      gap: 10px;
    }
    .ls-proj-row__actions {
      flex: 1 1 100%;
      flex-direction: row;
      flex-wrap: wrap;
      align-items: center;
      gap: 8px 18px;
    }
    .ls-proj-row__locate { padding: 6px 0; }
  }

  /* --- 600px: the footer stacks -------------------------------------------
     Half of a 600px column is ~250px, which still holds "Suite 750 - 580
     Hornby Street" on two lines; below it the address starts breaking mid
     line, so the groups go one per row. The nav keeps its two-up list — ten
     links in one column is most of a phone screen of scrolling for something
     the drawer already offers, which is why it used to be hidden outright
     down here; two columns of five costs 130px and keeps a way out of the
     bottom of a long page. */
  @media (max-width: 600px) {
    .ls-footer__cols { grid-template-columns: 1fr; gap: 34px; }
    .ls-footer__brand { max-width: none; padding-top: 0; }
  }

  /* --- 420px: map legend --------------------------------------------------
     Three items in a wrapping flex row, each shrink-wrapped to its own label
     (114px, 92px, 119px), so once the row cannot hold them two land on the
     first line and the third is orphaned below at an arbitrary left edge.
     Stacked with the figure beside its label rather than over it — the
     .ls-stat-row treatment — the three read as a list against the band's
     left edge, the same edge as the heading above them.

     The row needs 377px and the wrap gives it 381px at 414px wide: it fits,
     but on 4px, which a font fallback would eat. So the breakpoint is set
     above that marginal case rather than at the ~410px where it measurably
     breaks. At 430 and up the row has 23px of slack and is left alone. */
  @media (max-width: 420px) {
    .ls-proj-maplegend { flex-direction: column; gap: 12px; }
    .ls-proj-maplegend > * {
      display: flex; align-items: baseline; column-gap: 12px;
    }
    .ls-proj-maplegend__l { margin-top: 0; }
  }
}

/* ==========================================================================
   MOTION — the entrance
   --------------------------------------------------------------------------
   One vocabulary for the whole site: a unit fades up over a short rise as it
   reaches the viewport, and units that reach it together arrive one after
   another. Nothing scales, nothing blurs, nothing slides in from the side.
   The fade is deliberately shorter than the travel, so a block is legible
   before it has finished settling.

   Everything here is gated behind `ls-anim` on <html>, which js/ls-reveal.js
   sets — and only when the browser can animate and the visitor has not asked
   for reduced motion. So with JavaScript off, on an old browser, under
   `prefers-reduced-motion: reduce`, or in print, this whole layer is inert
   and the page renders exactly as it did before it existed.

   The rule tagged `--ls-rv-units: 1` is the single source of truth for what
   reveals; ls-reveal.js reads that selector back out of the CSSOM rather
   than keeping a second copy. Edit the list here and the script follows.
   ========================================================================== */
@layer motion {

  :root {
    --ls-rv-rise: 18px;   /* how far a unit travels                          */
    --ls-rv-dur:  780ms;  /* the travel                                      */
    --ls-rv-fade: 520ms;  /* the fade: shorter, so copy is readable early    */
    --ls-rv-step: 90ms;   /* gap between two units arriving together         */
    --ls-rv-ease: cubic-bezier(.17, .72, .26, 1);
    --ls-count-dur: 1200ms;  /* hero figures ramp 0 -> printed value         */
  }

  @media screen and (prefers-reduced-motion: no-preference) {

    /* --- The start state -------------------------------------------------
       Outermost match wins: ls-reveal.js hands `ls-rv-off` to any unit
       sitting inside another unit and lets it ride in with its parent, so
       this list can stay coarse. `ls-rv-done` is added the moment a unit is
       released, which drops it out of this rule entirely — that is what
       leaves a card's own hover lift intact afterwards.

       The one thing that must stay out of this list is a structural wrapper.
       Naming one swallows everything inside it, and both offenders here were
       found the same way — by someone noticing a run of items arriving as a
       single slab. `.ls-splitlayout` wraps a heading and the whole milestone
       timeline: thirteen rows that should have counted themselves in came as
       one. `.ls-head` is nothing but `margin-bottom`, yet on management.html
       it wraps a kicker, a bio and a grid of three tiles, and on projects.html
       each directory group — so the bios and the permit rows came as one too.

       The tell is a listed selector whose own children are also listed. A real
       unit holds text; a wrapper holds units. `.ls-wrap`, `.ls-head`,
       `.ls-splitlayout`, `.ls-grid`, `.ls-timeline`, `.ls-stack` are
       spacing and layout, never units — their children are. Dropping one can
       orphan a leaf that has no class of its own on the list, which is why
       `.ls-cta` and `.ls-proj-group__head` are named above: without them the
       "View all" link and each group's title would sit static beside content
       that animates. */
    html.ls-anim :is(

      /* Section furniture -------------------------------------------- */
      .ls-subhead, .ls-yearhead, .ls-yearhead__count--block,
      .ls-yearbar, .ls-crumbs,
      .ls-proj-group__head,
      h1, h2, h3, h4,
      .ls-kicker, .ls-lead, .ls-prose, .ls-copy, .ls-note, .ls-row,
      .ls-quote, .ls-callout, .ls-disclaimer, .ls-caption, .ls-morelink,
      .ls-cta,
      .ls-stat-row, .ls-mgmt-intro, .ls-inv-stats, .ls-inv-foot,
      .ls-corp-parent, .ls-corp-jvnote, .ls-fs-sedar, .ls-fs-note,
      .ls-proj-listtitle, .ls-proj-maphead, .ls-proj-maplegend,
      .ls-proj-hero__lead, .ls-kim-banner, .ls-kim-note, .ls-kim-list,
      .ls-kim-doc-note, .ls-kim-doclink,
      .ls-article__head, .ls-article__foot, .ls-article__box,
      .ls-article__list, .ls-article__note, .ls-article__back,

      /* Repeating units — the ones that read as a sequence ----------- */
      .ls-card, .ls-newsrow, .ls-panel, .ls-inv-card, .ls-doccard,
      .ls-tile, .ls-flagship, .ls-proj-flag, .ls-proj-row,
      .ls-corp-step, .ls-mgmt-bio, .ls-timeline__row, .ls-kim-step,
      .ls-kim-fact, .ls-kim-panel, .ls-kim-aside, .ls-kim-strip,
      .ls-point, .ls-contact-card, .ls-contact-line,
      .ls-statstrip__cell, .ls-proj-statstrip__cell,
      .ls-specs__cell, .ls-proj-whygrid__cell,
      .ls-figure,

      /* Media and tables --------------------------------------------- */
      figure, .ls-figframe, .ls-img, .ls-mapframe, .ls-photoband,
      .ls-kim-table, .ls-proj-table,

      /* The subscribe row -------------------------------------------- */
      .ls-formrow, .ls-formconsent, .ls-formnote, .ls-confirm,

      /* Page asides ---------------------------------------------------- */
      .ls-sidenav, .ls-projnav,

      /* Footer ------------------------------------------------------- */
      .ls-footer__cols > *, .ls-footer__alert, .ls-footer__legal,
      .ls-footer__bar

    ):not(:where(
      /* The home hero and the bar run their own choreography below.

         The two page asides arrive as one block each, which is why the aside
         is listed above and everything inside it is excluded here. They are
         navigation, not content: a column of eight section links counting
         itself in, one link at a time, turns the chrome into the thing you
         watch. Whole and once, alongside the article it sits beside.

         Transforming a sticky element is safe — sticky is resolved in layout
         and the transform is a paint offset, so the aside still sticks — and
         ls-reveal.js fills backwards only, so nothing survives the
         animation to interfere with it later. */
      .ls-home-hero *, .ls-nav, .ls-nav *,
      .ls-sidenav *, .ls-projnav *,
      [data-ls-rv-skip], [data-ls-rv-skip] *,
      /* Set by ls-reveal.js — see the note above. */
      .ls-rv-done, .ls-rv-off
    )) {
      --ls-rv-units: 1;
      opacity: 0;
      transform: translate3d(0, var(--ls-rv-rise), 0);
    }

    /* Small, dense units travel less. An 18px hop on a 60px stat cell reads
       as a jump; on a 300px card the same distance reads as a settle. */
    html.ls-anim :is(
      .ls-kicker, .ls-crumbs, .ls-contact-line, .ls-figure,
      .ls-statstrip__cell, .ls-proj-statstrip__cell,
      .ls-specs__cell, .ls-proj-whygrid__cell,
      .ls-timeline__row, .ls-kim-fact, .ls-footer__bar
    ) { --ls-rv-rise: 10px; }

    /* Body copy is read, not looked at: it arrives without drawing a line,
       and a run of it lands almost together. At the full 90ms step the six
       paragraphs of a news release would take half a second to file in, which
       turns reading into waiting; the legal pages run to nineteen. Counting
       is for things you are meant to count — cards, releases, figures. */
    html.ls-anim :is(.ls-copy, .ls-note, .ls-prose, .ls-point,
                      .ls-article__list, .ls-kim-list) {
      --ls-rv-rise: 12px;
      --ls-rv-step: 38ms;
    }

    /* Full-bleed media has no edge to travel against, so it only fades. */
    html.ls-anim :is(.ls-photoband, .ls-mapframe, .ls-img) { --ls-rv-rise: 0px; }

    /* Everything from here down is keyed off `ls-anim` for the same reason
       the start state above is: these are the only rules on the site that can
       leave text at opacity 0, and ls-reveal.js's guard timer clears that
       class if its machinery ever fails to run. Ungated, the headline would
       be the one piece of the page with no way back. */

    /* --- The bar ----------------------------------------------------------
       Opacity only, and on the inner wrapper. A transform here would make
       `.ls-nav__inner` the containing block for the mobile drawer, which is
       positioned absolute against `.ls-nav` itself. */
    html.ls-anim .ls-nav__inner { animation: lsRvFade 620ms linear both; }

    /* --- The home hero ----------------------------------------------------
       The photograph emerges from the section's own gradient and settles out
       of a slight enlargement, which is the only scale anywhere on the site.
       Then the headline, then the buttons, then the figures.

       The scrims are deliberately NOT animated. Every one of them (the side
       wash, the veil, the top fade, and the copy panel and booster that back
       the headline) is a dark layer over an already dark gradient, so at rest
       they cost nothing visually — but fading them in alongside the photo
       hands the headline half a second over an unscrimmed photograph, which
       is exactly the contrast case the hero was tuned to avoid. Full strength
       from the first frame means the photograph arrives already scrimmed. */
    /* The photograph waits for its own pixels. Every other animation here runs
       on a wall clock from page load, which is right for markup that is
       already parsed — but on a cold cache the hero JPEG can still be arriving
       after 1500ms, so the fade would play out over nothing and the picture
       would then simply appear. Held paused on the first keyframe until
       ls-reveal.js has seen the image decode, then played.

       `both` is what makes pausing safe: the first keyframe is applied for as
       long as the animation sits at time zero. And if the image never arrives
       at all, the hero keeps its gradient-only frame, which the headline is
       legible on — better than a broken picture fading in. */
    html.ls-anim .ls-home-hero__img {
      animation: lsRvHeroPhoto 1500ms cubic-bezier(.2, .7, .2, 1) both;
      animation-play-state: paused;
    }
    html.ls-anim .ls-home-hero__img.is-ready { animation-play-state: running; }
    html.ls-anim .ls-home-hero__title    { animation: lsRvRise 900ms var(--ls-rv-ease) 240ms both; }
    html.ls-anim .ls-home-hero__actions  { animation: lsRvRise 860ms var(--ls-rv-ease) 400ms both; }
    html.ls-anim .ls-home-hero__statcell { animation: lsRvRise 800ms var(--ls-rv-ease) both; }
    html.ls-anim .ls-home-hero__statcell:nth-child(1) { animation-delay: 560ms; }
    html.ls-anim .ls-home-hero__statcell:nth-child(2) { animation-delay: 640ms; }
    html.ls-anim .ls-home-hero__statcell:nth-child(3) { animation-delay: 720ms; }
    html.ls-anim .ls-home-hero__statcell:nth-child(4) { animation-delay: 800ms; }

    @keyframes lsRvFade {
      from { opacity: 0; }
      to   { opacity: 1; }
    }
    @keyframes lsRvRise {
      from { opacity: 0; transform: translate3d(0, 20px, 0); }
      to   { opacity: 1; transform: none; }
    }
    @keyframes lsRvHeroPhoto {
      from { opacity: 0; transform: scale(1.045); }
      to   { opacity: 1; transform: none; }
    }
  }

  /* The two decorative pulses predate this layer and were looping through
     `reduce`; they stop here, at the ring's resting size. */
  @media (prefers-reduced-motion: reduce) {
    .ls-home-hero__pulse, .ls-proj-hero__pulse {
      animation: none; opacity: .4; transform: scale(1.2);
    }
  }
}
