/*
  Shared top nav bar.

  The markup is rendered by <site-nav> (js/site-nav.js), so there is exactly ONE
  copy of it for the whole site. Do not hand-write a <header class="top-nav">
  into a page -- put <site-nav current="..."> there instead and fix bugs here.

  Every number below is measured from the AxureRP original's nav master
  (files/projects-start/styles.css):

    bar               0,0    1444x66
    line             39,65   1405x1    #fff at .192 alpha, fading to 0 over
                                       the last 309.1px of its length
    name             20,0     281x65   Josefin 44px / letter-spacing 1.1px
                                       opacity .2, text flush RIGHT, text block
                                       pinned to the top with 17px padding
    tab Projects    329,12    148x54   Kumbh 26px  rgba(255,255,255,.698)
    tab About Me    477,12    176x54
    tab Contact     653,12    144x54
    chevron ->      321,27     12x26   opacity .2   #33ff00
    chevron <-        0,27     12x26   opacity .74  rotate(180deg)

  The name and all three tab labels share a baseline at y = 50. That was measured
  in the original with a zero-height baseline probe, not derived from font
  metrics -- so the construction here (paddings + flex alignment) deliberately
  mirrors the original's rather than inventing its own.
*/

/* The bar is the same fixed-width, centred canvas as the page content beneath
   it — NOT a full-bleed strip. The original's nav master is the "nav-all"
   box, 0,0 1444x66, and every coordinate below is measured against that box.

   Without an explicit width this element takes `width: auto` and fills <body>,
   which silently equals the page width only while the viewport is narrower
   than the page. On any wider window the bar stretched to the viewport while
   the content stayed centred, so the name and tabs drifted out of alignment
   with everything below them. */
.top-nav {
  position: relative;
  width: var(--page-width);
  margin: 0 auto;
  height: 66px;
}

/* The line. Sits on the nav's last pixel row and runs to the right edge. The fade
   length is absolute (309.1px from the terminus), so it holds at any width. */
.top-nav::after {
  content: "";
  position: absolute;
  left: 39px;
  right: 0;
  bottom: 0;
  height: 1px;
  background: linear-gradient(
    to right,
    rgba(255, 255, 255, 0.192) 0,
    rgba(255, 255, 255, 0.192) calc(100% - 309.1px),
    rgba(255, 255, 255, 0) 100%
  );
}

/* ---- the name ------------------------------------------------------ */

.top-nav .brand {
  position: absolute;
  left: 20px;
  top: 0;
  width: 281px;
  height: 65px;
  box-sizing: border-box;
  display: flex;
  align-items: flex-start;    /* original: align-self: flex-start */
  justify-content: flex-end;  /* original: text-align: right */
  padding-top: 17px;
  font-family: var(--font-heading);
  font-weight: 400;
  font-size: 44px;
  letter-spacing: 1.1px;
  color: var(--color-white);
  opacity: 0.2;
}

/* The original swaps opacity with no transition -- it is instant, not a fade. */
.top-nav .brand:hover,
.top-nav .brand:focus-visible {
  opacity: 0.5;
}

/* ---- the two chevrons (forward and back) --------------------------- */

/* THE SLOT — a 12x26 window with `overflow: hidden`, and the chevron slides
   INSIDE it. This is the original's own construction, not a refinement of it:
   Axure wraps every widget it slides in a container the widget's own size and
   sets `overflow: hidden` on it (visibility.js, `_makeContainer` — the `else`
   branch of the flip test), then translates the widget by exactly that width.
   The glyph is therefore never seen outside its own 12px slot; it wipes.

   THE SLOT IS WHAT MAKES THE MOVE A WIPE. Without it the glyph flies 12px
   through open space; inside it, the move is the cut edge travelling, so the
   arrow reads as shrinking out of / growing into its window. (It was first
   added to tame the source's bounce, whose 1-3px rebound hops were visible
   jitter on a bare glyph. The bounce is gone since 2026-09-11 — see "EASING"
   below — but the wipe is the whole gesture and the slot stays.)

   The slot carries the position and the opacity; the chevron inside carries the
   transform. */
.top-nav .nav-chevron-slot {
  position: absolute;
  top: 27px;
  width: 12px;
  height: 26px;
  overflow: hidden;
}

.top-nav .nav-chevron {
  display: block;
  width: 12px;
  height: 26px;
  color: var(--color-accent-dim);  /* #33ff00, sampled from the original PNG */
  stroke-width: 2.3;
}

