/* App Garden — support, legal and checkout pages.
   Master copy. Mirrored to hardcoded-value-detector/site.css, the apex
   site.css, and each add-in repo's site/site.css. Styles the existing markup
   only, so the Paddle checkout on the buy page and the key handover on the
   claim page keep their structure untouched.

   The cinematic direction, carried onto the prose pages. The homepage is the
   full version of it — the grid plane, the parallax, a glow per section; here
   the same palette, the same ribbon and the same type scale dress a column of
   text, and the atmosphere comes too, in one fixed pair of layers off the body
   rather than a dozen divs. This paragraph said the opposite until 2026-09-06:
   the sheen was deliberately left behind, and leaving the homepage read as
   leaving the site.

   Both colour schemes are designed, not derived. Dark is the direction's home
   ground, and it is the softer #0f1412 rather than the homepage's near-black:
   these pages are read rather than looked at, and #030303 under a column of
   body text is a glare, not a stage. Light is not that inverted — the raised
   surfaces become paper on paper, and shadows do the separating that hairlines
   do on dark.

   Green is the brand: the Bloom's one green petal, and the mark's own green.
   Magenta means one thing and one thing only: a defect. It is absent from the
   identity so it can keep meaning that here.

   Webfonts are progressive enhancement. Every family has a system fallback of
   similar proportion, so these pages still render correctly with no network
   fetch — a reviewer's machine, an offline check, or a blocked font CDN all get
   a complete page. */
@import url("https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;600&family=Schibsted+Grotesk:wght@400;500;600;700;800&display=swap");

:root {
  color-scheme: light dark;

  --paper: #f7f6f3;
  --ink: #101311;
  --muted: #5c625b;
  --faint: #6f756e;

  /* the Bloom's green petal */
  --accent: #1f6b4f;
  --accent-soft: #1a5b43;
  --link: #1a5b43;

  /* the one magenta, and it means a defect */
  --flag: #c41e5c;
  --flag-ink: #ffffff;
  --flag-wash: #fdf2f6;

  /* A button's fill runs light-to-dark down the pill in both schemes, so the two
     stops are named rather than mixed off --accent, which would invert the
     gradient in one of them. */
  --btn-a: #27805e;
  --btn-b: #1f6b4f;
  --btn-ink: #f7f6f3;

  --card: #ffffff;
  --band: #eceae4;
  --rule: rgba(16, 19, 17, 0.13);
  --hair: rgba(16, 19, 17, 0.08);
  --surf: rgba(16, 19, 17, 0.028);
  --surf-2: rgba(16, 19, 17, 0.05);
  --nav-bg: rgba(247, 246, 243, 0.78);

  /* the atmosphere: the homepage's green sheen, damped for a page of prose */
  --sheen-a: 84%;
  --sheen-b: 90%;
  --sheen-c: 88%;
  --vignette: rgba(16, 19, 17, 0.09);
  --grain-op: 0.05;

  --pill: 980px;
  --lift: 0 18px 44px -30px rgba(16, 19, 17, 0.28);
  /* A scrim always darkens. Never derive it from --ink, which inverts. */
  --scrim: rgba(16, 19, 17, 0.55);

  --display: "Schibsted Grotesk", "Segoe UI", system-ui, sans-serif;
  --body: "Schibsted Grotesk", "Segoe UI", system-ui, sans-serif;
  --mono: "IBM Plex Mono", ui-monospace, Consolas, monospace;
}

