/* ==========================================================================
   Linc Consultancy - design system
   --------------------------------------------------------------------------
   Editorial, typography-led layout. The rules are deliberate:

   - Hairlines, never boxes. Content sits on the page instead of inside cards,
     so the eye follows the type rather than counting containers.
   - Headlines are LIGHT (300) and large. Heavy type at large sizes reads as a
     product launch; light type at large sizes reads as a consultancy.
   - Orange appears roughly once per section. The brand guide calls the orange
     dot "the moment where ideas connect", which only works if it is rare.
   - No shadows, no gradient text, no blurred colour blobs, no lift on hover.
     Motion is limited to hairlines, underlines and a 4px arrow nudge.
   ========================================================================== */

:root {
  --teal: #004851;
  --teal-deep: #00343b;
  --aqua: #4897ae;
  --orange: #ff5b00;
  --gray: #c1c1c1;
  --paper: #ffffff;
  --mist: #f5f7f7;

  /* Text tiers. Body copy never sits at full teal: it is too heavy against
     white at paragraph length. */
  --ink: #004851;
  --ink-soft: rgba(0, 72, 81, 0.74);
  --ink-mute: rgba(0, 72, 81, 0.54);
  --ink-faint: rgba(0, 72, 81, 0.34);

  /* Hairlines. The single most-used element in the whole design. */
  --rule: rgba(0, 72, 81, 0.13);
  --rule-strong: rgba(0, 72, 81, 0.26);
  --rule-on-dark: rgba(255, 255, 255, 0.16);
  --rule-on-dark-strong: rgba(255, 255, 255, 0.34);

  --ease: cubic-bezier(0.22, 0.8, 0.24, 1);
  /* Entrance curve: fast out of the gate, long settle. Used for everything
     that arrives on screen. */
  --ease-enter: cubic-bezier(0.22, 1, 0.36, 1);
}

html {
  scroll-behavior: smooth;
  /* Stops the fixed navbar covering section headings on anchor jumps. */
  scroll-padding-top: 5.5rem;
}

body {
  font-family: 'Figtree', system-ui, -apple-system, 'Segoe UI', sans-serif;
  background: var(--paper);
  color: var(--ink);
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  /* Slightly open body tracking keeps Figtree from feeling cramped. */
  letter-spacing: -0.005em;
}

::selection {
  background: var(--orange);
  color: #fff;
}

/* --------------------------------------------------------------------------
   Typography
   Sizes use clamp() so they scale continuously with the viewport instead of
   jumping at breakpoints. That continuity is a large part of feeling refined.
   -------------------------------------------------------------------------- */

.font-display {
  font-family: 'Outfit', 'Figtree', system-ui, sans-serif;
}

/* Hero headline. */
.display-xl {
  font-family: 'Outfit', 'Figtree', system-ui, sans-serif;
  font-size: clamp(2.6rem, 6.4vw, 5.4rem);
  font-weight: 300;
  line-height: 1.03;
  letter-spacing: -0.038em;
}

/* Section headline. */
.display-lg {
  font-family: 'Outfit', 'Figtree', system-ui, sans-serif;
  font-size: clamp(2.05rem, 4.2vw, 3.5rem);
  font-weight: 300;
  line-height: 1.08;
  letter-spacing: -0.032em;
}

/* Pull quotes, vision and mission. */
.display-md {
  font-family: 'Outfit', 'Figtree', system-ui, sans-serif;
  font-size: clamp(1.45rem, 2.3vw, 2.1rem);
  font-weight: 300;
  line-height: 1.32;
  letter-spacing: -0.022em;
}

/* Row titles, names, project titles. */
.display-sm {
  font-family: 'Outfit', 'Figtree', system-ui, sans-serif;
  font-size: clamp(1.15rem, 1.5vw, 1.4rem);
  font-weight: 400;
  line-height: 1.28;
  letter-spacing: -0.018em;
}

/* Emphasis inside a light headline. Replaces the old gradient-filled text:
   weight contrast is quieter and ages better than a gradient. */
