/* ===========================================================
   AtomicNorth - the sliding hero and the service strip below it

   Shared, not home-only. The home page slides four photographic
   panels with a four-card strip beneath; application-management.php
   keeps one fixed image and slides the strip alone. Both are driven
   by the same custom property, --at, and the same controller in
   assets/js/hero-slider.js, so there is one implementation rather
   than a copy per page.

   Load order: after site.css and chrome.css, alongside the page's
   own stylesheet.
   =========================================================== */

/* ---------- split hero: copy left, plates bleeding off the right ---------
   The plate panel is positioned rather than gridded, because it has to run
   past the shell to the viewport edge; a grid column would stop at the
   gutter. A left-to-right fade carries the type over it, the same device the
   contact page's photographic hero uses.

   The panels are a track that slides rather than a stack that swaps. .hplates
   is the window and clips; .htrack is a four-across flex row inside it, each
   panel one window wide, moved by translateX(--at * -100%). The percentage
   resolves against the track's own box, which is one window wide, so --at is
   simply the panel index and nothing has to know there are four.

   Why a track and not four stacked panels with a transform each: one moving
   element, one transition, and the panels either side are genuinely there
   during the move, which is what makes it read as a slide instead of two
   things crossing. It also means every panel always has a real box, so
   drawPlate() can measure it -- a display:none or visibility:hidden canvas
   measures zero. */
.hero-split{ position:relative }
.hero-split .hero-in{ max-width:620px; position:relative; z-index:2 }

.hplates{ position:absolute; inset:0 0 0 auto; width:62%; overflow:hidden }
.htrack{ display:flex; width:100%; height:100%;
  transform:translateX(calc(var(--at, 0) * -100%));
  transition:transform .72s cubic-bezier(.4, 0, .2, 1) }
.hplate{ flex:0 0 100%; min-width:0; margin:0; position:relative; overflow:hidden }
/* A hero with no track, where the single panel is the window itself. The
   flex sizing above needs .htrack to be the flex parent; a .hplate sitting
   straight inside .hplates is an ordinary block, so it collapses to the
   image's own layout height and leaves the bottom of the hero empty. The
   child combinator is deliberate: on a page with a track the .hplate is one
   level deeper and this rule does not reach it. */
.hplates > .hplate{ position:absolute; inset:0 }
/* The renders are 2:1 and the panel is roughly square, so the browser scales
   each one to the panel's height and shows a little over half its width. The
   --focus each image carries says which half; it is a custom property rather
   than object-position itself so that the phone rule further down can still
   override it, which an inline object-position could not.
   canvas is kept so a panel can go back to a drawn scene without touching
   this file. */
.hplate img, .hplate canvas{ display:block; width:100%; height:100%;
  object-fit:cover; object-position:var(--focus, 70%) 50% }

/* Motion turned off: the panel still changes, it just cuts. The index is the
   only thing driving position, so dropping the transition is the whole edit
   and every control keeps working. */
@media(prefers-reduced-motion:reduce){
  .htrack{ transition:none }
}
.hplates-fade{ position:absolute; inset:0; z-index:1; pointer-events:none; background:
  linear-gradient(94deg, var(--ink-950) 0%, var(--ink-950) 40%,
    rgba(43,45,49,.94) 50%, rgba(43,45,49,.58) 66%, rgba(43,45,49,.14) 100%),
  linear-gradient(to top, rgba(43,45,49,.6) 0%, rgba(43,45,49,0) 30%) }

/* The hero has no arrows and no dots. The panels are decorative and say
   nothing the four cards below do not already say in words, so a control for
   choosing between them was furniture. The rail under the cards reports the
   position instead, without asking to be operated. */

/* ---------- service family strip ---------------------------------------
   Numbered because these are the four families in the order the nav lists
   them, so the numbers carry the same order a visitor meets elsewhere. No
   thumbnail art: there are four cards and only three plate scenes that are
   not charts, and a card with a picture on three of four reads as broken. */
.famstrip{ background:var(--ink-950); padding:0 0 clamp(26px,3vw,44px) }
.famcards{ list-style:none; margin:0; padding:0;
  display:grid; grid-template-columns:repeat(4,minmax(0,1fr)); gap:14px }
.famcards li{ display:flex }
.famcards a{ position:relative; display:flex; flex-direction:column; gap:7px;
  width:100%; padding:20px 20px 22px; text-decoration:none;
  background:var(--ink-900); border:1px solid var(--line-soft); border-radius:4px;
  transition:border-color .22s, background .22s, transform .22s }
.famcards a::after{ content:""; position:absolute; inset:auto 0 0 0; height:2px;
  background:var(--orange); transform:scaleX(0); transform-origin:left;
  transition:transform .28s cubic-bezier(.22,.75,.2,1) }
