/* ============================================================
   2iResourcing Motion — child theme additions
   ------------------------------------------------------------
   Every hiding rule is gated behind .twoim-on, a class the script
   adds at runtime. No JS, no hiding: the page renders exactly as
   the parent theme intends. Reduced-motion disables the lot.
   ============================================================ */

.twoim {
  --twoim-ease: cubic-bezier(.22,.61,.36,1);
  --twoim-dur: .85s;
}

/* ---- 1. Headline reveal, word by word -------------------- */
.twoim-line { display: block; overflow: hidden; padding-bottom: .08em; }
.twoim-word { display: inline-block; will-change: transform; }

.twoim-on .twoim-split .twoim-word { transform: translateY(110%); }
.twoim-on .twoim-split.twoim-in .twoim-word {
  transform: none;
  transition: transform var(--twoim-dur) var(--twoim-ease);
}

/* ---- 2. Section rise, with per-item stagger --------------- */
.twoim-on [data-twoim-rise] {
  opacity: 0;
  transform: translateY(26px);
}
.twoim-on [data-twoim-rise].twoim-in {
  opacity: 1;
  transform: none;
  transition:
    opacity var(--twoim-dur) var(--twoim-ease),
    transform var(--twoim-dur) var(--twoim-ease);
  transition-delay: var(--twoim-delay, 0ms);
}

/* ---- 3. Hero image: slow scale-down as it settles --------- */
.twoim-on .home-hero .hero-art img,
.twoim-on .page-hero-photo img {
  transform: scale(1.06);
  transition: transform 1.4s var(--twoim-ease);
}
.twoim-on .home-hero.twoim-in .hero-art img,
.twoim-on .page-hero-photo.twoim-in img {
  transform: scale(1);
}

/* ---- 4. Partner logo marquee ----------------------------- */
/* Parent rc4 removed the loop deliberately; this restores it as
   an opt-out, and it only engages once the script duplicates the
   row, so a static fallback is always what renders first.        */