.accent {
  font-weight: 500;
  color: var(--teal);
}

.accent-soft {
  color: var(--aqua);
  font-weight: 400;
}

/* Small caps label above every section heading. */
.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  font-family: 'Figtree', system-ui, sans-serif;
  font-size: 0.6875rem;
  font-weight: 600;
  line-height: 1.6;
  text-transform: uppercase;
  letter-spacing: 0.2em;
  color: var(--ink-mute);
}

.eyebrow-on-dark {
  color: rgba(255, 255, 255, 0.6);
}

/* Intro paragraph under a section heading. */
.lede {
  font-size: clamp(1rem, 1.25vw, 1.1875rem);
  line-height: 1.65;
  color: var(--ink-soft);
  font-weight: 400;
}

.lede-on-dark {
  color: rgba(255, 255, 255, 0.72);
}

.body-text {
  font-size: 0.9375rem;
  line-height: 1.7;
  color: var(--ink-soft);
}

.body-text-on-dark {
  color: rgba(255, 255, 255, 0.68);
}

/* --------------------------------------------------------------------------
   The brand dot
   The identity's core mark. Used once per section as a focus point, and after
   a headline word the way the logo places it under the arch.
   -------------------------------------------------------------------------- */
.brand-dot {
  display: inline-block;
  /* Kept small on purpose. At headline sizes anything larger stops reading as
     the logo's dot and starts reading as a bullet. */
  width: 0.21em;
  height: 0.21em;
  border-radius: 50%;
  background: var(--orange);
  vertical-align: baseline;
  /* Nudged so it optically sits on the baseline rather than floating. */
  margin-left: 0.12em;
  transform: translateY(-0.04em);
}

/* Hero second line: three words, each led by the dot. The dot sits before
   the word here, so its margin flips to the right. Wraps as a unit per word
   on narrow screens. Doubled class so it beats .line-inner's display:block,
   which is declared later in this file. */
.line-inner.hero-pillars {
  display: flex;
  flex-wrap: wrap;
  column-gap: 0.55em;
}

.hero-pillars .brand-dot {
  margin-left: 0;
  margin-right: 0.12em;
}

.eyebrow .brand-dot {
  width: 5px;
  height: 5px;
  margin: 0;
  transform: none;
  /* When the label wraps to two lines the flex container would centre the dot
     across both. Pin it to the first line instead. */
  align-self: flex-start;
  margin-top: 0.45em;
}

/* --------------------------------------------------------------------------
   Hairlines
   -------------------------------------------------------------------------- */
.rule {
  border: 0;
  border-top: 1px solid var(--rule);
  margin: 0;
}

.rule-on-dark {
  border: 0;
  border-top: 1px solid var(--rule-on-dark);
  margin: 0;
}

/* --------------------------------------------------------------------------
   Navigation
   -------------------------------------------------------------------------- */
#navbar {
  background: rgba(255, 255, 255, 0);
  border-bottom: 1px solid transparent;
  transition: background 0.4s var(--ease), border-color 0.4s var(--ease);
}

#navbar.nav-scrolled {
  background: rgba(255, 255, 255, 0.92);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  border-bottom-color: var(--rule);
}

.nav-link {
  position: relative;
  color: var(--ink-soft);
  font-size: 0.8125rem;
  font-weight: 500;
  letter-spacing: 0.01em;
  transition: color 0.25s var(--ease);
}

/* scaleX rather than width: width is a layout property, so animating it forces
   a recalc every frame. A scaled transform stays on the compositor. */
.nav-link::after {
  content: '';
  position: absolute;
  left: 0;
  bottom: -0.4rem;
  width: 100%;
  height: 1px;
  background: var(--orange);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 0.32s var(--ease-enter);
}

.nav-link:hover {
  color: var(--teal);
}

.nav-link:hover::after {
  transform: scaleX(1);
}

/* --------------------------------------------------------------------------
   Buttons
   One solid button per view at most. Radius is 2px, not a pill: pills read
   friendly and consumer, near-square reads considered.
   -------------------------------------------------------------------------- */