/* Anchor positions, on the SLOT. The rest state — transform, visibility and
   the transition — is set on the chevron in the swap block below, so each
   chevron's resting and hovered states sit side by side and stay legible. */
.top-nav .nav-chevron-forward-slot {
  left: 321px;
  opacity: 0.2;
}

.top-nav .nav-chevron-back-slot {
  left: 0;
  opacity: 0.74;
}

/*
  Hovering the NAME swaps the chevrons -- forward one out, back one in, marking
  the name as a "back" affordance.

  Straight from the original's OnMouseOver / OnMouseOut action lists
  (files/about-intro/data.js):

      Hide ICON-arrow right   slide left,  ease in bounce,  300ms
      Wait 100 ms
      Show ICON-arrow left    slide right, ease out bounce, 300ms

      Hide ICON-arrow left    slide left,  ease in bounce,  300ms
      Wait 100 ms
      Show ICON-arrow right   slide right, ease in bounce,  300ms

  So both chevrons SLIDE over 300ms; the outgoing one starts immediately and
  the incoming one 100ms later, which is what puts them on screen together.
  The source's bounce is NO LONGER USED — see "EASING — OWNER'S CHANGE" below.

  This was previously built as an instant visibility swap with 100ms/300ms
  delays -- the 300ms DURATION had been read as a delay, and the slide and the
  bounce were missing entirely.

  visibility still steps (so a hidden chevron leaves the accessibility tree),
  but it is held until the outgoing slide has finished and released as the
  incoming one begins, so the movement is never cut short.

  SLIDE DISTANCE IS THE SOURCE'S OWN, 12px — corrected from an earlier note here
  that called it a choice. Axure's data records only direction, duration and
  easing, but its RUNTIME supplies the distance: `_slideStateIn` and
  `_slideStateOut` (visibility.js) take `width = axObject.width()` and move the
  widget by exactly that, having first offset it by the same amount. The
  chevron is 12px wide, so the travel is 12px. Nothing here was guessed.

  The travel happens inside the clipping slot above — see .nav-chevron-slot for
  why that is the difference between a wipe and a twitch.

  :has() keys the whole thing off the name alone rather than the nav strip.
*/
.top-nav .nav-chevron {
  transition-property: transform, visibility;
  transition-duration: 300ms, 0s;
}

/* ==========================================================================
   DIRECTION OF TRAVEL — OWNER'S CHANGE, AND IT DEPARTS FROM THE SOURCE
   ==========================================================================
   Both chevrons now travel LEFT on hover and RIGHT on unhover, so the whole
   gesture moves one way and reads as "go back".

   THE SOURCE MOVES THEM IN OPPOSITE DIRECTIONS. Traced through the runtime
   rather than inferred from the action labels:

     action.js:616        passes the raw options to $ax('#id').hide()/.show()
     axQuery.std.js:399   _setVisibility -> _getAnimateInfo(options, 0, useHide)
                          hide  -> easingHide  = "slideLeft"
                          show  -> easing      = "slideRight"
     visibility.js        _slideStateOut, direction "left"
                            -> MoveWidget(-width)          exits leftward
                          _slideStateIn, direction "right"
                            -> child.css('left', oldLeft - width)   parks LEFT
                            -> MoveWidget(+width)          enters rightward

   So on hover the export slides the forward chevron out to the LEFT while
   sliding the back chevron in from the LEFT, i.e. rightward. The two cross.
   For a control whose whole meaning is "back", that is incoherent, and it is
   what read as the arrow coming from the wrong side.

   THE FIX IS ONE VALUE: the back chevron parks 12px to the RIGHT of its slot
   instead of 12px to the left, so it travels left into place. Nothing else
   changed — not the 12px distance, not the 300ms, not the 100ms stagger, and
   not the easing (the bounce is the source's own and is a separate question).

     hover    forward  0 -> -12  (left)      back  +12 -> 0  (left)
     unhover  forward -12 -> 0   (right)     back  0 -> +12  (right)

   The clipping slot above is what makes this read as a wipe either way: at
   rest the back chevron sits wholly outside its 12x26 window and is trimmed.
   ========================================================================== */