@media (prefers-color-scheme: dark) {
  :root {
    --paper: #0f1412;
    --ink: #e8ebe6;
    --muted: #a2aaa1;
    --faint: #8e968d;

    --accent: #86d0a6;
    --accent-soft: #b3e4c8;
    --link: #86d0a6;

    --flag: #ff7ba4;
    --flag-ink: #0f1412;
    --flag-wash: #2c1a22;

    --btn-a: #b3e4c8;
    --btn-b: #86d0a6;
    --btn-ink: #08120c;

    --card: #171f1c;
    --band: #141a17;
    --rule: rgba(255, 255, 255, 0.1);
    --hair: rgba(255, 255, 255, 0.06);
    --surf: rgba(255, 255, 255, 0.035);
    --surf-2: rgba(255, 255, 255, 0.06);
    --nav-bg: rgba(15, 20, 18, 0.72);

    /* Dark is the sheen's home ground, so the glows carry more of the accent
       and the vignette is a real one rather than a hint. */
    --sheen-a: 74%;
    --sheen-b: 84%;
    --sheen-c: 82%;
    --vignette: rgba(0, 0, 0, 0.5);
    --grain-op: 0.16;

    /* No usable shadow on a dark ground; raised surfaces carry a border. */
    --lift: none;
    --scrim: rgba(0, 0, 0, 0.7);
  }
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

body {
  position: relative;
  isolation: isolate;
  overflow-x: clip;
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font: 400 1.0625rem/1.6 var(--body);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* ---- page-wide atmosphere -------------------------------------------- */

/* The homepage's green sheen, carried onto every other page. The homepage
   builds it from a dozen absolutely-positioned .glow divs, one per section;
   here it is drawn entirely from the body's own two pseudo-elements, and that
   is deliberate. These pages are twenty-odd HTML files spread over eight
   repositories, so anything needing markup would have to be added to all of
   them by hand and would drift the first time one was rebuilt and the others
   were not. A stylesheet change reaches every page by the mirroring step that
   already exists.

   Pure radial-gradients, as on the homepage: no blur filter and no blend mode,
   so neither layer re-composites while the page scrolls. Both are fixed, which
   also means a long policy page scrolls through the sheen rather than
   dragging it along.

   `isolation: isolate` above is what makes `z-index: -1` safe. Without a
   stacking context on the body the negative layer would paint behind the
   root's background and vanish. */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(
      58rem 46rem at 8% -12%,
      color-mix(in oklab, var(--accent), transparent var(--sheen-a)),
      transparent 72%
    ),
    radial-gradient(
      50rem 42rem at 96% 14%,
      color-mix(in oklab, var(--accent), transparent var(--sheen-b)),
      transparent 72%
    ),
    radial-gradient(
      56rem 44rem at 46% 112%,
      color-mix(in oklab, var(--accent), transparent var(--sheen-c)),
      transparent 72%
    ),
    radial-gradient(120% 90% at 50% 42%, transparent 46%, var(--vignette) 100%);
}

/* Plain alpha, not a blend mode: a fixed full-screen mix-blend layer has to
   re-composite on every scrolled frame, and this one only needs to sit on top.
   z-index 60 puts it over the sticky masthead (50) and under the drawer
   backdrop (65) and the drawer (70), so an open drawer is not grained. */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 60;
  pointer-events: none;
  opacity: var(--grain-op);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.82' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)' opacity='0.42'/%3E%3C/svg%3E");
}

/* Forced colours replace every background we just drew with the system's own,
   and a full-page grain over the text is noise in the literal sense. Drop
   both rather than let the OS approximate them. */
@media (forced-colors: active) {
  body::before,
  body::after {
    display: none;
  }
}

main {
  max-width: 46rem;
  margin: 0 auto;
  padding: clamp(2.5rem, 7vw, 4rem) clamp(1.25rem, 5vw, 2rem) 4rem;
}

/* ---- headings -------------------------------------------------------- */

h1 {
  margin: 0 0 0.9rem;
  font-family: var(--display);
  font-weight: 800;
  font-size: clamp(2.1rem, 6vw, 3.2rem);
  line-height: 1.01;
  letter-spacing: -0.04em;
  text-wrap: balance;
}

/* Section rules were an earlier direction's device. This one separates with
   space and weight instead, so an h2 is a heading, not a ruled band. */
h2 {
  margin: 2.75rem 0 0.75rem;
  font-family: var(--display);
  font-weight: 700;
  font-size: 1.45rem;
  line-height: 1.2;
  letter-spacing: -0.028em;
}

h3 {
  margin: 0 0 0.6rem;
  font-family: var(--display);
  font-weight: 600;
  font-size: 1.15rem;
  line-height: 1.25;
  letter-spacing: -0.022em;
}

/* The standfirst under the page title. */
.lead {
  margin: 0 0 1.25rem;
  color: var(--muted);
  font-size: 1.3rem;
  line-height: 1.5;
  text-wrap: pretty;
}

p {
  margin: 0 0 1.1rem;
  text-wrap: pretty;
}

strong {
  font-weight: 600;
  color: var(--ink);
}

em {
  font-style: italic;
}

a {
  color: var(--link);
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
}

a:hover {
  color: var(--ink);
}

:focus-visible {
  outline: 2px solid var(--accent-soft);
  outline-offset: 3px;
  border-radius: 4px;
}

