/**
 * Tabs block — side rail variant (parts/page/block-tabs-rail.php).
 *
 * Loads after css/style.css (functions.php declares theme-styles as a
 * dependency), so nothing here needs !important.
 *
 * Font sizes are px, not the --text-* tokens: style.css sets
 * html { font-size: 62.5% } so 1rem = 10px and the --text-* scale (authored
 * against a 16px root) would render ~37% small. The --space-* tokens are
 * already px and are safe to use directly. Same convention as
 * css/blocks/apply-panel.css and css/blocks/semester-timeline.css.
 *
 * Nothing here targets .block-tabs__list-item / .block-tabs__tab-content, so
 * the compiled bundle.js Tabs class and this variant cannot collide.
 */

/* ---- shell ----------------------------------------------------------- */

.block-tabs--rail {
  margin: var(--space-16) 0;

  /* THE sticky fix. style.css:7330 sets `overflow: hidden` on .block-tabs, and
     this variant carries that class too, so it inherited it. overflow:hidden
     makes the block a scroll container, and a scroll container becomes the
     scrollport that any descendant position:sticky resolves against — so
     .tabs-rail__nav-inner below was sticking to a box that never scrolls
     (i.e. not sticking at all, just scrolling away with the page), AND having
     its `top` inset applied as a plain offset from the block's top even at
     rest, which pushed the rail down the page instead of starting it flush.
     Both reported symptoms, one cause.

     overflow-x:clip keeps a horizontal-overflow guard (what the original rule
     was presumably for) while NOT creating a scroll container — that is
     precisely how `clip` differs from `hidden`, and it is why overflow-y must
     stay `visible` here rather than hidden/clip-with-scrollport semantics.
     Declaration order matters: engines without `overflow-x: clip` support drop
     that line as invalid and keep `overflow: visible`, which still sticks. */
  overflow: visible;
  overflow-x: clip;
}

/* style.css:7324 zeroes .block-tabs's bottom margin when it's the page's
   last block, so its own compensating padding on .block-tabs__tab-content
   (style.css:7487) is the only thing standing between the tab content and
   the footer. .tabs-rail__panel has no such padding, so on this variant
   that rule alone leaves zero gap and the content runs flush into the
   footer. Same fix, same intent, just restoring a smaller margin instead of
   adding panel padding: not the full --space-16 rhythm of a block followed
   by more page content, but not flush either. */
.page-content > .block-tabs--rail:last-child {
  margin-bottom: var(--space-8);
}

.tabs-rail {
  display: block;
}

/* Nav is [hidden] until JS enhances. Belt-and-braces: some resets set
   display on divs and beat the UA [hidden] rule. */
.tabs-rail__nav[hidden] {
  display: none;
}

/* ---- title ------------------------------------------------------------ */

/* DOM order is title -> nav -> panels (mobile/no-JS reads correctly stacked
   in that order). At >= 992px the grid below re-places .tabs-rail__title
   into the content column's own top row via grid-area, independent of DOM
   order, so its top edge lines up with the rail's "On this page" eyebrow
   instead of spanning full-width above the whole two-column layout. */
.tabs-rail__title {
  margin: 0 0 var(--space-8);
}

.tabs-rail__title > *:first-child {
  margin-top: 0;
}

/* ---- desktop: two columns, rail left -------------------------------- */