/* ==========================================================================
   EASING — OWNER'S CHANGE 2026-09-11, AND IT DEPARTS FROM THE SOURCE
   ==========================================================================
   NO BOUNCE. The export's easeInBounce / easeOutBounce (still in base.css as
   --ease-in-bounce / --ease-out-bounce, now unused) are replaced by plain
   cubic eases, and the rule is the same in both directions:

     the chevron LEAVING its slot   ease-IN   (--ease-in-cubic)
     the chevron ARRIVING in it     ease-OUT  (--ease-out-cubic)

   Inside the clipping slot that reads as: the outgoing glyph shrinks away,
   gathering speed; the incoming one grows into the window and settles.
   The owner's own words for each of the four moves —

     hover     forward  "shrinks to the left"                 ease in
               back     "grows from the right, expands left"  ease out
     unhover   back     "shrinks from the left"               ease in
               forward  "expands from the left"               ease out

   The source gave the forward chevron ease-IN-bounce on BOTH its exit and its
   return; that asymmetry is gone. Distance (12px), 300ms, the 100ms stagger
   and the visibility steps are all untouched.
   ========================================================================== */

/* At rest: forward chevron home and visible, back chevron parked 12px to the
   RIGHT of its slot and hidden. */
.top-nav .nav-chevron-forward {
  transform: translateX(0);
  visibility: visible;
  transition-timing-function: var(--ease-out-cubic), linear;
  transition-delay: 100ms, 100ms;   /* returning: starts after the 100ms wait */
}

.top-nav .nav-chevron-back {
  transform: translateX(12px) rotate(180deg);
  visibility: hidden;
  transition-timing-function: var(--ease-in-cubic), linear;
  transition-delay: 0s, 300ms;      /* leaving: starts at once, hides after */
}

.top-nav:has(.brand:hover) .nav-chevron-forward,
.top-nav:has(.brand:focus-visible) .nav-chevron-forward {
  transform: translateX(-12px);
  visibility: hidden;
  transition-timing-function: var(--ease-in-cubic), linear;
  transition-delay: 0s, 300ms;      /* leaving: starts at once, hides after */
}

.top-nav:has(.brand:hover) .nav-chevron-back,
.top-nav:has(.brand:focus-visible) .nav-chevron-back {
  transform: translateX(0) rotate(180deg);
  visibility: visible;
  transition-timing-function: var(--ease-out-cubic), linear;
  transition-delay: 100ms, 100ms;   /* arriving: after the 100ms wait */
}

/* ---- the tabs ---------------------------------------- */

/* Both the link tabs and the current PAGE's <span> share this box; only the
   links get the hover treatment below — and a current-SECTION tab is a link,
   so it gets it too. See js/site-nav.js for the three states. */
.top-nav-tabs .tab {
  position: absolute;
  top: 12px;
  height: 54px;
  box-sizing: border-box;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 5px 2px 2px;       /* original .text padding, and it is asymmetric */
  font-family: var(--font-body);
  font-weight: 400;
  font-size: 26px;
  color: rgba(255, 255, 255, 0.698);
  transition: background-color 0.2s var(--ease-out-cubic);
}

.top-nav-tabs .nav-projects { left: 329px; width: 148px; }
.top-nav-tabs .nav-about    { left: 477px; width: 176px; }
.top-nav-tabs .nav-contact  { left: 653px; width: 144px; }

/* Hover is on `a` only, which is the point of the element choice rather than a
   `.current` exclusion: the tab for the page you are ON is a <span> and cannot
   match this, while the SAME tab on any other page in that section is an <a>
   and does. That is what makes "Projects" look clickable on a case study and
   inert on projects-start, with one selector and no state flags. */
.top-nav-tabs a.tab:hover,
.top-nav-tabs a.tab:focus-visible {
  background-color: rgba(180, 229, 245, 0.09);
}

/* Selected tab: full-white label plus a 4px accent rule. The rule is a
   pseudo-element rather than a border so it cannot shift the label's baseline
   (in the original the border lived on a separate overlay layer).

   This is the SECTION marker, so it is on the <span> and on the current-section
   <a> alike — the underline says "you are in Projects", not "this control is
   dead". */
.top-nav-tabs .tab.current {
  color: var(--color-white);
}

/* `cursor: default` belongs to inertness, not to selectedness, so it is on the
   <span> only. Putting it on `.tab.current` — which is what this rule used to
   say — gave the current-section LINK an arrow cursor, telling the reader it
   was not clickable at the exact moment they needed to believe it was. */
.top-nav-tabs span.tab.current {
  cursor: default;
}

.top-nav-tabs .tab.current::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 4px;
  background: var(--color-accent);
}