code {
  font-family: var(--mono);
  font-size: 0.88em;
  background: var(--surf);
  border: 1px solid var(--rule);
  border-radius: 5px;
  padding: 0.08em 0.34em;
}

/* ---- lists ------------------------------------------------------------ */

ul {
  margin: 0 0 1.1rem;
  padding-left: 1.3rem;
}

li {
  margin-bottom: 0.6rem;
}

li::marker {
  color: var(--faint);
}

/* `ul` above sets the indent for unordered lists and `ol` had no rule at all, so
   the two shipped pages that use one (Two-file reconciliation and Change diff)
   sat at the browser's 40px against everything else's 1.3rem. Same indent for
   both; the guides lean on ordered lists heavily. */
ol {
  margin: 0 0 1.1rem;
  padding-left: 1.3rem;
}

/* ---- guide pages ------------------------------------------------------- */

/* These four rules used to live in an inline <style> written by the guide
   builder, out of a reluctance to add anything to a stylesheet with eleven
   byte-identical copies. That was the right call while the rules were still
   moving; all seven guides now exist and they have stopped, and the builder's
   own comment said to fold them in at exactly this point.

   The reason it matters is not tidiness. Every colour in that inline block was
   a literal rgba(255, 255, 255, …) — correct on the dark ground and invisible
   on the light one, because it was written against a screenshot rather than
   against the token system. A guide is the one page type that is mostly
   pictures, so a figure border that disappears takes the page's structure with
   it. */

figure {
  margin: 1.75rem 0;
}

/* Shot at 800px for 2x and displayed at 400, which is the house width in the
   guide rig's harness/shoot.mjs. The two numbers have to agree: a screenshot of
   small pane text that has been scaled either way is unreadable, and an
   unreadable screenshot is the whole guide. */
figure img {
  display: block;
  width: 400px;
  max-width: 100%;
  height: auto;
  border: 1px solid var(--rule);
  border-radius: 10px;
}

figcaption {
  margin-top: 0.6rem;
  max-width: 34rem;
  color: var(--muted);
  font-size: 0.92rem;
}

kbd {
  font-family: var(--mono);
  font-size: 0.88em;
  background: var(--surf);
  border: 1px solid var(--rule);
  border-radius: 5px;
  padding: 0.08em 0.34em;
}

/* The rules table in the guide: a rule code, then what the rule finds.
 *
 * Unstyled, it collapsed to the narrowest layout the browser could manage — the
 * first column squeezed until `XL-01` broke across two lines *inside its own
 * chip*, so a column of codes read "XL- / 01" all the way down. A code that
 * cannot survive being read is not an identifier.
 *
 * So: the code column takes exactly the width of its content and never wraps,
 * the description takes the rest, and a hairline between rows carries the eye
 * across a table with seventeen of them. `table-layout: auto` is doing the work
 * here, and `width: 1%` is the usual way of saying "shrink this column to fit"
 * without naming a width that a longer rule code would break. */
main table {
  width: 100%;
  margin: 1.4rem 0;
  border-collapse: collapse;
  font-size: 0.95rem;
}

main table td {
  padding: 0.5rem 0 0.5rem 1rem;
  border-top: 1px solid var(--rule);
  vertical-align: baseline;
}

main table tr:first-child td {
  border-top: 0;
}

main table td:first-child {
  width: 1%;
  padding-left: 0;
  padding-right: 0.35rem;
  white-space: nowrap;
}

/* "Pro" beside a heading, so a reader scanning the headings can see which steps
   they cannot do on the free tier without reading the paragraph. Accent rather
   than currentColor: it is a tier marker, not emphasis, and magenta is reserved
   for defects. */
