/* ============================================================================
 * sidenav — an ink column of grouped links
 * ============================================================================
 *
 * A working surface's entire chrome in one column: the wordmark, every
 * destination at once, and the account cluster at the foot. HQ wears it.
 *
 * WHAT IT IS FOR. A band has room for one group, so it needs a row of tabs above
 * it to choose which — and reaching a list of five things then costs two clicks,
 * with no way to see the shape of the product without clicking through it. A
 * column has room for every group at once, so the map is on screen at rest.
 *
 * The marketing site keeps `header.html` instead, and that is not an
 * inconsistency: a navbar carries two links and a CTA to a stranger who has just
 * arrived, and a reader three levels into the CLI reference has already arrived.
 *
 * ---- Using it --------------------------------------------------------------
 *
 *   <link rel="stylesheet" href="/shared/components/sidenav/sidenav.css">
 *
 * That URL is the same on every surface — nginx serves sites/shared/ at /shared/
 * for the website, and scripts/sync-shared.py mirrors the path into the surfaces
 * that embed their frontend. Nothing here is reachable by a relative path, on
 * purpose: a component that can only be found from one directory is not shared.
 *
 * The MARKUP is the host's, because it differs: HQ builds it from its NAV table
 * in app.js, where the gating decides what a credential may even see. The
 * contract is the class names, listed in README.md beside this file.
 *
 * POSITIONING IS THE HOST'S TOO, as with the navbar. This file owns the box
 * model, the type and the states; HQ pins it `fixed` against the viewport from
 * its own sheet. Position is not a property of a component that can be used
 * twice.
 *
 * ---- The rules that keep it identical wherever it is placed -----------------
 *
 * IT STATES EVERY PROPERTY THAT AFFECTS ITS BOX, and never inherits one. The
 * surfaces set different body leading on purpose — the site 1.625, HQ 1.5 — so a
 * part that inherits it is a different size depending on who loaded it. That is
 * not hypothetical: this column's group heading measured 17.875px on one surface
 * and 16.5px on the other from identical declarations.
 *
 * IT IS IN `@layer component`. The layer order is declared once in brand.css
 * (brand, site, component, page), so this file outranks a site's own layout and
 * is outranked by the page that hosts it, wherever the <link> happens to sit in
 * the document. Before layers that precedence was the order of the tags, which
 * is exactly the "behaves differently depending on placement" this file must not
 * have.
 *
 * --brand-1 is the "you are here" mark on EVERY Drift sidebar, and it is NOT a
 * per-section colour. Colouring one group orange and the next purple reassigns
 * the ABC triad — orange is Atomic, purple is Backbone, green is Canvas, and
 * that mapping is load-bearing. The group heading sitting directly over the
 * marked row already says which group it is, in words.
 * ========================================================================== */