.btn-solid {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  background: var(--teal);
  color: #fff;
  font-size: 0.875rem;
  font-weight: 500;
  letter-spacing: 0.01em;
  /* Full pill. The brand mark is an arch over a circle, so round geometry is
     native to the identity rather than borrowed. */
  border-radius: 999px;
  transition: background 0.3s var(--ease);
}

.btn-solid:hover {
  background: var(--orange);
}

.btn-line {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  background: transparent;
  color: var(--teal);
  border: 1px solid var(--rule-strong);
  font-size: 0.875rem;
  font-weight: 500;
  border-radius: 999px;
  transition: border-color 0.3s var(--ease), color 0.3s var(--ease);
}

/* --------------------------------------------------------------------------
   Media panel
   Soft imagery against crisp type: the panel carries a generous radius while
   headlines stay sharp. Until a real photograph is dropped in, the panel shows
   the brand arch pattern on teal, which reads as a deliberate brand plate
   rather than a missing image.
   -------------------------------------------------------------------------- */
.media {
  position: relative;
  overflow: hidden;
  border-radius: 14px;
  background: var(--teal);
  /* 16:11 is close to the reference and holds its height before an image
     loads, so nothing on the page jumps. */
  aspect-ratio: 16 / 11;
}

/* Portrait variant, for the three office cards. */
.media-tall {
  aspect-ratio: 3 / 4;
}

.media img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* Brand plate shown when the panel has no photograph yet. */
.media-plate::after {
  content: '';
  position: absolute;
  inset: 0;
  background-image: url('assets/brand/pattern-arch-white-2.png');
  background-size: cover;
  background-position: center;
  opacity: 0.16;
}

/* The mark is a centred logo, not a full-bleed photo, so it has to cancel the
   inset/cover rules that .media img sets for real photographs. */
.media-plate .media-mark {
  position: absolute;
  inset: auto;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: 38%;
  height: auto;
  max-width: 210px;
  object-fit: contain;
  opacity: 0.92;
  /* Above the pattern overlay, which is a later-painted pseudo-element. */
  z-index: 1;
}

.btn-line:hover {
  border-color: var(--orange);
  color: var(--orange);
}

.btn-line-on-dark {
  color: #fff;
  border-color: var(--rule-on-dark-strong);
}

.btn-line-on-dark:hover {
  border-color: var(--orange);
  color: var(--orange);
}

/* Orange button, for use ON the teal sections where .btn-solid's teal would be
   invisible. This has to be its own class rather than `btn-solid bg-linc-orange`:
   styles.css loads after tailwind.css, so .btn-solid's background would win over
   the utility and silently render a teal button on a teal ground. */
.btn-accent {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  background: var(--orange);
  color: #fff;
  font-size: 0.875rem;
  font-weight: 500;
  letter-spacing: 0.01em;
  /* Full pill. The brand mark is an arch over a circle, so round geometry is
     native to the identity rather than borrowed. */
  border-radius: 999px;
  transition: background 0.3s var(--ease), color 0.3s var(--ease);
}

.btn-accent:hover {
  background: #fff;
  color: var(--teal);
}

/* Text link with an arrow that nudges. The main interaction of the whole site. */
.link-arrow {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.875rem;
  font-weight: 500;
  color: var(--teal);
  transition: color 0.25s var(--ease);
}

.link-arrow .arrow {
  transition: transform 0.3s var(--ease);
}

.link-arrow:hover {
  color: var(--orange);
}

.link-arrow:hover .arrow {
  transform: translateX(4px);
}

/* --------------------------------------------------------------------------
   Editorial rows
   Replaces the old card grids. A row is a hairline, an index numeral, a title
   and a description. Hovering tints the row and turns its rule orange.
   -------------------------------------------------------------------------- */
.row-item {
  position: relative;
  border-top: 1px solid var(--rule);
  transition: background-color 0.35s var(--ease);
}