@media (min-width: 992px) {
  .tabs-rail.is-enhanced {
    display: grid;
    grid-template-columns: minmax(180px, 260px) minmax(0, 1fr);
    grid-template-rows: auto 1fr;
    grid-template-areas:
      "nav title"
      "nav panels";
    column-gap: var(--space-12);
    align-items: start;
  }

  .tabs-rail.is-enhanced .tabs-rail__title {
    grid-area: title;
    margin-bottom: var(--space-6);
  }

  /* align-items: start above sizes every grid item to its own content
     height. .tabs-rail__nav spans both rows, so without an override its box
     shrinks to the short nav content instead of stretching down to match
     title + panels — leaving the sticky child inside it (below) with no
     room to stay pinned once the page scrolls past that short box, so it
     scrolls away instead of tracking the (much taller) panel content. */
  .tabs-rail.is-enhanced .tabs-rail__nav {
    grid-area: nav;
    align-self: stretch;
  }

  /* Sticky lives on this inner wrapper rather than on .tabs-rail__nav itself.
     NOTE: the older comment here (and in block-tabs-rail.php) blamed a
     "row-spanning grid item" for an at-rest ~90px downward shift and treated
     this indirection as the cure. That was a misdiagnosis — the shift came
     from .block-tabs's `overflow: hidden` making the block a scrollport (see
     the .block-tabs--rail rule at the top of this file), which applied the
     `top` inset as a static offset from the block's top. With that reset, a
     row-spanning grid item sticks correctly. The indirection is kept only
     because it is harmless and .tabs-rail__nav is the thing that must carry
     grid-area/align-self; moving sticky back up would buy nothing.

     At rest the rail sits at its normal flow position, flush with the
     title/panels column. The top offset engages only once scrolling would
     otherwise carry it closer to the viewport top than the fixed .main-header
     is tall, so it clears the header instead of tucking underneath it.
     --main-header-height is the same live-measured variable .page-hero etc.
     use (set on documentElement by the inline script at header.php:57) — the
     header's real height varies by breakpoint, so a hardcoded px value drifts
     out of sync and lets the header overlap the rail. */
  .tabs-rail.is-enhanced .tabs-rail__nav-inner {
    position: sticky;
    top: calc(var(--main-header-height, 111px) + var(--space-4));
  }

  .tabs-rail.is-enhanced .tabs-rail__panels {
    grid-area: panels;
  }
}

.tabs-rail__eyebrow {
  margin: 0 0 var(--space-4);
  color: var(--color-grey-700);
  /* .c-eyebrow is 1.4rem = 14px at the 10px root; nudge down for a label. */
  font-size: 12px;
}

/* ---- the list ------------------------------------------------------- */

/* offsetParent for the JS scroll math: tab.offsetLeft must be relative to
   the scroller, not to some ancestor. */
.tabs-rail__scroller {
  position: relative;
}

.tabs-rail__list {
  display: flex;
  flex-direction: row;
  /* NO gap. The hairline is each item's own left/bottom border; a gap would
     chop it into dashes. Spacing comes from the tabs' padding. */
  gap: 0;
}

.tabs-rail__tab {
  -webkit-appearance: none;
  appearance: none;
  display: block;
  margin: 0;
  border: 0;
  background: none;
  font-family: var(--font-body);
  font-size: 16px;
  font-weight: var(--weight-medium);
  line-height: var(--leading-tight);
  color: var(--color-grey-700);
  text-align: left;
  cursor: pointer;
  transition: color 160ms ease, border-color 160ms ease, background-color 160ms ease;
}

.tabs-rail__tab:hover {
  color: var(--nu-cool-black);
}

.tabs-rail__tab:focus-visible {
  outline: var(--focus-ring);
  /* Negative offset, not the usual +2px: on the mobile scroller a ring that
     sits outside the button is the first thing the edge mask fades out. */
  outline-offset: -2px;
}

/* ================= mobile / tablet: horizontal strip ================== */

