/* DigLTBlue base: reset essentials, typography defaults, focus, and every
   shared primitive the template tags emit (lt-heading, lt-rule, lt-kicker,
   lt-prose, lt-btn, lt-icon).

   Class prefix note: primitives keep the `lt-` prefix — it stands for Lewis &
   Tibbitts, not for the theme, and inc/template-tags.php emits these names
   literally. V2-only section components use the same prefix for consistency.

   Mobile-first: base rules are the <640px state, media queries are min-width. */

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

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--color-canvas);
  font-family: var(--font-body);
  font-weight: 400;
  font-size: var(--fs-body);
  line-height: var(--lh-tight);
  color: var(--color-navy);
  -webkit-font-smoothing: antialiased;
}

/* The whole page sits on a white frame over the canvas tone, exactly as the
   1440 artboard does. */
.lt-main { display: block; background: var(--color-white); }

img,
svg,
video { max-width: 100%; }

img { height: auto; }

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

button { cursor: pointer; }

address { font-style: normal; }

/* Links — orange on light, per the mock's `a{color:#F45900}` / hover navy. */
a { color: var(--color-orange); text-decoration: none; }
a:hover { color: var(--color-navy); }

/* Dark bands invert the pair. */
.lt-section--navy a:not(.lt-btn) { color: var(--color-white); }
.lt-section--navy a:not(.lt-btn):hover { color: var(--color-orange); }

/* Focus — never remove an outline without replacing it. */
:focus-visible {
  outline: var(--focus-ring-width) solid var(--focus-ring-color);
  outline-offset: var(--focus-offset);
}

.lt-section--navy :focus-visible,
.lt-hero :focus-visible { outline-color: var(--color-white); }

/* Skip link + screen-reader text */
.lt-skip-link {
  position: absolute;
  top: 0;
  left: -9999px;
  z-index: 100;
  padding: 12px 20px;
  background: var(--color-orange);
  color: var(--color-white);
  font-weight: var(--weight-label);
  font-size: var(--fs-nav);
  letter-spacing: var(--ls-button);
  text-transform: uppercase;
}

.lt-skip-link:focus { left: 0; }

.screen-reader-text {
  position: absolute !important;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  overflow: hidden;
  clip: rect(1px, 1px, 1px, 1px);
  clip-path: inset(50%);
  white-space: nowrap;
  word-wrap: normal;
}

.screen-reader-text:focus {
  position: static !important;
  width: auto;
  height: auto;
  margin: 0;
  clip: auto;
  clip-path: none;
}

/* ── Section shells ───────────────────────────────────────────────── */
.lt-section { padding: var(--pad-y) var(--pad-x); }

.lt-section--white { background: var(--color-white); }
.lt-section--wash { background: var(--color-surface-alt); }
.lt-section--navy { background: var(--color-navy); color: var(--color-on-navy); }
.lt-section--flush { padding: 0; }

.lt-section__inner { max-width: var(--content-max); margin-inline: auto; }

/* The V2 stack: every section is a single flex column. Gap is the section's
   own rhythm, so parts never need margins between children. */
.lt-stack { display: flex; flex-direction: column; gap: 48px; }
.lt-stack--tight { gap: 32px; }
.lt-stack--loose { gap: 48px; }

/* Heading + accent rule pair. The rule spans the block it belongs to — that
   full-width 2px orange line under each heading is the design's signature. */
