/* =========================================================================
   nav.css — the one header, on all twelve pages.

   Loaded by every page and depending on no other stylesheet, because it has to look the same
   whether it sits above `style.css` (marketing) or `dashboard.css` (app). Those two defined
   two different headers with no shared class between them, which is how the site came to
   feel like two websites wearing one name.

   The tokens it reads — `--ink`, `--hair`, `--ease` and friends — are declared by every page
   stylesheet and carry fallbacks here anyway. `--nav-h` is not read but DECLARED below: the
   bar's own height is the header's business, and leaving it to the page is what produced
   three different bars on one site.
   ========================================================================= */

/* The header owns its own height.
 *
 * It did not, and that produced three different bars on one site: `style.css` and the five
 * document stylesheets say 88px, `dashboard.css` says 64px, and `login.css` has no concept of
 * a nav at all — so the sign-in page fell through to a hard-coded fallback and rendered
 * shorter than every other page. Unifying the component and then letting its height come
 * from whichever stylesheet happened to load is the same fault the component was built to
 * remove, one level down.
 *
 * `nav.css` is loaded last on all thirteen pages, so declaring the token here settles it
 * everywhere — including for the things that measure themselves against it: the rules page's
 * sticky contents list, its `scroll-margin-top`, and the assets table's sticky header. Those
 * were offsetting against a number that did not match the bar in front of them.
 *
 * 88px is the marketing scale, which is where the design language lives, and it is what a
 * 46px pill needs to sit in without crowding. The app pages gain 24px of chrome and are the
 * better for matching. The 70px step under 820px is the one the page stylesheets already
 * carried; it is kept so the mobile bar does not grow. */
/* The bar's own type scale, declared rather than left to five fallbacks.
 *
 * `--fs-nav` and `--fs-btn` were referenced at five call sites and defined nowhere, so every
 * one of them silently ran on its fallback. That works until somebody wants to change the
 * scale and has to find all five — which is what happened here.
 *
 * 19px for the row, up from 17. The header holds five items in a centred block, and at 17px
 * with the corrected 40px word spacing that block came to 563px inside a 1521px bar — the
 * type was never the problem, but a compact row of small type in a wide bar reads as an
 * afterthought. Growing the glyphs gives it presence from the words rather than from air.
 *
 * 17px for the pills, up from 16, so the account control and the sign-in pair do not look
 * undersized beside a 19px row. The mark stays at 24px: it is the largest thing on the bar
 * and should remain so. */
:root{
  --nav-h:88px;
  --fs-nav:19px;
  --fs-btn:17px;
  --fs-logo:24px;
}
@media (max-width:820px){ :root{ --nav-h:70px; } }

/* Nothing until there is something behind it.
 *
 * This was `rgba(5,5,5,.9)` with a 14px blur and a hard 1px border, on every page, always.
 * At ninety percent opacity there is nothing left for a blur to do — the glass was doing no
 * work and the result was an opaque black band with a rule under it, sitting on top of a
 * near-black page. A rectangle you can see the edges of but not the point of.
 *
 * A bar earns its surface when content passes beneath it, and not before. At the top of the
 * page there is nothing behind the header, so it wears nothing: no fill, no blur, no border,
 * and the mark and the links sit directly on the hero. `is-stuck` arrives the moment the
 * page moves and brings the glass with it — a lower opacity than before, so the blur is
 * visible as blur, and `saturate` so colour passing underneath tints it rather than turning
 * grey.
 *
 * `is-stuck` comes from a sentinel and an IntersectionObserver rather than a scroll handler;
 * see nav.js. A `scroll` listener that writes a class runs on the main thread on every frame
 * of every scroll, which is a strange price to pay for a background colour.
 *
 * `will-change` is deliberately absent. Promoting a sticky, full-width, backdrop-filtered
 * element to its own layer for the sake of one class change costs more than the change. */
/* The sentinel nav.js observes. Zero height, zero ink, first child of the body — it exists
   only so the browser can report when the top of the document leaves the viewport. */
.sitenav__sentinel{ position:absolute; top:0; left:0; width:1px; height:1px; pointer-events:none; }