@media (max-width: 991px) {
  .tabs-rail__nav {
    margin: 0 0 var(--space-8);
  }

  .tabs-rail__scroller {
    overflow-x: auto;
    overflow-y: hidden;
    overscroll-behavior-x: contain;
    -webkit-overflow-scrolling: touch;

    /* No visible scrollbar, all engines. */
    scrollbar-width: none;          /* Firefox */
    -ms-overflow-style: none;       /* legacy Edge */

    /* Edge fade. Driven by two custom props so a single mask declaration
       serves all four states; js/tabs-rail.js toggles the classes below. */
    --fade: 32px;
    --fade-start: 0px;
    --fade-end: 0px;
    -webkit-mask-image: linear-gradient(
      to right,
      transparent 0,
      #000 var(--fade-start),
      #000 calc(100% - var(--fade-end)),
      transparent 100%
    );
    mask-image: linear-gradient(
      to right,
      transparent 0,
      #000 var(--fade-start),
      #000 calc(100% - var(--fade-end)),
      transparent 100%
    );
  }

  .tabs-rail__scroller::-webkit-scrollbar {
    display: none;                  /* Chrome / Safari */
  }

  .tabs-rail__scroller.has-overflow-start { --fade-start: var(--fade); }
  .tabs-rail__scroller.has-overflow-end   { --fade-end: var(--fade); }

  .tabs-rail__list {
    /* Nowrap + w-max so items keep intrinsic width and overflow instead of
       squashing. */
    flex-wrap: nowrap;
    width: max-content;
    min-width: 100%;
    border-bottom: 1px solid var(--color-grey-300);
  }

  .tabs-rail__tab {
    flex: 0 0 auto;
    padding: var(--space-3) var(--space-4);
    /* 44px WCAG 2.5.8 target. */
    min-height: 44px;
    white-space: nowrap;
    /* The strip's hairline lives on the list; the active segment is this
       2px underline, sitting on top of it (translateY(1px) covers the grey). */
    border-bottom: 2px solid transparent;
    transform: translateY(1px);
  }

  .tabs-rail__tab[aria-selected="true"] {
    color: var(--nu-cool-black);
    font-weight: var(--weight-bold);
    border-bottom-color: var(--color-brand-red);
  }

  /* First/last item flush with the text column. */
  .tabs-rail__tab:first-child { padding-left: 0; }
  .tabs-rail__tab:last-child  { padding-right: var(--space-6); }
}

/* No mask support (older Firefox ESR, IE-era engines): drop the fade rather
   than paint a gradient in a guessed background colour — see note in the
   implementation plan. The scroller still works, it just has a hard edge. */