@layer component {

/* ---- The masthead's geometry, published ------------------------------------
 * The three numbers that decide where the column's LIST begins: its own top
 * padding, the wordmark row's height, and the air below that row. Tokens rather
 * than literals because a bar placed beside the column has to close level with
 * that line — the docs' top bar is built from exactly these, so the two halves
 * of the chrome start their content on the same row and neither can be tuned
 * out of agreement with the other.
 *
 * On :root, not on .sidenav, for the same reason: something outside the column
 * reads them. --sidenav-gutter stays internal below, because nothing does. */
:root {
  --sidenav-top: 12px;
  --sidenav-mark-h: 2.5rem;
  /* EQUAL to --sidenav-top, and the equality is load-bearing wherever a control
     beside the column is centred on the wordmark: the wordmark's midpoint is
     top + mark-h/2 and a full-height neighbour's is (top + mark-h + gap)/2, and
     those agree only when the air below the mark matches the air above it.
     Written as the token so the two cannot be set apart by hand. */
  --sidenav-mark-gap: var(--sidenav-top);
}

.sidenav {
  /* ONE gutter for everything in the column, so the wordmark, the group
     headings and the links all start on the same line and only the active
     marker sits outside it. Internal, unlike --sidenav-w above: nothing outside
     the column measures anything against it. */
  --sidenav-gutter: 20px;

  /* THE PALETTE, IN FIVE NAMES. The column is ink because that is what a page's
     primary navigation is here, but ink is the DEFAULT rather than the fact:
     `subnav` re-points these to stand a second column on a light ground, and it
     does so by naming five values instead of re-stating a dozen rules.

     Every rule below draws from these and none names a colour of its own. That
     is the whole point — a hard-coded #fff on the active link is invisible the
     first time someone grounds this component in white, and it is invisible in a
     place nobody thinks to look because the rule reads as correct. */
  --sidenav-ground: var(--ink, #1b2844);
  --sidenav-fg: var(--on-ink, #d6dcea);
  --sidenav-fg-muted: var(--on-ink-muted, #8ea0c4);
  --sidenav-fg-strong: #fff;
  --sidenav-raised: var(--ink-raised, #26344f);

  box-sizing: border-box;
  width: var(--sidenav-w);
  background: var(--sidenav-ground);
  /* The foot is pushed to the bottom by margin-top:auto, which needs a column
     with a definite height — the host gives it one by pinning the element. */
  display: flex;
  flex-direction: column;
  padding: var(--sidenav-top) 0 0;
  overflow-y: auto;
  /* A column that scrolls independently of the page must not hand its overscroll
     to the page behind it: reaching the end of the list would otherwise start
     scrolling the content, which reads as the sidebar jumping. */
  overscroll-behavior: contain;
}

/* The mark and its badge share a row. The row carries the padding so the two
   inside it sit flush against the gutter. */
.sidenav-head {
  display: flex;
  align-items: center;
  gap: 10px;
  /* STATED rather than left to the wordmark's font metrics, so the column's
     first list item lands at a height the stylesheet knows — and so a bar
     beside the column can be built to close on that same line. */
  height: var(--sidenav-mark-h);
  padding: 0 var(--sidenav-gutter);
  margin-bottom: var(--sidenav-mark-gap);
}

/* The real mark, not a plain word. Ink letters would vanish on the ink field,
   so the glyphs go white and the last two rules go white with them; the triad
   is unchanged, because the triad never changes. Nothing closes the row: the
   column carries the triad in these underlines, and a 4px band under them would
   be a second statement of the same thing. */
.sidenav-mark {
  display: block;
  font-family: 'Tinos', Georgia, serif;
  font-style: italic;
  font-weight: 700;
  /* The same token as the row's height, with line-height 1, so the mark fills
     its row exactly and changing one changes both. */
  font-size: var(--sidenav-mark-h);
  line-height: 1;
  color: var(--sidenav-fg-strong);
  text-decoration: none;
}
.sidenav-mark .lg {
  text-decoration: underline;
  /* The navbar's values, unscaled — this mark is the navbar's size, so the
     rules have to be its weight too. */
  text-underline-offset: 4px;
  text-decoration-thickness: 3px;
}
.sidenav-mark .lg-1 { text-decoration-color: var(--brand-1, #f1a006); }
.sidenav-mark .lg-2 { text-decoration-color: var(--brand-2, #8269eb); }
.sidenav-mark .lg-3 { text-decoration-color: var(--brand-3, #10b981); }
.sidenav-mark .lg-4,
.sidenav-mark .lg-5 { text-decoration-color: var(--sidenav-fg-strong); }
.sidenav-head .alpha-tag { margin-top: 4px; }

/* The list itself: every group heading, every link, and every branch. It is a
   named part rather than an anonymous wrapper because the narrow layout has to
   distinguish a link sitting directly in the list from one inside a branch, and
   `>` is the only thing that can say that. */
.sidenav-list { display: block; }

/* The group heading. The big number is the space ABOVE it, which is what
   separates one group from the links of the group before; the small one binds
   it to its own list.

   THE FIRST HEADING KEEPS IT TOO. The wordmark's own gap and this one do
   different jobs — that one closes the masthead, this one opens a group — and
   zeroing the first heading's share reads as the list having been shoved up
   against the mark. It is 20px, and it is worth resisting the rule that removes
   it: `:first-of-type` keys on TAG NAME, not on class, so whether such a rule
   fires at all depends on what else happens to be a <div> beside it. */
.sidenav-group {
  display: block;
  font-size: 11px;
  font-weight: 600;
  /* STATED, not inherited. Every other property here is already the same on
     both surfaces; leaving this one to the host made the identical component
     17.875px tall on the docs and 16.5px in HQ, because the two set different
     body leading on purpose. A component that measures differently depending on
     who loaded it is the box-model rule in BRAND.html, applied to type. */
  line-height: 1.5;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--sidenav-fg-muted);
  padding: 20px var(--sidenav-gutter) 6px;
}

.sidenav-link {
  /* The 3px marker is part of the left padding rather than added to it, so the
     label sits on the same line whether or not this is the current page. */
  padding: 7px var(--sidenav-gutter) 7px calc(var(--sidenav-gutter) - 3px);
  /* Icon and label on one line, the icon holding a fixed column so every label
     starts at the same x whatever its glyph is. */
  display: flex;
  align-items: center;
  gap: 9px;
  width: 100%;
  box-sizing: border-box;
  border: none;
  border-left: 3px solid transparent;
  background: none;
  font-family: inherit;
  font-size: 14.5px;
  font-weight: 500;
  line-height: 1.5;
  text-align: left;
  color: var(--sidenav-fg);
  text-decoration: none;
  cursor: pointer;
}
/* A fixed box, sized on BOTH axes. Every Drift icon is square on a 64-unit
   grid, so the box could be square too — it is stated twice anyway, because a
   glyph that ever ships wider would push its label out of line with the ten
   above it. */
.sidenav-link svg {
  height: 15px;
  width: 17px;
  flex: none;
  fill: currentColor;
  /* The muted links carry muted glyphs; a hover and the current row bring both
     up together. Without this the icons read as brighter than their own text. */
  opacity: 0.65;
}
.sidenav-link:hover {
  background: var(--sidenav-raised);
  color: var(--sidenav-fg-strong);
}
.sidenav-link:hover svg,
.sidenav-link.active svg { opacity: 1; }
.sidenav-link.active {
  border-left-color: var(--brand-1, #f1a006);
  background: var(--sidenav-raised);
  color: var(--sidenav-fg-strong);
}
.sidenav-link:focus-visible {
  outline: 2px solid var(--brand-2, #8269eb);
  outline-offset: -2px;
}
/* A destination that exists but has nothing behind it yet. It stays in the
   column so the group is not a gap in the map, and it must not pretend to be
   actionable. */
.sidenav-link:disabled {
  cursor: not-allowed;
  opacity: 0.45;
}
.sidenav-link:disabled:hover { background: none; color: var(--sidenav-fg); }
.sidenav-link:disabled:hover svg { opacity: 0.65; }

/* ---- A link with pages under it --------------------------------------------
 * The row splits in two: the NAME is the link and only the chevron toggles, so
 * an entry that has somewhere to go is never a heading you cannot open.
 *
 * Closed is the resting state, and the host opens the branch holding the
 * current page. Without that, landing on a child marks it active inside a list
 * that is not displayed, which reads as the column having lost you — and
 * nothing on screen suggests a chevron would help.
 *
 * The step is the parent's ICON COLUMN, so a child's text starts where its
 * parent's text does and the nesting reads without a guide line. A child
 * carries no glyph of its own: the indent already says what it belongs to, and
 * repeating the parent's mark down the list adds a picture and no information. */
.sidenav { --sidenav-step: 26px; }
.sidenav-branch { position: relative; }

/* `>` on all four, never a descendant selector. A branch inside a branch is the
   whole point of the depth rules below, and with `.sidenav-branch.open
   .sidenav-child` an outer branch opening would reveal its grandchildren too:
   the inner branch's own closed state would be ignored and the column would
   dump every page at once. Each level answers only for its own children. */
.sidenav-branch > .sidenav-child,
.sidenav-branch > .sidenav-branch { display: none; }
.sidenav-branch.open > .sidenav-child { display: flex; }
.sidenav-branch.open > .sidenav-branch { display: block; }

.sidenav-branchrow { display: flex; align-items: center; }
.sidenav-branchrow > .sidenav-link { flex: 1; min-width: 0; }
/* The chevron shrinks to its glyph and keeps the row's right gutter, so every
   arrow lands on the same edge instead of beside its own name. */
.sidenav-branchrow > .sidenav-toggle {
  width: auto;
  flex: none;
  padding-left: 4px;
  border-left: none;
}
/* The row lights as ONE object, because it reads as one row even though the two
   controls in it do different things. */
.sidenav-branchrow:hover { background: var(--sidenav-raised); }
.sidenav-branchrow:hover > .sidenav-link,
.sidenav-branchrow:hover > .sidenav-toggle { background: none; color: var(--sidenav-fg-strong); }
.sidenav-branchrow:hover svg { opacity: 1; }

.sidenav-child {
  padding-left: calc(var(--sidenav-gutter) - 3px + var(--sidenav-step));
  font-size: 13.5px;
}

/* One more step for a branch nested inside a branch, and for its children.
   Depth is the only thing telling a reader that "NoSQL" belongs to "API
   reference" rather than to "SDK". A nested row indents its NAME; its chevron
   stays on the right edge with every other chevron, which is why the toggle
   takes the plain 4px back. */
.sidenav-branch .sidenav-branch > .sidenav-branchrow > .sidenav-link {
  padding-left: calc(var(--sidenav-gutter) - 3px + var(--sidenav-step));
  font-size: 13.5px;
}
.sidenav-branch .sidenav-branch > .sidenav-branchrow > .sidenav-toggle {
  padding-left: 4px;
}
.sidenav-branch .sidenav-branch > .sidenav-child {
  padding-left: calc(var(--sidenav-gutter) - 3px + var(--sidenav-step) * 2);
  font-size: 13px;
}

/* The chevron is the one thing that turns. Stated after the icon box above, so
   the smaller of the two wins at equal specificity. */
.sidenav-toggle svg {
  height: 9px;
  width: 9px;
  transition: transform 0.15s ease;
}
.sidenav-toggle[aria-expanded="true"] svg { transform: rotate(90deg); }

/* ---- A row whose label carries a description -------------------------------
 * A server-rendered column can afford to say more about each destination than
 * fits in it: the docs put a title and a one-line description in every link,
 * show the title, and keep the description in the DOM for the search index that
 * reads the tree back out. A host with plain text labels never emits either and
 * these two rules do nothing.
 *
 * The title stops being a heading and simply IS the row's text, which means
 * inheriting ALL FOUR of the properties that made it one. line-height is the
 * one that hides: left at a heading's tight 1.1 the row measures 29.9px while
 * the link around it states 1.5 and expects 35.75 — six pixels lost on every
 * one of ~70 rows, which reads as a cramped column rather than as one wrong
 * declaration. */
.sidenav-link .big {
  font-size: inherit;
  font-weight: inherit;
  line-height: inherit;
  margin-bottom: 0;
}
/* It earns its place where the reader is choosing between cards; in a column
   beside the prose it triples the height of a list whose whole job is to be
   skimmed. Hidden, not dropped — the index still needs it. */
.sidenav-link .label { display: none; }

/* An accessible name for a control whose only visible content is a glyph: the
   branch chevrons. Positioned out of sight rather than hidden, because
   display:none and visibility:hidden would take it from a screen reader too.
   Stated here rather than borrowed from a host, so a surface that has no such
   utility class of its own still gets a correctly-named chevron. */
.sidenav .sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* The foot: who you are and how you leave, at the bottom of the column rather
   than in the row you navigate with. margin-top:auto is what pins it there, and
   the top rule is the only edge in the column — it separates the account
   cluster from the last group without drawing a box around it. */
.sidenav-foot {
  margin-top: auto;
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  padding: 16px var(--sidenav-gutter);
  border-top: 2px solid var(--sidenav-raised);
}


/* A 284px column is most of a phone. Below the breakpoint the sidebar goes back
   into normal flow at the top of the document — the HOST drops the pinning,
   since the pinning was never the component's — and the links become a wrapping
   row. The marker moves with them: a row cannot carry a left edge, so the
   current link is underlined instead. */
@media (max-width: 900px) {
  .sidenav {
    width: 100%;
    height: auto;
    overflow: visible;
  }
  /* Only the FLAT links become a row — `.sidenav-list >` is what excludes the
     ones inside a branch. See the branch note below. */
  .sidenav-list > .sidenav-link {
    display: inline-flex;
    width: auto;
    border-left: none;
    border-bottom: 3px solid transparent;
    /* The marker is on the bottom edge here, so the left padding stops
       reserving room for it and goes back to the plain gutter. */
    padding-left: var(--sidenav-gutter);
  }
  .sidenav-list > .sidenav-link.active {
    border-left: none;
    border-bottom-color: var(--brand-1, #f1a006);
  }
  /* Tighter than the column's own rhythm. In a column the air between rows is
     what makes a long list scannable; in flow above the content it is the whole
     of what the reader has to scroll past before reaching the page they opened,
     and every group heading buys a row of it back. */
  .sidenav-group { padding-top: 14px; padding-bottom: 4px; }
  .sidenav-link { padding-top: 5px; padding-bottom: 5px; }
  .sidenav-head { margin-bottom: 8px; }
  /* A BRANCH KEEPS ITS COLUMN SHAPE AT EVERY WIDTH — its own line, its chevron,
     its children stacked and indented under it. Flattening it into the wrapping
     row destroys the one thing that makes the children readable: a child's label
     only means anything under its parent's name, and two lists in the same
     column can hold the same four words. Collapsed, a branch costs one row here,
     which is what the row layout was protecting in the first place. */
  .sidenav-branch { width: 100%; }
}

} /* @layer component */