.lt-head {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

/* ── Headings ─────────────────────────────────────────────────────── */
.lt-heading {
  margin: 0;
  font-family: var(--font-display);
  font-weight: var(--weight-display);
  line-height: 1.15;
  letter-spacing: var(--ls-display);
  text-transform: uppercase;
  color: inherit;
  text-wrap: balance;
}

.lt-heading--hero { font-size: var(--fs-hero); line-height: var(--lh-hero); }
.lt-heading--xl   { font-size: var(--fs-display); }
.lt-heading--lg   { font-size: var(--fs-display-sm); }
.lt-heading--md   { font-size: var(--fs-title); }
.lt-heading--sm   { font-size: var(--fs-title-sm); }
.lt-heading--xs   { font-size: var(--fs-title-xs); }

/* ── Kicker ───────────────────────────────────────────────────────── */
/* Montserrat, not Oswald — every eyebrow in the mock inherits the body face.
   Size, tracking and colour belong to the component class beside it. */
.lt-kicker {
  margin: 0;
  font-weight: var(--weight-label);
  text-transform: uppercase;
}

/* ── Accent rule ──────────────────────────────────────────────────── */
.lt-rule {
  display: block;
  flex: none;
  width: 100%;
  height: var(--rule-h);
  background: var(--color-orange);
}

.lt-rule--center { width: var(--rule-w-centered); max-width: 100%; margin-inline: auto; }
.lt-rule--footer { width: var(--rule-w-footer); }

/* ── Prose ────────────────────────────────────────────────────────── */
.lt-prose { color: var(--color-navy); max-width: var(--prose-max); }

.lt-prose > * + * { margin-top: 18px; }

.lt-prose p,
.lt-prose ul,
.lt-prose ol {
  margin: 0;
  font-size: var(--fs-body);
  line-height: var(--lh-prose);
  color: inherit;
  text-wrap: pretty;
}

.lt-prose ul,
.lt-prose ol { padding-left: 1.25em; }

.lt-prose li + li { margin-top: 8px; }

.lt-prose strong { font-weight: 600; }

.lt-prose a { color: var(--color-orange); text-decoration: underline; text-underline-offset: 3px; }
.lt-prose a:hover { color: var(--color-navy); }

.lt-prose--sm p,
.lt-prose--sm ul,
.lt-prose--sm ol { font-size: var(--fs-body-sm); }

.lt-prose--wide { max-width: var(--prose-max-wide); }
.lt-prose--full { max-width: none; }

.lt-prose--dark { color: var(--color-on-navy-body); }
.lt-prose--dark strong { color: var(--color-white); }
.lt-prose--dark a { color: var(--color-orange); }
.lt-prose--dark a:hover { color: var(--color-white); }

/* ── Buttons ──────────────────────────────────────────────────────── */
/* Square, Montserrat 600, 13px, .1em tracking. No radius anywhere in V2. */
.lt-btn {
  display: inline-block;
  border: 0;
  border-radius: 0;
  font-family: var(--font-body);
  font-weight: var(--weight-label);
  font-size: var(--fs-nav);
  line-height: 1.2;
  letter-spacing: var(--ls-button);
  text-transform: uppercase;
  text-decoration: none;
  text-align: center;
  cursor: pointer;
  transition: background-color var(--t-fast) var(--ease),
              border-color var(--t-fast) var(--ease),
              color var(--t-fast) var(--ease);
}

.lt-btn--solid,
.lt-btn--cta {
  padding: var(--btn-pad);
  background: var(--color-orange);
  color: var(--color-white);
}

.lt-btn--solid:hover,
.lt-btn--cta:hover { background: var(--color-navy); color: var(--color-white); }

.lt-btn--outline {
  padding: var(--btn-pad-outline);
  background: transparent;
  border: var(--btn-border-w) solid var(--color-navy);
  color: var(--color-navy);
}

.lt-btn--outline:hover { background: var(--color-navy); color: var(--color-white); }

/* Over navy the outline flips to white and fills to orange on hover. */
.lt-section--navy .lt-btn--outline,
.lt-hero .lt-btn--outline,
.lt-careers .lt-btn--outline,
.lt-drawer .lt-btn--outline {
  border-color: var(--color-white);
  color: var(--color-white);
}

.lt-section--navy .lt-btn--outline:hover,
.lt-hero .lt-btn--outline:hover,
.lt-careers .lt-btn--outline:hover,
.lt-drawer .lt-btn--outline:hover {
  background: var(--color-orange);
  border-color: var(--color-orange);
  color: var(--color-white);
}

.lt-btn--block { display: block; width: 100%; }

/* ── Icons ────────────────────────────────────────────────────────── */
.lt-icon {
  display: inline-block;
  flex: none;
  width: 1em;
  height: 1em;
  fill: currentColor;
  vertical-align: middle;
}

/* ── Image slots ──────────────────────────────────────────────────── */
/* Every photo in the mock is a grey plate with a centred micro-label. When a
   real image is present it fills the plate; when it is not, the label is what
   the client sees — and what tells them a photo is still owed. */
.lt-slot {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--color-placeholder);
  overflow: hidden;
}

.lt-slot__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.lt-slot__label {
  font-size: var(--fs-micro);
  font-weight: var(--weight-label);
  letter-spacing: var(--ls-caption);
  text-transform: uppercase;
  color: var(--color-navy);
  text-align: center;
  padding: 0 12px;
}

/* A note the client is meant to read: "PENDING FINAL VERIFICATION" etc. */
.lt-pending {
  font-size: var(--fs-nano);
  font-weight: var(--weight-label);
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--color-muted);
}

.lt-section--navy .lt-pending,
.lt-careers .lt-pending { color: var(--color-on-navy-muted); }

/* ── Mobile-only / desktop-only ───────────────────────────────────── */
.lt-only-desktop { display: none; }

@media (min-width: 640px) {
  .lt-only-desktop { display: initial; }
  .lt-only-mobile { display: none; }

  .lt-btn--block { display: inline-block; width: auto; }
}

