/* ==========================================================================
   FELT SHARK — PERSISTENT APP NAV
   --------------------------------------------------------------------------
   ONE nav for every app screen. Before this, the rail existed only inside
   table.html and pup-tank.html as hand-copied markup, so every other screen
   (Academy, Ask Tiger, Hand Analysis, Skills, Settings...) simply had no way
   back and no sense of place.

   It is position:fixed, and app-nav.js adds matching padding to <body>, so it
   drops into any existing page layout without restructuring that page.

   The ACTIVE item is green with a green caret -- "you are here".
   ========================================================================== */

:root {
  /* ⭐⭐ THE RAIL'S LOCKED LABEL, AND IT IS MEASURED AGAINST THE RAIL'S OWN
     GROUND. #7F8B87 = 4.60:1 over the composited stack a locked item actually
     sits on: rgba(34,221,187,.12) over rgba(3,12,18,.94) over black, which
     resolves to rgb(6.6, 36.4, 37.3) at luminance 0.01467.
     ⛔⛔ IT REPLACES A COPIED CONSTANT. `#79827E` was written here-and-in
     academy.css with the same "measured, not chosen by eye" claim attached --
     and it WAS measured, against `.level-tab`'s background, where it gives
     4.67:1. On the rail it gives 4.10, below the floor, on the one control
     that says where you are. One value cannot be the dimmest tint of two
     different grounds.
     ⚠️ IT LIVES HERE AND NOT IN nav-buttons.css because EIGHT pages mount the
     rail without that file -- paywall, start, welcome, pup-tank, table and the
     three recovery pages -- so a token declared there would resolve to nothing
     on the screens somebody reaches when they are locked out. check_nav_css
     proves all 28 rail pages load THIS file. #19's rule holds: this file
     declares the base, nav-buttons.css owns the responsive overrides.
     ⭐ 4.60 rather than the bare 4.5 (#7E8986) leaves a step of margin, and
     the LOCK is carried by the padlock and its number rather than by dimness
     -- FEATURE_GATING_v8: "a lock WITH a number is a date." */
  --nav-locked: #7F8B87;

  /* DOUBLED, to match the table's nav. Eric asked for the nav buttons to be
     2x on the tables; the shared rail on every other screen has to agree or
     the app reads as two different products. The item is a ROW (icon beside
     label) for the same reason it is on the table: eight items have to fit the
     viewport height, so the growth has to be horizontal. */
  /* Eric, 2026-08-16: "cut it almost in half width wise, but it is nice
     and big now" — so the WIDTH halves and the type does NOT shrink with
     it. The label wraps to a second line instead (ASK TIGER, HAND
     ANALYSIS), which is what buys the width back without touching
     legibility, and the row keeps its full height so the tap target is
     unchanged. Was clamp(150px, 16vw, 250px). */
  /* Two corrections in one day: "cut it almost in half" took this from
     clamp(150,16vw,250) to clamp(88,8.5vw,132), and that overshot --
     "the nav buttons are too small". Landing between the two. Still a
     real reduction from 250 at the top end, but the touch target and the
     type stay generous, which is the point for a 50+ audience. */
  --fs-nav-w: clamp(124px, 12vw, 176px);
  /* ⛔⛔ `--fs-nav-green` IS NOT DECLARED HERE ANY MORE, AND THAT IS THE FIX.
     It said `#64DC83` -- the retired green -- while `nav-buttons.css` aliases
     the same name to the teal accent. Two `:root` declarations of one custom
     property, equal specificity, so the winner was whichever <link> came
     last: settings.html links this file SECOND and rendered the whole rail
     in rgb(100,220,131) while all twenty-nine other pages rendered
     rgb(34,221,187). Eric found it by clicking Settings.
     ⭐ `nav-buttons.css` owns the accent (its own header says why), so the
     only declaration lives there and no load order can change the answer.
     ⚠️ Same division as #19: this file declares the base, that file owns the
     accent and every responsive override. */
  --fs-nav-idle: #8A9490;
}

.fs-nav {
  position: fixed;
  left: 0; top: 0; bottom: 0;
  width: var(--fs-nav-w);
/* ⭐⭐ EVER PRESENT — Eric, 2026-09-11: "the nav panel NEVER disappears. A
   student can ALWAYS go somwhere using the nav panel. Even when we ask them
   to give feedback and contact us."
   ⛔ App overlays are `position:fixed;inset:0` at 9000-10000 (feedback
   survey, stat explanation, level intro, graduation, delete account) and the
   rail was 400, so each of them buried the only way out. Measured on
   ask-tiger and table-layout: a full-screen card with no rail behind it.
   ⚠️ 99000 is deliberately BELOW the two gates that must cover everything:
   the age gate (100000) is a legal gate before entry, and the rotate notice
   (99999) says the device is the wrong way round -- a rail you can press
   behind either of those would be a way past a gate.
   guard:check_nav_always */
  z-index: 99000;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 2px;
  padding: 10px 5px;
  overflow-y: auto;
  overflow-x: hidden;
  background: rgba(3, 12, 18, 0.94);
  border-right: 1px solid rgba(255, 255, 255, 0.08);
  backdrop-filter: blur(4px);
  font-family: var(--font-display, 'Space Grotesk', sans-serif);
  -webkit-overflow-scrolling: touch;
}

