/* ==========================================================================
   Nxtcell Mobility, range components
   Two premium patterns, one per page, so no layout family repeats:
     .rail   scroll-pinned horizontal product rail   (Products)
     .feat   asymmetric category bento               (Portfolio)
   Both degrade to an honest scroll-snap / stack on touch and reduced motion.
   ========================================================================== */

/* ==========================================================================
   A. THE RAIL
   A vertical scroll drives a horizontal pan across the range. Pinned with
   position:sticky and scrubbed by a scroll timeline, so there is no scroll
   listener and no hijack: the page still scrolls at its normal rate.
   ========================================================================== */
.rail{position:relative}
.rail__stage{
  position:sticky;
  top:0;
  min-height:100dvh;
  display:flex;
  flex-direction:column;
  justify-content:center;
  overflow:hidden;
  background:var(--navy);
  color:#fff;
}
.rail__field{position:absolute;inset:0;z-index:0;pointer-events:none}

.rail__head{
  position:relative;z-index:2;
  max-width:var(--wrap);width:100%;
  margin:0 auto;padding:0 var(--pad);
  display:flex;align-items:flex-end;justify-content:space-between;gap:2rem;
  margin-bottom:clamp(28px,4vh,54px);
}
.rail__head h2{color:#fff;margin:0;max-width:16ch}
.rail__count{
  font-family:var(--font-mono);font-size:var(--t-xs);letter-spacing:.16em;
  text-transform:uppercase;color:rgba(255,255,255,.5);white-space:nowrap;
  padding-bottom:.55rem;
}
.rail__count b{color:var(--cyan);font-weight:500}

.rail__viewport{position:relative;z-index:2;width:100%;overflow:hidden}
.rail__track{
  display:flex;
  gap:clamp(18px,2.2vw,34px);
  padding-inline:max(var(--pad),calc((100vw - var(--wrap)) / 2 + var(--pad)));
  width:max-content;
  will-change:transform;
}

/* one product panel */
.rail__item{
  flex:0 0 clamp(260px,25vw,368px);
  display:flex;flex-direction:column;
  border:1px solid var(--navy-line);
  background:rgba(13,30,45,.92);
  padding:1.5rem 1.5rem 1.7rem;
  position:relative;
  transition:border-color .4s var(--ease-out),background-color .4s var(--ease-out);
}
@media (hover:hover) and (pointer:fine){
  .rail__item:hover{border-color:rgba(111,198,236,.45);background:rgba(18,40,58,.95)}
}
.rail__idx{
  font-family:var(--font-mono);font-size:var(--t-xs);letter-spacing:.16em;
  color:var(--cyan);margin-bottom:1.1rem;display:block;
}
.rail__shot{
  height:clamp(190px,24vh,280px);
  display:flex;align-items:center;justify-content:center;
  margin-bottom:1.4rem;
  /* the product wipes into view rather than fading */
  clip-path:inset(0 0 100% 0);
  transition:clip-path .8s var(--ease-out);
}
.rail.in .rail__shot{clip-path:inset(0 0 0 0)}
.rail__shot img{
  max-height:100%;width:auto;object-fit:contain;
  filter:drop-shadow(0 22px 40px rgba(0,0,0,.55));
  transition:transform .7s var(--ease-out);
}
@media (hover:hover) and (pointer:fine){
  .rail__item:hover .rail__shot img{transform:translate3d(0,-8px,0) scale(1.03)}
}
.rail__kind{
  font-family:var(--font-mono);font-size:var(--t-xs);letter-spacing:.14em;
  text-transform:uppercase;color:rgba(255,255,255,.52);margin:0 0 .5rem;
}
.rail__item h3{color:#fff;margin:0 0 .6rem;font-size:clamp(1.15rem,1rem + .5vw,1.4rem)}
.rail__item p{color:rgba(255,255,255,.7);font-size:var(--t-md);margin:0 0 1.2rem;max-width:34ch}

/* the spec readout: a technical table, not chips */
.rail__specs{list-style:none;margin:auto 0 0;padding:0;border-top:1px solid var(--navy-line)}
.rail__specs li{
  display:flex;align-items:baseline;justify-content:space-between;gap:1rem;
  margin:0;padding:.55rem 0;border-bottom:1px solid rgba(255,255,255,.07);
  font-size:var(--t-sm);
}
.rail__specs li:last-child{border-bottom:0}
.rail__specs dt,.rail__specs .k{
  font-family:var(--font-mono);font-size:var(--t-xs);letter-spacing:.09em;
  text-transform:uppercase;color:rgba(255,255,255,.45);
}
.rail__specs .v{
  font-family:var(--font-head);font-weight:600;color:#fff;
  font-variant-numeric:tabular-nums;text-align:right;
}

/* progress under the rail */
.rail__bar{
  position:relative;z-index:2;
  max-width:var(--wrap);width:100%;margin:clamp(24px,3.4vh,46px) auto 0;
  padding:0 var(--pad);
}
.rail__bar span{display:block;height:2px;background:var(--navy-line);position:relative;overflow:hidden}
.rail__bar span::after{
  content:"";position:absolute;inset:0;background:var(--cyan);
  transform-origin:0 50%;transform:scaleX(var(--railp,0));
}

/* scroll-driven pan, where the browser supports it */
@supports (animation-timeline:view()){
  @media (min-width:881px) and (prefers-reduced-motion:no-preference){
    /* view-timeline, not scroll-timeline: .rail does not scroll, it passes
       through the viewport. `contain` spans exactly the pinned period. */
    .rail{height:var(--rail-h,320vh);view-timeline:--railview block}
    .rail__track{
      animation:railPan linear both;
      animation-timeline:--railview;
      animation-range:contain 0% contain 100%;
    }
    @keyframes railPan{
      from{transform:translate3d(0,0,0)}
      to{transform:translate3d(var(--rail-pan,0px),0,0)}
    }
    .rail__bar span::after{
      animation:railFill linear both;
      animation-timeline:--railview;
      animation-range:contain 0% contain 100%;
      transform:scaleX(0);
    }
    @keyframes railFill{from{transform:scaleX(0)}to{transform:scaleX(1)}}
  }
}

/* touch, narrow screens and reduced motion: an honest swipeable rail */
@media (max-width:880px),(prefers-reduced-motion:reduce){
  .rail{height:auto!important}
  .rail__stage{position:static;min-height:0;padding:clamp(40px,7vw,64px) 0}
  .rail__viewport{
    overflow-x:auto;overflow-y:hidden;
    scroll-snap-type:x mandatory;
    -webkit-overflow-scrolling:touch;
    scrollbar-width:none;
  }
  .rail__viewport::-webkit-scrollbar{display:none}
  .rail__track{animation:none;transform:none!important;padding-inline:var(--pad)}
  .rail__item{scroll-snap-align:center;flex-basis:min(78vw,340px)}
  .rail__shot{clip-path:none}
  /* the progress rail stays: on touch it reports the swipe rather than the
     page scroll, so the reader still knows how far through the range they
     are. site.js writes --railp from the viewport's own scrollLeft. */
  .rail__bar{display:block}
  .rail__bar span::after{transition:transform .18s linear}
}
@media (max-width:880px) and (prefers-reduced-motion:reduce){
  .rail__bar span::after{transition:none}
}

/* ==========================================================================
   B. THE FEATURE BENTO
   Three categories, three cells, one large. Not three equal cards.
   Cell count matches content exactly.
   ========================================================================== */
.feat{
  display:grid;
  grid-template-columns:1.32fr 1fr;
  grid-template-rows:auto auto;
  gap:0;
}
.feat__cell{
  position:relative;
  border:1px solid var(--line);
  margin:0 0 0 -1px;
  padding:clamp(24px,2.6vw,38px);
  display:flex;flex-direction:column;
  background:#fff;
  overflow:hidden;
  transition:border-color .4s var(--ease-out);
}
.feat__cell:first-child{margin-left:0}
.feat__cell + .feat__cell{margin-top:0}
.feat__cell:nth-child(3){margin-top:-1px}
/* the lead category runs the full width, with its shot beside the copy, so
   the two smaller cells below it sit on one honest row */
.feat__cell--lead{
  grid-column:1 / -1;
  display:grid;
  grid-template-columns:1.04fr 1fr;
  gap:clamp(26px,3.2vw,52px);
  align-items:center;
  margin-left:0;
}
.feat__body{display:flex;flex-direction:column;min-width:0}
.feat__cell--lead .feat__media{margin:0}
.feat__cell--lead .feat__spec{margin:1.5rem 0 0}
@media (hover:hover) and (pointer:fine){
  .feat__cell:hover{border-color:var(--ink-40);z-index:1}
}

/* the lead cell carries the image, the other two carry structure */
.feat__media{
  position:relative;
  margin:0 0 1.6rem;
  background:var(--bg-soft);
  clip-path:inset(0 100% 0 0);
  transition:clip-path .95s var(--ease-out);
}
.reveal.in .feat__media,.feat__media.in{clip-path:inset(0 0 0 0)}
.feat__media img{width:100%;height:auto;display:block}
.feat__cell:first-child .feat__media{aspect-ratio:4/3;overflow:hidden}
.feat__cell:first-child .feat__media img{height:100%;object-fit:cover}

.feat__kind{
  font-family:var(--font-mono);font-size:var(--t-xs);letter-spacing:.15em;
  text-transform:uppercase;color:var(--blue-700);margin:0 0 .75rem;
}
.feat__cell h3{
  font-size:clamp(1.3rem,1rem + 1.1vw,2.05rem);
  letter-spacing:-.03em;margin:0 0 .7rem;
}
.feat__cell > p{color:var(--ink-70);font-size:var(--t-md);margin:0 0 1.3rem;max-width:42ch}

/* a technical readout instead of a bullet list */
.feat__spec{list-style:none;margin:auto 0 0;padding:0;border-top:1px solid var(--line)}
.feat__spec li{
  display:grid;grid-template-columns:1fr auto;align-items:baseline;gap:1rem;
  margin:0;padding:.62rem 0;border-bottom:1px solid var(--line-hair);
  /* each row slides up as the cell arrives */
  opacity:0;transform:translate3d(0,10px,0);
  transition:opacity .5s var(--ease-out),transform .5s var(--ease-out);
}
.feat__spec li:last-child{border-bottom:0}
.reveal.in .feat__spec li,.feat__spec.in li{opacity:1;transform:none}
.reveal.in .feat__spec li:nth-child(1){transition-delay:.06s}
.reveal.in .feat__spec li:nth-child(2){transition-delay:.13s}
.reveal.in .feat__spec li:nth-child(3){transition-delay:.20s}
.reveal.in .feat__spec li:nth-child(4){transition-delay:.27s}
.feat__spec .k{
  font-family:var(--font-mono);font-size:var(--t-xs);letter-spacing:.08em;
  text-transform:uppercase;color:var(--ink-55);
}
.feat__spec .v{
  font-family:var(--font-head);font-weight:600;color:var(--ink);
  font-variant-numeric:tabular-nums;font-size:var(--t-md);
}

@media (max-width:900px){
  .feat{grid-template-columns:1fr}
  .feat__cell{margin:-1px 0 0 0;grid-row:auto!important}
  .feat__cell:first-child{margin-top:0}
}

@media (prefers-reduced-motion:reduce){
  .feat__media{clip-path:none}
  .feat__spec li{opacity:1;transform:none;transition:none}
  .rail__shot{clip-path:none}
}

/* --------------------------------------------------------------------------
   B.2 CELL MEDIA
   Every cell carries its category, not just the lead one. The lead image
   grows to fill whatever height the column ends up at; the two right-hand
   cells take a fixed wide crop at the top, so the three read as one family.
   Each one wipes in from the left, then drifts slowly for as long as it is
   on screen, so the bento is never completely still.
   -------------------------------------------------------------------------- */
.feat__cell:first-child .feat__media{aspect-ratio:4/3}
.feat__media--wide{
  aspect-ratio:16/10;
  overflow:hidden;
}
.feat__media--wide img{
  height:100%;
  object-fit:cover;
  object-position:50% 38%;
  mix-blend-mode:multiply;
}
/* the lead product shot is never cropped: it sits on the tinted panel
   whatever height the column ends up at */
.feat__cell:first-child .feat__media{background:var(--bg-soft)}
.feat__cell:first-child .feat__media img{object-fit:contain;mix-blend-mode:multiply}

@supports (animation-timeline:view()){
  @media (prefers-reduced-motion:no-preference) and (min-width:901px){
    .feat__media img{
      animation:mediaDrift linear both;
      animation-timeline:view();
      animation-range:cover 0% cover 100%;
    }
    @keyframes mediaDrift{
      from{transform:translate3d(0,-1.6%,0) scale(1.04)}
      to{transform:translate3d(0,1.6%,0) scale(1.04)}
    }
  }
}

@media (max-width:900px){
  .feat__cell--lead{grid-template-columns:1fr;gap:0;display:flex;flex-direction:column}
  .feat__cell--lead .feat__media{margin:0 0 1.6rem}
  .feat__media--wide{aspect-ratio:16/9}
}

@media (prefers-reduced-motion:reduce){
  .feat__media img{animation:none;transform:none}
}

/* ==========================================================================
   C. THE NXTPAPER INSTRUMENT
   A demonstration rather than a photograph: the same page rendered twice,
   once on a glossy panel and once on a matte NXTPAPER surface, with a seam
   sweeping between them. The seam position is one animated custom property,
   so the clip and the light on the seam always agree.
   ========================================================================== */
@property --nxp{syntax:"<percentage>";inherits:true;initial-value:56%}

.split__media--bare{overflow:visible}
.split__media--bare img{border-radius:0}

.nxp{
  --nxp:52%;
  position:relative;
  margin:0 auto;
  max-width:430px;
}
.nxp figcaption{
  margin-top:1.15rem;
  font-family:var(--font-mono);
  font-size:var(--t-xs);
  line-height:1.6;
  letter-spacing:.02em;
  color:var(--ink-55);
  max-width:38ch;
}

/* the body */
.nxp__device{
  position:relative;
  width:100%;
  aspect-ratio:3/4;
  padding:13px;
  border-radius:20px;
  background:linear-gradient(152deg,#33434f 0%,#111f2b 44%,#24333f 100%);
  box-shadow:
    0 0 0 1px rgba(10,24,38,.55),
    inset 0 1px 0 rgba(255,255,255,.14),
    0 44px 80px -46px rgba(10,24,38,.62);
}
.nxp__cam{
  position:absolute;top:5px;left:50%;
  width:6px;height:6px;border-radius:50%;
  background:#080f16;
  box-shadow:0 0 0 1px rgba(255,255,255,.1);
  transform:translateX(-50%);
}

.nxp__screen{
  position:relative;
  width:100%;height:100%;
  border-radius:9px;
  overflow:hidden;
  isolation:isolate;
  background:#fff;
}

/* the two renderings of one page */
.nxp__page{
  position:absolute;inset:0;
  padding:clamp(20px,6%,32px);
  display:flex;flex-direction:column;justify-content:center;
}
.nxp__page--glass{
  background:linear-gradient(168deg,#f8fbfd 0%,#dde7f0 62%,#cfdce8 100%);
  color:#0B1118;
}
.nxp__page--paper{
  background:#F4F1E9;
  color:#17140F;
  clip-path:inset(0 0 0 var(--nxp));
}

.nxp__eyebrow{
  font-family:var(--font-mono);font-size:.6rem;letter-spacing:.2em;
  text-transform:uppercase;margin:0 0 .85rem;opacity:.5;
}
.nxp__head{
  font-family:var(--font-head);font-weight:680;
  font-size:clamp(1.02rem,.82rem + .7vw,1.34rem);
  letter-spacing:-.025em;line-height:1.14;margin:0 0 .8rem;
}
.nxp__body{
  font-size:clamp(.68rem,.6rem + .28vw,.8rem);
  line-height:1.62;margin:0;opacity:.78;
}
.nxp__rule{display:block;height:1px;margin:1.05rem 0;background:currentColor;opacity:.16}

/* glossy: a room reflected across the panel, always drifting */
.nxp__glare{
  position:absolute;inset:-6%;
  pointer-events:none;
  background:
    linear-gradient(116deg,transparent 26%,rgba(255,255,255,.80) 34%,rgba(255,255,255,.26) 41%,transparent 48%),
    linear-gradient(116deg,transparent 58%,rgba(10,24,38,.14) 65%,rgba(10,24,38,.07) 77%,transparent 86%);
  animation:nxpGlare 9.5s var(--ease-in-out) infinite alternate;
}
@keyframes nxpGlare{
  from{transform:translate3d(-9%,-5%,0)}
  to{transform:translate3d(9%,5%,0)}
}

/* matte: a fine tooth across the whole surface, and no reflection at all */
.nxp__grain{
  position:absolute;inset:0;pointer-events:none;
  opacity:.55;mix-blend-mode:multiply;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='170' height='170'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='170' height='170' filter='url(%23n)' opacity='.34'/%3E%3C/svg%3E");
  background-size:170px 170px;
}

/* the seam, drawn from the same variable that drives the clip */
.nxp__seam{
  position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(90deg,
    transparent calc(var(--nxp) - 22px),
    rgba(111,198,236,.09) calc(var(--nxp) - 4px),
    rgba(111,198,236,.55) calc(var(--nxp) - 1px),
    #4FB4DE var(--nxp),
    rgba(111,198,236,.30) calc(var(--nxp) + 1px),
    rgba(111,198,236,.07) calc(var(--nxp) + 5px),
    transparent calc(var(--nxp) + 22px));
}

.nxp__tag{
  position:absolute;bottom:11px;
  font-family:var(--font-mono);font-size:.58rem;letter-spacing:.15em;
  text-transform:uppercase;padding:.3rem .5rem;line-height:1;
  border-radius:2px;pointer-events:none;
}
.nxp__tag--a{left:11px;color:#3C4B5C;background:rgba(255,255,255,.78);border:1px solid rgba(12,26,40,.14)}
.nxp__tag--b{right:11px;color:#0D75A8;background:rgba(244,241,233,.9);border:1px solid rgba(29,156,215,.32)}

/* the stylus rests against the edge and breathes */
.nxp__stylus{
  position:absolute;
  top:16%;right:-13px;
  width:11px;height:54%;
  border-radius:6px;
  background:linear-gradient(90deg,#141f29 0%,#44535f 40%,#1b2732 100%);
  box-shadow:0 22px 34px -22px rgba(10,24,38,.75);
  transform:rotate(9deg);
  animation:nxpStylus 7.5s var(--ease-in-out) infinite alternate;
}
.nxp__stylus::after{
  content:"";position:absolute;left:1.5px;bottom:-9px;
  width:7px;height:11px;border-radius:0 0 4px 4px;
  background:linear-gradient(180deg,#2a3844,#0d151d);
  clip-path:polygon(0 0,100% 0,62% 100%,38% 100%);
}
@keyframes nxpStylus{
  from{transform:rotate(8.4deg) translate3d(0,-9px,0)}
  to{transform:rotate(11deg) translate3d(0,9px,0)}
}

/* --------------------------------------------------------------------------
   The control. A real range input carries the interaction, so dragging,
   tapping and the arrow keys all work and the comparison is announced to
   assistive technology. The visible handle rides the same variable as the
   clip and the seam.
   -------------------------------------------------------------------------- */
.nxp__range{
  position:absolute;inset:0;z-index:4;
  width:100%;height:100%;margin:0;padding:0;
  -webkit-appearance:none;appearance:none;
  background:transparent;
  cursor:ew-resize;
  touch-action:pan-y;
}
.nxp__range:focus{outline:none}
.nxp__range::-webkit-slider-runnable-track{height:100%;background:transparent}
.nxp__range::-webkit-slider-thumb{
  -webkit-appearance:none;appearance:none;
  width:52px;height:100%;
  background:transparent;border:0;
  cursor:ew-resize;
}
.nxp__range::-moz-range-track{height:100%;background:transparent}
.nxp__range::-moz-range-thumb{
  width:52px;height:100%;
  background:transparent;border:0;border-radius:0;
  cursor:ew-resize;
}

.nxp__handle{
  position:absolute;z-index:5;
  top:50%;left:var(--nxp);
  width:46px;height:46px;
  margin:-23px 0 0 -23px;
  border-radius:50%;
  display:flex;align-items:center;justify-content:center;
  background:rgba(255,255,255,.94);
  color:var(--navy);
  box-shadow:0 0 0 1px rgba(10,24,38,.12),0 6px 18px -6px rgba(10,24,38,.45);
  pointer-events:none;
  transition:transform .32s var(--ease-out),box-shadow .32s var(--ease-out);
}
.nxp__handle svg{width:22px;height:22px}
@media (hover:hover) and (pointer:fine){
  .nxp__range:hover ~ .nxp__handle{transform:scale(1.09)}
}
.nxp__range:active ~ .nxp__handle{transform:scale(1.04);box-shadow:0 0 0 1px rgba(10,24,38,.18),0 3px 10px -4px rgba(10,24,38,.5)}
.nxp__range:focus-visible ~ .nxp__handle{
  box-shadow:0 0 0 3px var(--blue),0 0 0 6px rgba(29,156,215,.28),0 6px 18px -6px rgba(10,24,38,.45);
}

/* One pass on arrival, to show the seam moves. It is not a loop: the first
   drag cancels it and the reader owns the position from then on. */
@media (prefers-reduced-motion:no-preference){
  .nxp.in{animation:nxpIntro 1.6s var(--ease-out) .35s both}
  .nxp.is-set{animation:none}
}
@keyframes nxpIntro{
  from{--nxp:84%}
  to{--nxp:52%}
}

@media (max-width:1040px) and (min-width:901px){
  .nxp__stylus{display:none}
}
@media (max-width:560px){
  /* The stylus stays on phones. The instrument gives up a little width so
     the stylus has somewhere to rest: leaving it hanging off the edge would
     make the whole page scroll sideways, which is worse than losing it. */
  .nxp{max-width:calc(100% - 30px)}
  .nxp__stylus{right:-16px;width:9px;height:50%}
  .nxp__device{aspect-ratio:4/5}
}

@media (prefers-reduced-motion:reduce){
  .nxp{--nxp:52%}
  .nxp.in,.nxp__glare,.nxp__stylus{animation:none}
  .nxp__stylus{transform:rotate(9deg)}
  .nxp__handle{transition:none}
}

/* --------------------------------------------------------------------------
   A.2 SWIPE AFFORDANCE
   On touch the rail is swiped, not scrubbed, so it says so once and then
   gets out of the way as soon as the reader moves it.
   -------------------------------------------------------------------------- */
.rail__hint{
  display:none;
  align-items:center;gap:.45rem;
  font-family:var(--font-mono);font-size:var(--t-xs);letter-spacing:.14em;
  text-transform:uppercase;color:rgba(255,255,255,.5);
  margin-top:.9rem;
}
.rail__hint svg{width:15px;height:15px;color:var(--cyan)}
@media (max-width:880px){
  .rail__hint{display:flex}
  .rail.is-swiped .rail__hint{opacity:0;transition:opacity .4s var(--ease-out)}
}
@media (prefers-reduced-motion:no-preference){
  .rail__hint svg{animation:hintNudge 2.6s var(--ease-in-out) infinite}
  @keyframes hintNudge{
    0%,100%{translate:0 0}
    45%{translate:5px 0}
  }
}