.row-item:last-child {
  border-bottom: 1px solid var(--rule);
}

/* The orange rule is a pseudo-element that grows from the left, so the layout
   never shifts and no border colour flickers. scaleX keeps it off the layout
   path entirely. */
.row-item::before {
  content: '';
  position: absolute;
  top: -1px;
  left: 0;
  width: 100%;
  height: 1px;
  background: var(--orange);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 0.5s var(--ease-enter);
}

.row-item:hover {
  background-color: rgba(0, 72, 81, 0.022);
}

.row-item:hover::before {
  transform: scaleX(1);
}

/* The row title slides a touch to the right on hover, echoing the arrow nudge
   used on links. Gated to real pointers so a tap on mobile doesn't stick. */
.row-title {
  transition: transform 0.45s var(--ease-enter);
}

@media (hover: hover) and (pointer: fine) {
  .row-item:hover .row-title {
    transform: translateX(6px);
  }

  .row-item:hover .row-arrow {
    transform: translateX(5px);
  }
}

/* A whole row can be a link. Making the anchor the grid means the entire row is
   the click target, and it stays keyboard-focusable for free. */
.row-link {
  color: inherit;
  text-decoration: none;
}

/* Understated until the row is hovered, so six arrows do not shout down the
   page. */
.row-arrow {
  opacity: 0.45;
  transition: transform 0.45s var(--ease-enter), opacity 0.3s var(--ease);
}

.row-item:hover .row-arrow {
  opacity: 1;
}

/* The row is the target, so the focus ring belongs on the whole row rather
   than tight around the text. */
.row-link:focus-visible {
  outline: 2px solid var(--orange);
  outline-offset: -2px;
}

.row-num {
  font-family: 'Outfit', system-ui, sans-serif;
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.14em;
  color: var(--ink-faint);
  transition: color 0.3s var(--ease);
}

.row-item:hover .row-num {
  color: var(--orange);
}

/* --------------------------------------------------------------------------
   Services
   Each practice area: title, a quiet line of what it covers, a one-line
   summary, then the same service seen from each of the two kinds of client.
   -------------------------------------------------------------------------- */
.svc-tags {
  font-size: 0.8125rem;
  line-height: 1.65;
  color: var(--ink-mute);
}

.svc-summary {
  color: var(--ink);
}

/* Small label over each client-type column. The dot is the section's orange
   moment, repeated as a quiet bullet rather than a focus point. */
.audience {
  display: flex;
  align-items: flex-start;
  gap: 0.55rem;
  font-size: 0.6875rem;
  font-weight: 600;
  line-height: 1.6;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--aqua);
}

.audience .brand-dot {
  width: 5px;
  height: 5px;
  margin: 0.5em 0 0;
  transform: none;
  flex-shrink: 0;
}

/* --------------------------------------------------------------------------
   Track record
   Editorial rows that open. The summary stays a plain row; the plus turns
   into a minus when the project is open.
   -------------------------------------------------------------------------- */
.project summary {
  cursor: pointer;
  list-style: none;
}

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

.project summary:focus-visible {
  outline: 2px solid var(--orange);
  outline-offset: -2px;
}

.project-meta {
  font-size: 0.8125rem;
  line-height: 1.6;
  color: var(--ink-mute);
}

.project-tag {
  font-size: 0.6875rem;
  font-weight: 600;
  line-height: 1.6;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--aqua);
}

.project-service {
  font-family: 'Outfit', 'Figtree', system-ui, sans-serif;
  font-size: 0.9375rem;
  font-weight: 400;
  line-height: 1.45;
  color: var(--ink);
}

.project-head {
  font-family: 'Outfit', 'Figtree', system-ui, sans-serif;
  font-size: clamp(1.25rem, 1.8vw, 1.6rem);
  font-weight: 300;
  line-height: 1.3;
  letter-spacing: -0.02em;
  color: var(--teal);
}

.project-sub {
  font-size: 0.9375rem;
  color: var(--aqua);
}

