/* fx.css: client logo marquee and button fill sweep.
   Loaded after style.css. Motion runs only under .mo (set in the head when reduced motion is off). */

/* ---------- Client logo marquee ---------- */
.marq { position: relative; display: flex; flex-direction: column; gap: 12px; }
.marq__view {
  overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 24px, #000 calc(100% - 24px), transparent 100%);
          mask-image: linear-gradient(90deg, transparent 0, #000 24px, #000 calc(100% - 24px), transparent 100%);
}
.marq__track { display: flex; width: max-content; }
.marq .logos { display: flex !important; flex-wrap: nowrap; gap: 16px; margin: 0; padding: 0 16px 0 0; list-style: none; grid-template-columns: none !important; }
.marq .logo { flex: 0 0 clamp(168px, 20vw, 260px); width: clamp(168px, 20vw, 260px); margin: 0; }
@media (max-width: 560px) { .marq .logo { padding: 16px 18px; height: 96px; } .marq .logo img { height: 36px; } }
.mo .marq__track { animation: marq var(--marq-dur, 40s) linear infinite; }
@keyframes marq { from { transform: translateX(0); } to { transform: translateX(calc(-100% / var(--marq-sets, 2))); } }
.marq:focus-within .marq__track,
.marq.is-paused .marq__track,
.marq.is-offscreen .marq__track { animation-play-state: paused; }
/* hover: fx.js eases the loop down to a stop and back up, instead of an instant pause */
.marq__pause {
  align-self: flex-end; display: inline-flex; align-items: center; gap: 8px; min-height: 44px; padding: 6px 14px; -webkit-user-select: none; user-select: none;
  font: 600 var(--fs-14, 0.875rem)/1 var(--sans, "IBM Plex Sans", Arial, sans-serif); color: var(--ink, #1F1E21);
  background: transparent; border: 1px solid var(--control-line, #85828A); border-radius: 999px; cursor: pointer; /* 3.6:1 on white */
}
.marq__pause:hover { border-color: var(--ink, #1F1E21); }
.marq__pause svg { width: 12px; height: 12px; }
.marq__pause .i-play { display: none; }
.marq.is-paused .marq__pause .i-play { display: block; }
.marq.is-paused .marq__pause .i-pause { display: none; }
/* tiles: gentle lift, never recoloured */
.marq .logo { transition: transform 200ms var(--ease-out, cubic-bezier(0.23,1,0.32,1)), opacity 200ms ease; }
/* moving logos stay still under the pointer: no lift, full opacity */
/* no JS or reduced motion: the original row stays as it was (fx.js does nothing) */

/* ---------- One logo row look, Clients, Home and Partners alike ----------
   Logos sit straight on the page, no white tiles, same size, gap and speed everywhere.
   Never recoloured: Magick Woods has white lettering only, so it keeps a dark tile. */
.logos--bare { grid-template-columns: repeat(4, minmax(0, 220px)); gap: 48px; align-items: center; }
.logos--bare .logo { background: none; padding: 0; height: 72px; border-radius: 0; }
.logos--bare .logo img { height: 52px; }
.logos--bare .logo--on-dark { background: #1C1B1F; padding: 12px 20px; border-radius: 6px; }
.logos--bare .logo--on-dark img { height: 28px; }
.marq .logos--bare { gap: clamp(56px, 8vw, 112px); padding-right: clamp(56px, 8vw, 112px); }
.marq .logos--bare .logo { flex-basis: clamp(150px, 16vw, 220px); width: clamp(150px, 16vw, 220px); height: 72px; }
@media (max-width: 560px) {
  .logos--bare { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 28px; }
  .marq .logos--bare .logo { height: 64px; padding: 0; } .marq .logos--bare .logo img { height: 40px; }
  .marq .logos--bare .logo--on-dark { padding: 10px 16px; } .marq .logos--bare .logo--on-dark img { height: 24px; }
}

/* ---------- Button fill sweep ---------- */
.btn { position: relative; overflow: hidden; isolation: isolate; }
.btn::before {
  content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background: var(--sweep, rgba(31, 30, 33, 0.9));
  transform: scaleX(0); transform-origin: left center;
}
.mo .btn::before { transition: transform 220ms var(--ease-out, cubic-bezier(0.23,1,0.32,1)); }
.mo .btn { transition: color 220ms var(--ease-out, cubic-bezier(0.23,1,0.32,1)), transform 120ms ease-out; }
@media (hover: hover) and (pointer: fine) {
  .btn:hover::before { transform: scaleX(1); }
}
.btn:focus-visible::before { transform: scaleX(1); }
.mo .btn:active { transform: scale(0.97); }
.btn:hover, .btn:focus-visible { box-shadow: none; }

/* sweep colour per button; text stays at 4.5:1 or better in both states */
.btn--red { --sweep: #E28B85; }                 /* ink text on logo red  ->  ink text on a lighter red (6.7:1), like the SLaiCE button */
.btn--ink { --sweep: #D1655D; }                 /* paper on ink  ->  ink on logo red (4.5:1) */
.btn--ink:hover, .btn--ink:focus-visible { color: #1F1E21; }
.btn--teal, .btn--cream { --sweep: #2F5D8C; }   /* white on navy  ->  white on blue (6.9:1) */
.btn--line { --sweep: #1F1E21; }
.btn--line:hover, .btn--line:focus-visible { color: #F6F4EF; background: transparent; }
.btn--line-cream { --sweep: #1F3A5F; }
.btn--line-cream:hover, .btn--line-cream:focus-visible { color: #FFFFFF; background: transparent; }

/* ---------- Phone contact bar ---------- */
.mcta { display: none; }
@media (max-width: 700px) {
  .mcta {
    display: block; position: fixed; z-index: 60; left: 0; right: 0; bottom: 0;
    padding: 10px max(16px, env(safe-area-inset-right, 0px)) calc(10px + env(safe-area-inset-bottom, 0px)) max(16px, env(safe-area-inset-left, 0px));
    background: rgba(251, 250, 247, 0.98);
    box-shadow: 0 -1px 0 var(--line, #E6E3DC);
    transform: translateY(110%); visibility: hidden;
  }
  .mcta .btn { display: flex; width: 100%; justify-content: center; }
  .mcta.is-on { transform: none; visibility: visible; }
  .mo .mcta { transition: transform 200ms var(--ease-out, cubic-bezier(0.23,1,0.32,1)), visibility 0s linear 200ms; }
  .mo .mcta.is-on { transition: transform 320ms cubic-bezier(0.32, 0.72, 0, 1), visibility 0s; }
}

/* ---------- Consulting engagement path, scroll-linked (desktop) ---------- */
@media (min-width: 900px) and (prefers-reduced-motion: no-preference) {
  .mo .rise.is-scroll .rise-svg { transition: none !important; }
  /* the node discs follow .is-on in style.css (opacity and scale only) */
  .mo .rise.is-scroll .rise-step > * { opacity: 0.72; transition: opacity 300ms ease; } /* still about 6:1, so waiting steps stay readable */
  .mo .rise.is-scroll .rise-step.is-on > * { opacity: 1; }
}

/* ---------- Key figures settle into place (no counting through untrue values) ---------- */
[data-count] { display: inline-block; overflow: clip; vertical-align: bottom; padding-bottom: 0.06em; }
.cnt-in { display: inline-block; }
@media (prefers-reduced-motion: no-preference) {
  .mo [data-count]:not(.is-settled) .cnt-in { transform: translateY(105%); }
  .mo [data-count].is-settled .cnt-in { transform: none; transition: transform 700ms cubic-bezier(0.16, 1, 0.3, 1); }
}
/* ---------- Masking demo: fixed width while it types ---------- */
.js-mask { display: inline-block; white-space: nowrap; }
/* ---------- Race replay ---------- */
.race-again { margin-top: 18px; min-height: 44px; display: inline-flex; align-items: center; gap: 8px; padding: 0; border: 0; background: none; font: inherit; font-weight: 600; color: var(--navy, #1F3A5F); cursor: pointer; text-decoration: underline; text-decoration-thickness: 2px; text-underline-offset: 5px; opacity: 0; pointer-events: none; }
.race-again.is-shown { opacity: 1; pointer-events: auto; transition: opacity 200ms ease; }
.race-again.is-shown.is-running { opacity: 0.6; }

html.menu-open .mcta { transform: translateY(110%) !important; visibility: hidden !important; }

/* the logo row can take keyboard focus (to pause it); show where focus is */
.marq__view:focus-visible { outline: 2px solid var(--blue, #2F5D8C); outline-offset: 4px; border-radius: 4px; }

/* ---------- Play-once figures (data-lines / .play: site.js adds .is-armed, then .is-play when scrolled into view) ----------
   Each one explains its figure, plays once and stops. Reduced motion: the finished figure shows. */
@media (prefers-reduced-motion: no-preference) {
  /* Security: without the story script the line draws and the target lights; with it (.n-story, fx.js) it plays in four beats */
  .mo .sec-net.is-armed .net-rise { clip-path: inset(-10% 100% -10% -2%); }
  .mo .sec-net.is-armed .net-tgt i.on { background: #fff; }
  .mo .sec-net.is-play:not(.n-story) .net-rise { clip-path: inset(-10% -2% -10% -2%); transition: clip-path 900ms var(--ease-in-out) 150ms; }
  .mo .sec-net.is-play:not(.n-story) .net-tgt i.on { background: var(--blue, #2F5D8C); transition: background-color 240ms ease 1050ms; }
  .mo .sec-net.n-story .net-rise { clip-path: inset(-10% 100% -10% -2%); }
  .mo .sec-net.n-story.n-line .net-rise { clip-path: inset(-10% -2% -10% -2%); transition: clip-path 800ms var(--ease-in-out); }
  .mo .sec-net.n-story .net-src i.on { transition: box-shadow 200ms ease, transform 200ms var(--ease-out); }
  .mo .sec-net.n-story .net-src i.on.is-pick { box-shadow: 0 0 0 2px var(--red, #D1655D); transform: scale(1.12); }
  .mo .sec-net.n-story .net-tgt i.on { background: #fff; }
  .mo .sec-net.n-story .net-tgt i.on.is-in { background: var(--blue, #2F5D8C); animation: net-pop 320ms var(--ease-out); }
  .mo .sec-net.n-story { outline-color: transparent; }
  .mo .sec-net.n-story.n-seal { outline-color: rgba(31, 58, 95, 0.45); transition: outline-color 500ms ease; }
  .mo .sec-net.n-story.n-seal .net-l { animation: net-pop 360ms var(--ease-out); }
  @keyframes net-pop { 0% { transform: scale(0.6); } 60% { transform: scale(1.15); } 100% { transform: none; } }

  /* Clients, airport ledger: the moved years colour in from 2017 to 2026 (the archive years stay grey) */
  .mo .tl2-led.is-armed :is(.ty--hist, .ty--now) i { background: var(--cell); }
  .mo .tl2-led.is-play .ty--hist i { background: var(--blue); }
  .mo .tl2-led.is-play .ty--now i { background: #B9514A; }
  .mo .tl2-led.is-play :is(.ty--hist, .ty--now) i { transition: background-color 260ms ease calc(150ms + (var(--i, 12) - 12) * 45ms); }

  /* Clients, automaker month: the five blocked days stack up, then the free time runs to day 30 */
  .mo .month2.is-armed .m2-blk i { transform: scaleY(0); transform-origin: bottom; }
  .mo .month2.is-armed .m2-free { transform: scaleX(0); transform-origin: left; }
  .mo .month2.is-play .m2-blk i { transform: none; transition: transform 300ms var(--ease-out); }
  .mo .month2.is-play .m2-blk i:nth-child(2) { transition-delay: 60ms; }
  .mo .month2.is-play .m2-blk i:nth-child(3) { transition-delay: 120ms; }
  .mo .month2.is-play .m2-blk i:nth-child(4) { transition-delay: 180ms; }
  .mo .month2.is-play .m2-blk i:nth-child(5) { transition-delay: 240ms; }
  .mo .month2.is-play .m2-free { transform: none; transition: transform 700ms var(--ease-in-out) 350ms; }
  .mo .month2.is-play .m2-row--us .m2-free { transition-delay: 500ms; }

  /* About: the Big 4 years fill in one by one */
  .mo .years-cells.is-armed i.ey { background: var(--cell); }
  .mo .years-cells.is-play i.ey { background: var(--blue); transition: background-color 240ms ease calc(150ms + var(--i, 0) * 35ms); }
}

/* ---------- Depth (no libraries; WordPress-safe). Only under .mo, so reduced motion keeps every figure flat ----------
   Charts never rest tilted: real 3D is used only for moves that end flat (the carve-out swing, the calendar flips);
   elsewhere depth is a small lift with a soft shadow, so text and numbers stay readable.
   perspective() sits inside each transform, so no wrapper needs a perspective of its own.
   The slice boards (SLaiCE hero and Home teaser) stay flat: their states in style.css carry the story. */
/* 1. Use cases, carve-out: the new SAP system swings up from flat as it lifts out of the source */
@media (prefers-reduced-motion: no-preference) {
  .mo .lift { perspective: 900px; }
  .mo .lift.is-armed .lift-new { transform-origin: 50% 100%; transform: translateY(clamp(56px, 6vw, 96px)) rotateX(58deg); opacity: 0.4; }
  .mo .lift.is-play .lift-new { transform: none; opacity: 1; transition: transform 800ms var(--ease-expo) 150ms, opacity 300ms ease 150ms; }
}
@media (prefers-reduced-motion: no-preference) and (max-width: 600px) {
  .mo .lift.is-armed .lift-new { transform: translateY(24px) rotateX(58deg); }
}

/* 2. Use cases, company mandate: no tilt (text stays readable). The two India company codes lift off the global
      ledger with a soft shadow, like cards picked up off a table, as they're picked */
@media (prefers-reduced-motion: no-preference) {
  .mo .split .led--global .lc.is-on i { transition: transform 500ms var(--ease-expo) 250ms, box-shadow 500ms var(--ease-expo) 250ms; }
  .mo .split.is-play .led--global .lc.is-on i { transform: translateY(-3px); box-shadow: 0 6px 8px -5px rgba(31, 58, 95, 0.45); }
}
/* 3. Use cases, test systems: each refresh day flips over like a card to show its colour */
@media (prefers-reduced-motion: no-preference) {
  .mo .cal.is-play :is(.cal-t, .cal-d) { animation: cal-flip 520ms var(--ease-in-out) var(--cd, 0ms) both; }
  /* the colour swaps while the tile is edge-on, halfway through the flip */
  .mo .cal.is-play :is(.cal-t, .cal-d) { transition-duration: 0s; transition-delay: calc(var(--cd, 0ms) + 260ms); }
  .mo .cal.is-play :is(.cal-t, .cal-d) .cal-n { transition-duration: 0s; transition-delay: calc(var(--cd, 0ms) + 260ms); }
}
@keyframes cal-flip { 0% { transform: perspective(500px) rotateY(0); } 50% { transform: perspective(500px) rotateY(90deg); } 100% { transform: perspective(500px) rotateY(0); } }
/* 4. Clients, airport ledger: no tilt. The moved years lift a little with a soft shadow; 2026 lifts the same amount so it stays in line, and stands out by colour */
@media (prefers-reduced-motion: no-preference) {
  .mo .tl2-led .ty:is(.ty--hist, .ty--now) i { transition: transform 500ms var(--ease-expo) calc(450ms + (var(--i, 12) - 12) * 45ms), box-shadow 500ms var(--ease-expo) calc(450ms + (var(--i, 12) - 12) * 45ms), background-color 260ms ease calc(150ms + (var(--i, 12) - 12) * 45ms); }
  .mo .tl2-led.is-play .ty--hist i { transform: translateY(-2px); box-shadow: 0 5px 7px -5px rgba(31, 58, 95, 0.45); }
  .mo .tl2-led.is-play .ty--now i { transform: translateY(-2px); box-shadow: 0 5px 8px -5px rgba(185, 81, 74, 0.6); }
}

/* ---------- Small moments, site-wide ---------- */
/* Header: a soft shadow once the page scrolls under it (site.js adds .is-scrolled) */
.site-head { transition: box-shadow 200ms ease; }
.site-head.is-scrolled { box-shadow: 0 1px 0 var(--line, #E6E3DC), 0 8px 18px -14px rgba(28, 27, 31, 0.22); }

/* Privacy and Accessibility contents: the existing underline marks the section you're reading (site.js sets aria-current) */

/* Inner page titles without their own drawing: a short red rising stroke draws in under the heading, once */
.hero--page:not(:has(.hero-art, .routes)) .display::after {
  content: ""; display: block; width: clamp(96px, 9vw, 140px); height: clamp(18px, 1.7vw, 26px); margin-top: clamp(14px, 1.4vw, 22px);
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 140 26' fill='none'%3E%3Cpath d='M3 23 H52 C72 23 82 21 94 15 S118 4 137 3' stroke='%23D1655D' stroke-width='4' stroke-linecap='round'/%3E%3C/svg%3E") left center / contain no-repeat;
}
@media (prefers-reduced-motion: no-preference) {
  .mo .hero--page:not(:has(.hero-art, .routes)) .display::after { clip-path: inset(-20% 100% -20% 0); animation: wipe 700ms var(--ease-in-out) 300ms forwards; }
}
