
/* ═══════════════════════════════════════════════════════════
   THE RACK — left navigation
   Replaces the boxed sidebar.

   THE PROBLEM
   Rounded card groups with icon+label rows is the Discord /
   Facebook sidebar. Recognisable at a glance as a template,
   and it fought the Forge Floor sitting next to it.

   THE IDEA
   The Keep has a spine. So does the nav. Items HANG OFF a
   vertical rule with a connector dash; the active item lights
   a node on the rule and slides toward the content. One visual
   language across the page instead of two.

   No boxes. No backdrop blur. The rail is a structure, not a
   stack of cards.
   ═══════════════════════════════════════════════════════════ */

.left-rail{
  /* ⚠️ STICKY, NOT RELATIVE — AND THIS LINE IS THE WHOLE REASON THE
     NAV SCROLLED AWAY.
     style.css makes both rails `position:sticky` with a top offset, a
     max-height and their own overflow. rack.css loads AFTER it, and
     this rule said `position:relative` — so the offset, the max-height
     and the overflow all survived and only the STICKY died. The rail
     then rode the page: on a 806px laptop window Command's last item
     (Config) sat 125px below the fold, and scrolling down to reach it
     scrolled the menu away with it.
     `relative` was only ever here so the ::before spine has something
     to anchor to. `sticky` establishes a containing block exactly the
     same way, so the spine is unaffected. Do not put it back.
     style.css even carries the warning that this is easy to break —
     see the note above .layout about overflow-x. */
  position:sticky;
  padding:26px 0 40px 26px;
  background:none !important;
  border:none !important;
}

/* The rule itself — fades in at the top, out at the bottom, so it
   reads as part of the room rather than a drawn border.
   NOTE: 18% grey at 1px was invisible against black. A structural
   line has to be seen to do its job — 2px with more contrast, and a
   faint crimson bloom so it belongs to the palette. */
.left-rail::before{
  content:'';position:absolute;left:9px;top:34px;bottom:60px;width:2px;
  border-radius:2px;
  background:linear-gradient(180deg,
    transparent 0%,
    rgba(178,34,34,.45) 6%,
    rgba(120,128,138,.30) 30%,
    rgba(120,128,138,.30) 74%,
    transparent 100%);
  box-shadow:0 0 10px rgba(224,32,32,.12);
}

/* ── Groups: no card, just spacing and a whisper of a label ── */
.rail-group{
  background:none !important;
  border:none !important;
  box-shadow:none !important;
  backdrop-filter:none !important;
  padding:0 !important;
  margin:0 0 26px !important;
  border-radius:0 !important;
}

/* Labels sit to the RIGHT of the rule so nothing has to punch a hole
   in it. The previous version painted #000 behind the label, which
   did not match the real page background and showed as a band. */
.rail-label{
  display:block;margin:0 0 10px 0;
  padding:0 0 0 20px;
  background:none !important;
  font-family:'Share Tech Mono',monospace;font-size:8px;letter-spacing:3px;
  text-transform:uppercase;color:#3a3f47 !important;
}

/* ── Items hang off the rule ── */
.rail-item{
  position:relative;display:block;
  padding:8px 12px 8px 20px;margin:0 0 1px;
  font-family:'Barlow Condensed',sans-serif;font-weight:600;font-size:13.5px;
  letter-spacing:1.6px;text-transform:uppercase;
  color:#5c636d;text-decoration:none;
  background:none !important;border:none !important;border-radius:0 !important;
  transition:color .18s, transform .18s cubic-bezier(.22,1,.36,1);
}

/* Connector dash from the rule to the item */
.rail-item::before{
  content:'';position:absolute;left:-17px;top:50%;
  width:12px;height:1px;background:rgba(154,154,159,.2);
  transform:translateY(-.5px);transition:.18s;
}
/* Node on the rule */
.rail-item::after{
  content:'';position:absolute;left:-20px;top:50%;
  width:5px;height:5px;border-radius:50%;
  background:#23262b;transform:translate(0,-2.5px);
  transition:.2s;
}