.sitenav{
  position:sticky; top:0; z-index:40;
  box-sizing:border-box;
  height:var(--nav-h);
  background:transparent;
  /* Long enough to read as a morph rather than a switch.
   *
   * .32s is the site's interaction duration — right for a button answering a click, too
   * quick for a surface materialising, where the eye has time to watch and a fast change
   * just registers as "it changed". .55s on the fill, and the blur trails it by .1s so the
   * glass thickens after the tint arrives instead of both landing together.
   *
   * `ease-out` on the way in: it starts immediately, which keeps it tied to the scroll that
   * caused it, and settles slowly. */
  transition:background .55s cubic-bezier(.16,.84,.44,1),
             backdrop-filter .55s cubic-bezier(.16,.84,.44,1) .1s,
             -webkit-backdrop-filter .55s cubic-bezier(.16,.84,.44,1) .1s;
}

.sitenav.is-stuck{
  background:rgba(8,8,8,.62);
  backdrop-filter:blur(22px) saturate(150%);
  -webkit-backdrop-filter:blur(22px) saturate(150%);
}

/* The edge, as a hairline that fades out rather than a rule that stops.
 *
 * A `border-bottom` runs the full width and ends in two hard corners against the window,
 * which is the single strongest cue that a bar is a box drawn on top of a page. The same
 * line as a gradient — full strength across the middle, gone by the edges — separates the
 * header from what is under it without ever drawing its own frame.
 *
 * Absolutely positioned so it costs no layout height, which is why the element keeps its
 * exact `--nav-h` whether the line is showing or not. */
.sitenav::after{
  content:"";
  position:absolute; left:0; right:0; bottom:0; height:1px;
  background:linear-gradient(90deg,
              transparent,
              var(--hair-2, rgba(255,255,255,.11)) 14%,
              var(--hair-2, rgba(255,255,255,.11)) 86%,
              transparent);
  opacity:0;
  /* The hairline comes in last, once there is a surface for it to be the edge of. */
  transition:opacity .5s cubic-bezier(.16,.84,.44,1) .18s;
  pointer-events:none;
}
.sitenav.is-stuck::after{ opacity:1; }

/* The drawer is opaque by necessity — it covers the page rather than floating over a few
   pixels of it — so an open drawer takes the glass regardless of scroll position. Without
   this, opening the menu at the top of a page renders a list of links over live content. */
.sitenav:has(.sitenav__drawer:not([hidden])){
  background:rgba(8,8,8,.92);
  backdrop-filter:blur(22px) saturate(150%);
  -webkit-backdrop-filter:blur(22px) saturate(150%);
}

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

/* Edge to edge, and the CONTENTS held off the edge.
 *
 * The bar itself still spans the window — an app bar belongs to the window, and a
 * `max-width` on `.sitenav` made it look like it was floating above the page rather than
 * fixed to it. That decision stands; this is about what sits inside it.
 *
 * The padding was a flat 20px, which put the mark at x=20 on a 1568px screen against a
 * content column whose left rule is at x=24. So the logo sat four pixels OUTSIDE the page's
 * own edge, and the sign-in pair sat four pixels outside it on the right. Not floating
 * inward — jammed into the corners, which is what reads as "too far out".
 *
 * `clamp(24px, 3vw, 60px)`: never tighter than the content column's own gutter, about 47px
 * at a laptop width, and capped so it does not keep marching inward on a 27-inch monitor
 * and pull the mark away from the corner it belongs near. The three-item row in the middle
 * is absolutely centred on the bar and does not move with any of this. */
.sitenav__in{
  position:relative;               /* the centred row is positioned against this */
  height:100%;
  padding-inline:clamp(24px, 3vw, 60px);
  display:flex; align-items:center; gap:8px;
}