/* ── Section reveal ───────────────────────────────────────────────── */
/*
 * Every section in <main> after the first fades and rises as it scrolls into
 * view. The first is excluded deliberately: on the homepage that is the hero,
 * already on screen at first paint, and animating it would only hold up the
 * LCP; on interior pages it is the title band, for the same reason.
 *
 * FAIL-SAFE BY CONSTRUCTION. The rule is behind two gates, and the content is
 * fully visible unless BOTH pass:
 *
 *   @supports (animation-timeline: view())
 *     A browser without scroll-driven animations never applies the rule, so it
 *     never sees the 0-opacity keyframe — it simply gets the page. There is no
 *     JS fallback and none is wanted: the fallback IS the content.
 *
 *   prefers-reduced-motion: no-preference
 *     Opt-in rather than opt-out, so a visitor asking for less motion is never
 *     relying on an animation to reveal the page.
 *
 * This is the same failure mode the header's entrance keyframe had — a fixed
 * bar parked off-screen for as long as animations did not run. On chrome that
 * was a missing bar; on body copy it would be an invisible page, so here the
 * animation only ever exists where it is known to run.
 *
 * RANGE. Expressed in `cover`, not `entry`. The `entry` phase ends only once an
 * element has fully entered the scrollport, which never happens for a section
 * taller than the viewport — .lt-capabilities is ~2200px — and an end keyframe
 * that is never reached would strand that section permanently faded out. A
 * `cover` percentage is reachable at any element height.
 *
 * The end was 20%, and the reveal was going unnoticed: `cover` spans element
 * height + viewport height, so for a 400px section in a 900px viewport 20% is
 * only ~260px of scrolling after the section first appears. The fade finished
 * while the section was still in the bottom sliver of the screen — over before
 * it reached the reader's eye. 35% lands the finish nearer mid-viewport for a
 * typical section, which is where it actually gets seen.
 *
 * TRADE-OFF, deliberately accepted: the previous note claimed a section on
 * screen at load has the range already behind it and so paints solid. That was
 * not true even at 20% — .lt-credentials sits ~12% into its cover range at
 * first paint on a 900px viewport — and a later end makes it more translucent
 * at load before resolving on the first scroll. That is the cost of a reveal
 * that can actually be seen; pull the end back toward 20% to trade it away.
 */