/* Workstreams as a run of items separated by hairline dots, so a list of
   eleven reads as one line of evidence rather than a bulleted column. */
.project-list {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 0;
  list-style: none;
  padding: 0;
  font-size: 0.875rem;
  line-height: 1.6;
  color: var(--ink-soft);
}

.project-list li:not(:last-child)::after {
  content: '·';
  margin: 0 0.75rem;
  color: var(--ink-faint);
}

.project-toggle {
  position: relative;
  display: inline-block;
  width: 14px;
  height: 14px;
  color: var(--ink-mute);
  transition: color 0.3s var(--ease);
}

.project-toggle::before,
.project-toggle::after {
  content: '';
  position: absolute;
  left: 0;
  top: 50%;
  width: 100%;
  height: 1.5px;
  margin-top: -0.75px;
  background: currentColor;
  transition: transform 0.35s var(--ease-enter);
}

.project-toggle::after {
  transform: rotate(90deg);
}

.project[open] .project-toggle::after {
  transform: rotate(0deg);
}

.project:hover .project-toggle,
.project[open] .project-toggle {
  color: var(--orange);
}

.project[open] .row-num {
  color: var(--orange);
}

/* Dark variant of the editorial row. */
.row-item-dark {
  border-top-color: var(--rule-on-dark);
}

.row-item-dark:last-child {
  border-bottom-color: var(--rule-on-dark);
}

.row-item-dark:hover {
  background-color: rgba(255, 255, 255, 0.035);
}

.row-item-dark .row-num {
  color: rgba(255, 255, 255, 0.38);
}

/* --------------------------------------------------------------------------
   Statistics
   Bare numerals on hairlines. No boxes, no badges.
   -------------------------------------------------------------------------- */
.stat-value {
  font-family: 'Outfit', system-ui, sans-serif;
  font-size: clamp(2.1rem, 3.4vw, 3rem);
  font-weight: 300;
  line-height: 1;
  letter-spacing: -0.03em;
  color: var(--teal);
}

.stat-label {
  font-size: 0.75rem;
  font-weight: 500;
  line-height: 1.45;
  letter-spacing: 0.02em;
  color: var(--ink-mute);
}

/* --------------------------------------------------------------------------
   Team
   A thin ruled circle holding initials. Restrained stand-in until there are
   real portraits, which this layout is designed to accept later.
   -------------------------------------------------------------------------- */
.initials {
  width: 52px;
  height: 52px;
  border-radius: 50%;
  border: 1px solid var(--rule-strong);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: 'Outfit', system-ui, sans-serif;
  font-size: 0.8125rem;
  font-weight: 500;
  letter-spacing: 0.06em;
  color: var(--ink-mute);
  transition: border-color 0.35s var(--ease), color 0.35s var(--ease);
}

.person:hover .initials {
  border-color: var(--orange);
  color: var(--orange);
}

/* Portrait panel. Same radius as .media so photos across the page read as one
   family. The teal ground matches the backdrop the portraits were shot on, so
   nothing flashes white while an image loads. */
.portrait {
  position: relative;
  overflow: hidden;
  border-radius: 14px;
  background: var(--teal);
  aspect-ratio: 4 / 5;
}

.portrait img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center bottom;
  display: block;
}

/* An orange hairline under the portrait on hover, the same gesture as the
   editorial rows. */
.portrait::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 2px;
  background: var(--orange);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 0.5s var(--ease-enter);
}

.person:hover .portrait::after {
  transform: scaleX(1);
}

.role {
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--aqua);
}

/* --------------------------------------------------------------------------
   Clients
   Gradient values are sampled from the logo sheet the client supplied: the
   logos were cut out of it, so their edges only sit cleanly on this ground.
   -------------------------------------------------------------------------- */