.rail-item:hover{color:#c8cdd4;transform:translateX(4px)}
.rail-item:hover::before{background:rgba(255,91,74,.55);width:15px}
.rail-item:hover::after{background:var(--fx-glow);
  box-shadow:0 0 9px rgba(224,32,32,.8)}

/* ── Active: the rule is HOT at this point ── */
.rail-item.active{
  color:#fff2f0;transform:translateX(6px);
  font-weight:700;
}
.rail-item.active::before{
  background:linear-gradient(90deg,var(--fx-hot),rgba(255,91,74,.2));
  width:15px;height:2px;transform:translateY(-1px)}
.rail-item.active::after{
  background:var(--fx-hot);width:7px;height:7px;
  transform:translate(-1px,-3.5px);
  box-shadow:0 0 0 3px #000, 0 0 16px rgba(255,91,74,.95)}

/* The old icon spans are inconsistent unicode and add nothing here —
   the rule and the type carry it. */
.left-rail .rail-item .ico{display:none}
.left-rail .dot-red{display:none}

/* ── Divisions read as a roster, not menu items ──
   They are the company's arms, not navigation. Indented, smaller,
   with an index number so the block scans as a manifest. */
.rail-group:has(.rail-label) .rail-item[href^="/division/"]{
  font-size:12px;letter-spacing:1.2px;color:#4a5058;
  padding-left:20px}
.rail-item[href^="/division/"]:hover{color:#c8cdd4}

/* ── THE OATH PROMPT ──
   Was a big crimson card at the bottom of the rail, permanently
   shouting. A pitch that is always on stops being a pitch and becomes
   furniture — or worse, something people resent.

   Now it is a line, not a card. Same place in the rail, but it reads
   as one more item until you hover it, at which point it warms up.
   The real pitch lives on /oath and at the moments it is relevant
   (hitting a limit, opening a Partner feature), not in the corner of
   every page forever. */
.upgrade-box{
  position:relative;
  margin:22px 0 0 !important;
  padding:0 !important;
  background:none !important;
  border:none !important;
  border-left:none !important;
  box-shadow:none !important;
  border-radius:0 !important;
  backdrop-filter:none !important;
}
.upgrade-box::before{display:none !important}

.upgrade-title{
  display:block;
  padding:8px 12px 8px 20px;
  font-family:'Barlow Condensed',sans-serif;font-weight:700;font-size:13px;
  letter-spacing:1.8px;text-transform:uppercase;
  color:#7a5252;margin:0;transition:color .18s}

/* The description only appears on hover — it is context, not a banner. */
.upgrade-desc{
  max-height:0;overflow:hidden;opacity:0;
  padding:0 12px 0 20px;margin:0;
  font-family:'Rajdhani',sans-serif;font-size:12px;color:#4a5058;
  line-height:1.5;
  transition:max-height .28s cubic-bezier(.22,1,.36,1), opacity .2s,
             padding .28s}

.upgrade-box:hover .upgrade-title{color:#ff8a70}
.upgrade-box:hover .upgrade-desc{
  max-height:60px;opacity:1;padding:0 12px 9px 20px}

/* The button is a link, not a slab.
   NOTE: margin-left indents it to line up with the nav items, but the
   rail has no right padding — so a left margin alone pushed the button
   past the rail edge and clipped its right corners. It needs BOTH
   sides, and box-sizing so the width maths includes the padding. */
.upgrade-box .btn-blood{
  display:block !important;
  box-sizing:border-box;
  width:auto;
  margin:0 18px 0 20px !important;
  padding:8px 14px !important;font-size:11px !important;
  letter-spacing:1.6px !important;
  border-radius:4px !important;
  opacity:.55;transition:opacity .2s}
.upgrade-box:hover .btn-blood{opacity:1}

/* ── Sign-out sits apart from navigation ── */
.rail-logout{margin-top:14px;color:#3a3f47 !important}
.rail-logout:hover{color:#ff8a70 !important}

/* ── Narrow screens: the rule costs more than it gives ── */
@media(max-width:1100px){
  .left-rail{padding-left:14px}
  .left-rail::before{display:none}
  .rail-item::before,.rail-item::after{display:none}
  .rail-item{padding-left:8px}
  .rail-label{margin-left:0;padding-left:8px}
}

/* ═══════════════════════════════════════════════════════════
   THE STRAND — added 2026-09-11
   Two strands wound together, drawn by /assets/js/strand.js.

   ⚠️ EVERY RULE HERE IS SCOPED TO .has-strand, WHICH ONLY THE
   SCRIPT ADDS. If the script does not run, none of this applies
   and the rail is exactly the straight rule above — which is the
   version that shipped and works. The enhancement can fail
   without taking the navigation with it.

   The script also declines below 1100px and on the admin rail;
   the media query at the bottom of this file is the one that
   decides the narrow-screen answer, and this follows it rather
   than inventing a second one.
   ═══════════════════════════════════════════════════════════ */

.left-rail.has-strand{ padding-left:54px }

.rail-strand{
  position:absolute;left:0;top:0;width:54px;
  overflow:visible;pointer-events:none;z-index:0;
}

/* The SVG now draws the rule, the connector and the node, so the
   hand-drawn ones step aside. Not deleted above — they are what
   renders when the script is absent. */
.left-rail.has-strand::before{ display:none }
.left-rail.has-strand .rail-item::before,
.left-rail.has-strand .rail-item::after{ display:none }

/* The label sat against a spine at left:9px. The strand's centre is at
   26 and it swings 12 either way, so the label needs to clear 38 — and
   the 1·8·7 digits sit further left again, at 14 - 8. */
.left-rail.has-strand .rail-label{ padding-left:0 }
.left-rail.has-strand .rail-item{ padding-left:2px }
.left-rail.has-strand .rail-group:has(.rail-label) .rail-item[href^="/division/"]{
  padding-left:12px
}
.left-rail.has-strand .upgrade-title,
.left-rail.has-strand .upgrade-desc{ padding-left:2px }
.left-rail.has-strand .upgrade-box .btn-blood{ margin-left:2px !important }

/* Items sit above the strand so a rung never crosses a letter. */
.left-rail.has-strand .rail-item,
.left-rail.has-strand .rail-label,
.left-rail.has-strand .upgrade-box{ position:relative;z-index:1 }