/* ---- THE RAIL SCROLLS, AND NOW IT SAYS SO -----------------------------
   app-nav.js sets .has-more / .has-less. A gradient over the edge is the
   affordance every scrollable list uses, and it costs no height -- which
   matters here, because height is the thing there is none of.

   ⚠️ Pinned with position:sticky INSIDE the scroller, not fixed to the
   viewport: the rail IS the scrolling box, so a fixed overlay would sit
   still while the rail moved under it and fade the wrong rows. */
.fs-nav::before,
.fs-nav::after {
  content: '';
  position: sticky;
  left: 0; right: 0;
  height: 26px;
  margin: 0 -5px;                 /* cancel the rail's own 5px side padding */
  flex: 0 0 auto;
  pointer-events: none;
  opacity: 0;
  transition: opacity .18s ease;
  z-index: 2;
}
.fs-nav::before { top: 0;    margin-bottom: -26px;
  background: linear-gradient(to bottom, rgba(3,12,18,.94), rgba(3,12,18,0)); }
.fs-nav::after  { bottom: 0; margin-top: -26px;
  background: linear-gradient(to top,    rgba(3,12,18,.94), rgba(3,12,18,0)); }
.fs-nav.has-less::before { opacity: 1; }
.fs-nav.has-more::after  { opacity: 1; }

/* ⛔ In bottom-bar mode the rail is a ROW and there is no vertical overflow
   to hint at; a gradient there would just dim two tabs. */