.band-clients {
  background: linear-gradient(100deg, #125c68 0%, #2a7688 50%, #4695ab 100%);
}

/* .accent-soft's aqua is the same colour as the right of this band, so the
   headline accent here is a pale wash of it instead. */
.accent-on-band {
  color: #c4e4ec;
  font-weight: 400;
}

.logo-wall {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-start;
  gap: 2.75rem 3.5rem;
  /* No margin reset here: Tailwind's preflight already zeroes it, and a
     reset in this later-loading file would cancel the mt-* utility. */
  list-style: none;
  padding: 0;
}

.logo-wall img {
  display: block;
  width: auto;
  max-width: 100%;
}

/* Wide wordmarks are sized by height; square badges get a taller box so each
   logo carries roughly the same visual weight. Heights stay near the source
   files' own pixel size, since they were cut from a screenshot. */
.logo-mark {
  height: 38px;
}

.logo-badge {
  height: 64px;
}

@media (max-width: 640px) {
  .logo-wall {
    gap: 2rem 2.25rem;
  }

  .logo-mark {
    height: 30px;
  }

  .logo-badge {
    height: 52px;
  }
}

/* --------------------------------------------------------------------------
   Brand pattern
   The arch cascade from the identity guide, used as texture at very low
   opacity. Twice in the whole page, never behind body copy.
   -------------------------------------------------------------------------- */
.pattern {
  position: absolute;
  /* Vertical overscan so the parallax shift in app.js can never drag a hard
     edge into view. The parent clips it with overflow-hidden. */
  inset: -40px 0;
  /* -v2 is a byte-identical copy of pattern-arch.png under a new name.
     GoDaddy's edge cache holds a broken object for the original URL: bare
     requests hang forever while the same path with a query string returns all
     66,399 bytes. A new filename is a clean URL and sidesteps it. The original
     file is left in place, unreferenced. */
  background-image: url('assets/brand/pattern-arch-v2.png');
  background-size: cover;
  background-position: center right;
  background-repeat: no-repeat;
  opacity: 0.06;
  pointer-events: none;
  /* Faded out across the left half so headlines and body copy always sit on
     clean ground and the texture lives in the empty right of the layout. */
  -webkit-mask-image: linear-gradient(to right, transparent 0%, transparent 34%, #000 78%);
  mask-image: linear-gradient(to right, transparent 0%, transparent 34%, #000 78%);
}

.pattern-light {
  background-image: url('assets/brand/pattern-arch-white.png');
  opacity: 0.05;
}

/* --------------------------------------------------------------------------
   Form
   -------------------------------------------------------------------------- */
.field-label {
  display: block;
  font-size: 0.6875rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.16em;
  color: rgba(255, 255, 255, 0.6);
  margin-bottom: 0.6rem;
}

/* Underline inputs rather than boxes: fewer edges, same affordance. */
.input {
  width: 100%;
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--rule-on-dark);
  border-radius: 0;
  padding: 0.55rem 0 0.7rem;
  color: #fff;
  font-size: 0.9375rem;
  font-family: inherit;
  transition: border-color 0.3s var(--ease);
}

.input::placeholder {
  color: rgba(255, 255, 255, 0.36);
}

.input:focus {
  outline: none;
  border-bottom-color: var(--orange);
}

.input:-webkit-autofill,
.input:-webkit-autofill:focus {
  -webkit-text-fill-color: #fff;
  /* Kills Chrome's yellow autofill wash without hiding the text. */
  transition: background-color 9999s ease-out;
}

textarea.input {
  resize: none;
}

/* --------------------------------------------------------------------------
   Footer
   -------------------------------------------------------------------------- */
.footer-link {
  font-size: 0.875rem;
  color: rgba(255, 255, 255, 0.62);
  transition: color 0.25s var(--ease);
}

.footer-link:hover {
  color: var(--orange);
}

/* --------------------------------------------------------------------------
   Reveal on scroll
   Deliberately smaller and faster than before: 14px and 0.7s. A big slow slide
   draws attention to the animation; a small quick one just feels smooth.
   -------------------------------------------------------------------------- */
.reveal {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 0.7s var(--ease-enter), transform 0.7s var(--ease-enter);
  /* app.js sets --rd on grouped children to stagger them. Total stagger per
     group is capped at 300ms so nothing ever feels like it is queueing. */
  transition-delay: var(--rd, 0ms);
}

.reveal.visible {
  opacity: 1;
  transform: none;
}

/* --------------------------------------------------------------------------
   Masked line reveal
   The editorial signature: each headline line rises from behind its own
   overflow-hidden box. Uses transform only, so it composites cleanly.

   The padding/negative-margin pair widens the mask below the baseline so
   descenders (g, y, p) are not clipped, without adding real layout space.
   -------------------------------------------------------------------------- */
.line {
  display: block;
  overflow: hidden;
  padding-bottom: 0.14em;
  margin-bottom: -0.14em;
}

.line-inner {
  display: block;
  transform: translateY(108%);
  transition: transform 0.9s var(--ease-enter);
  transition-delay: var(--rd, 0ms);
}

.line-reveal.visible .line-inner {
  transform: none;
}

/* --------------------------------------------------------------------------
   Hairline that draws itself in
   Used once, on the rule above the hero statistics.
   -------------------------------------------------------------------------- */
.rule-draw {
  height: 1px;
  background: var(--rule);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 1s var(--ease-enter);
  transition-delay: var(--rd, 0ms);
}

.rule-draw.visible {
  transform: scaleX(1);
}

/* --------------------------------------------------------------------------
   Press feedback
   Kept at 0.985 and 130ms: perceptible as acknowledgement, too quick to read
   as an animation. Applied on :active so touch gets it too.
   -------------------------------------------------------------------------- */
.btn-solid,
.btn-accent,
.btn-line {
  transition: background 0.3s var(--ease), color 0.3s var(--ease),
    border-color 0.3s var(--ease), transform 0.13s var(--ease-enter);
}

.btn-solid:active,
.btn-accent:active,
.btn-line:active {
  transform: scale(0.985);
}

/* Failsafe: most of the page is .reveal, so if JavaScript is disabled or
   app.js fails to load the site would render almost blank. index.html adds a
   `js` class to <html> inline and removes it if app.js errors, so this
   override shows all content when scripting is unavailable. Specificity is
   deliberately higher than .reveal.visible so it wins in that case only. */
html:not(.js) .reveal,
html:not(.js) .reveal.visible,
html:not(.js) .line-inner,
html:not(.js) .rule-draw {
  opacity: 1;
  transform: none;
  transition: none;
}

/* Honour an OS-level "reduce motion" preference. Every entrance becomes an
   instant final state; hover feedback stays, since colour change is not
   motion. */
@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  .reveal,
  .reveal.visible,
  .line-inner,
  .rule-draw,
  .rule-draw.visible {
    opacity: 1;
    transform: none;
    transition: none;
  }

  .link-arrow .arrow,
  .row-item,
  .row-item::before,
  .row-title,
  .row-arrow,
  .btn-solid,
  .btn-accent,
  .btn-line {
    transition: none;
  }

  .btn-solid:active,
  .btn-accent:active,
  .btn-line:active {
    transform: none;
  }
}

/* --------------------------------------------------------------------------
   Mobile menu
   -------------------------------------------------------------------------- */
.mobile-menu {
  transition: transform 0.45s var(--ease);
}

.mobile-link {
  font-family: 'Outfit', 'Figtree', system-ui, sans-serif;
  font-size: 1.75rem;
  font-weight: 300;
  letter-spacing: -0.025em;
  color: var(--teal);
  border-bottom: 1px solid var(--rule);
  padding-bottom: 1rem;
  width: 100%;
  transition: color 0.25s var(--ease);
}

.mobile-link:hover {
  color: var(--orange);
}

/* --------------------------------------------------------------------------
   Focus visibility
   Keyboard users must be able to see where they are. Applied only to
   :focus-visible so mouse clicks stay clean.
   -------------------------------------------------------------------------- */
a:focus-visible,
button:focus-visible,
input:focus-visible,
textarea:focus-visible {
  outline: 2px solid var(--orange);
  outline-offset: 3px;
}
