/* ================================================================
   Product page: desktop layout correction and motion layer
   Version 1.40.2

   Enqueue AFTER sidenotes-routes-spec-product. Declares no colour,
   no type size and no new token. Everything is scoped to
   .sn-product, so the header, navigation and footer cannot be
   reached from here.

   ----------------------------------------------------------------
   HOW THE SHELL LIST WAS CHOSEN

   Version 1.40.0 applied a two column shell to fourteen sections
   picked by reading the markup. Measuring the rendered page proved
   half of those wrong.

   The measurement: for every section, the horizontal extent of the
   actual ink inside .sec-body as a fraction of the wrap it sits in.
   Taken on all four university pages at 1440, patch off.

     admission      0.18 to 0.26
     certificate    0.38 to 0.51
     fees           0.45
     othersubjects  0.46 to 0.88
     services       0.51 to 0.94
     commitment     0.51
     highlights     0.77 to 0.81
     everything else 0.93 to 0.94

   Twelve of the eighteen sections were already using their width.
   Their bodies hold an attribute grid, a tab rail, a chip row or a
   table, all of which span. Putting one of those inside an 820px
   body column shrinks something that was already correct, and the
   first pass measurably made four sections worse: location, whofor,
   overview and exams each lost 0.13 to 0.15 of their utilisation.

   othersubjects is excluded despite measuring 0.46 on one page: it
   gained 0.08 on Amity and lost 0.02 on Manipal while growing 39px
   taller, so it is a wash that costs height. A change that does not
   clearly win does not ship.

   So the shell applies to the narrow sections only. Two of them vary
   by university, because a section that is prose on one page carries
   a table on another, so the selector uses :has() to opt out per
   page rather than per section. Browsers without :has() get the page
   exactly as it is today, which is the right fallback for a layout
   enhancement.
   ================================================================ */