@media (max-width: 600px) {
  .fs-nav::before, .fs-nav::after { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .fs-nav::before, .fs-nav::after { transition: none; }
}

.fs-nav-brand {
  display: block;
  border: none;
  background: none;
  cursor: pointer;
  color: var(--fs-nav-green);
  font-weight: 700;
  font-size: clamp(15px, 1.8vw, 20px);
  letter-spacing: 0.06em;
  line-height: 1.05;
  text-align: center;
  padding: 6px 0 12px;
}

.fs-nav-item {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  width: 100%;
  min-height: 44px;              /* touch target floor */
  padding: 8px 2px;
  border: none;
  background: none;
  cursor: pointer;
  border-radius: 8px;
  color: var(--fs-nav-idle);
  transition: color .15s, background .15s;
}
.fs-nav-item:hover { color: #F4F6F5; background: rgba(255,255,255,0.05); }
.fs-nav-item:focus-visible { outline: 2px solid var(--fs-nav-green); outline-offset: -2px; }

/* Icon and label sizes are NOT reduced with the panel width — the width
   came down, the buttons did not. */
.fs-nav-item .fs-nav-ico { font-size: clamp(27px, 2.6vw, 34px); line-height: 1; }
.fs-nav-item .fs-nav-lbl {
  font-size: clamp(13px, 1.15vw, 16px);
  letter-spacing: 0.03em;
  text-align: center;
  line-height: 1.15;
}

/* ---- "you are here" -------------------------------------------------------
   Green text + a green caret. The caret is a real element so screen readers
   get aria-current instead of relying on colour alone. */
.fs-nav-item.is-active {
  color: var(--fs-nav-green);
  background: var(--nav-accent-soft);
}
/* ⭐ THE ACTIVE MARKER IS ON BOTH EDGES. Eric, 2026-08-19: "can you make the
   neon green line that is on the LEFT side... be on the left AND right? This is
   easier to see which FEATURE we are on."

   One edge reads as a list bullet -- an ornament at the start of a row. Two
   edges read as a bracket around the whole item, which is what "you are here"
   should look like, and it survives being seen out of the corner of the eye.
   ::before is the left rail, ::after the right; the rounding on each faces
   inward so they read as one enclosure rather than two stray marks. */
.fs-nav-item.is-active::before,
.fs-nav-item.is-active::after {
  content: '';
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  /* ⛔ `height: 62%` MADE THE MARK A DIFFERENT LENGTH ON ONE ITEM. Tour is the
     only rail item with `sep: true`, and its divider adds 13px of padding, so
     its box is ~82px against ~73px — 62% of which is 50.8px against 45.3px.
     The "you are here" mark means ONE thing, so it must look like one thing on
     every item; a percentage ties it to whatever padding an item happens to
     carry. ⭐ 45px is the height nine of the ten already had, measured, not
     chosen. */
  width: 3px; height: 45px;
  background: var(--fs-nav-green);
  box-shadow: 0 0 8px var(--nav-accent-glow);
}
.fs-nav-item.is-active::before { left: 0;  border-radius: 0 3px 3px 0; }
.fs-nav-item.is-active::after  { right: 0; border-radius: 3px 0 0 3px; }
.fs-nav-item .fs-nav-caret {
  position: absolute;
  right: 4px; top: 50%;
  transform: translateY(-50%);
  font-size: clamp(11px, 1.1vw, 15px);
  font-weight: 700;
  color: var(--fs-nav-green);
  opacity: 0;
  transition: opacity .15s;
}
.fs-nav-item.is-active .fs-nav-caret { opacity: 1; }

.fs-nav-item.is-disabled { opacity: .38; cursor: not-allowed; }
.fs-nav-item.is-disabled:hover { background: none; color: var(--fs-nav-idle); }

/* narrow screens: icons only */
/* ⛔ THE 900px HIDE LIVES IN nav-buttons.css NOW, AND IT HAD TO.
   This block said `.fs-nav-brand { display: none }` below 900px. But
   nav-buttons.css declares `.fs-nav-brand { display: flex }` with no media
   query at all, at the same specificity, and it is linked AFTER this file —
   so the later unconditional rule beat the earlier conditional one and THE
   BRAND SHOWED ON EVERY PHONE. Measured at 667x375: 30px of logo plus its
   gap, on a rail that was already 35px short of fitting its six
   destinations, with a rule in the stylesheet insisting it was hidden.
   ⚠️ Exactly the shape of the --fs-nav-w bug three notes below: two files
   styling one thing, resolved by link order. Same fix — this file declares
   the BASE, nav-buttons.css owns every responsive override. */
@media (max-width: 900px) {
  .fs-nav-lbl { display: none; }
  /* ⛔ --fs-nav-w IS NOT SET HERE ANY MORE. It said 112px, and
     nav-buttons.css §2b.3 sets 96px inside a @media with the IDENTICAL
     condition -- same property, same breakpoint, two files, two values.
     Which one won was decided by <link> ORDER, so the rail measured 96px
     on academy.html and 112px on settings.html, on the same phone, in the
     same session. Neither page was wrong about anything it could see.
     ⭐ Ownership is now clean: this file declares the BASE width at :root
     and nav-buttons.css owns every responsive override (900px and 600px).
     Guarded by tools/check_nav_css.py. */
}

/* ==========================================================================
   ⭐⭐ A DIALOG STOPS SHORT OF THE RAIL -- Eric, 2026-09-11: "It covers the
   content area, the nav rail stays visible and clickable down the left the
   whole time. You can always leave."

   ⛔⛔ THIS IS NOT A STACKING FIX, AND FOUR ATTEMPTS AT ONE FAILED.
   MEASURED on table-layout.html with each overlay actually open: the rail is
   z-index 99000 in the ROOT stacking context, `.se-scrim` is 900, and the
   scrim still won `elementFromPoint` at the rail's own centre. A full-screen
   `inset:0` veil COVERS the rail's column; no z-index changes that.

   ⭐ `--fs-veil-left` IS PUBLISHED BY js/app-nav.js FROM THE RAIL'S MEASURED
   RIGHT EDGE. One copy, derived from the element, so it is right for the
   fixed rail, for the inline scene rail (sized by a grid track this file does
   not own) and for the off-canvas drawer, which publishes 0 and lets the veil
   cover the screen. ⛔ Never a length typed here: the scene rail's
   `clamp(140px,13%,190px)` is a percentage of `.shell`, and a fixed veil
   resolves percentages against the viewport -- two different boxes.

   ⚠⚠ (0,2,0) ON PURPOSE. Every one of these six veils injects its own
   `inset:0` into a runtime <style>, which lands LATER in document order than
   this stylesheet -- so a bare `.se-scrim` here would lose on order while
   looking perfectly correct in source. #19 and #21: raise specificity, never
   reorder and hope. `:root` is (0,1,0), so `:root .se-scrim` is (0,2,0) and
   does not depend on link order at all.
   ⭐ The fallback is 0px, so a page that never mounts a rail is unaffected.
   guard:check_nav_always
   ========================================================================== */
:root .se-scrim,
:root .fs-sv-wrap,
:root .fs-li-veil,
:root .fs-del-wrap,
:root .fs-fb-wrap,
:root .fs-cer-veil { left: var(--fs-veil-left, 0px); }