.tag {
  display: inline-block;
  vertical-align: middle;
  margin-left: 0.5rem;
  padding: 0.1rem 0.5rem;
  border: 1px solid var(--accent);
  border-radius: var(--pill);
  color: var(--accent);
  font-size: 0.62em;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

/* ---- buy page: billing cycle switch ----------------------------------- */

.cycle {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 1.25rem;
  margin-bottom: 1.75rem;
  padding: 0.9rem 1.1rem;
  background: var(--card);
  border: 1px solid var(--rule);
  border-radius: 14px;
  box-shadow: var(--lift);
  font-size: 0.92rem;
}

.cycle label {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  cursor: pointer;
}

.cycle input {
  accent-color: var(--accent);
}

/* ---- buy page: plans --------------------------------------------------- */

.plans {
  display: grid;
  gap: 1.5rem;
  grid-template-columns: 1fr;
  align-items: start;
  margin-bottom: 1.75rem;
}

@media (min-width: 44rem) {
  .plans {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

.plan {
  background: var(--card);
  border: 1px solid var(--rule);
  border-radius: 20px;
  box-shadow: var(--lift);
  padding: 1.75rem;
}

.plan ul {
  margin: 0 0 1.5rem;
  padding: 0;
  list-style: none;
  border-top: 1px solid var(--hair);
  font-size: 0.95rem;
}

.plan li {
  margin: 0;
  padding: 0.6rem 0;
  border-bottom: 1px solid var(--hair);
  line-height: 1.45;
  color: var(--muted);
}

.price {
  margin: 0 0 1.25rem;
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  flex-wrap: wrap;
  color: var(--faint);
  font-size: 0.95rem;
}

.price strong {
  font-family: var(--display);
  font-weight: 800;
  font-size: 2.6rem;
  letter-spacing: -0.042em;
  line-height: 1;
}

/* ---- controls ---------------------------------------------------------- */

button {
  font-family: var(--display);
  font-size: 0.95rem;
  font-weight: 600;
  letter-spacing: -0.012em;
  text-transform: none;
  color: var(--btn-ink);
  background: linear-gradient(180deg, var(--btn-a), var(--btn-b));
  border: 0;
  border-radius: var(--pill);
  padding: 0.9rem 1.7rem;
  cursor: pointer;
  box-shadow: 0 10px 34px -14px color-mix(in oklab, var(--accent), transparent 25%),
    inset 0 1px 0 rgba(255, 255, 255, 0.28);
  transition: box-shadow 320ms ease, transform 260ms cubic-bezier(0.22, 1, 0.36, 1);
}

button:hover {
  transform: translateY(-1px);
  box-shadow: 0 18px 56px -14px color-mix(in oklab, var(--accent), transparent 8%),
    inset 0 1px 0 rgba(255, 255, 255, 0.4);
}

input[type="number"] {
  font-family: var(--mono);
  font-size: 0.9rem;
  color: inherit;
  background: var(--card);
  border: 1px solid var(--rule);
  border-radius: 10px;
  padding: 0.55rem 0.7rem;
  width: 4.8rem;
}

.plan label {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  margin-right: 0.75rem;
  font-size: 0.9rem;
  color: var(--muted);
}

/* ---- notes and errors --------------------------------------------------- */

.status {
  color: var(--faint);
  font-size: 0.9rem;
  line-height: 1.5;
}

.error {
  color: var(--flag);
  background: var(--flag-wash);
  border: 1px solid var(--flag);
  border-radius: 14px;
  padding: 0.9rem 1.1rem;
  font-size: 0.95rem;
  line-height: 1.5;
}

/* The buy page toggles #failed with the hidden attribute; never let a
   display rule above outrank it. */
[hidden] {
  display: none !important;
}

/* ---- claim page --------------------------------------------------------- */

#claim {
  margin-bottom: 1.5rem;
}

/* The key itself, once claim.js writes it in. Unscoped as well as scoped: the
   script sets className="key" on an element it appends to #claim, but the class
   is the contract, not its position.

   user-select: all is load-bearing — one click takes the whole key, which is how
   it gets typed into the pane on a second machine without dropping a
   character. */
.key,
#claim code,
#claim .key {
  display: block;
  font-family: var(--mono);
  font-size: 1.05rem;
  margin: 0 0 1.1rem;
  padding: 1rem 1.1rem;
  word-break: break-all;
  user-select: all;
  background: var(--card);
  border: 1px solid var(--rule);
  border-left: 4px solid var(--accent);
  border-radius: 14px;
}

/* ---- footer -------------------------------------------------------------- */

footer {
  margin-top: 3.5rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--rule);
  color: var(--faint);
  font-size: 0.9rem;
}

footer p {
  margin: 0;
}

footer a {
  color: var(--muted);
  text-decoration: none;
  border-bottom: 1px solid var(--rule);
}

footer a:hover {
  color: var(--ink);
  border-bottom-color: var(--accent);
}

/* ---- masthead and index drawer ------------------------------------------ */

/* Every page wears the same top row. The homepage keeps its own inline copy:
   it is deliberately self-contained and loads no stylesheet, so a change here
   has to be made there too. */