.twoim-marquee { overflow: hidden; position: relative; }
.twoim-marquee .twoim-track {
  display: flex;
  width: max-content;
  animation: twoim-drift 46s linear infinite;
}
.twoim-marquee:hover .twoim-track,
.twoim-marquee:focus-within .twoim-track { animation-play-state: paused; }
.twoim-marquee .twoim-set { display: flex; flex-shrink: 0; align-items: center; }
@keyframes twoim-drift {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}
/* soften the cut at both edges */
.twoim-marquee::before,
.twoim-marquee::after {
  content: ""; position: absolute; top: 0; bottom: 0; width: 72px; z-index: 2;
  pointer-events: none;
}
.twoim-marquee::before { left: 0;  background: linear-gradient(90deg, #fff, transparent); }
.twoim-marquee::after  { right: 0; background: linear-gradient(270deg, #fff, transparent); }

/* ---- 5. Counters hold their width while counting ---------- */
.twoim-count { font-variant-numeric: tabular-nums; }

/* ---- 6. Link and button feedback ------------------------- */
.twoim .button,
.twoim .text-link { transition: transform .22s var(--twoim-ease), background-color .22s ease, color .22s ease; }
.twoim .button:hover { transform: translateY(-2px); }
.twoim .button:active { transform: translateY(0); }

/* ---- 7. Lenis ------------------------------------------- */
html.lenis, html.lenis body { height: auto; }
.lenis.lenis-smooth { scroll-behavior: auto !important; }
.lenis.lenis-stopped { overflow: hidden; }

/* ---- 8. Row wipe ------------------------------------------
   Rows uncover from the left along the rule that already divides
   them, so the motion reads as structural rather than decorative.

   NOTE: clip-path counts towards intersection geometry, so these
   elements are invisible to an IntersectionObserver while clipped.
   The script therefore observes their container, never them. Do not
   "simplify" that back to observing the rows — it deadlocks.        */
.twoim-on [data-twoim-wipe] {
  clip-path: inset(0 100% 0 0);
  opacity: 0;
}
.twoim-on [data-twoim-wipe].twoim-in {
  clip-path: inset(0 0 0 0);
  opacity: 1;
  transition:
    clip-path 1.05s var(--twoim-ease),
    opacity .5s ease;
  transition-delay: var(--twoim-delay, 0ms);
}

/* ---- 9. Scroll progress hairline --------------------------
   The reading position, taken from the intern's reel rail. */
.twoim-progress {
  position: fixed;
  inset: 0 0 auto 0;
  height: 2px;
  z-index: 9999;
  background: linear-gradient(90deg, #034a91, #e87a1a);
  transform: scaleX(0);
  transform-origin: 0 50%;
  pointer-events: none;
  will-change: transform;
}
.admin-bar .twoim-progress { top: 32px; }
@media (max-width: 782px) { .admin-bar .twoim-progress { top: 46px; } }

/* ---- 10. Expertise deck recede ----------------------------
   The parent already stacks these with sticky tops. This is the
   part that was missing: a card that has been covered sinks back
   and takes on a paper veil, so the stack reads as depth rather
   than as three cards that happen to overlap.
   --twoim-recede is written by the script, 0 → 1.              */
@media (min-width: 992px) {
  .twoim .expertise-stack .expertise-panel {
    transform-origin: 50% 0;
    transform: scale(calc(1 - (var(--twoim-recede, 0) * 0.055)))
               translateY(calc(var(--twoim-recede, 0) * -10px));
    transition: box-shadow .4s ease;
  }
  .twoim .expertise-stack .expertise-panel::after {
    content: "";
    position: absolute;
    inset: 0;
    background: #082e55;
    opacity: calc(var(--twoim-recede, 0) * 0.22);
    pointer-events: none;
    border-radius: inherit;
    z-index: 3;
  }
}

/* ---- 11. Photo drift and push-in --------------------------
   A slow parallax with a scroll-linked scale, so photographs feel
   set into the page instead of pasted onto it. Both custom
   properties default to a no-op, so an unscripted page is normal. */
.twoim .twoim-drift {
  transform: translate3d(0, var(--twoim-shift, 0px), 0) scale(var(--twoim-push, 1));
  will-change: transform;
}
.expertise-photo,
.service-photo,
.article-card__image { overflow: hidden; }

/* ---- 12. Row hover ----------------------------------------- */
.twoim [data-twoim-wipe] { position: relative; }
.twoim .service-row,
.twoim .scope-row { transition: background-color .3s ease; }
.twoim .service-row:hover,
.twoim .scope-row:hover { background-color: #f5f7f9; }
.twoim .service-row:hover .wp-block-button__link,
.twoim .scope-row:hover .wp-block-button__link { transform: translateX(4px); }

/* ---- 12a. Links inside running text ------------------------
   WCAG 1.4.1: a link set apart from its surrounding text only by
   colour is invisible to anyone who cannot distinguish the two.
   Lighthouse flagged the "2iSolutions" link in the footer. Buttons
   and the arrow links are excluded — those are already obvious
   from their shape. */
.site-footer .footer-intro a,
.lp-footer-inner a,
.page-content p a:not(.wp-element-button):not(.button):not(.text-link) {
  text-decoration: underline;
  text-underline-offset: 0.18em;
  text-decoration-thickness: from-font;
}

/* ---- 12b. Statistics band ----------------------------------
   Big figures with a label underneath. Each number carries the
   .counter class, so the odometer in motion.js rolls it up as it
   comes into view; without the script the final figure is simply
   already on screen. */
.twoim-stats {
  display: grid;
  /* auto-fit rather than a fixed count, so adding or removing a figure
     later rebalances the row instead of leaving an orphan on its own */
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  /* Row gap set separately: with subgrid the tiles span two row tracks, so a
     single gap value would also push every label away from its figure. */
  gap: 10px clamp(24px, 4vw, 56px);
  margin-top: 44px;
  padding-block: 36px;
  border-top: 1px solid var(--line, #d6dee6);
  border-bottom: 1px solid var(--line, #d6dee6);
}
.twoim-stat > * { margin: 0; }
.twoim-stat .counter {
  display: block;
  font-size: clamp(34px, 4vw, 54px);
  line-height: 1.05;
  letter-spacing: -0.035em;
  font-weight: 500;
  color: var(--blue, #034a91);
  font-variant-numeric: tabular-nums;
}
/* Aligning the figures and their labels.

   A clean integer gets the odometer, which is an inline-flex strip of digit
   cells. Anything with a decimal (99.32%) falls back to the plain count-up,
   which is ordinary text. Those two sit differently, so one tile's label
   ended up out of line with the rest.

   Twice I tried to fix that by forcing matching heights, and twice it caused
   something worse — the digit cell height is what the reel's travel distance
   is measured against, so resizing it left every reel stopping short.

   Subgrid solves it without touching either: all four figures share one row
   track and all four labels share another, so they line up no matter how the
   number happens to be rendered. */
.twoim-stat {
  display: grid;
  grid-template-rows: auto auto;
  align-content: end;
}
@supports (grid-template-rows: subgrid) {
  .twoim-stats { grid-template-rows: auto auto; }
  .twoim-stat {
    grid-row: span 2;
    grid-template-rows: subgrid;
  }
}
.twoim-stat .counter { align-self: end; line-height: 1; }
.twoim-odo-sep { display: inline-block; }

.twoim-stat .twoim-stat-label {
  margin-top: 0;            /* the row gap above handles the spacing now */
  font-size: 14px;
  font-weight: 500;
  line-height: 1.45;
  /* ink rather than muted grey: at this size the label is doing real work,
     and muted made it read as a caption the eye skips */
  color: var(--ink, #172636);
  max-width: 22ch;
}
@media (max-width: 900px) {
  .twoim-stats { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 460px) {
  .twoim-stats { grid-template-columns: 1fr; gap: 28px; }
}

/* ---- 13. Dropdown menus -----------------------------------
   The parent toggles .sub-menu between display:none and block, and display
   cannot be transitioned — so the panel appears instantly. These rules animate
   the panel and stagger its items instead.

   Scoped above 900px, where the parent switches to the stacked mobile menu and
   the sub-menu becomes static. Gated on .twoim, the class the script adds, so
   an unscripted page keeps the plain instant dropdown. */
@media (min-width: 901px) {
  .twoim .menu-item:hover > .sub-menu,
  .twoim .menu-item:focus-within > .sub-menu {
    animation: twoim-drop .26s var(--twoim-ease) both;
  }
  @keyframes twoim-drop {
    from { opacity: 0; transform: translateY(-8px); }
    to   { opacity: 1; transform: none; }
  }

  /* Items arrive just behind the panel, one after another.

     The delay is carried on a custom property rather than set with
     transition-delay directly. The reveal rule below uses the transition
     shorthand, which resets delay to 0s, and it outranks any nth-child rule —
     so a plain `transition-delay: 40ms` here is silently thrown away and every
     item moves together. Custom properties inherit instead of competing. */
  .twoim .sub-menu li {
    --twoim-sub-delay: 0ms;
    opacity: 0;
    transform: translateY(-5px);
  }
  .twoim .sub-menu li:nth-child(1) { --twoim-sub-delay: 40ms; }
  .twoim .sub-menu li:nth-child(2) { --twoim-sub-delay: 80ms; }
  .twoim .sub-menu li:nth-child(3) { --twoim-sub-delay: 120ms; }
  .twoim .sub-menu li:nth-child(4) { --twoim-sub-delay: 160ms; }
  .twoim .sub-menu li:nth-child(5) { --twoim-sub-delay: 200ms; }
  .twoim .sub-menu li:nth-child(6) { --twoim-sub-delay: 240ms; }
  .twoim .sub-menu li:nth-child(n+7) { --twoim-sub-delay: 280ms; }

  .twoim .menu-item:hover > .sub-menu li,
  .twoim .menu-item:focus-within > .sub-menu li {
    opacity: 1;
    transform: none;
    transition:
      opacity .3s var(--twoim-ease) var(--twoim-sub-delay),
      transform .3s var(--twoim-ease) var(--twoim-sub-delay);
  }

  /* a rule draws in from the left as the pointer lands */
  .twoim .sub-menu a {
    padding-left: 14px;
    transition: color .2s ease, padding-left .25s var(--twoim-ease);
  }
  .twoim .sub-menu a::before {
    content: "";
    position: absolute;
    left: 0;
    top: 50%;
    width: 8px;
    height: 1px;
    background: #e87a1a;
    transform: scaleX(0);
    transform-origin: 0 50%;
    transition: transform .25s var(--twoim-ease);
  }
  .twoim .sub-menu a:hover,
  .twoim .sub-menu a:focus-visible {
    color: #034a91;
    padding-left: 22px;
  }
  .twoim .sub-menu a:hover::before,
  .twoim .sub-menu a:focus-visible::before { transform: scaleX(1); }
}

/* ---- reduced motion wins over all of the above ----------- */
@media (prefers-reduced-motion: reduce) {
  .twoim *,
  .twoim *::before,
  .twoim *::after {
    animation: none !important;
    transition: none !important;
    opacity: 1 !important;
    transform: none !important;
    clip-path: none !important;
  }
  .twoim-progress { display: none !important; }
  .twoim .expertise-stack .expertise-panel::after { opacity: 0 !important; }
}

/* ============================================================
   v1.1 — hero treatment
   ============================================================ */

/* ---- Pixel reveal -----------------------------------------
   A grid of tiles sits over the image and staggers away.
   The wrapper and tiles are built by JS, so with no script the
   image simply shows, unobstructed.                            */
.twoim-pixel { position: relative; overflow: hidden; }
.twoim-pixel-grid {
  position: absolute; inset: 0; z-index: 2;
  display: grid; pointer-events: none;
}
.twoim-pixel-tile {
  background: var(--twoim-pixel-bg, #082E55);
  opacity: 1;
  transition: opacity .5s ease;
}
.twoim-pixel.twoim-in .twoim-pixel-tile { opacity: 0; }

/* ---- Hero: full-bleed image with a readable overlay -------- */
.twoim .home-hero { position: relative; isolation: isolate; }
.twoim .home-hero .hero-art { position: relative; }
.twoim .home-hero .hero-art img {
  width: 100%;
  border-radius: 10px;
}

/* slow drift while the hero is on screen */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .twoim .home-hero .hero-art img {
      animation: twoim-hero-drift linear both;
      animation-timeline: view();
      animation-range: entry 0% exit 100%;
    }
  }
}
@keyframes twoim-hero-drift {
  from { transform: scale(1.07) translateY(-1.5%); }
  to   { transform: scale(1)    translateY(1.5%); }
}

/* ---- Odometer digits -------------------------------------- */
.twoim-odo { display: inline-flex; align-items: baseline; }
.twoim-odo-digit {
  display: inline-block; overflow: hidden;
  height: 1em; line-height: 1em;
}
.twoim-odo-reel {
  display: block;
  transition: transform 1.1s cubic-bezier(.22,.61,.36,1);
  transition-delay: var(--twoim-odo-delay, 0ms);
}
.twoim-odo-reel span { display: block; height: 1em; line-height: 1em; }

/* ============================================================
   Blog archive — /blog/ and category pages
   ------------------------------------------------------------
   Three defects and one absence, found 31 Oct 2026:

   1. 182px of dead space between the hero lead and the first
      content (70px hero padding-bottom + 112px section
      padding-top). The page opened on a void.
   2. The search input computed to 32px wide — flex shrink with
      min-width:0 collapsed it to its content box. It read as
      broken next to a full-size Submit button.
   3. 23 category links rendered as plain underlined text,
      wrapping to three lines. Unscannable.
   4. Ten identical cards, no hierarchy: the newest post carried
      exactly as much weight as the tenth.

   Scoped to body.blog / body.archive so nothing else moves.
   ============================================================ */

body.blog .page-hero,
body.archive .page-hero {
  padding-bottom: 26px;
}
body.blog main > .section,
body.archive main > .section {
  padding-top: 34px;
}

/* ---- Filter row -------------------------------------------- */
body.blog .archive-tools,
body.archive .archive-tools {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 20px 32px;
  padding-bottom: 28px;
  border-bottom: 1px solid var(--line, #d6dee6);
  margin-bottom: 40px;
}

body.blog .category-links,
body.archive .category-links {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  flex: 1 1 560px;
}

/* Chips rather than a wall of underlined text. The border is the
   affordance — these are filters, not prose links — so no fill,
   no shadow, and the theme's own 2px radius. */
body.blog .category-links a,
body.archive .category-links a {
  display: inline-block;
  padding: 6px 12px;
  border: 1px solid var(--line, #d6dee6);
  border-radius: 2px;
  font-size: 13.5px;
  line-height: 1.3;
  color: var(--muted, #5b6b7c);
  text-decoration: none;
  transition: border-color .18s ease, color .18s ease;
}
body.blog .category-links a:hover,
body.blog .category-links a:focus-visible,
body.archive .category-links a:hover,
body.archive .category-links a:focus-visible {
  border-color: var(--orange, #e87a1a);
  color: var(--ink, #172636);
}
body.archive .category-links a[aria-current],
body.archive .category-links a.is-current {
  border-color: var(--ink, #172636);
  color: var(--ink, #172636);
}

/* ---- Search ------------------------------------------------- */
body.blog .search-form,
body.archive .search-form {
  display: flex;
  gap: 8px;
  flex: 0 1 320px;
  min-width: 260px;
}
body.blog .search-form input[type="search"],
body.archive .search-form input[type="search"] {
  flex: 1 1 auto;
  min-width: 0;            /* the bug was this with no basis to grow from */
  width: auto;
  padding: 9px 12px;
  border: 1px solid var(--line, #d6dee6);
  border-radius: 2px;
  font: inherit;
  font-size: 14px;
  color: var(--ink, #172636);
  background: #fff;
}
body.blog .search-form input[type="search"]:focus,
body.archive .search-form input[type="search"]:focus {
  outline: 2px solid var(--orange, #e87a1a);
  outline-offset: 1px;
  border-color: transparent;
}

/* ---- Grid --------------------------------------------------- */
/* 3 columns was still 3 at 900px, which squeezed the titles. */
@media (max-width: 1080px) {
  body.blog .article-grid,
  body.archive .article-grid { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 640px) {
  body.blog .article-grid,
  body.archive .article-grid { grid-template-columns: 1fr; }
}

/* ---- The lead article --------------------------------------
   The one piece of hierarchy on the page. Full width, image
   beside the copy, title at display size. Everything else stays
   deliberately quiet so this is the thing the eye lands on.    */
body.blog .article-grid > .article-card:first-child {
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: 1.15fr 1fr;
  gap: clamp(24px, 3.5vw, 48px);
  align-items: center;
  padding-bottom: 42px;
  margin-bottom: 12px;
  border-bottom: 1px solid var(--line, #d6dee6);
}
body.blog .article-grid > .article-card:first-child .article-card__image {
  aspect-ratio: 16 / 10;
}
body.blog .article-grid > .article-card:first-child h2 {
  font-size: clamp(26px, 3vw, 40px);
  line-height: 1.12;
  letter-spacing: -0.02em;
}
body.blog .article-grid > .article-card:first-child .article-card__body > p:last-child {
  font-size: 17px;
  line-height: 1.65;
  max-width: 52ch;
}
@media (max-width: 860px) {
  body.blog .article-grid > .article-card:first-child {
    grid-template-columns: 1fr;
    align-items: start;
  }
}

/* ---- Card detail -------------------------------------------
   No shadows, no boxes, no hover lift — the parent theme's
   editorial style is flat on purpose. Only the excerpt is
   clamped, so titles across a row start on the same line.      */
body.blog .article-card__body > p:last-child,
body.archive .article-card__body > p:last-child {
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
body.blog .article-grid > .article-card:first-child .article-card__body > p:last-child {
  -webkit-line-clamp: 4;
}
body.blog .article-card h2 a:hover,
body.archive .article-card h2 a:hover {
  color: var(--blue, #1b4f8a);
}

/* ---- Pagination --------------------------------------------- */
body.blog .navigation .page-numbers,
body.archive .navigation .page-numbers {
  display: inline-block;
  min-width: 38px;
  padding: 7px 10px;
  border: 1px solid var(--line, #d6dee6);
  border-radius: 2px;
  margin-right: 6px;
  text-align: center;
  text-decoration: none;
  font-size: 14px;
  color: var(--muted, #5b6b7c);
}
body.blog .navigation .page-numbers.current,
body.archive .navigation .page-numbers.current {
  border-color: var(--ink, #172636);
  color: var(--ink, #172636);
}
body.blog .navigation a.page-numbers:hover,
body.archive .navigation a.page-numbers:hover {
  border-color: var(--orange, #e87a1a);
  color: var(--ink, #172636);
}

/* ---- Filter row on phones -----------------------------------
   23 chips wrap to eleven rows at 390px — a whole screen of
   filters before the visitor reaches a single article. One
   swipeable row instead, which is 34px rather than ~400px.
   No bleed margins: a negative margin-inline here pushes the
   document wider than the viewport and reintroduces page-level
   horizontal scroll.                                           */
@media (max-width: 760px) {
  body.blog .archive-tools,
  body.archive .archive-tools { gap: 14px; }

  body.blog .category-links,
  body.archive .category-links {
    flex: 1 1 100%;
    max-width: 100%;
    flex-wrap: nowrap;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    padding-bottom: 2px;
  }
  body.blog .category-links::-webkit-scrollbar,
  body.archive .category-links::-webkit-scrollbar { display: none; }

  body.blog .category-links a,
  body.archive .category-links a { flex: 0 0 auto; }

  body.blog .search-form,
  body.archive .search-form { flex: 1 1 100%; min-width: 0; }
}

/* ============================================================
   Single post — column alignment
   ------------------------------------------------------------
   The article was built on three different left edges:

     title / byline   left 568   (header.wrap.post-header, 980px, no padding)
     hero image       left 572   (div.post-cover, 1100px)
     body copy        left 678   (div.prose, 760px, auto-centred
                                  inside a 1368px wrap)

   The body text sat 110px right of the title above it, which is
   what read as broken. The fix is to give the content wrap the
   same content width as the header (980 + its own 64px padding
   either side) and stop auto-centring the prose inside it, so
   all three share one left edge.

   The measure stays near 780px. At 18px Roboto that is already
   ~88 characters per line, which is at the top of what is
   comfortable to read — widening it further would cost more in
   readability than it gains in presence.

   Second, separate bug: .post-header and .post-cover zero their
   horizontal padding to build the desktop column, and never
   restore it. Below 1020px the title and hero image ran flush
   to the screen edge while the breadcrumb and body kept their
   20px gutter. Audited 31 Oct 2026.
   ============================================================ */

/* Give the content wrap and the cover the same column the header
   already uses — 980px, no padding — rather than deriving it from
   each one's own gutter. The gutters are responsive (64px at
   1920, 51px at 1280, 20px at 390), so any arithmetic against a
   fixed value drifts: an earlier calc(980px + 128px) landed the
   text 13px off the title at 1280 and the image 28px off at 1024.
   Matching max-widths with the padding zeroed holds at every
   width, and the mobile gutter is restored for all three below. */
body.single article > div.wrap {
  max-width: 980px;
  padding-inline: 0;
}
body.single article > div.wrap > .prose {
  margin-inline: 0;
  max-width: 780px;
}
body.single .post-cover {
  max-width: 980px;
  padding-inline: 0;
}

@media (max-width: 1020px) {
  body.single .post-header,
  body.single .post-cover,
  body.single article > div.wrap {
    padding-inline: 20px;
  }
}