@media (max-width: 991px) {
  @supports not ((-webkit-mask-image: linear-gradient(#000, #000)) or (mask-image: linear-gradient(#000, #000))) {
    .tabs-rail__scroller {
      -webkit-mask-image: none;
      mask-image: none;
    }
    /* Cheap affordance in place of the fade. */
    .tabs-rail__scroller.has-overflow-end .tabs-rail__list {
      padding-right: var(--space-6);
    }
  }
}

/* ===================== desktop: vertical hairline ===================== */

@media (min-width: 992px) {
  .tabs-rail__list {
    flex-direction: column;
    /* The continuous hairline is the SUM of the items' own left borders.
       Because the items are contiguous (no gap, no margin) the 2px borders
       butt together into one unbroken line, and the active item simply
       recolours its own segment — no absolutely-positioned overlay, no JS
       measuring of offsets, and it survives wrapped 2-line labels. */
    border-left: 0;
  }

  .tabs-rail__tab {
    width: 100%;
    padding: var(--space-3) var(--space-2) var(--space-3) var(--space-4);
    border-left: 2px solid var(--color-grey-300);
    white-space: normal;
  }

  .tabs-rail__tab:hover {
    border-left-color: var(--color-grey-700);
    background-color: var(--color-grey-100);
  }

  .tabs-rail__tab[aria-selected="true"] {
    color: var(--nu-cool-black);
    font-weight: var(--weight-bold);
    border-left-color: var(--color-brand-red);
  }

  .tabs-rail__tab[aria-selected="true"]:hover {
    border-left-color: var(--color-brand-red-dark);
    background-color: transparent;
  }
}

/* ---- panels ---------------------------------------------------------- */

.tabs-rail__panel[hidden] {
  display: none;
}

.tabs-rail__panel:focus-visible {
  outline: var(--focus-ring);
  outline-offset: var(--focus-ring-offset);
}

.tabs-rail__panel > *:first-child {
  margin-top: 0;
}

/* WYSIWYG content headings — editors write an h3 matching the tab name as
   the visible in-panel title (the real title is the visually-hidden
   .tabs-rail__panel-title h2 above, kept for aria-labelledby) and h4s for the
   sections within it, e.g. "Connectivity Requirements".
   A panel can carry several h4s, so giving every one of them the same loud
   red-eyebrow treatment as the h3 (previous pass) diluted the accent —
   nothing but red, no clear "this is the important line" anymore, and it
   fights the red inline links in the same paragraph. One red moment per
   panel instead: the h3 keeps the site's red-eyebrow-as-heading pattern
   (.c-eyebrow + .git__heading on "Get in Touch"), and h4 switches to this
   theme's OTHER existing pattern for a tab-content subheading — dark text,
   red left border — already used one file over by the classic (non-rail)
   variant at .block-tabs__tab-content h4 in style.css. Same accent, spent
   once instead of four times.

   :not([class]) scopes both rules to Word-pasted WYSIWYG headings, which
   never carry a class attribute. css/blocks/panel-sections.css's own
   headings (.ps__card-title, .pst__label) do carry a class and are styled
   there instead — without the scope, these bare-element rules would win on
   source order over the class-based ones with equal specificity. */
.tabs-rail__panel h3:not([class]) {
  font-family: var(--font-body);
  font-weight: var(--weight-bold);
  font-size: 2.8rem;
  color: var(--color-brand-red);
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

/* 2.2rem, not the 1.6rem this started at: the panel's body copy itself is
   2rem (style.css's WYSIWYG paragraph size), so a subheading sized below
   that read as smaller than the text under it — backwards hierarchy. This
   keeps it clearly the larger of the two while staying under h3. */
.tabs-rail__panel h4:not([class]) {
  font-size: 2.2rem;
  color: var(--nu-cool-black);
  padding-left: var(--space-3);
  border-left: 3px solid var(--color-brand-red);
}

/* Opt-out of the rule above for a legacy WYSIWYG h4 that should read as a
   red eyebrow label instead of a dark subheading with a left border — e.g.
   "Dates and Timelines" ahead of the semester timeline on Program
   Information. Same red/uppercase/letter-spaced language as the panel's
   own h3 title above, sized down since this labels a sub-element within
   the panel rather than being the panel's own title. */
.tabs-rail__panel h4.tabs-rail__heading-eyebrow {
  font-family: var(--font-body);
  font-weight: var(--weight-bold);
  font-size: 1.6rem;
  color: var(--color-brand-red);
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

/* The stacked no-JS document needs visible titles and separation; once JS
   owns the switching the tab name IS the title, so the h2 becomes redundant
   ink (it stays in the DOM for aria-labelledby / outline purposes). */
.tabs-rail:not(.is-enhanced) .tabs-rail__panel + .tabs-rail__panel {
  margin-top: var(--space-12);
}

.tabs-rail.is-enhanced .tabs-rail__panel:not(.tabs-rail__panel--structured) .tabs-rail__panel-title {
  position: absolute;
  margin: -1px;
  padding: 0;
  width: 1px;
  height: 1px;
  overflow: hidden;
  border: 0;
  clip: rect(0 0 0 0);
}

/* Structured panels (panel_sections authored) keep this h2 visible instead
   of hiding it: it's the one place the title text exists in the DOM, so
   reusing it as the visible red eyebrow avoids a second, duplicate element
   that would repeat the tab name for sighted users and, in the no-JS
   stacked state where nothing is hidden, literally print it twice. Values
   match the legacy WYSIWYG h3 rule above so the visual language is
   unchanged from what editors were hand-authoring. */
.tabs-rail__panel--structured .tabs-rail__panel-title {
  font-family: var(--font-body);
  font-weight: var(--weight-bold);
  font-size: 2.8rem;
  line-height: var(--leading-tight);
  color: var(--color-brand-red);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  margin: 0 0 var(--space-6);
}

@media (max-width: 767px) {
  .tabs-rail__panel--structured .tabs-rail__panel-title {
    font-size: 2.2rem;
  }
}

/* ---- motion ---------------------------------------------------------- */

.tabs-rail.is-enhanced .tabs-rail__panel.is-active {
  animation: tabsRailFadeIn 240ms ease both;
}

@keyframes tabsRailFadeIn {
  from { opacity: 0; }
  to   { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .tabs-rail__tab {
    transition: none;
  }

  .tabs-rail.is-enhanced .tabs-rail__panel.is-active {
    animation: none;
  }

  /* style.css gives .block-tabs__tab-content an unguarded
     `animation: fadeIn .5s`; this variant does not use that class, but the
     nested semester timeline sits under .block-tabs, so kill any inherited
     animation in this subtree too. */
  .block-tabs--rail,
  .block-tabs--rail * {
    animation: none;
  }
}