@media (prefers-reduced-motion: no-preference) {
  @supports (animation-timeline: view()) {
    .lt-main > * + * {
      animation-name: lt-reveal;
      /* `auto` hands timing to the range below; the shorthand would reset it to 0s. */
      animation-duration: auto;
      animation-timing-function: linear;
      animation-fill-mode: both;
      animation-timeline: view();
      animation-range: cover 0% cover 35%;
    }

    /*
     * DESKTOP: the sections stop moving and the IMAGES carry the motion.
     *
     * Each image slides in from the edge it already sits against — the one on
     * the right of the intro comes in from the right, the capability photos on
     * the left come in from the left — so the movement reads as the layout
     * assembling itself rather than as decoration bolted on. The one full-bleed
     * band has no side to come from, so it rises instead, with a harder bounce
     * to make up for having no direction to express — and it rises whole,
     * scrim and copy included, for the reason given on that rule below.
     *
     * 1024px matches the breakpoint the rest of the theme already treats as
     * desktop. It is also the width below which this whole idea stops meaning
     * anything: the columns stack, every image becomes full-width, and "left"
     * and "right" no longer describe where anything is. Below it the original
     * section reveal stands untouched.
     *
     * WHY THE SECTION REVEAL GOES OPACITY-ONLY HERE. Left as-is it would drag
     * each section 48px up the Y axis while the images inside travel on their
     * own timelines — two motions on the same pixels, and on .lt-careers two
     * motions on the same axis, which flattens the very bounce this is meant to
     * emphasise. The sections still fade; they just no longer move. Restore
     * `transform: translateY(48px)` to lt-reveal-fade's `from` to get the old
     * behaviour back underneath the image motion.
     *
     * THE BOUNCE IS SCRUBBED, NOT PLAYED. This is a scroll-driven timeline, so
     * `cubic-bezier` maps scroll progress -> transform rather than time ->
     * transform. The overshoot is real (the curve's y passes 1 near the end, so
     * the image crosses its resting spot and swings past it before settling),
     * but it is driven by the reader's scroll: stop mid-range and it holds
     * mid-bounce; scroll back and it plays in reverse. That is the trade for
     * keeping this CSS-only. A bounce that always plays once at its own speed
     * needs an IntersectionObserver and a time-based animation, which would put
     * the page's visibility behind JS — what the comment above refuses.
     *
     * OVERFLOW. The Y reveal could never widen the page; these can. Both the
     * travel and the overshoot push images past their resting position, and on
     * a slot that already sits flush to the viewport edge that lands outside it
     * and would raise a horizontal scrollbar. `clip` rather than `hidden` on
     * purpose: `hidden` would make .lt-main a scroll container and break any
     * `position: sticky` descendant, while `clip` cuts the paint without that
     * side effect and is allowed to pair with a visible Y axis.
     */
    @media (min-width: 1024px) {
      .lt-main {
        overflow-x: clip;
      }

      .lt-main > * + * {
        animation-name: lt-reveal-fade;
      }

      /*
       * WHAT ANIMATES: whichever element owns the whole picture.
       *
       * Where the slot sits in normal flow beside its text (.lt-intro__media,
       * .lt-capabilities__media) the slot itself is the picture, so it moves.
       *
       * Where the slot is `position: absolute; inset: 0` behind an overlay
       * inside a box that clips — the environments tiles, and .lt-careers
       * below — it is NOT the whole picture: its caption or scrim is a
       * sibling that would stay put while the photograph slid around beneath
       * it, inside a frame that never moved. There the TILE or BAND animates
       * and takes its overlay with it.
       */
      .lt-intro__media,
      .lt-capabilities__media,
      .lt-environments__tile {
        animation-duration: auto;
        animation-fill-mode: both;
        animation-timeline: view();
        /* Later and longer than the section fade underneath it: the image is
           the thing being noticed, so it should still be arriving once its
           section has settled. */
        animation-range: cover 5% cover 45%;
        animation-timing-function: cubic-bezier(.34, 1.56, .64, 1);
      }

      /* Sits right of its text — enters from the right. */
      .lt-intro__media,
      .lt-environments__tile:not(.lt-environments__tile--lead) {
        animation-name: lt-reveal-from-right;
      }

      /* Sits left of its text — enters from the left. */
      .lt-capabilities__media,
      .lt-environments__tile--lead {
        animation-name: lt-reveal-from-left;
      }

      /*
       * The full-bleed band rises as ONE piece — photo, scrim and copy
       * together — so it is the SECTION that animates here, not the image
       * inside it.
       *
       * Animating .lt-careers__media instead does not work, and the reason is
       * structural rather than a matter of taste: that slot is
       * `position: absolute; inset: 0` behind a `.lt-careers__scrim` and the
       * copy, inside a band that clips. Translating it slides the photograph
       * around underneath a stationary blue overlay and stationary text —
       * the image visibly moving behind a window that does not move with it.
       *
       * Specificity: `.lt-main > .lt-careers` (0,2,0) has to out-rank the
       * `.lt-main > * + *` fade (0,1,0) above, which would otherwise win on
       * source order and flatten this back to an opacity change.
       */
      .lt-main > .lt-careers {
        animation-name: lt-reveal-up;
        animation-timing-function: cubic-bezier(.22, 1.9, .48, 1);
        animation-range: cover 5% cover 45%;
      }
    }
  }
}

@keyframes lt-reveal {
  from {
    opacity: 0;
    /* Was 24px. Opacity already spans the full 0->1, so travel is the only
       lever left for making the reveal read more strongly. */
    transform: translateY(48px);
  }

  to {
    opacity: 1;
    transform: none;
  }
}

/*
 * Desktop image reveals. 64px of sideways travel against the section reveal's
 * 48px of vertical: horizontal movement reads more weakly than vertical,
 * because there is no reading-flow cue to measure it against, so it needs the
 * extra distance to register at all.
 *
 * The sign is the whole point — each image enters from the side it already
 * lives on, so nothing crosses the text it belongs to on its way in.
 */
@keyframes lt-reveal-from-left {
  from {
    opacity: 0;
    transform: translateX(-64px);
  }

  to {
    opacity: 1;
    transform: none;
  }
}

@keyframes lt-reveal-from-right {
  from {
    opacity: 0;
    transform: translateX(64px);
  }

  to {
    opacity: 1;
    transform: none;
  }
}

/*
 * Full-bleed images rise. 96px, the longest travel here, because a band that
 * spans the viewport needs more distance before the movement is legible at
 * all — and because the harder easing paired with it wants the room to swing.
 */
@keyframes lt-reveal-up {
  from {
    opacity: 0;
    transform: translateY(96px);
  }

  to {
    opacity: 1;
    transform: none;
  }
}

/*
 * Desktop section reveal: fade with no movement, so the sections stay still
 * under the images travelling across them. See the note in the rule above.
 */
@keyframes lt-reveal-fade {
  from { opacity: 0; }
  to   { opacity: 1; }
}

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