/* These two values are the homepage's `.wrap`, not this file's own measure.
   The homepage carries an inline copy of the ribbon inside a 74rem `.wrap`
   with a 5rem gutter; matching it here is what stops the mark jumping
   sideways when you leave the homepage for any other page. `main` above is
   still 46rem — the ribbon has always been wider than the prose it sits
   over, and stays so. */
.masthead {
  position: sticky;
  top: 0;
  z-index: 50;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem 1.5rem;
  min-height: 66px;
  max-width: 74rem;
  margin: 0 auto;
  padding: 0.6rem clamp(1.25rem, 5vw, 5rem);
  background: var(--nav-bg);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--rule);
}

.masthead-left {
  display: flex;
  align-items: center;
  gap: 0.9rem;
}

/* The Bloom is inline in each page rather than an <img> pointing at /logos.
   Only the apex serves that path, so on a per-add-in preview host the sourced
   file 404s and the ribbon loses its mark; inline, every project's copy of the
   ribbon is complete on its own. */
.brand {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  color: var(--ink);
  font-weight: 700;
  letter-spacing: -0.018em;
  font-size: 1.02rem;
  text-decoration: none;
}

.brand:hover {
  color: var(--ink);
}

.brand svg {
  display: block;
  width: 24px;
  height: 24px;
}

.petal {
  fill: var(--ink);
}

.petal-accent {
  fill: var(--accent);
}

/* Windows High Contrast forces `color` and `background-color` to the system
   pair but Chrome leaves SVG `fill` alone, so the Bloom kept its dark ink on a
   forced-black ribbon and disappeared. Repaint it in system colours. */
@media (forced-colors: active) {
  .petal {
    fill: CanvasText;
  }

  .petal-accent {
    fill: Highlight;
  }
}

.masthead-note {
  margin: 0;
  margin-left: auto;
  font-family: var(--mono);
  font-size: 0.72rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--faint);
}

@media (max-width: 47.9rem) {
  .masthead-note {
    display: none;
  }
}

/* On an add-in's own pages the ribbon note names that add-in rather than carrying
   the house line, because the h1 below is a benefit sentence and nothing else on
   the page says which of the seven you are looking at. It therefore survives the
   narrow-screen rule above -- the house line is decoration and can go, a product
   name is the page's own label and cannot. */
.masthead-note.is-product {
  display: block;
  color: var(--muted);
}

/* Without JS the drawer is a plain list in the flow, so the toggle would
   control nothing. Only reveal it once we know scripting is on. */
.nav-toggle {
  display: none;
}

.js .nav-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.55rem;
  min-width: 44px;
  min-height: 44px;
  background: var(--surf);
  border: 1px solid var(--rule);
  border-radius: 12px;
  box-shadow: none;
  color: inherit;
  font-family: var(--display);
  font-size: 0.85rem;
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
  padding: 0.5rem 0.8rem;
  cursor: pointer;
}

.js .nav-toggle:hover {
  transform: none;
  border-color: var(--ink);
  box-shadow: none;
}

/* Three stacked worksheet rows, not a hamburger. */
.rows {
  display: grid;
  gap: 2px;
  width: 0.95rem;
}

.rows span {
  height: 2px;
  background: currentColor;
}

.rows span:nth-child(2) {
  background: var(--accent);
}

/* ---- the Add-ins menu in the top row ------------------------------------ */

/* Seven add-ins is too many for a flat row of links. On wide screens the top
   row carries an Add-ins button that opens a panel; below that width the row
   hides it and the drawer does the same job. Both are plain markup: with no
   JS the button is hidden and the drawer's list is still there. */

.site-nav {
  display: none;
}

.js .site-nav {
  display: none;
}

@media (min-width: 60rem) {
  .js .site-nav {
    display: flex;
    align-items: center;
    gap: 1.6rem;
    font-size: 0.92rem;
  }

  .js .site-nav a {
    color: var(--muted);
    text-decoration: none;
  }

  .js .site-nav a:hover {
    color: var(--ink);
  }
}

/* Static, deliberately: the menu below is centred on its containing block, and
   the toggle is the wrong thing to centre 44rem of menu on -- it sits right of
   centre in the ribbon, so half the panel fell off the right of the viewport.
   Leaving this static makes the sticky .masthead the containing block instead,
   which spans the page, so the menu centres on the page and cannot overhang. */
.addins {
  position: static;
}

.addins-toggle {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  min-height: 44px;
  padding: 0.4rem 0.2rem;
  background: none;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  color: var(--ink);
  font-family: var(--display);
  font-size: 0.92rem;
  font-weight: 600;
  letter-spacing: 0;
  text-transform: none;
  cursor: pointer;
}