@supports selector(:has(*)){
@media(min-width:1100px){

  .sn-product :is(#certificate,#fees,#admission,#commitment,#services,
                  #excludes,#payment,#entrance)
    > .wrap:not(:has(.lv,.rail-grid,.tabs,.hgrid,.roles-grid,.tscroll,
                     .tflat,.grid-head,.fgrid,table)){
    display:grid;
    grid-template-columns:300px minmax(0,1fr);
    column-gap:var(--s-8);
    align-items:start;
  }

  .sn-product :is(#certificate,#fees,#admission,#commitment,#services,
                  #excludes,#payment,#entrance)
    > .wrap:not(:has(.lv,.rail-grid,.tabs,.hgrid,.roles-grid,.tscroll,
                     .tflat,.grid-head,.fgrid,table))
    > .sec-head{
    grid-column:1;
    position:sticky;
    top:calc(var(--hdr) + 72px);
    margin-bottom:0;
  }

  .sn-product :is(#certificate,#fees,#admission,#commitment,#services,
                  #excludes,#payment,#entrance)
    > .wrap:not(:has(.lv,.rail-grid,.tabs,.hgrid,.roles-grid,.tscroll,
                     .tflat,.grid-head,.fgrid,table))
    > .sec-body{
    grid-column:2;
  }

  /* In the gutter the heading is a label, not a banner. */
  .sn-product .wrap > .sec-head h2{
    font-size:clamp(21px,1.7vw,27px);
    line-height:1.15;
    letter-spacing:-0.02em;
  }
  .sn-product .wrap > .sec-head .sec-sub{
    max-width:none;
    font-size:var(--fs-sm);
    margin-top:var(--s-3);
  }

  /* The body column is 796px, so caps sized for a 1160px wrap should
     give way. */
  .sn-product .fee-card{max-width:none}
  .sn-product .prose{max-width:74ch}
}
}

/* ---------------------------------------------------------------
   Full width sections that were still ragged
   --------------------------------------------------------------- */

@media(min-width:1100px){
  /* The six ranking marks were a wrapping flex row, so six content
     widths produced three ragged rows. Against a dark band the
     ragged right edge is the most visible thing on the screen. */
  .sn-product .marks{
    display:grid;
    grid-template-columns:repeat(3,minmax(0,1fr));
    gap:var(--s-4);
  }
  .sn-product .mark{margin:0}
}

/* ---------------------------------------------------------------
   Rhythm. Desktop only. Mobile was already correct.
   --------------------------------------------------------------- */

@media(min-width:1100px){
  .sn-product > section{padding-top:var(--s-7);padding-bottom:var(--s-7)}
  .sn-product .band{padding:var(--s-7) 0}
  .sn-product .sec-head{margin-bottom:var(--s-5)}
}

/* The hero left column bottomed out above the form card, collecting
   the slack at the bottom as a void under the badges. */
@media(min-width:1101px){
  .sn-product .phero .wrap{align-items:stretch}
  .sn-product .phero-main{display:flex;flex-direction:column}
  .sn-product .phero-main .hbadges{margin-top:auto;padding-top:var(--s-5)}
}

/* ---------------------------------------------------------------
   Hero creative

   Measured across the 17 delivered abstract assets: the ink occupies
   26 to 50 per cent of the frame width and 22 to 68 per cent of the
   height, and never enters the right third. The brief asked for an
   open right third and got an empty two thirds. Rendered at 520px in
   the hero column the motif lands around 200px, adrift in white.

   Two corrections, neither of which needs the assets regenerated.

   1. multiply drops the white ground out against the tinted hero
      band, so the image stops reading as a pasted white rectangle.
      On a white ground it is a no-op, so it is safe everywhere.

   2. No crop and no zoom. An earlier version of this file scaled the
      image 1.25 on the measured ink centroid, because the first
      delivery carried its motif at 26 to 50 per cent of the frame
      and rendered too small. The re-cut set composes at a uniform
      64 by 60 per cent, so the zoom is no longer correcting
      anything: it now oversizes the motif and it would have to be
      re-derived every time an asset changed. The composition is
      correct in the asset, which is where it belongs.

   Verified against all 25 abstract assets, not sampled.
   --------------------------------------------------------------- */

.sn-product .phero-viz{mix-blend-mode:multiply}
.sn-product .phero-viz img{
  aspect-ratio:16/9;
  object-fit:cover;
  object-position:50% 50%;
}

/* The people variants are photographs with a full bleed frame, so
   the blend does not apply to them. */
.sn-product .phero-viz img[src*="-people-"]{
  mix-blend-mode:normal;
}

/* ================================================================
   MOTION LAYER

   Opacity and transform only, so nothing here can shift layout.
   Every rule sits inside a reduced motion guard. The reveal fails
   open: the hidden state lives under [data-reveal], which only JS
   applies, so a blocked script leaves a fully visible page rather
   than a blank one.
   ================================================================ */

@media(prefers-reduced-motion:no-preference){
  .sn-product [data-reveal]{
    opacity:0;
    transform:translateY(10px);
    transition:opacity 420ms cubic-bezier(0.2,0,0,1),
               transform 420ms cubic-bezier(0.2,0,0,1);
  }
  .sn-product [data-reveal].is-in{opacity:1;transform:none}

  .sn-product [data-reveal] > *{transition-delay:0ms}
  .sn-product [data-reveal].is-in > :nth-child(2){transition-delay:60ms}
  .sn-product [data-reveal].is-in > :nth-child(3){transition-delay:120ms}
  .sn-product [data-reveal].is-in > :nth-child(4){transition-delay:180ms}
}

/* Scroll progress, one hairline along the bottom of the jump bar.
   Adds no height and replaces nothing. */
.sn-product .jumpnav{position:sticky}
.sn-product .jumpnav::after{
  content:"";position:absolute;left:0;bottom:-1px;height:2px;width:100%;
  background:var(--teal);
  transform:scaleX(var(--sn-progress,0));
  transform-origin:0 50%;
  transition:transform 90ms linear;
  pointer-events:none;
}
@media(prefers-reduced-motion:reduce){
  .sn-product .jumpnav::after{transition:none}
}

/* Cards. A directory reads as a document, so the lift is small and
   the border does most of the work. */
@media(prefers-reduced-motion:no-preference){
  .sn-product .cards > *{
    transition:transform var(--m-hover),
               border-color var(--m-hover),
               box-shadow var(--m-hover);
  }
  @media (hover:hover) and (pointer:fine){.sn-product .cards > *:hover{
    transform:translateY(-2px);
    border-color:var(--teal);
    box-shadow:var(--lift);
  }}
}

/* Tab panels swapped instantly, which loses the reader's place. */
@media(prefers-reduced-motion:no-preference){
  .sn-product [role="tabpanel"]:not([hidden]){
    animation:sn-panel var(--m-panel) both;
  }
  @keyframes sn-panel{
    from{opacity:0;transform:translateY(6px)}
    to{opacity:1;transform:none}
  }
}

.sn-product .jumplist a{transition:color var(--m-hover),border-bottom-color var(--m-panel)}

.sn-product .fee-card .fee-figure,
.sn-product [data-count]{font-variant-numeric:tabular-nums}

/* The motion layer must not weaken the keyboard path. */
.sn-product [data-reveal] :focus-visible,
.sn-product .cards > * :focus-visible{
  outline:2px solid var(--teal);
  outline-offset:2px;
}