.famcards a:hover, .famcards a:focus-visible{ background:var(--ink-850);
  border-color:#3A3D44; transform:translateY(-2px) }
.famcards a:hover::after, .famcards a:focus-visible::after{ transform:scaleX(1) }
.famcards a:focus-visible{ outline:2px solid var(--blue-pale); outline-offset:2px }
/* The card matching the panel on screen, outlined the way the reference
   outlines 01. Driven by the slider, so the two rows always agree. */
.famcards a.is-current{ border-color:var(--orange); background:var(--ink-850) }
.famcards a.is-current::after{ transform:scaleX(1) }
.fnum{ font-size:12px; font-weight:800; letter-spacing:.16em; color:var(--orange) }
.fname{ font-size:17px; font-weight:700; letter-spacing:-.01em; color:#fff;
  line-height:1.2 }
.fblurb{ font-size:13px; line-height:1.5; color:var(--fg-mid) }

/* The rail. A hairline the width of the row with one card's worth of orange
   on it, translated by the same index as the panels. At desktop width all
   four cards are already on screen, so there is nothing for the row itself to
   slide -- the rail is what moves, and it is the thing that tells you the
   panel above changed on its own.
   --n is written by the script; the 4 is the fallback so a scriptless page
   still shows a sane quarter rather than a full bar. */
.famrail{ position:relative; height:2px; margin:18px 0 0; overflow:hidden;
  background:var(--line-soft) }
.famrail > span{ position:absolute; inset:0 auto 0 0; display:block;
  width:calc(100% / var(--n, 4)); background:var(--orange);
  transform:translateX(calc(var(--at, 0) * 100%));
  transition:transform .72s cubic-bezier(.4, 0, .2, 1) }
@media(prefers-reduced-motion:reduce){
  .famrail > span{ transition:none }
  .famcards{ scroll-behavior:auto }
}

@media(max-width:1100px){
  .hplates{ width:54% }
  .hero-split .hero-in{ max-width:none }
}
/* Below 900px four cards will not fit, so the row becomes a track of its own
   and slides with the panels. It is a scroll container rather than a second
   transform: the browser clamps the last card to the end instead of leaving a
   gap, it is swipeable, and the script only has to set scrollLeft. Native
   smooth scrolling handles the movement, and it respects the reduced-motion
   setting on its own. The scrollbar is hidden because the arrows and the rail
   already say there is more. */
@media(max-width:900px){
  .famcards{ display:flex; grid-template-columns:none; gap:14px;
    overflow-x:auto; overscroll-behavior-x:contain;
    scroll-snap-type:x mandatory; scroll-behavior:smooth;
    -webkit-overflow-scrolling:touch; scrollbar-width:none;
    padding-bottom:2px }
  .famcards::-webkit-scrollbar{ display:none }
  .famcards li{ flex:0 0 min(64%, 320px); scroll-snap-align:start }
  /* A lifted card inside a scroll container would be clipped at the top. */
  .famcards a:hover, .famcards a:focus-visible{ transform:none }
}
@media(max-width:820px){
  /* The panel goes behind the whole hero on a phone, with a heavier fade,
     rather than squeezing into a column too narrow to read as anything. */
  .hplates{ inset:0; width:100% }
  /* Full-bleed behind the copy: the box is now wider than the source ratio,
     so the crop is vertical and the frame can sit centred. */
  .hplate img, .hplate canvas{ object-position:60% 50% }
  /* Heavier than it was for the drawn scenes. A photograph has bright detail
     everywhere, and here it is sitting directly under the paragraph rather
     than beside it, so the middle of the scrim has to carry the contrast. */
  .hplates-fade{ background:
    linear-gradient(180deg, rgba(43,45,49,.94) 0%, rgba(43,45,49,.86) 46%, rgba(43,45,49,.95) 100%) }
  .hero-split .hero-in{ padding-bottom:0 }
}
@media(max-width:520px){
  .famcards li{ flex:0 0 82% }
}

/* ---------- six-line variant, application-management.php ----------------
   Six cards will not sit in one readable row at any width worth
   supporting: at 1024 the shell leaves 144px each, which is narrower
   than "Automation testing". So this variant is a scroll track at
   every width rather than a grid that collapses into one. That is
   also the better answer for the page it is on: with no panels
   sliding above it, the row itself is the motion.

   Declared after every .famcards rule, including the media queries,
   so it wins the cascade at all widths without !important. */
.famcards-6{
  display:flex; grid-template-columns:none; gap:14px;
  overflow-x:auto; overscroll-behavior-x:contain;
  scroll-snap-type:x mandatory; scroll-behavior:smooth;
  -webkit-overflow-scrolling:touch; scrollbar-width:none;
  padding-bottom:2px;
}
.famcards-6::-webkit-scrollbar{ display:none }
.famcards-6 li{ flex:0 0 min(27%, 310px); scroll-snap-align:start }
/* A lifted card inside a scroll container is clipped at the top. */
.famcards-6 a:hover, .famcards-6 a:focus-visible{ transform:none }
@media(max-width:1000px){ .famcards-6 li{ flex:0 0 min(46%, 320px) } }
@media(max-width:620px){  .famcards-6 li{ flex:0 0 82% } }
@media(prefers-reduced-motion:reduce){ .famcards-6{ scroll-behavior:auto } }