.addins-toggle:hover {
  transform: none;
  background: none;
  box-shadow: none;
  color: var(--accent-soft);
}

.addins-toggle svg {
  transition: transform 0.18s ease;
}

.addins-toggle[aria-expanded="true"] svg {
  transform: rotate(180deg);
}

.addins-menu {
  position: absolute;
  top: calc(100% + 0.5rem);
  left: 50%;
  transform: translateX(-50%);
  z-index: 30;
  width: min(44rem, calc(100vw - 2rem));
  max-width: calc(100vw - 2rem);
  padding: 1rem;
  background: var(--paper);
  border: 1px solid var(--rule);
  border-radius: 18px;
  box-shadow: 0 28px 60px -30px rgba(0, 0, 0, 0.5);
}

.addins-menu[hidden] {
  display: none !important;
}

.addins-menu ul {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.25rem 0.5rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.addins-menu li {
  margin: 0;
}

.addins-menu a {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 0.2rem 0.9rem;
  padding: 0.75rem 0.85rem;
  border-radius: 12px;
  text-decoration: none;
  color: var(--ink);
}

.addins-menu a:hover,
.addins-menu a:focus-visible {
  background: var(--surf-2);
  color: var(--ink);
}

.addins-name {
  font-size: 0.95rem;
  font-weight: 600;
}

.addins-what {
  font-size: 0.85rem;
  color: var(--muted);
}

.addins-price {
  grid-row: span 2;
  align-self: center;
  font-family: var(--mono);
  font-size: 0.78rem;
  color: var(--faint);
  white-space: nowrap;
}

/* ---- drawer -------------------------------------------------------------- */

.drawer {
  background: var(--paper);
}

.js .drawer {
  position: fixed;
  top: 0;
  bottom: 0;
  left: 0;
  z-index: 70;
  width: min(21rem, 86vw);
  overflow-y: auto;
  border-right: 1px solid var(--rule);
  transform: translateX(-100%);
  transition: transform 0.28s ease;
}

.js .drawer[data-open="true"] {
  transform: none;
}

.drawer-inner {
  padding: 1.5rem 1.5rem 3rem;
}

.drawer-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding-bottom: 1rem;
  border-bottom: 1px solid var(--rule);
}

/* The drawer's own heading is a label, not a section heading. */
.drawer-title {
  margin: 0;
  font-family: var(--mono);
  font-weight: 500;
  font-size: 0.72rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--faint);
}

.drawer-close {
  display: none;
  background: none;
  border: 0;
  border-radius: 12px;
  box-shadow: none;
  color: inherit;
  font-size: 1.35rem;
  line-height: 1;
  min-width: 44px;
  min-height: 44px;
  padding: 0.35rem 0.5rem;
  cursor: pointer;
}

.js .drawer-close {
  display: block;
}

.drawer-close:hover {
  transform: none;
  background: none;
  box-shadow: none;
  color: var(--accent-soft);
}

.drawer-group {
  margin-top: 1.6rem;
}

.drawer-group h3 {
  margin: 0 0 0.5rem;
  font-family: var(--display);
  font-weight: 600;
  font-size: 0.95rem;
  letter-spacing: -0.014em;
  text-transform: none;
}

.drawer-group ul {
  margin: 0;
  padding: 0;
  list-style: none;
}

.drawer-group li {
  margin: 0;
}

.drawer-group a {
  display: block;
  padding: 0.5rem 0 0.5rem 0.8rem;
  border-left: 2px solid var(--rule);
  color: var(--muted);
  font-size: 0.92rem;
  text-decoration: none;
}

.drawer-group a:hover,
.drawer-group a:focus-visible {
  border-left-color: var(--accent);
  color: var(--ink);
}

.drawer-group a[aria-current="page"] {
  border-left-color: var(--accent);
  color: var(--ink);
  font-weight: 600;
}

.drawer-backdrop {
  display: none;
}

.js .drawer-backdrop {
  display: block;
  position: fixed;
  inset: 0;
  z-index: 65;
  background: var(--scrim);
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.28s ease, visibility 0.28s;
}

.js .drawer-backdrop[data-open="true"] {
  opacity: 1;
  visibility: visible;
}

@media (prefers-reduced-motion: reduce) {
  .js .drawer,
  .js .drawer-backdrop,
  .addins-toggle svg,
  button {
    transition: none;
  }
}
