/* THE NAVIGATION'S OWN STYLESHEET.
   Lifted out of site/styles.css on 2026-08-03, unchanged and in the same order.

   WHY IT IS A SEPARATE FILE. The nav is GENERATED into every page by
   scripts/site/gen-nav.mjs, but its CSS lived in styles.css, which only 20 of the 23
   pages load. /templates/, /partners/ and /partners/terms/ carry their own design
   systems and never link it, so those three were served the markup with none of the
   rules: the search icon rendered 0x25, the cart rendered as a raw 16x31 <button>
   with the UA's 2px outset border, and the login icon was a bare white box. That is
   what the founder was looking at when he said the menu bar items were still fucked.
   Generated markup needs generated CSS. gen-nav.mjs stamps the <link> to this file
   into every page in the roster and --check fails when one is missing, so the markup
   and the rules can no longer travel separately.

   FALLBACKS ON --surface, --paper AND --ease-out-expo. Those three are declared in
   styles.css but NOT in catalogue.css, so on /templates/ they resolve to nothing and
   a dropdown panel would paint transparent over the grid. Every use below carries a
   literal fallback; the token still wins wherever it is declared.

   Loaded BEFORE the page's own stylesheet, so a page can still override a rule here. */

/* NAV */
.nav {
  width: var(--container); margin: 0 auto; min-height: 70px;
  display: flex; align-items: center; justify-content: space-between; gap: 24px;
  position: sticky; top: 0; z-index: 100;
  background: color-mix(in srgb, var(--paper, #f6f3ed) 80%, transparent);
  backdrop-filter: blur(12px);
}
.brand { display: inline-flex; align-items: center; gap: 10px; padding: 13px 0; }
.brand-logo { height: 22px; width: auto; }
/* The mark rides beside the wordmark so both marks of the identity read at once
   (founder 2026-07-29). Sized just above the wordmark: the mark is a framed square,
   so matching x-heights would make it read smaller than it is. Under 520px the
   wordmark drops and the mark carries the brand alone, which is what the old
   <picture> swap did at 720px. */
.brand-mark { height: 26px; width: auto; display: block; flex: 0 0 auto; }
/* (the 26px landing override is gone: it IS the base now) */
/* WORDMARK OFF WITH THE BURGER, AND THE MARK GROWS (founder 2026-08-01: "when its the
   hamburger, remove the noboringsites. word logo and only have the nobs logo but slightly
   bigger so its more visible and u can see the words and it fits cleanly").
   This used to happen only under 520px, so between 520 and 1080 the wordmark was still
   fighting the links for the same row. It now switches at the same width the burger does,
   which is the only width at which the question is actually asked. */
@media (max-width: 1080px) {
  /* .bar TOO, not just .nav. Scoping this to .nav alone left the 297px wordmark on every
     Class B page — legal, status, intake and the template CHECKOUT — where at 320px it
     overflowed the document by 32px. Caught by scripts/site/audit-responsive.mjs. */
  .nav .brand-logo.light-only, .nav .brand-logo.dark-only,
  .bar .brand-logo.light-only, .bar .brand-logo.dark-only { display: none; }
  .nav .brand-mark, .bar .brand-mark { height: 40px; }
}
/* Never wrap, never shrink. white-space alone was not enough: both sit in a flex row, so
   the browser was free to shrink them below their content width and wrap anyway. The
   responsive audit caught both still on two lines at 1081px. */
.nav-login-btn, .nav-cta { white-space: nowrap; flex: 0 0 auto; }

/* THE NAV ICON PAIR — search and cart. One rule, because two controls that sit shoulder to
   shoulder must be one component or they drift apart the way the theme toggle and the login
   button already did once.

   BOXED, LIKE THE OLD THEME TOGGLE (founder 2026-08-03: "the buttons here i dont like how
   they arent boxed. look at how we used to do the taskbar with the dark/light mode button
   and make all of them like that"). They spent one day bare, which left four unframed glyphs
   floating against a solid CTA and read as unfinished at a glance. The reference is our own
   pre-ce9320a5 theme toggle: a ghost square on --surface with a --line border, accent border
   and ink on hover, a 1px lift and a press.
   ONE HEIGHT FOR THE WHOLE BAR: 44px, not the old 40. Every other control in .nav-right —
   the login button and the CTA — is 44px tall, and the old row shipped a 44px toggle beside
   40px icons, which is the mismatch that comment history already records once.
   1.5px, not the toggle's old 1px: the house-button law below sets 1.5px on both the filled
   and the ghost variant precisely so controls side by side are the same box, and the login
   button sitting next to these carries it. */
.nav-icon { position: relative; display: inline-grid;
  place-items: center; flex: 0 0 auto; width: 44px; height: 44px; padding: 0; cursor: pointer; text-decoration: none;
  border: 1.5px solid var(--line); border-radius: var(--radius-button);
  background: var(--surface, #fbf8f2); color: var(--ink);
  transition: border-color 0.2s ease, background 0.2s ease, color 0.2s ease, transform 0.3s var(--spring, cubic-bezier(.22,.61,.36,1)); }
.nav-icon svg { width: 19px; height: 19px; }
.nav-icon:hover { border-color: var(--accent); color: var(--accent-text); transform: translateY(-1px); }
.nav-icon:active { transform: translateY(1px); }
.nav-icon:focus-visible { outline: 2px solid var(--accent-text); outline-offset: 2px; }
/* the count sits ON the bag, like the reference. Hidden at zero by the [hidden] attribute
   rather than by a class, so it is out of the accessibility tree too. */
.cart-badge { position: absolute; top: -6px; right: -6px; min-width: 18px; height: 18px;
  padding: 0 5px; border-radius: 999px; background: var(--accent); color: #fff;
  font: 600 11px/18px var(--body); text-align: center; pointer-events: none; }

@media (max-width: 519.98px) {
  /* .nav .brand-logo.light-only, not .brand-logo — a media query adds NO specificity, so
     the plain `.brand-logo{display:none}` this used to be (0,1,0) lost to
     `.light-only{display:block}` (0,1,0) declared 17 lines LATER, and the rule never once
     fired. Measured 2026-08-01: the wordmark still painted at 320-540px and overhung
     .nav-right by 31px at 390 — .nav has overflow:visible, so the tail ran under the theme
     button and the brand read "noboringsit". Both themes, every page with the paired nav. */
  .nav .brand-logo.light-only, .nav .brand-logo.dark-only { display: none; }
  /* ...UNLESS it is the only brand element on the page. The landing nav pairs a
     .brand-mark with the wordmark, so hiding the wordmark under 520px leaves the mark
     carrying the brand. 25 other pages — including /templates/, /templates/buy/, every
     legal page and the whole portal — still use the older <picture> nav, which has NO
     .brand-mark: its single <img class="brand-logo"> already swaps itself to the square
     mark at 719.98px via <source>. So this rule was deleting the entire logo on those
     pages on every phone. Measured 2026-08-01: .brand rendered 0px wide at 390 on
     /migrate/. The picture's own source swap is the fallback the rule assumed existed. */
  picture .brand-logo { display: block; height: 26px; }
}
/* Landing nav wordmark sits at 22px — the size the catalogue nav already uses.
   At the shared 44px it rendered 297x44, exactly as tall as the CTA pill, and
   dominated the bar (founder 2026-07-23). Gated to >=720px on purpose: below
   that the <picture> swaps to mark.svg, which needs the full 44px to stay
   legible. .nav-scoped so the 24px footer lockup is untouched. */
/* (the 22px landing override is gone: it IS the base now) */
.light-only { display: block; } .dark-only { display: none; }
[data-theme="dark"] .light-only { display: none; } [data-theme="dark"] .dark-only { display: block; }
.nav-links { display: flex; align-items: center; gap: 26px; color: var(--muted); font-size: 0.9rem; font-weight: 500; }
.nav-links a { transition: color 0.2s; }
.nav-links a:hover { color: var(--ink); }
.nav-right { display: flex; align-items: center; gap: 12px; }
/* THE BOX EVERY OTHER ICON COPIES. This is the control the founder pointed at on 2026-08-03
   ("look at how we used to do the taskbar with the dark/light mode button and make all of
   them like that"), so it is declared identically to .nav-icon above and the two must move
   together. Same 44px, same 1.5px --line border, same --surface fill. */
.theme-toggle {
  width: 44px; height: 44px; border-radius: var(--radius-button); border: 1.5px solid var(--line);
  background: var(--surface, #fbf8f2); color: var(--ink); cursor: pointer; font-size: 16px; line-height: 1;
  display: grid; place-items: center; transition: border-color 0.2s, background 0.2s, color 0.2s, transform 0.3s var(--spring, cubic-bezier(.22,.61,.36,1));
}
/* Reacts like .nav-login-btn, not just a border tint (founder 2026-08-02: "it should
   react the same way as the login button on hover and not just be static. same with the
   dark mode light mode configurator button"). Same three moves: accent border, accent ink,
   1px lift, and a press. */
.theme-toggle:hover { border-color: var(--accent); color: var(--accent-text); transform: translateY(-1px); }
.theme-toggle:active { transform: translateY(1px); }
.theme-toggle:focus-visible { outline: 2px solid var(--accent-text); outline-offset: 2px; }
.ico-moon { display: none; } [data-theme="dark"] .ico-sun { display: none; } [data-theme="dark"] .ico-moon { display: inline; }

/* THEME SETTINGS — System / Light / Dark, saved in localStorage as `nbs-theme`.
   The sun/moon beside it is the quick flip and pins an explicit choice; this menu
   is how you get back to "follow my machine". System is the default for anyone who
   has never chosen, and it keeps tracking the OS live. */
.theme-mode-wrap { position: relative; display: inline-flex; }
.theme-mode-menu {
  position: absolute; top: calc(100% + 10px); right: 0; z-index: 200;
  width: max-content; min-width: 168px; padding: 8px;
  display: flex; flex-direction: column; gap: 2px;
  background: var(--surface, #fbf8f2); border: 1px solid var(--line); border-radius: var(--radius-tile);
  box-shadow: 0 24px 60px -20px rgba(0, 0, 0, 0.35);
}
.theme-mode-menu[hidden] { display: none; }
.theme-mode-opt {
  display: flex; align-items: center; justify-content: space-between; gap: 14px;
  padding: 9px 12px; border-radius: 10px; border: 0; background: none; cursor: pointer;
  font-family: var(--body); font-weight: 600; font-size: 0.875rem; color: var(--ink);
  transition: background 0.15s;
}
/* Hover and focus were one rule with `outline:none`, so the keyboard focus state was an
   8% tint and nothing else: measured 1.14:1 light and 1.13:1 dark against the menu, and
   visually identical to hover, so a keyboard user could not tell which of the three rows
   they were on. WCAG 2.4.11 / 1.4.11 (the 3:1 non-text floor). Every other control on the
   site gets the 2px Klein ring from the global :focus-visible rule; these three explicitly
   opted out of it. They no longer do. Split, so hover keeps the tint alone. */
.theme-mode-opt:hover { background: color-mix(in srgb, var(--accent) 8%, transparent); }
.theme-mode-opt:focus-visible {
  background: color-mix(in srgb, var(--accent) 8%, transparent);
  outline: 2px solid var(--accent); outline-offset: -2px;
}
.tm-tick { width: 15px; height: 15px; flex: 0 0 auto; opacity: 0; color: var(--accent-text); }
.theme-mode-opt[aria-checked="true"] { color: var(--accent-text); }
.theme-mode-opt[aria-checked="true"] .tm-tick { opacity: 1; }
/* THE HOUSE BUTTON (founder 2026-07-26: "cant u see the back and next buttons.
   thats the branding"). One component everywhere: 12px radius, 1.5px border on BOTH
   the filled and the ghost variant so a primary and a secondary sitting side by side
   are the same box, a Klein drop shadow on the filled one, a 1px lift on hover and a
   1px press on active. Lifted verbatim from the quiz flow's .btn / .btn-next.ready,
   which is the canonical definition. 999px pills are for CHIPS only, never buttons. */
.nav-cta {
  display: inline-flex; align-items: center; gap: 8px; height: 44px; padding: 0 18px;
  background: var(--accent); color: var(--accent-ink);
  border: 1.5px solid var(--accent); border-radius: var(--radius-button);
  font-weight: 600; font-size: 0.875rem; white-space: nowrap;
  box-shadow: 0 8px 20px -10px color-mix(in srgb, var(--accent) 55%, transparent);
  transition: background 0.25s ease, border-color 0.25s ease, box-shadow 0.25s ease,
    transform 0.3s var(--spring);
}
.nav-cta:hover {
  background: var(--accent-lift); border-color: var(--accent-lift); transform: translateY(-1px);
  box-shadow: 0 12px 26px -10px color-mix(in srgb, var(--accent) 60%, transparent);
}
.nav-cta:active {
  transform: translateY(1px);
  box-shadow: 0 6px 14px -10px color-mix(in srgb, var(--accent) 50%, transparent);
}
.nav-cta:focus-visible { outline: 2px solid var(--accent-text); outline-offset: 2px; }
.nav-cta .chev-n { width: 15px; height: 15px; flex: 0 0 auto; transition: transform 0.4s var(--ease-out-expo, cubic-bezier(.16,1,.3,1)); }
.nav-cta:hover .chev-n { transform: translateX(3px); }

/* small screens: the hero CTA + the sticky bar carry the action; a third
   persistent nav CTA is clutter (landing only — other pages keep theirs) */
@media (max-width: 640px) { .landing .nav-right > .nav-cta { display: none; } }

/* nav LOGIN — a secondary ghost button (never competes with the Klein CTA) that
   opens the centred login pop-up (same shell as the plan checkout) */
.nav-login-btn {
  display: inline-flex; align-items: center; gap: 8px; height: 44px; padding: 0 18px;
  border-radius: var(--radius-button); border: 1.5px solid var(--line); background: var(--surface, #fbf8f2); color: var(--ink);
  font-family: var(--body); font-weight: 600; font-size: 0.875rem; cursor: pointer;
  transition: border-color 0.2s, color 0.2s, background 0.2s, transform 0.3s var(--spring);
}
.nav-login-btn:hover { border-color: var(--accent); color: var(--accent-text); transform: translateY(-1px); }
.nav-login-btn:active { transform: translateY(1px); }
.nav-login-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
@media (max-width: 720px) { .nav-login-btn { padding: 0 12px; } }

/* ============================================================
   UNIFIED NAV — mobile drawer + secondary sub-bar (2026-07-20)
   Desktop: .nav-links stays a direct flex child of .nav exactly as
   before; the drawer is a separate mobile-only element (hidden).
   Mobile <=860: .nav-links + desktop actions hide, the burger shows
   and toggles a dropdown panel. No JS — <details> holds the open
   state, so it works with scripts disabled.
   ============================================================ */
.nav-drawer { display: none; }

/* 1080, NOT 860 (founder 2026-08-01, at ~944px: "the log in should never be on 2 lines and
   the noboringsites. should never interfere with the wording here. its clear that it should
   become a hamburger at this width").
   Measured at 944: the wordmark ran under "Templates" and .nav-login-btn wrapped to two
   lines. The old 860 was chosen when the nav had four flat links; it now carries five items
   with a dropdown plus three right-hand controls, so the collision point moved up and the
   breakpoint never followed. */
@media (max-width: 1080px) {
  /* BOTH WORD-BUTTONS GO; THE ICON BOXES STAY. Login went back to the word "Log in" on
     2026-08-03, which is the element that wrapped to two lines at 944 and prompted this
     breakpoint in the first place, so it is hidden here again exactly as it was before it
     spent a day as a glyph. The drawer below carries its own .drawer-login, so nothing is
     lost. Search and cart are fixed 44px squares that cannot wrap and stay visible. */
  .nav-right > .nav-cta, .nav-right > .nav-login-btn { display: none; }
  .nav-drawer { display: block; position: relative; }
  .nav-burger {
    display: grid; place-items: center; width: 44px; height: 44px; list-style: none;
    border-radius: var(--radius-button); border: 1px solid var(--line);
    background: var(--surface, #fbf8f2); color: var(--ink); cursor: pointer;
  }
  .nav-burger::-webkit-details-marker { display: none; }
  .nav-burger:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
  .burger-lines, .burger-lines::before, .burger-lines::after {
    content: ""; display: block; width: 18px; height: 2px; border-radius: 2px; background: currentColor;
    transition: transform .2s var(--ease-out-expo, cubic-bezier(.16,1,.3,1)), opacity .2s;
  }
  .burger-lines { position: relative; }
  .burger-lines::before { position: absolute; top: -6px; left: 0; }
  .burger-lines::after  { position: absolute; top: 6px;  left: 0; }
  .nav-drawer[open] .burger-lines { background: transparent; }
  .nav-drawer[open] .burger-lines::before { transform: translateY(6px) rotate(45deg); }
  .nav-drawer[open] .burger-lines::after  { transform: translateY(-6px) rotate(-45deg); }

  .nav-drawer-panel { display: none; }
  .nav-drawer[open] .nav-drawer-panel {
    display: flex; flex-direction: column; align-items: stretch; gap: 2px;
    position: absolute; top: calc(100% + 12px); right: 0; z-index: 200;
    width: min(80vw, 300px); padding: 10px;
    background: var(--surface, #fbf8f2); border: 1px solid var(--line); border-radius: 14px;
    box-shadow: 0 24px 60px -20px rgba(0, 0, 0, 0.35);
  }
  .nav-drawer-panel a {
    padding: 12px 14px; border-radius: 10px; color: var(--ink); font-size: 0.98rem; font-weight: 500;
  }
  .nav-drawer-panel a:hover { background: color-mix(in srgb, var(--ink) 6%, transparent); }
  .nav-drawer-panel a[aria-current="page"] { color: var(--accent-text); font-weight: 600; }
  .nav-drawer-panel .drawer-label { font-family: var(--mono); font-size: 0.62rem; letter-spacing: 0.08em; text-transform: uppercase; color: var(--muted); padding: 12px 14px 4px; margin: 0; }
  .nav-drawer-panel .drawer-top { font-weight: 700; color: var(--ink); }
  .nav-drawer-panel .drawer-login { margin-top: 6px; padding-top: 14px; border-top: 1px solid var(--line); }
  .nav-drawer-panel .nav-cta { justify-content: center; height: auto; margin-top: 8px; padding: 13px 16px; }
}

/* NAV DROPDOWNS — Resources / Community (desktop). Theme-aware surface panel
   with a two-line item (title + one-line description). Pure CSS: opens on
   hover and on keyboard focus-within, no JS. The mobile drawer lists the same
   items flat under section labels. */
.nav-dd { position: relative; display: inline-flex; }
.nav-dd-toggle {
  display: inline-flex; align-items: center; gap: 5px;
  font-family: var(--body); font-size: 0.9rem; font-weight: 500; line-height: 1;
  color: var(--muted); background: none; border: 0; padding: 0; cursor: pointer;
  transition: color 0.2s;
}
.nav-dd-toggle:hover, .nav-dd:hover .nav-dd-toggle, .nav-dd:focus-within .nav-dd-toggle { color: var(--ink); }
/* Home and About Us carry no panel, so they are anchors rather than toggles. Every
   type property below is copied from .nav-dd-toggle above: in a row of five, one item
   a hair heavier or a hair larger reads as a defect, not a distinction. The only
   difference is the missing chevron and the missing 5px gap that held it. */
/* NOWRAP on every top-level item, toggles included. Keeping the login icon visible at
   <=1080 (below) gave .nav-right 52px more, and at 1081 "About Us" broke onto two lines
   inside a 44px bar - caught by the responsive audit, not by eye. A nav item that wraps is
   a defect at any width, so this is the invariant rather than another breakpoint. */
.nav-links > .nav-link, .nav-dd-toggle { white-space: nowrap; }
.nav-links > .nav-link {
  display: inline-flex; align-items: center;
  font-family: var(--body); font-size: 0.9rem; font-weight: 500; line-height: 1;
  color: var(--muted); text-decoration: none; transition: color 0.2s;
}
.nav-links > .nav-link:hover { color: var(--ink); }
.nav-links > .nav-link[aria-current="page"] { color: var(--ink); }
.dd-chev { width: 13px; height: 13px; flex: 0 0 auto; transition: transform 0.2s var(--ease-out-expo, cubic-bezier(.16,1,.3,1)); }
.nav-dd:hover .dd-chev, .nav-dd:focus-within .dd-chev { transform: rotate(180deg); }
.nav-dd-panel {
  position: absolute; top: calc(100% + 12px); left: 50%;
  z-index: 200; width: max-content; max-width: 340px; padding: 8px;
  display: flex; flex-direction: column; gap: 2px;
  background: var(--surface, #fbf8f2); border: 1px solid var(--line); border-radius: var(--radius-tile);
  box-shadow: 0 24px 60px -20px rgba(0, 0, 0, 0.35);
  opacity: 0; visibility: hidden; pointer-events: none;
  transform: translateX(-50%) translateY(6px);
  transition: opacity 0.18s ease, transform 0.18s var(--ease-out-expo, cubic-bezier(.16,1,.3,1)), visibility 0.18s;
}
.nav-dd-panel::before { content: ""; position: absolute; top: -12px; left: 0; right: 0; height: 12px; }
.nav-dd:hover .nav-dd-panel, .nav-dd:focus-within .nav-dd-panel {
  opacity: 1; visibility: visible; pointer-events: auto; transform: translateX(-50%) translateY(0);
}
.dd-item { display: flex; flex-direction: column; gap: 1px; padding: 9px 12px; border-radius: 10px; text-decoration: none; transition: background 0.15s; }
.dd-item:hover, .dd-item:focus-visible { background: color-mix(in srgb, var(--accent) 8%, transparent); outline: none; }
.dd-item b { font-family: var(--body); font-weight: 700; font-size: 0.92rem; color: var(--ink); letter-spacing: -0.01em; }
.dd-item span { font-size: 0.8rem; line-height: 1.3; color: var(--muted); }
.dd-item[aria-current="page"] b { color: var(--accent-text); }
/* THE BURGER BREAKPOINT IS 1080, SO THE LINK ROW MUST HIDE AT 1080 TOO.
   .nav-links{display:none} used to sit in the 860 query while :372 shows the burger and
   :444 hides the dropdown toggles at 1080. Across that 220px band the flex row was still
   painting with every toggle inside it hidden, leaving one orphaned text link floating
   mid-bar next to a burger that already listed it. It affected / and all 12 sibling Class A
   pages, and no gate saw it because check-nav-parity renders at 1440 only.
   These two declarations belong together: hiding the dropdowns without hiding their
   container is what created the orphan. */
@media (max-width: 1080px) { .nav-dd, .nav-links { display: none; } }

/* Tier 2 — secondary sub-bar: a page's own in-page section anchors, demoted
   below the global primary nav so it never reads as the site menu. */
.nav-sub {
  width: var(--container); margin: 0 auto; min-height: 46px;
  display: flex; align-items: center; gap: 22px;
  border-bottom: 1px solid var(--line);
  font-size: 0.82rem; overflow-x: auto; scrollbar-width: none;
  /* A flex scroller still needs min-width:0 and non-shrinking children, or the row lays
     itself out wider than its box and the DOCUMENT scrolls instead of the strip. That was
     48px of horizontal page scroll on /migrate/ at 320. */
  min-width: 0;
}
.nav-sub > * { flex: 0 0 auto; }
.nav-sub::-webkit-scrollbar { display: none; }
.nav-sub .nav-sub-label {
  font-family: var(--mono); font-size: 0.68rem; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--muted); white-space: nowrap;
}
.nav-sub a { color: var(--muted); white-space: nowrap; font-weight: 500; transition: color 0.2s; }
.nav-sub a:hover, .nav-sub a[aria-current="true"] { color: var(--ink); }


/* ============================================================
   THE CART DRAWER lives here for the same reason the nav does: it is STAMPED into
   every Class A page by gen-nav.mjs (out of scripts/site/footer.html), so on
   /templates/ - which never loads site/styles.css - it rendered as a bare <ul> of
   bullet points dumped under the footer, with the close cross as an empty box and
   the Checkout button as an underlined link. Generated markup, generated CSS.
   ============================================================ */
/* ---- THE CART DRAWER ----
   Shopify's shape, per the founder's reference: a scrim, a right-hand panel that slides in
   and out, a cross top-right, a scrolling item list, and a subtotal pinned to the bottom.
   `hidden` controls presence; `.in` controls the slide, which is why close() waits out the
   transition before re-hiding rather than yanking it off screen. */
.cart-wrap { position: fixed; inset: 0; z-index: 200; }
.cart-scrim { position: absolute; inset: 0; background: rgba(12, 10, 12, 0.5);
  opacity: 0; transition: opacity 0.28s ease; }
.cart-wrap.in .cart-scrim { opacity: 1; }
.cart-panel { position: absolute; top: 0; right: 0; height: 100%; width: min(420px, 100vw);
  display: flex; flex-direction: column; background: var(--paper, #f6f3ed);
  border-left: 1px solid var(--line); box-shadow: -18px 0 46px -28px rgba(20, 18, 20, 0.5);
  transform: translateX(100%); transition: transform 0.28s cubic-bezier(0.22, 1, 0.36, 1); }
.cart-wrap.in .cart-panel { transform: translateX(0); }
.cart-head { display: flex; align-items: center; justify-content: space-between;
  padding: 20px 20px 14px; border-bottom: 1px solid var(--line); }
.cart-head h2 { font-family: var(--display); font-weight: 900; font-size: 1.4rem;
  letter-spacing: -0.02em; margin: 0; color: var(--ink); }
.cart-close { display: grid; place-items: center; width: 38px; height: 38px; padding: 0;
  cursor: pointer; border: 1.5px solid var(--line); border-radius: var(--radius-button);
  background: var(--surface, #fbf8f2); color: var(--ink);
  transition: background 0.2s ease, border-color 0.2s ease, color 0.2s ease, transform 0.3s var(--spring); }
.cart-close svg { width: 18px; height: 18px; }
.cart-close:hover { background: #d63a2e; border-color: #d63a2e; color: #fff; transform: rotate(90deg); }
.cart-close:focus-visible { outline: 2px solid var(--accent-text); outline-offset: 2px; }
.cart-empty { margin: 0; padding: 40px 20px; color: var(--muted); text-align: center; }
.cart-list { list-style: none; margin: 0; padding: 6px 20px; overflow-y: auto; flex: 1 1 auto; }
.cart-row { display: flex; align-items: flex-start; gap: 14px; justify-content: space-between;
  padding: 16px 0; border-bottom: 1px solid var(--line); }
.cart-row:last-child { border-bottom: 0; }
.cart-row-name { display: block; font-family: var(--display); font-weight: 900;
  font-size: 1.02rem; letter-spacing: -0.015em; color: var(--ink); }
.cart-row-note { display: block; margin-top: 3px; font-size: 0.82rem; color: var(--muted); }
.cart-row-side { display: flex; align-items: center; gap: 10px; flex: 0 0 auto; }
.cart-row-price { font-family: var(--mono); font-size: 0.86rem; color: var(--ink); }
.cart-row-del { display: grid; place-items: center; width: 32px; height: 32px; padding: 0;
  cursor: pointer; background: none; border: 0; color: var(--muted); border-radius: 8px; }
.cart-row-del svg { width: 16px; height: 16px; }
.cart-row-del:hover { color: #d63a2e; }
.cart-foot { border-top: 1px solid var(--line); padding: 16px 20px 20px; }
.cart-subtotal { display: flex; justify-content: space-between; align-items: baseline;
  font-family: var(--display); font-weight: 900; font-size: 1.1rem; color: var(--ink); }
.cart-note { margin: 8px 0 14px; font-size: 0.82rem; color: var(--muted); line-height: 1.45; }
/* SELF-CONTAINED, not `.btn`. Both carry .btn/.btn-primary/.btn-ghost for the 20 pages
   that load site/styles.css, but /templates/ does not, and there they rendered as two
   underlined text links under the subtotal - the checkout button on a page that sells
   things, looking like a footnote. Copying the whole button system into this file to fix
   two buttons would be worse; these two carry their own. Where .btn IS loaded it declares
   the same shape, so nothing changes on those pages. */
.cart-go, .cart-cont {
  display: flex; align-items: center; justify-content: center; width: 100%;
  height: 46px; padding: 0 18px; border-radius: var(--radius-button, 12px);
  font-family: var(--body); font-size: 0.94rem; font-weight: 600; line-height: 1;
  text-decoration: none; cursor: pointer; border: 1.5px solid transparent;
  transition: background 0.2s, border-color 0.2s, color 0.2s, transform 0.2s;
}
.cart-go { background: var(--accent); color: #fff; margin-bottom: 9px; }
.cart-go:hover { transform: translateY(-1px); }
.cart-go:active { transform: translateY(1px); }
.cart-cont { background: none; color: var(--ink); border-color: var(--line); }
.cart-cont:hover { border-color: var(--accent); color: var(--accent-text); }
.cart-go:focus-visible, .cart-cont:focus-visible { outline: 2px solid var(--accent-text); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) {
  .cart-go, .cart-cont { transition: none; }
  .cart-go:hover, .cart-go:active { transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .cart-scrim, .cart-panel, .cart-close { transition: none; }
  .cart-close:hover { transform: none; }
}

/* ============================================================================
   GLOBAL SEARCH OVERLAY (.sx-*)
   Markup is built by site/public/js/search.js; the trigger lives in the nav.

   ITS OWN TOKENS, ON PURPOSE. /templates/, /partners/ and /partners/terms/ load
   catalogue.css instead of styles.css, and catalogue.css declares neither --surface
   nor --surface-2 nor --ease-out-expo. A panel that paints transparent over the
   marketplace grid is exactly the bug this stylesheet was split out to end, so the
   overlay depends on nothing from either sheet. The values below ARE the house
   values, copied, not approximated.

   The scrim is a per-theme literal rather than color-mix(in srgb, var(--ink) …),
   which is what .care-checkout-backdrop uses: in dark mode --ink is #e9edf0, so
   that recipe paints a 52% WHITE wash over a dark page.
   ============================================================================ */
:root {
  --sx-scrim: rgba(20, 18, 20, 0.42);
  --sx-panel: #fbf8f2;            /* --surface */
  --sx-bar: #f1ece3;              /* --surface-2 */
  --sx-ink: #141214;
  --sx-mut: #6f695e;
  --sx-line: rgba(20, 18, 20, 0.12);
  --sx-line-soft: rgba(20, 18, 20, 0.07);
  --sx-accent: #2438e6;           /* Klein Volt */
  --sx-sel: rgba(20, 18, 20, 0.05);
  --sx-mark: rgba(36, 56, 230, 0.14);
  --sx-shadow: 0 1px 1px rgba(20, 18, 20, 0.04), 0 8px 16px -4px rgba(20, 18, 20, 0.06),
    0 32px 64px -16px rgba(20, 18, 20, 0.18);
}
[data-theme="dark"] {
  --sx-scrim: rgba(4, 7, 10, 0.66);
  --sx-panel: #171c24;
  --sx-bar: #141a22;
  --sx-ink: #e9edf0;
  --sx-mut: #93a0b3;
  --sx-line: rgba(255, 255, 255, 0.12);
  --sx-line-soft: rgba(255, 255, 255, 0.07);
  --sx-accent: #7c97f5;
  --sx-sel: rgba(255, 255, 255, 0.07);
  --sx-mark: rgba(124, 151, 245, 0.2);
  --sx-shadow: 0 1px 1px rgba(0, 0, 0, 0.3), 0 8px 16px -4px rgba(0, 0, 0, 0.35),
    0 32px 64px -16px rgba(0, 0, 0, 0.55);
}

/* 999 is the .care-checkout-backdrop rung. 300 would sit under that backdrop and 200
   would let the marketplace's own cart drawer cover the panel. */
.sx-wrap { position: fixed; inset: 0; z-index: 999; }
html.sx-open { overflow: hidden; }

/* NO backdrop-filter. A full-viewport blur forces a compositor readback of everything
   behind it on every frame of the open animation, and on this site that layer is a
   12-card thumbnail grid or a physics loop. The two best-looking palettes in the field
   (Linear, Vercel) blur nothing; opacity buys the same read for free. */
.sx-scrim {
  position: absolute; inset: 0; background: var(--sx-scrim);
  opacity: 0; transition: opacity 120ms cubic-bezier(0.4, 0, 1, 1);
}
.sx-panel {
  position: relative; display: flex; flex-direction: column; overflow: hidden;
  width: min(640px, calc(100vw - 32px)); margin: clamp(56px, 11vh, 128px) auto auto;
  background: var(--sx-panel); border: 1px solid var(--sx-line);
  border-radius: var(--radius-card, 18px); box-shadow: var(--sx-shadow);
  opacity: 0; transform: translateY(-6px) scale(0.98);
  transition: opacity 120ms cubic-bezier(0.4, 0, 1, 1), transform 120ms cubic-bezier(0.4, 0, 1, 1);
}
/* One duration and one curve for both layers on the way in. 180ms, not the 480ms the
   checkout modal uses: that is a surface you open once, this is one you hit every visit
   and it has to feel instant. Not --spring either — a 640px panel that overshoots on
   every open reads cheap. */
.sx-wrap.sx-in .sx-scrim { opacity: 1; transition-duration: 180ms; transition-timing-function: var(--ease-out-expo, cubic-bezier(0.22, 1, 0.36, 1)); }
.sx-wrap.sx-in .sx-panel {
  opacity: 1; transform: none;
  transition-duration: 180ms; transition-timing-function: var(--ease-out-expo, cubic-bezier(0.22, 1, 0.36, 1));
}

.sx-bar {
  display: flex; align-items: center; gap: 12px; flex: none;
  height: 56px; padding: 0 12px 0 16px;
  background: var(--sx-bar); border-bottom: 1px solid var(--sx-line-soft); color: var(--sx-mut);
}
.sx-input {
  flex: 1; min-width: 0; height: 100%; border: 0; background: none; outline: none;
  font-family: var(--body, "Hanken Grotesk", system-ui, sans-serif);
  /* 18px sits above the 16px floor that makes iOS Safari zoom the page on focus. */
  font-size: 18px; font-weight: 500; line-height: 1;
  color: var(--sx-ink); caret-color: var(--sx-accent);
}
.sx-input::placeholder { color: var(--sx-mut); opacity: 1; }
/* The UA's own clear button is a black blob that lands next to the Esc chip and reads as
   a browser control someone left in, not as part of the page. Escape clears the query and
   the phone sheet has a Cancel; neither Linear nor Vercel ships a clear affordance at all. */
.sx-input::-webkit-search-cancel-button, .sx-input::-webkit-search-decoration { -webkit-appearance: none; appearance: none; display: none; }

.sx-esc, .sx-ret {
  display: grid; place-items: center; flex: none; height: 20px; min-width: 34px;
  padding: 0 6px; border-radius: 4px; background: var(--sx-panel);
  box-shadow: 0 0 0 1px var(--sx-line);
  font-family: var(--mono, "JetBrains Mono", ui-monospace, monospace);
  font-size: 11px; font-weight: 500; letter-spacing: 0.04em; color: var(--sx-mut);
}
.sx-ret { min-width: 20px; opacity: 0; }
/* A key chip on a phone is a lie, and there is no footer legend to hide it in. */
@media (hover: none), (pointer: coarse) { .sx-esc, .sx-ret { display: none; } }

.sx-cancel {
  display: none; flex: none; padding: 6px 4px; border: 0; background: none; cursor: pointer;
  font-family: var(--body, system-ui, sans-serif); font-size: 15px; font-weight: 600;
  color: var(--sx-accent);
}

/* The panel grows to its own content. Without the transition it snaps on every
   keystroke, which is the cheapest-looking thing a palette can do. */
.sx-scroll {
  height: var(--sx-h, 0px); max-height: min(520px, calc(100dvh - 220px));
  overflow-y: auto; overscroll-behavior: contain; scroll-padding-block: 8px;
  transition: height 120ms var(--ease-precision, cubic-bezier(0.4, 0, 0.2, 1));
}
.sx-list { list-style: none; margin: 0; padding: 8px; }

.sx-group {
  position: sticky; top: 0; z-index: 1; display: flex; align-items: center;
  justify-content: space-between; gap: 12px; padding: 0 10px;
  background: var(--sx-panel);
  font-family: var(--mono, ui-monospace, monospace); font-size: 0.68rem; font-weight: 500;
  line-height: 28px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--sx-mut);
}
.sx-clear {
  border: 0; background: none; cursor: pointer; padding: 0;
  font-family: inherit; font-size: 0.66rem; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--sx-mut); transition: color 0.18s;
}
.sx-clear:hover { color: var(--sx-ink); }

.sx-row { border-radius: 12px; }
.sx-hit {
  display: flex; align-items: center; gap: 12px; min-height: 56px; padding: 8px 10px;
  border-radius: 12px; text-decoration: none; color: inherit; overflow-wrap: anywhere;
}
.sx-row[data-t="template"] .sx-hit { min-height: 72px; }
/* A 5% wash and a 2px bar, NOT a saturated fill. DocSearch paints the selected row solid
   brand blue and forces every child to #fff !important, which on a row carrying a
   thumbnail, a trade and a price annihilates all three at once. */
.sx-row.is-sel { background: var(--sx-sel); box-shadow: inset 2px 0 0 var(--sx-accent); }
.sx-row.is-sel .sx-ret { opacity: 1; }
.sx-row, .sx-ret { transition: background-color 90ms linear, opacity 90ms linear; }
/* Pointer-gated, or a touch device shows a phantom highlighted row under a finger that
   has already lifted. */
@media (hover: hover) and (pointer: fine) {
  .sx-row:hover { background: var(--sx-sel); }
}

.sx-thumb {
  flex: none; width: 60px; height: 45px; border-radius: 8px; object-fit: cover;
  border: 1px solid var(--sx-line); background: var(--sx-bar);
}
.sx-ico { flex: none; display: grid; place-items: center; width: 24px; height: 24px; color: var(--sx-mut); }
.sx-txt { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.sx-title {
  font-family: var(--body, system-ui, sans-serif); font-size: 15px; font-weight: 650;
  line-height: 1.35; color: var(--sx-ink);
  overflow: hidden; text-overflow: ellipsis; display: -webkit-box;
  -webkit-line-clamp: 1; -webkit-box-orient: vertical;
}
.sx-sub {
  font-family: var(--body, system-ui, sans-serif); font-size: 13px; line-height: 1.35; color: var(--sx-mut);
  overflow: hidden; text-overflow: ellipsis; display: -webkit-box;
  -webkit-line-clamp: 1; -webkit-box-orient: vertical;
}
/* Accent tint, not a yellow highlighter and not Vercel's amber: this palette has no
   amber, and --hlite-warm is a heading device. */
.sx-row mark { background: var(--sx-mark); color: inherit; font-weight: 650; border-radius: 3px; padding: 0 1px; }

.sx-empty { padding: 26px 12px 22px; text-align: center; }
.sx-empty p {
  margin: 0; font-family: var(--body, system-ui, sans-serif); font-size: 15px; line-height: 1.5;
  color: var(--sx-mut); overflow-wrap: anywhere;
}
.sx-empty b { color: var(--sx-ink); font-weight: 600; }

.sx-live {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}

.sx-hit:focus-visible, .sx-cancel:focus-visible, .sx-clear:focus-visible {
  outline: 2px solid var(--sx-accent); outline-offset: 2px;
}

/* Full-screen sheet on a phone. Our rows carry 60px thumbnails, so an inset card here
   would leave the title clamped to about four words. */
@media (max-width: 640px) {
  .sx-panel { width: 100%; height: 100dvh; margin: 0; border: 0; border-radius: 0; }
  .sx-bar { height: 60px; }
  .sx-cancel { display: block; }
  /* Cancel is the affordance here; a key chip beside it is two answers to one question.
     The (hover:none) rule above does not cover a narrow DESKTOP window, which is what a
     390px-wide browser is. */
  .sx-esc { display: none; }
  .sx-scroll { height: auto; max-height: calc(100dvh - 60px); transition: none; }
  .sx-hit { min-height: 64px; padding-block: 10px; }
  .sx-title { -webkit-line-clamp: 2; }
  .sx-sub { -webkit-line-clamp: 2; }
  .sx-row[data-t="template"] .sx-hit { min-height: 76px; }
  .sx-thumb { width: 64px; height: 48px; }
}

/* Both transition AND transform. Killing the transition alone leaves the panel snapping
   in from its offset start, which is the house pattern in every other guard here. */
@media (prefers-reduced-motion: reduce) {
  .sx-scrim, .sx-panel, .sx-scroll, .sx-row, .sx-ret { transition: none; }
  .sx-panel { transform: none; }
}