.sitenav__mark{
  display:flex; align-items:center; gap:11px;
  height:32px; flex:none;
  color:var(--ink, #EDEAE5); text-decoration:none;
}
.sitenav__mark svg{ width:26px; height:26px; flex:none; }
.sitenav__mark span{
  font-family:var(--display, system-ui);
  font-size:var(--fs-logo, 24px); font-weight:600;
  letter-spacing:-.022em; line-height:1;
}

/* Centred on the PAGE, and stays there whatever flanks it.

   Two earlier attempts got this wrong in opposite directions. `margin-inline:auto` centred
   the row between the mark and the end group — two things of different widths, so it sat
   80px left of centre signed out and 180px left signed in, and moved again whenever the
   account pill's label changed. Anchoring it to the mark fixed the drift and gave up the
   centring.

   Absolute positioning gives both: the row is at 50% of the bar regardless of how wide the
   mark or the pill are, so a longer name cannot move it by a pixel. It is taken out of the
   flex flow, which is why `.sitenav__end` carries the auto margin instead.

   The trade is that it can no longer push its neighbours apart, so it must not be allowed
   to collide with them — the width steps below, and the drawer at 960px, are what keep it
   from doing so. Measured at 1080 with the narrowed gaps the row is 529px against 918px of
   clear space, which is the tightest case before the drawer takes over.

   Superseded note, kept because it is the reason this is absolute:
   Anchored to the mark, not floated between two groups of unequal width.
 *
 * This was `margin-inline:auto`, which on a flex item eats the free space on both sides
 * equally — so the menus were centred between the mark and the end group rather than on the
 * page. Measured at 1536: 80px left of centre signed out, 180px left signed in. The block
 * MOVED 100px on sign-in, and it moved again whenever the account pill's label changed,
 * which made the position of the site navigation a function of how long somebody's name is.
 *
 * Anchoring left fixes it by removing the question. The left cluster is identity plus
 * navigation and never changes width; the right cluster is your account and is free to. The
 * single `margin-right:auto` puts all the slack in one place, between the two, where a
 * changing name simply widens a gap instead of shifting the menus. */
/* The marketing scale, everywhere.
 *
 * The first version of this file took its proportions from the app bar — 14.5px links in
 * muted grey, 36px buttons — and dropped them into an 88px marketing header. The bar was
 * right and everything inside it was two sizes too small for the space it sat in.
 *
 * These are the numbers the site was designed at: 17px links at full ink with a gold hover,
 * a 46px pill, a 24px mark. The app pages carry a shorter bar because a trading screen wants
 * its vertical space, but the type and the controls are the same size in both. */
.sitenav__primary{
  /* 14px between boxes, which is 40px between words now that every item is padded the same.
     It was 46px between boxes and up to 72px between words. */
  display:flex; align-items:center; gap:14px;
  position:absolute;
  left:50%;
  transform:translateX(-50%);
}

/* The sign-in page's header: the mark, floating over its own background.
 *
 * Not a bar. `login.html` is a full-bleed video with a single card centred on it, and a
 * blurred rule across the top would cut that in half for the sake of one link. Transparent
 * and absolutely positioned, so the page reads as one composition and the mark is simply
 * there when somebody wants out. */
.sitenav--minimal{
  position:absolute; top:0; left:0; right:0;
  height:auto; padding:26px 0;
  background:transparent; border-bottom:0;
  backdrop-filter:none; -webkit-backdrop-filter:none;
}
/* The sign-in page's mark keeps its own tighter inset: there is nothing on the right for it
   to balance against, so matching the full bar would leave it stranded. */
.sitenav--minimal .sitenav__in{ padding-inline:clamp(24px, 2vw, 40px); }

/* ---------------------------------------------------------------- the links

   Flat, all of them. The hover dropdowns lived here and are gone with `menu()` in nav.js:
   two menus of two links each, styled as controls, sitting in a row of plain links that
   were not. See the note on `PRIMARY` for why four links did not need deferring.

*/
.sitenav__primary a,
.sitenav__account a{
  position:relative;                 /* the underline is positioned against this */
  display:inline-flex; align-items:center;
  height:42px; padding:0 13px; border-radius:999px;
  font-size:var(--fs-nav, 17px); font-weight:450;
  color:var(--ink, #EDEAE5); white-space:nowrap; text-decoration:none;
  transition:color .25s var(--ease, ease);
}
/* The underline, drawn from the middle out.

   The links only changed colour, which on a bar of six is a weak signal — you
   find out which one you are on by reading it again. A rule that grows from the
   centre of the word points at the word.

   `scaleX` on a full-width element rather than animating `width`: width is a
   layout property and animating it on six links in a flex row asks the browser
   to re-measure the bar sixty times a second. A transform is composited.

   `aria-current` gets it permanently and at full width. Same rule, no second
   mechanism to keep in step — which is the reason the current page is marked by
   the attribute rather than by a class in the first place. */
.sitenav__primary a::after{
  content:"";
  position:absolute; left:13px; right:13px; bottom:7px; height:1px;
  background:currentColor;
  transform:scaleX(0);
  transform-origin:50% 50%;
  transition:transform .34s cubic-bezier(.22,.61,.36,1), opacity .34s ease;
  opacity:.55;
  pointer-events:none;
}
.sitenav__primary a:hover::after{ transform:scaleX(1); }
.sitenav__primary a[aria-current="page"]::after{ transform:scaleX(1); opacity:1; }

@media (prefers-reduced-motion:reduce){
  .sitenav__primary a::after{ transition:none; }
}

.sitenav__primary a:hover,
.sitenav__account a:hover{ color:var(--gold, #D3B07C); }

/* `aria-current` rather than a class. The browser's own signal for "you are here", so the
   state cannot be applied on one page and forgotten on another — which is exactly what a
   hand-maintained `class="is-active"` across twelve files does. */
.sitenav__primary a[aria-current="page"],
.sitenav__account a[aria-current="page"]{ color:#FBF9F5; font-weight:600; }

/* The end of the bar holds ONE thing in each state: the account pill signed in, or the
   two sign-in pills signed out. Those two are a pair — one action and its alternative — so
   they sit close enough to read as a pair. 46px between them made them look like two
   unrelated destinations that happened to share a corner.

   14px, which is the same distance the ticket's own button pairs use. */
.sitenav__end{ display:flex; align-items:center; gap:14px; margin-left:auto; }

/* The account destinations, on the same rhythm as the section menus.
 *
 * They were on a 34px gap behind a hairline while the menus beside them were on 46px, so
 * the two halves of one bar ticked at different rates — and the hairline then drew a line
 * under the difference. On checkout, where both halves show at once, that is what read as
 * two navigations glued together.
 *
 * They are still a different KIND of place. What says so is that they sit beside the
 * account control rather than beside the menus, which is a stronger signal than a 1px rule
 * nobody can see. */
.sitenav__account{
  display:flex; align-items:center; gap:46px;
}

/* ---------------------------------------------------------------- the account control

   The pill that ends the bar when somebody is signed in, at the same 46px as `Log in` ends
   it when they are not. This was a 38px disc of gold with no label and no border: the only
   round filled object on the bar, floating at the edge with nothing to anchor it, and
   giving no clue what pressing it would do.

   Padding is asymmetric on purpose — 6px at the disc end, 16px at the caret end — so the
   disc sits inset by the same optical margin as the text does. */
.sitenav__you{
  display:inline-flex; align-items:center; gap:10px;
  height:46px; padding:0 16px 0 6px; border-radius:999px;
  border:1px solid var(--hair-2, rgba(255,255,255,.14));
  background:transparent; cursor:pointer; flex:none;
  color:var(--ink, #EDEAE5);
  font:inherit; font-size:var(--fs-btn, 16px); font-weight:500;
  transition:border-color .3s var(--ease, ease), background-color .3s var(--ease, ease),
             color .3s var(--ease, ease);
}
.sitenav__you i{
  display:grid; place-items:center;
  width:34px; height:34px; border-radius:50%; flex:none;
  background:linear-gradient(135deg,#D3B07C,#8B6F45);
  font-family:var(--display, system-ui); font-style:normal;
  font-size:15px; font-weight:600; line-height:1; color:#1B1509;
}
.sitenav__you span{ white-space:nowrap; }
/* ==========================================================================
   THE ACCOUNT MENU

   Anchored to the button rather than to the bar, so it stays under the avatar
   whatever the name beside it is — "Alexandra" and "Jo" make the button two
   different widths, and a menu positioned from the bar would drift with it.

   `margin-top:0` with `top:100%`: the menu touches the button's bottom edge.
   A visual gap would be prettier and would be a strip of nothing between two
   halves of one control, which is where a pointer heading for the menu leaves
   both and the whole thing closes. The padding inside does the spacing.
   ========================================================================== */
.sitenav__youwrap{ position:relative; flex:none; }

/* `[hidden]` needs the guard because `display:grid` below would otherwise win — the same
   reason `.sitenav__drawer[hidden]` needs one, and the same reason `terminal.css` opens with
   a blanket `[hidden]{display:none !important}`. Without it `menu.hidden = true` is silently
   a no-op and the menu is open from the moment the header renders. */
.youmenu[hidden]{ display:none; }

.youmenu{
  position:absolute; top:100%; right:0; z-index:60;
  min-width:180px; padding:6px;
  border-radius:12px; border:1px solid var(--hair-2, rgba(255,255,255,.14));
  background:#101010;
  box-shadow:0 18px 40px -22px rgba(0,0,0,.9);
  display:grid; gap:2px;
}
.youmenu__item{
  width:100%; padding:9px 12px; border-radius:8px;
  border:0; background:transparent; text-align:left;
  color:var(--ink, #EDEAE5); font:inherit; font-size:14px; cursor:pointer;
  transition:background-color .15s var(--ease, ease), color .15s var(--ease, ease);
}
.youmenu__item:hover{ background:rgba(255,255,255,.06); }
.youmenu__item:focus-visible{
  outline:2px solid rgba(255,255,255,.7); outline-offset:-2px;
}
/* The way out reads as the way out. Muted until reached, so it is not the first
   thing the eye lands on in a menu whose other item is the ordinary one. */
.youmenu__item--out{ color:#9A9691; }
.youmenu__item--out:hover{ background:rgba(255,75,75,.10); color:#FF8A8A; }

/* The caret turns over while the menu is open, which is the only thing on the
   button that says so. */
.sitenav__youwrap.is-open .sitenav__you svg{ transform:rotate(180deg); }


.sitenav__you svg{
  width:12px; height:12px; flex:none; color:#8E8A85;
  transition:transform .25s var(--ease, ease), color .25s var(--ease, ease);
}
.sitenav__you:hover{
  border-color:rgba(211,176,124,.55);
  background:rgba(211,176,124,.06);
  color:var(--gold, #D3B07C);
}
.sitenav__you:hover svg{ color:var(--gold, #D3B07C); }
.sitenav__you[aria-expanded="true"] svg{ transform:rotate(180deg); }

/* 46px tall and 110px wide, which is what the pair was before. A nav button is the most
   clickable thing on the page and it should look like it. */
.sitenav .btn{
  display:inline-flex; align-items:center; justify-content:center; gap:10px;
  height:46px; min-width:110px; padding-inline:22px; border-radius:999px;
  font-size:var(--fs-btn, 16px); font-weight:500;
  text-decoration:none; white-space:nowrap; flex:none;
  transition:transform .3s var(--ease, ease), background-color .3s var(--ease, ease),
             color .3s var(--ease, ease), border-color .3s var(--ease, ease),
             box-shadow .3s var(--ease, ease);
}
.sitenav .btn--ghost{
  border:1px solid var(--hair-2, rgba(255,255,255,.14));
  color:var(--ink, #EDEAE5); background:transparent;
}
.sitenav .btn--ghost:hover{
  border-color:rgba(211,176,124,.55); color:var(--gold, #D3B07C);
  background:rgba(211,176,124,.06);
}
.sitenav .btn--solid{ background:#fff; color:#0A0A0A; border:1px solid #fff; }
.sitenav .btn--solid:hover{
  transform:translateY(-1px); box-shadow:0 10px 30px -12px rgba(255,255,255,.4);
}

.sitenav__burger{
  display:none; width:42px; height:42px; place-items:center;
  border:0; background:transparent; cursor:pointer;
}
.sitenav__burger i{
  display:block; width:19px; height:1.5px; border-radius:2px;
  background:var(--ink, #EDEAE5);
}
.sitenav__burger i + i{ margin-top:5px; }

.sitenav__drawer{
  display:none; flex-direction:column; gap:2px;
  padding:10px 20px 18px;
  background:rgba(5,5,5,.98);
  border-bottom:1px solid var(--hair, rgba(255,255,255,.08));
}
.sitenav__drawer a{
  padding:12px 2px; font-size:15px; color:#8E8A85; text-decoration:none;
  border-bottom:1px solid var(--hair, rgba(255,255,255,.06));
}
.sitenav__drawer a[aria-current="page"]{ color:#FBF9F5; font-weight:600; }
/* `[hidden]` needs the guard because `display:flex` below would otherwise win. */
.sitenav__drawer[hidden]{ display:none; }

/* Measured: mark 111 + three menus 310 + three destinations 210 + the pill 134, which needs
   about 1030px at the full 46px gaps and 943 at these. Between there and 1080 the gaps close
   before anything is dropped — losing air is a smaller loss than losing a destination. */
@media (max-width:1080px){
  /* 8px between boxes, 34px between words. The padding stays — it is the hover target. */
  .sitenav__primary{ gap:8px; }
  .sitenav__end{ gap:10px; }
}

@media (max-width:960px){
  /* Both link groups fold into the drawer and the bar keeps only what a thumb needs: the
     mark, the primary action, and the way in.

     960 rather than 860, measured rather than guessed. Signed in the bar carries six items
     and a pill, and at the narrowed gaps below it comes to 943px — so between 860 and 943
     it was overflowing its own row. The signed-out bar has always fitted well below this;
     the breakpoint is set by the fuller of the two states, because a header that only holds
     together when nobody is signed in is the same fault this file was written to remove. */
  .sitenav__primary,
  .sitenav__account{ display:none; }
  .sitenav__burger{ display:grid; }
  .sitenav__drawer:not([hidden]){ display:flex; }
  .sitenav__end{ margin-left:auto; gap:10px; }
  /* The pill keeps its height on a phone; a 36px button is a miss target, not a control. */
  .sitenav .btn{ min-width:0; padding-inline:18px; }
  .sitenav .btn--ghost{ display:none; }
  /* The name and the caret go, the disc stays. There is nothing beside it at this width for
     it to be confused with, and the label is the part that costs the room. */
  .sitenav__you{ padding:0; border-color:transparent; background:transparent; }
  .sitenav__you span, .sitenav__you svg{ display:none; }
  .sitenav__you i{ width:38px; height:38px; font-size:16px; }
}

@media (max-width:420px){
  .sitenav__in{ padding-inline:14px; }
  .sitenav__mark span{ font-size:19px; }
}

/* ==========================================================================
   THE NOTICE
   One surface, on every page, styled here because `nav.css` is the only
   stylesheet all fourteen load.

   `terminal.css`, `analytics.css` and `checkout.css` each carry their own
   `.toast` rule and keep it — those three pages had a notice and it was
   positioned correctly. They are loaded AFTER this file on the pages that have
   them, so their version wins where it exists and this is what the other eleven
   get. Identical values on purpose: a notice that sits somewhere different
   depending on the page is a notice people stop looking for.
   ========================================================================== */
.toast{
  position:fixed; left:50%; bottom:26px; transform:translateX(-50%) translateY(8px);
  padding:11px 17px; border-radius:11px;
  background:#101010; border:1px solid var(--hair-2, rgba(255,255,255,.11));
  color:var(--ink, #EDEAE5); font-size:13px; line-height:1.45;
  opacity:0; pointer-events:none;
  transition:opacity .25s, transform .25s var(--ease, ease);
  z-index:50; max-width:min(520px, calc(100vw - 32px));
}
.toast.is-on{ opacity:1; transform:translateX(-50%) translateY(0); }

/* A failure reads as one. Not red text on a dark chip — a red EDGE, because the
   message itself has to stay legible and a coloured body at 13px does not. */
.toast--bad{ border-color:rgba(255,75,75,.55); }

@media (prefers-reduced-motion:reduce){
  .toast{ transition:opacity .25s; transform:translateX(-50%); }
  .toast.is-on{ transform:translateX(-50%); }
}
