/*
 * The site is styled from orknux-ui's design tokens (src/styles/tokens.css) so
 * the page and the application look like one thing. The type scale is the one
 * difference: an application screen packs information at 13px, a page being
 * read does not.
 *
 * Nothing is loaded from a third party — no CDN, no web font, no analytics.
 * The font stack names the faces orknux-ui bundles and falls back to whatever
 * the reader already has.
 */
:root {
  --color-bg: #09090b;
  --color-surface: #121214;
  --color-surface-raised: #18181b;
  --color-border: #27272a;
  --color-border-strong: #3f3f46;

  --color-text-primary: #fafafa;
  --color-text-secondary: #a1a1aa;
  --color-text-muted: #71717a;

  --color-accent: #fafafa;
  --color-accent-foreground: #09090b;

  /*
   * Iron-moss, from the brand set in orknux-server/docs. The mark's own colour
   * is the dark step and is used where it is a stroke against a surface; the
   * light step is what the brand board uses for accent text on a dark ground,
   * and it is the one that has to clear contrast on --color-bg rather than
   * match the mark exactly (#6F9877 on #09090b is 6.1:1).
   */
  --color-moss: #4A6B52;
  --color-moss-light: #6F9877;
  --color-moss-soft: rgba(74, 107, 82, 0.15);

  --font-sans: 'Geist Sans', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-mono: 'JetBrains Mono', ui-monospace, 'SFMono-Regular', 'Cascadia Mono', monospace;

  --radius-6: 6px;
  --radius-8: 8px;
  --radius-12: 12px;
  --radius-full: 999px;

  --shadow-card: 0 16px 16px rgba(0, 0, 0, 0.25);

  --page: 1120px;
  /*
   * The header's own width, wider than a page row's.
   *
   * It carries more across than any row below it - a wordmark, eight sections
   * and four buttons - and at --page it fitted by seven pixels in the font this
   * was written on. Seven pixels is not a margin, it is a coincidence, and the
   * first font that measured wider than Segoe UI spent it: the links wrapped
   * mid-word and the bar stopped being one line. See .topbar-inner.
   */
  --page-header: 1280px;
  /* The width below which the sections do not fit at all. See .nav. */
  --page-header-nav: 1240px;
  --top-nav-height: 64px;
  --docs-sidebar: 280px;
}

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

html {
  scroll-behavior: smooth;
  /* The sticky header must not cover the heading an anchor lands on. */
  scroll-padding-top: calc(var(--top-nav-height) + 16px);
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
}

/* Except the documentation, which is one page some ten thousand pixels long:
   a link from the sidebar to the far end of it animates through everything in
   between, which is a long way to watch and no help in finding anything. There
   the jump is a jump. */
html.guide {
  scroll-behavior: auto;
}

body {
  margin: 0;
  background: var(--color-bg);
  color: var(--color-text-secondary);
  font-family: var(--font-sans);
  font-size: 16px;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
}

h1,
h2,
h3 {
  color: var(--color-text-primary);
  line-height: 1.2;
  letter-spacing: -0.02em;
  margin: 0;
}

p {
  margin: 0;
}

a {
  color: var(--color-text-primary);
  text-decoration: none;
}

:focus-visible {
  outline: 2px solid var(--color-moss-light);
  outline-offset: 2px;
  border-radius: var(--radius-6);
}

.skip {
  position: absolute;
  left: -9999px;
}

.skip:focus {
  left: 16px;
  top: 16px;
  z-index: 10;
  padding: 8px 12px;
  background: var(--color-surface-raised);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-6);
}

/* Header ------------------------------------------------------------------ */

.topbar {
  position: sticky;
  top: 0;
  z-index: 5;
  /*
   * `min-height`, not `height`. Everything below is meant to keep the bar to
   * one line, but a fixed height does not enforce that - it only guarantees
   * that anything taller hangs out of the bottom of the bar instead of being
   * visible in it, which is what the wrapped nav did.
   */
  min-height: var(--top-nav-height);
  border-bottom: 1px solid var(--color-border);
  background: rgba(9, 9, 11, 0.8);
  backdrop-filter: blur(12px);
  /* So the row inside fills the bar's content box exactly. `height: 100%` no
     longer resolves against a parent that only states a minimum, and giving the
     row its own 64px would stack with the border and make the bar 65. */
  display: flex;
}

.topbar-inner {
  /*
   * Not --page. The bar is one line of text and it has to stay one line; a page
   * row can be as tall as its contents need. Pinned to the page's width it had
   * seven pixels to spare, and a system font a few percent wider than the one
   * it was measured in took the sections onto a second and third line inside a
   * bar that is one line high.
   *
   * `--font-sans` names Geist Sans and this site loads no @font-face, so what
   * actually draws the header is whatever the reader's system offers: Segoe UI
   * on Windows, Ubuntu or Cantarell or DejaVu on Linux. Those are not the same
   * width, so the header cannot be sized to the one the author happens to have.
   */
  max-width: var(--page-header);
  flex: 1;
  min-width: 0;
  margin: 0 auto;
  padding: 0 24px;
  display: flex;
  align-items: center;
  gap: 24px;
}

/*
 * Nothing in the bar wraps.
 *
 * A flex item is allowed to shrink below the width of its own text, and the
 * text then breaks - "What it does" over two lines, "Self-hosting" broken at
 * the hyphen, "Sign in" over two. That is what was reported as the header not
 * being centred vertically: each group is centred, but a group three lines tall
 * has nowhere to be centred in a bar one line high.
 */
.topbar-inner a,
.topbar-inner summary {
  white-space: nowrap;
}

/* The header is the same on every page. The documentation runs edge to edge
   under it, and letting the header follow made the wordmark and the nav jump
   to the left edge on the way from the landing page to /docs — a header that
   moves reads as a different site, which is the opposite of what a shared
   fragment is for. */

.wordmark {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 17px;
  font-weight: 600;
  letter-spacing: -0.01em;
}

.mark {
  display: block;
}

.nav {
  display: flex;
  gap: 20px;
  margin-right: auto;
  font-size: 14px;
}

.nav a {
  /* Fixed for the same reason the buttons are: so the row's height is this
     file's decision and not the system font's. */
  line-height: 20px;
  color: var(--color-text-secondary);
}

.nav a:hover {
  color: var(--color-text-primary);
}

.nav a.current {
  color: var(--color-moss-light);
}

.topbar-actions {
  display: flex;
  align-items: center;
  gap: 8px;
}

/*
 * All four buttons the same height, whatever font draws them.
 *
 * "Sign in" was the tall one: two words, so it was the first to be broken over
 * two lines when the bar ran out of room, and a button twice the height of the
 * three beside it. With nothing in the bar wrapping that cannot happen again -
 * but the height was still `normal` leading around 14px, which is a different
 * number in every font. 20px makes it 36px everywhere.
 */
.ghost {
  padding: 7px 12px;
  font-size: 14px;
  line-height: 20px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-6);
  background: var(--color-surface-raised);
}

.ghost:hover {
  border-color: var(--color-border-strong);
}

/* Hero -------------------------------------------------------------------- */

.hero {
  position: relative;
  max-width: 860px;
  margin: 0 auto;
  padding: 112px 24px 56px;
  text-align: center;
}

/* The one flourish: a moss wash behind the first screen. */
.hero::before {
  content: '';
  position: absolute;
  inset: -160px 0 auto;
  height: 480px;
  background: radial-gradient(closest-side, var(--color-moss-soft), transparent 70%);
  pointer-events: none;
  z-index: -1;
}

/* An error page has little on it; without this the footer rides up the screen. */
.hero.error {
  min-height: 62vh;
}

.eyebrow {
  display: inline-block;
  padding: 5px 12px;
  margin-bottom: 24px;
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--color-text-secondary);
  background: var(--color-surface-raised);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-full);
}

.hero h1 {
  font-size: clamp(34px, 5.2vw, 56px);
  letter-spacing: -0.03em;
}

.lead {
  margin: 24px auto 0;
  max-width: 680px;
  font-size: 18px;
  color: var(--color-text-secondary);
}

.actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 12px;
  margin-top: 36px;
}

.button {
  padding: 11px 20px;
  font-size: 15px;
  font-weight: 500;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-6);
  background: var(--color-surface-raised);
}

.button:hover {
  border-color: var(--color-border-strong);
}

.button.primary {
  background: var(--color-accent);
  color: var(--color-accent-foreground);
  border-color: var(--color-accent);
}

.button.primary:hover {
  background: #e4e4e7;
}

/* The graph --------------------------------------------------------------- */

.canvas {
  max-width: var(--page);
  margin: 0 auto;
  padding: 24px;
}

.shot {
  display: block;
  width: 100%;
  height: auto;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-12);
}

.canvas .shot {
  box-shadow: var(--shadow-card);
}

.section-shot {
  margin: 0 0 32px;
}

/*
 * A feature and the screen that shows it.
 *
 * The page was a picture and then ten boxes of prose, which asked a reader to
 * take every claim on trust and gave them one illustration for the lot. A row
 * each puts the sentence beside the thing it is about.
 */
.features {
  display: grid;
  gap: 72px;
  margin-bottom: 72px;
}

.feature {
  display: grid;
  grid-template-columns: 1.35fr 1fr;
  gap: 40px;
  align-items: center;
}

/* Alternating, so the eye has somewhere to go rather than down one gutter. The
   order is swapped rather than the columns, which keeps the reading order in
   the markup: heading, then what it says. */
.feature:nth-child(even) .feature-shot {
  order: 2;
}

.feature-words h3 {
  font-size: 20px;
  margin-bottom: 12px;
}

.feature-words p {
  color: var(--color-text-secondary);
}

/* One column below the width where two would each be too narrow to read the
   screenshot in. */
@media (max-width: 900px) {
  .feature {
    grid-template-columns: 1fr;
    gap: 20px;
  }

  .feature:nth-child(even) .feature-shot {
    order: 0;
  }
}

/* The breadth of the thing, which one screenshot of the canvas does not show. */
.gallery {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: 24px;
  list-style: none;
  padding: 0;
}
.gallery p {
  margin-top: 10px;
  color: var(--color-text-secondary);
  font-size: 14px;
}

/* Enlarging a screen ------------------------------------------------------- */

/*
 * A screenshot opens over the page when it is clicked, and Escape closes it.
 *
 * The `popover` attribute, and still no script — a test holds that the landing
 * page has none. This was `:target` first, which works and cannot hear Escape:
 * CSS reads the address, and the address does not change when somebody presses
 * a key. A thing held open over what you were reading and dismissed only by
 * finding a button is the wrong way round, so that was not good enough.
 *
 * A popover gets three things from the browser for two attributes: Escape,
 * the top layer, and buttons that open and close it by name. The top layer is
 * worth its own line — it is not painted inside any ancestor, so the transform
 * a revealing screenshot carries cannot become its containing block, which is
 * the hour this cost when it was `position: fixed`.
 *
 * What is lost against `:target`: Back no longer closes it, because there is
 * no history entry to go back to, and an address no longer names an open
 * picture. Neither was a feature anybody asked for.
 *
 * A browser without popover ignores the attribute, and `:popover-open` is then
 * an unknown selector that takes the rule with it — so `.zoom` stays
 * `display: none`, the button does nothing, and the page is what it was before
 * any of this. Which is the rule about the page being complete without it.
 */
.zoom-in {
  display: block;
  padding: 0;
  border: 0;
  background: none;
  cursor: zoom-in;
}

.zoom {
  display: none;
}

/*
 * As large as it can be without reaching the way out.
 *
 * Three attempts, and the sizes are worth writing down. Fitting it to the
 * window's height hardly enlarged anything: the screens are 8:5, a window is
 * wider than it is tall, so height bound first. Laying it out at its own
 * 2880px overshot — wider than the screen means panning in two directions to
 * read one screenshot. Spanning the width exactly was better and still wrong,
 * because 8:5 is then taller than the window, and what scrolled up under the
 * fixed Close button was the picture.
 *
 * So it is bounded by the window minus the band the button sits in, and it
 * scrolls nowhere. Nothing ever slides under the control that closes it, and
 * there is no state where the way out is behind a screenshot. That costs size
 * against the previous attempt and buys the picture being wholly on screen at
 * once, which for a screenshot of an interface is the thing being looked at.
 * Capped at 2880 so a very wide monitor gets the file, not a blown-up copy.
 */
.zoom:popover-open {
  /* The band down the top is the Close button's, and the picture is sized to
     stay out of it. --zoom-bar is that band, and the two are kept in step by
     being the same number. */
  --zoom-bar: 68px;

  display: flex;
  align-items: center;
  justify-content: center;
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  max-width: none;
  max-height: none;
  margin: 0;
  padding: var(--zoom-bar) 16px 16px;
  border: 0;
  overflow: hidden;
  background: none;
}

/* The dim belongs to the top layer's own backdrop now, rather than to a colour
   on the element. Nearly opaque rather than opaque: it should read as the page
   underneath with something held over it, not as a different screen. */
.zoom::backdrop {
  background: rgb(0 0 0 / 92%);
}

/* Behind the picture and over everything else, so the way out is anywhere the
   picture is not. A popover dismisses on a click outside itself, and this one
   covers the window, so there is no outside — this is it. */
.zoom-backdrop {
  position: fixed;
  inset: 0;
  z-index: 0;
  padding: 0;
  border: 0;
  background: none;
  cursor: zoom-out;
}

/* `max-` on both, with width and height auto, so whichever runs out first
   settles it and the 8:5 is kept either way. */
.zoom:popover-open > img {
  display: block;
  position: relative;
  z-index: 1;
  max-width: min(100%, 2880px);
  max-height: calc(100dvh - var(--zoom-bar) - 16px);
  width: auto;
  height: auto;
}

/* The way out, in the corner, for whoever reaches for a button rather than for
   Escape. */
.zoom-close {
  position: fixed;
  top: 16px;
  right: 16px;
  z-index: 2;
  padding: 8px 14px;
  border: 1px solid var(--color-border);
  border-radius: 999px;
  background: var(--color-surface);
  color: var(--color-text-primary);
  font-family: inherit;
  font-size: 14px;
  cursor: pointer;
}

.zoom-close:hover {
  border-color: var(--color-accent);
}

/*
 * A picture arrives as it comes into view.
 *
 * A scroll-driven animation, which is CSS: the landing page runs no script and
 * a reveal that needed one would be the first on it. Browsers without
 * animation-timeline ignore the whole block and show the images, which is the
 * behaviour worth having anyway.
 */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .section-shot .shot,
    .feature-shot,
    .gallery li {
      animation: rise linear both;
      animation-timeline: view();
      /* Finished well before the middle of the screen, so a reader is never
         reading something still moving. */
      animation-range: entry 10% cover 30%;
    }
  }
}

@keyframes rise {
  from {
    opacity: 0;
    transform: translateY(16px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

.graph {
  display: block;
  width: 100%;
  height: auto;
  padding: 24px 16px;
  background-color: var(--color-surface);
  /* The editor's dotted canvas. */
  background-image: radial-gradient(var(--color-border) 1px, transparent 1px);
  background-size: 20px 20px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-12);
  box-shadow: var(--shadow-card);
}

.node rect {
  fill: var(--color-surface-raised);
  stroke: var(--color-border-strong);
  stroke-width: 1;
}

.node.accent rect {
  stroke: var(--color-moss);
}

.node .kind {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.08em;
  fill: var(--color-text-muted);
}

.node .label {
  font-family: var(--font-sans);
  font-size: 13px;
  fill: var(--color-text-primary);
}

.node .port {
  fill: var(--color-bg);
  stroke: var(--color-border-strong);
}

.node.accent .port {
  stroke: var(--color-moss-light);
}

.edge-label text {
  font-family: var(--font-mono);
  fill: var(--color-text-muted);
}

figcaption {
  margin-top: 16px;
  text-align: center;
  font-size: 14px;
  color: var(--color-text-muted);
}

/* Sections ---------------------------------------------------------------- */

.section {
  max-width: var(--page);
  margin: 0 auto;
  padding: 72px 24px;
}

.section-head {
  max-width: 720px;
  margin-bottom: 40px;
}

.kicker {
  margin-bottom: 12px;
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--color-moss-light);
}

.section h2 {
  font-size: clamp(24px, 3vw, 32px);
}

.section-lead {
  margin-top: 16px;
  font-size: 17px;
}

/*
 * min() so a track never insists on being wider than the page: auto-fit alone
 * keeps the minimum and overflows once the viewport is narrower than it.
 */
.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(280px, 100%), 1fr));
  gap: 16px;
}

.cards.pairs {
  grid-template-columns: repeat(auto-fit, minmax(min(420px, 100%), 1fr));
}

.card {
  padding: 24px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-12);
}

.card h3 {
  font-size: 17px;
  margin-bottom: 10px;
}

.card p {
  font-size: 15px;
}

/* Quickstart -------------------------------------------------------------- */

.terminals {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(320px, 100%), 1fr));
  gap: 16px;
}

.terminal {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-12);
  overflow: hidden;
}

.terminal-caption {
  padding: 10px 16px;
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--color-text-muted);
  background: var(--color-surface-raised);
  border-bottom: 1px solid var(--color-border);
}

.terminal pre {
  margin: 0;
  padding: 16px;
  overflow-x: auto;
}

.terminal code {
  font-family: var(--font-mono);
  font-size: 13px;
  color: var(--color-text-primary);
  line-height: 1.9;
}

/* One command per line, without newlines having to survive the template. */
.terminal code span {
  display: block;
  white-space: pre;
}

.terminal code span::before {
  content: '$ ';
  color: var(--color-moss-light);
}

.note {
  margin-top: 20px;
  font-size: 15px;
  color: var(--color-text-muted);
}

/* Repositories ------------------------------------------------------------ */

.repo {
  display: block;
  color: inherit;
}

.repo:hover {
  border-color: var(--color-border-strong);
  background: var(--color-surface-raised);
}

.repo h3 {
  font-family: var(--font-mono);
  font-size: 15px;
}

.repo-link {
  display: inline-block;
  margin-top: 14px;
  font-size: 13px;
  color: var(--color-moss-light);
}

/* Documentation ----------------------------------------------------------- */

/*
 * Laid out like akhq.io/docs: the sidebar runs down the left edge of the
 * window rather than sitting inside the page's column, and the page is centred
 * in what is left of the width. The palette stays this site's.
 */
.docs {
  display: grid;
  grid-template-columns: var(--docs-sidebar) minmax(0, 1fr);
  align-items: start;
}

.docs-nav {
  position: sticky;
  top: var(--top-nav-height);
  /* The full height rather than the content's, so the rule beside it runs the
     length of the window the way the reference does. */
  height: calc(100vh - var(--top-nav-height));
  /*
   * A column, and the column itself does not scroll: the search box is pinned
   * at the top of it and .docs-nav-scroll below takes the overflow. It used to
   * be `overflow-y: auto` here, which scrolled the box away with the list - and
   * a search you have to scroll back up to reach is one you stop using.
   */
  display: flex;
  flex-direction: column;
  overflow: hidden;
  padding: 32px 24px 0;
  border-right: 1px solid var(--color-border);
  font-size: 14px;
}

/* The part that scrolls: everything except the box. */
.docs-nav-scroll {
  flex: 1;
  /* Without this the scroller is as tall as its content and never scrolls,
     because a flex item's automatic minimum size is its content. */
  min-height: 0;
  overflow-y: auto;
  padding-bottom: 48px;
}

.docs-nav ul {
  list-style: none;
  margin: 0;
  padding: 0;
}

.docs-nav li {
  display: block;
}

/*
 * `hidden` has to actually hide things in here.
 *
 * The rule above is an author rule and the one that acts on the hidden
 * attribute - `[hidden] { display: none }` - belongs to the browser, so the
 * author rule wins and every li in this sidebar stayed on screen however
 * plainly it had been marked hidden. The search set the property on each
 * section that did not match, correctly, and the list did not move: it looked
 * like a search that did nothing.
 *
 * Written as an attribute selector against the class so it outranks `.docs-nav
 * li`, and covering the whole sidebar rather than li alone, so the next thing
 * hidden in here does not have to rediscover this.
 */
.docs-nav [hidden] {
  display: none;
}

.docs-nav a {
  display: block;
  padding: 6px 0 6px 14px;
  margin-left: -2px;
  color: var(--color-text-secondary);
  border-left: 2px solid transparent;
}

.docs-nav a:hover {
  color: var(--color-text-primary);
}

/* Where you are, marked the way the reference marks it. */
.docs-nav a.current {
  color: var(--color-moss-light);
  border-left-color: var(--color-moss);
}

/* A section of the page, and the headings inside it under it. */
.docs-nav-sections > li {
  margin-top: 18px;
}

.docs-nav-sections > li > a {
  font-size: 15px;
  font-weight: 600;
  color: var(--color-text-primary);
}

.docs-nav-sections ul a {
  padding-left: 26px;
  font-size: 13px;
}

/* ---- Searching the manual from the sidebar ---- */

.docs-search {
  flex: none;
  margin-bottom: 12px;
}

.docs-search-box {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 0 10px;
  /* The height the sections stand at, stated rather than left to the font. */
  height: 34px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-6);
  color: var(--color-text-muted);
}

.docs-search-box:focus-within {
  border-color: var(--color-moss);
}

.docs-search input {
  flex: 1;
  min-width: 0;
  padding: 0;
  background: none;
  border: 0;
  outline: none;
  font: inherit;
  font-size: 13px;
  color: var(--color-text-primary);
}

.docs-search input::placeholder {
  color: var(--color-text-muted);
}

.docs-search-none {
  margin: 12px 0 0;
  font-size: 13px;
  color: var(--color-text-muted);
}

/*
 * While something is typed the sidebar is a list of results, not a table of
 * contents, so the spacing that separated one section from the next closes up:
 * results read as a list and sections read as a structure.
 */
.docs-nav.searching .docs-nav-sections > li {
  margin-top: 10px;
}

/* The line a section matched on, under the section it was found in. */
.docs-hit {
  margin: 2px 0 0;
  padding-left: 14px;
  font-size: 12px;
  line-height: 16px;
  color: var(--color-text-muted);
}

/*
 * The matched term, and it has to look matched.
 *
 * This was --color-moss on the page's own near-black, which measures 3.3:1 -
 * enough to exist and not enough to see. The bright text on it did the work and
 * the pill underneath read as nothing, so the term looked a shade lighter
 * rather than marked. The light moss carries 6.1:1 against the page and takes
 * dark ink at 5.9:1, which is a highlight rather than a hint of one.
 */
.docs-hit mark {
  padding: 0 3px;
  background: var(--color-moss-light);
  border-radius: 3px;
  font-weight: 600;
  color: var(--color-bg);
}

/*
 * The term where it actually is: in the manual.
 *
 * Two strengths, because there can be eighty of them on screen at once. Every
 * match gets a tint - enough to find with your eye while reading, not enough to
 * turn a paragraph into a highlighter accident - and the one being stepped
 * through gets the solid colour, so Enter visibly moves something.
 */
.docs-body mark[data-search-match] {
  padding: 0 1px;
  background: rgba(111, 152, 119, 0.28);
  border-radius: 2px;
  color: inherit;
}

.docs-body mark[data-search-match][data-current] {
  background: var(--color-moss-light);
  font-weight: 600;
  color: var(--color-bg);
}

/* Which of them you are on, under the box. */
.docs-search-status {
  margin: 8px 0 0;
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--color-text-muted);
}

/* And how many lines did, which is the difference between a mention and a
   section about the thing. */
.docs-hit-count {
  margin: 2px 0 0;
  padding-left: 14px;
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--color-moss-light);
}

/* Which documentation this is, and the way to another version of it. */
.docs-nav-version {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  padding: 12px 0 0 14px;
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--color-text-muted);
}

.docs-nav-version span {
  color: var(--color-moss-light);
}

.docs-nav-version a {
  display: inline;
  padding: 0;
  margin: 0;
  border: 0;
  color: var(--color-text-muted);
}

/* Every section of the one page, in the order the folder has them. */
.docs-section {
  margin-top: 56px;
  /* Under the sticky header rather than behind it, when an anchor is what
     brought the reader here. */
  scroll-margin-top: calc(var(--top-nav-height) + 16px);
}

.docs-section > h2 {
  padding-bottom: 10px;
  font-size: 26px;
  font-weight: 500;
  border-bottom: 1px solid var(--color-border);
}

.docs-source {
  margin-top: 20px;
  font-size: 13px;
  color: var(--color-text-muted);
}

/* The headings inside a section are linked to the same way. */
.prose h2,
.prose h3 {
  scroll-margin-top: calc(var(--top-nav-height) + 16px);
}

.docs-main {
  min-width: 0;
  padding: 48px 40px 96px;
}

.docs-body {
  max-width: 760px;
  margin: 0 auto;
}

.docs-title {
  font-size: clamp(28px, 3.4vw, 38px);
  font-weight: 500;
}

.docs-lead {
  margin-top: 16px;
  font-size: 16px;
}

.docs-contents {
  margin-top: 40px;
}

.docs-contents h2 {
  padding-bottom: 8px;
  font-size: 15px;
  font-weight: 600;
  border-bottom: 1px solid var(--color-border);
}

.docs-contents ul {
  list-style: none;
  margin: 0;
  padding: 0;
}

.docs-contents li {
  padding: 16px 0;
  border-bottom: 1px solid var(--color-border);
}

.docs-contents li a {
  font-size: 16px;
  color: var(--color-moss-light);
}

.docs-contents li p {
  margin-top: 4px;
  font-size: 14px;
}

/* The rendered markdown ---------------------------------------------------- */

.prose h1 {
  font-size: clamp(28px, 3.4vw, 38px);
  font-weight: 500;
  margin-bottom: 24px;
}

.prose h2 {
  margin: 48px 0 16px;
  padding-bottom: 8px;
  font-size: 22px;
  font-weight: 500;
  border-bottom: 1px solid var(--color-border);
}

.prose h3 {
  margin: 32px 0 12px;
  font-size: 17px;
}

.prose p,
.prose li {
  font-size: 16px;
}

.prose p,
.prose ul,
.prose ol,
.prose table,
.prose pre,
.prose blockquote {
  margin: 16px 0;
}

.prose a {
  color: var(--color-moss-light);
  text-decoration: underline;
  text-underline-offset: 3px;
}

.prose ul,
.prose ol {
  padding-left: 22px;
}

.prose li {
  margin: 6px 0;
}

.prose code {
  padding: 2px 5px;
  font-family: var(--font-mono);
  font-size: 14px;
  color: var(--color-text-primary);
  background: var(--color-surface-raised);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-4);
}

.prose pre {
  padding: 16px;
  overflow-x: auto;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-8);
}
/*
 * A screenshot is captured at whatever the screen was, which is wider than
 * this column and wider than a phone. Without this it renders at its own size,
 * pushes the page sideways and gives the whole site a horizontal scrollbar —
 * on every page, because the body scrolls, not the picture.
 */
.prose img {
  display: block;
  max-width: 100%;
  height: auto;
  margin: 16px 0;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-8);
}

.prose pre code {
  padding: 0;
  background: none;
  border: 0;
  font-size: 13px;
  line-height: 1.8;
}

/* What is still to be written, and it should read as unfinished. */
.prose blockquote {
  padding: 12px 16px;
  color: var(--color-text-muted);
  font-size: 15px;
  background: var(--color-surface);
  border: 1px dashed var(--color-border-strong);
  border-radius: var(--radius-8);
}

.prose blockquote p {
  margin: 0;
  font-size: 15px;
}

.prose table {
  width: 100%;
  border-collapse: collapse;
  font-size: 14px;
  display: block;
  overflow-x: auto;
}

.prose th,
.prose td {
  padding: 10px 14px;
  text-align: left;
  border: 1px solid var(--color-border);
}

.prose th {
  color: var(--color-text-primary);
  background: var(--color-surface-raised);
  font-weight: 500;
}

/* The foot of a page ------------------------------------------------------- */

.docs-meta {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  margin-top: 56px;
  font-size: 13px;
  color: var(--color-text-muted);
}

.docs-meta a {
  color: var(--color-moss-light);
}

.docs-neighbours {
  display: flex;
  justify-content: space-between;
  gap: 24px;
  margin-top: 20px;
  padding: 16px 20px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-8);
}

.docs-neighbours a {
  display: grid;
  gap: 2px;
}

.docs-neighbours .next {
  margin-left: auto;
  text-align: right;
}

.docs-neighbours span {
  font-size: 12px;
  color: var(--color-text-muted);
}

.docs-neighbours strong {
  font-size: 15px;
  font-weight: 500;
  color: var(--color-moss-light);
}

/* Footer ------------------------------------------------------------------ */

.footer {
  max-width: var(--page);
  margin: 40px auto 0;
  padding: 32px 24px 56px;
  border-top: 1px solid var(--color-border);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  font-size: 14px;
  color: var(--color-text-muted);
}

.footer p {
  max-width: 620px;
}

.footer nav {
  display: flex;
  gap: 20px;
}

.footer a {
  color: var(--color-text-secondary);
}

.footer a:hover {
  color: var(--color-text-primary);
}

/* Narrow ------------------------------------------------------------------ */

/*
 * Below this the sections do not fit, so they are not shown.
 *
 * 1240px is --page-header-nav; a media query cannot read a custom property, so
 * the number is repeated here and the token exists to say what it is. It used
 * to be 860 - a width chosen when the bar was measured in one font, and far
 * below the width at which a wider one runs out of room. Between the two the
 * header was neither one thing nor the other: the sections were still on the
 * page and no longer on one line.
 *
 * The wordmark takes over pushing the buttons right, because the margin that
 * did it belongs to the nav that is now gone.
 */
@media (max-width: 1240px) {
  .nav {
    display: none;
  }

  .wordmark {
    margin-right: auto;
  }
}

@media (max-width: 860px) {
  /* Scaled down to a phone's width the node labels are unreadable, so the
     graph keeps a legible size and is scrolled instead. */
  .canvas {
    overflow-x: auto;
  }

  .graph {
    min-width: 760px;
  }

  .hero {
    padding-top: 72px;
  }

  .section {
    padding: 56px 20px;
  }

  /* The sidebar becomes a list above the page rather than a column beside it. */
  .docs {
    grid-template-columns: 1fr;
  }

  .docs-nav {
    position: static;
    height: auto;
    padding: 24px 20px;
    border-right: 0;
    border-bottom: 1px solid var(--color-border);
  }

  /* Nothing to scroll inside a sidebar that is now a block above the page. */
  .docs-nav-scroll {
    overflow: visible;
    padding-bottom: 0;
  }

  .docs-main {
    padding: 32px 20px 64px;
  }
}

/* --------------------------------------------------------------------------
   Signing in, and whoever has.

   The menu is a details element rather than a script: the landing page runs
   none, and this sits on every page. What that costs is the marker, which
   every browser draws differently and none of them the way this header wants.
   -------------------------------------------------------------------------- */

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

.viewer {
  position: relative;
  /* Away from the buttons. At the group's own 8px it read as a fourth button
     rather than as the account it is, and a rule keeps the two apart without
     pushing the header around. */
  margin-left: 8px;
  padding-left: 16px;
  border-left: 1px solid var(--color-border);
}
.viewer > summary {
  display: flex;
  align-items: center;
  list-style: none;
  cursor: pointer;
}
/* Safari draws its own triangle and ignores list-style. */
.viewer > summary::-webkit-details-marker {
  display: none;
}
.viewer-initials {
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--color-text-primary);
  background: var(--color-surface);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-full);
}
.viewer > summary:hover .viewer-initials,
.viewer > summary:focus-visible .viewer-initials {
  border-color: var(--color-moss-light);
}

.viewer-menu {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  z-index: 20;
  min-width: 220px;
  padding: 12px;
  background: var(--color-surface);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-8);
}
.viewer-name {
  font-weight: 600;
}
.viewer-email {
  margin-bottom: 12px;
  color: var(--color-text-muted);
  font-size: 13px;
  /* An address is one line and longer than this box. */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/*
 * Everything the menu offers, drawn the same.
 *
 * One of these is a link and the other is a button in a form — signing out
 * changes something, so it cannot be a link — and a reader has no reason to
 * care which. Tokens arrived as a bare anchor beside a full-width button and
 * read as something that had fallen into the menu by accident.
 */
.viewer-item {
  display: block;
  width: 100%;
  padding: 7px 10px;
  color: var(--color-text-primary);
  font: inherit;
  font-size: 14px;
  text-align: left;
  text-decoration: none;
  background: transparent;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-6);
  cursor: pointer;
}
.viewer-item + .viewer-item,
.viewer-menu form .viewer-item {
  margin-top: 6px;
}
.viewer-item:hover {
  border-color: var(--color-moss-light);
}
/* The count rides on the menu entry as well as on the bell, so the one place
   somebody goes looking says how many. */
.viewer-count,
.bell-count {
  display: inline-block;
  min-width: 18px;
  padding: 0 5px;
  color: var(--color-bg);
  font-size: 11px;
  font-weight: 700;
  line-height: 18px;
  text-align: center;
  background: var(--color-moss-light);
  border-radius: 999px;
}
.viewer-count {
  float: right;
}
/* Anchored, so the count sits on the bell rather than beside it — the icon is
   the thing that is recognised at a glance and the number annotates it. */
.bell {
  position: relative;
}
.bell .bell-count {
  position: absolute;
  top: -2px;
  right: -4px;
}

/* Asking, for somebody the Publish button is not drawn for. Quieter than that
   button: it is the consolation on that row, not the thing to press. */
.market-access {
  margin-top: 24px;
}
.market-asked {
  margin: 0 0 8px;
  color: var(--color-text-muted);
  font-size: 14px;
}

/* Above the tags and closed up against them, because it narrows the same
   list by a different question. */
.market-filters {
  margin: 20px 0 0;
}
.market-filters + .market-tags {
  margin-top: 10px;
}

/* A switch that is a link. The track and the knob are drawn here rather than
   by a checkbox, because the thing that has to happen on click is a
   navigation — and a real checkbox would need a script to cause one. */
.switch {
  display: inline-flex;
  gap: 8px;
  align-items: center;
  color: var(--color-text-muted);
  font-size: 13px;
  text-decoration: none;
  white-space: nowrap;
}
.switch-track {
  position: relative;
  display: inline-block;
  width: 32px;
  height: 18px;
  background: var(--color-surface-raised);
  border: 1px solid var(--color-border-strong);
  border-radius: 999px;
  transition: background 0.15s ease, border-color 0.15s ease;
}
.switch-knob {
  position: absolute;
  top: 2px;
  left: 2px;
  width: 12px;
  height: 12px;
  background: var(--color-text-muted);
  border-radius: 50%;
  transition: transform 0.15s ease, background 0.15s ease;
}
.switch:hover {
  color: var(--color-text-primary);
}
.switch:hover .switch-track {
  border-color: var(--color-text-muted);
}
.switch.on {
  color: var(--color-text-primary);
}
.switch.on .switch-track {
  background: var(--color-moss);
  border-color: var(--color-moss-light);
}
.switch.on .switch-knob {
  background: var(--color-text-primary);
  transform: translateX(14px);
}
/* Somebody who asked not to be moved at is not shown a knob sliding. */
@media (prefers-reduced-motion: reduce) {
  .switch-track,
  .switch-knob {
    transition: none;
  }
}

/* Who may publish, and who is waiting.
   Four sections on one page, so the space between them is what says where one
   ends. Without it a heading sits against the paragraph above it and the page
   reads as one wall with bold words in it. */
.publishers section {
  margin-top: 48px;
}
.publishers h2 {
  margin-bottom: 6px;
}
/* A section's own sentence, which is not the page's opening one: `.lead` is
   set large for the paragraph under the title, and three more of them made
   every section shout as loudly as the page. */
.section-note {
  max-width: 68ch;
  margin: 0 0 4px;
  color: var(--color-text-muted);
  font-size: 14px;
}
/* Names with nothing to do to them. A bordered row each would be offering an
   action that does not exist. */
.publisher-names {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 12px 0 0;
  padding: 0;
}
.publisher-names span {
  padding: 5px 12px;
  color: var(--color-text-muted);
  font-size: 13px;
  border: 1px solid var(--color-border);
  border-radius: 999px;
}

/* A list of people rather than of things, so each row is a name, a sentence
   and the buttons that answer it. */
.publisher-list {
  /* A list's own indent, which nothing here is indented from: the rows would
     start a step to the right of the heading that names them. */
  margin: 12px 0 0;
  padding: 0;
  list-style: none;
}
.publisher-item {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 16px;
  align-items: center;
  justify-content: space-between;
  padding: 14px 0;
  border-bottom: 1px solid var(--color-border);
}
/* Nothing follows the last one, so a rule under it is a line under nothing. */
.publisher-item:last-child {
  border-bottom: none;
}
/* Two children and no more: who, and what to do about them. The sentence
   somebody wrote goes inside the first: left as a third child of the row it
   competed with the buttons for the same space and ended up against the right
   margin. */
.publisher-who {
  flex: 1;
  min-width: 18ch;
}
.publisher-line {
  margin: 0;
}
.publisher-line span {
  margin-right: 10px;
}
.publisher-name {
  font-weight: 600;
}
.publisher-handle {
  color: var(--color-moss-light);
  font-size: 14px;
}
.publisher-when {
  color: var(--color-text-muted);
  font-size: 13px;
}
/* Full width under the name, because it is a sentence somebody wrote and not
   a field: wrapping it into the narrow column beside the buttons would set it
   in a gutter. */
.publisher-reason {
  max-width: 62ch;
  margin: 4px 0 0;
  color: var(--color-text-muted);
  font-size: 14px;
}
.publisher-ungrantable {
  max-width: 62ch;
  margin: 4px 0 0;
  color: var(--color-text-muted);
  font-size: 14px;
}
/* The two answers side by side and the same size: neither is the default, and
   a Decline styled as an afterthought is one somebody presses by accident. */
.publisher-actions {
  display: flex;
  flex-shrink: 0;
  gap: 8px;
}
/* A button that cannot do anything should not look like the one to press. */
.publisher-actions button[disabled] {
  color: var(--color-text-muted);
  background: transparent;
  border-color: var(--color-border);
  cursor: not-allowed;
}
/* One field and a button: the publish form's width would leave the box
   stranded in the middle of a box. */
.publisher-grant {
  max-width: 42ch;
}
.pending-count {
  display: inline-block;
  min-width: 20px;
  padding: 0 6px;
  color: var(--color-bg);
  font-size: 12px;
  font-weight: 700;
  line-height: 20px;
  text-align: center;
  vertical-align: middle;
  background: var(--color-moss-light);
  border-radius: 999px;
}

.sign-in-ways {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin: 24px 0;
}
.sign-in-note,
.sign-in-failed {
  max-width: 52ch;
  color: var(--color-text-muted);
  font-size: 14px;
}
.sign-in-failed {
  padding: 10px 14px;
  color: var(--color-text-primary);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-8);
}

/* --------------------------------------------------------------------------
   The marketplace.
   -------------------------------------------------------------------------- */

.market {
  max-width: 860px;
  margin: 0 auto;
  padding: 48px 24px 80px;
}
/* .lead is centred by the hero it was written for, which reads as a caption
   under a heading that starts at the left edge. */
.market .lead {
  margin-left: 0;
  margin-right: 0;
}
/* Words you pick from, which wrap when there is a ninth, rather than a tab
   strip that claims the list is short and fixed. */
.market-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 24px 0 4px;
}
.market-tags a {
  padding: 5px 12px;
  color: var(--color-text-muted);
  font-size: 13px;
  text-decoration: none;
  border: 1px solid var(--color-border);
  border-radius: 999px;
  transition: color 0.15s ease, border-color 0.15s ease;
}
.market-tags a:hover {
  color: var(--color-text-primary);
  border-color: var(--color-text-muted);
}
/* The chosen one is filled rather than merely brighter: with eight of them in
   a row, a shade of grey apart is not an answer to "which am I looking at". */
.market-tags a.current {
  color: var(--color-text-primary);
  background: var(--color-moss-soft);
  border-color: var(--color-moss-light);
}

/* Among the facts they sit with, and links, so they read as facts you can
   follow rather than as buttons dropped into a definition list. */
.listing-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 10px;
}
.listing-tags a {
  color: var(--color-moss-light);
}

/* On a row in the list, where they are the first thing scanned. Quieter than
   the filter above them: these say what this one is, they are not asking to
   be clicked. */
/* Wider apart than words in a sentence, because that is what three of them at
   a sentence's spacing read as. */
.market-item-tags {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 10px;
}
.market-item-tags span {
  color: var(--color-text-muted);
}

.market-list {
  /* A list's own indent, which nothing else on the page is indented from: the
     rows started a step to the right of the filters that narrow them. */
  padding: 0;
  list-style: none;
}
.market-item {
  padding: 20px 0;
  border-bottom: 1px solid var(--color-border);
}
.market-item-name {
  font-size: 17px;
  font-weight: 600;
}
.market-item-summary {
  margin: 4px 0 8px;
  color: var(--color-text-muted);
}
.market-item-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  color: var(--color-text-muted);
  font-size: 13px;
}
.market-none,
.market-item-unrated,
.listing-unrated,
.listing-nofile {
  color: var(--color-text-muted);
}

/* Grey by default and lit when filled, so the shape of the rating is readable
   without counting: five marks, some of them on. */
.stars span {
  color: var(--color-border-strong);
}
.stars span.on {
  color: var(--color-moss-light);
}
.stars-count {
  margin-left: 4px;
  color: var(--color-text-muted);
}

.listing-facts {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 6px 16px;
  margin: 24px 0;
  font-size: 14px;
}
.listing-facts dt {
  color: var(--color-text-muted);
}
/* Download is what anybody came for; Edit is the owner's, and sits a little
   further off so it reads as a different kind of thing. Delete is not here at
   all — it is under the edit form, behind typing the key. */
.listing-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
  margin: 24px 0 32px;
}
/* A hint of a break after Download, not a gulf. 20px on top of the 12px gap
   was sized when Delete sat beyond it too and there were two groups to hold
   apart; with Edit alone out there it only looked like a mistake. */
.listing-actions .button.primary + .button {
  margin-left: 8px;
}
.listing-description,
.listing-reviews {
  margin-top: 32px;
}
.listing-rating {
  display: flex;
  gap: 10px;
  align-items: baseline;
  margin-bottom: 16px;
  color: var(--color-text-muted);
  font-size: 14px;
}

.review-list {
  list-style: none;
}
.review {
  padding: 16px 0;
  border-top: 1px solid var(--color-border);
}
.review-head {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: baseline;
  font-size: 13px;
}
.review-author {
  font-weight: 600;
}
.review-when {
  color: var(--color-text-muted);
}
.review-body {
  margin-top: 6px;
}

/* No narrower than what it sits under. A 52ch form beside a description that
   spans the column read as a different page element rather than part of this
   one. */
.review-form {
  display: grid;
  gap: 12px;
  margin-top: 32px;
  padding: 20px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-8);
}
.review-form label {
  display: grid;
  gap: 6px;
  font-size: 14px;
}
.review-form select,
.review-form textarea {
  padding: 8px 10px;
  color: var(--color-text-primary);
  font: inherit;
  font-size: 14px;
  background: var(--color-bg);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-6);
}
.review-form button {
  justify-self: start;
}
/* What somebody already wrote, above the form that is not drawn while it is. */
.review-mine {
  margin-top: 32px;
  padding: 20px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-8);
}
.review-mine h3 {
  margin-bottom: 8px;
}
.review-mine form {
  margin-top: 12px;
}

/* A description is markdown somebody else wrote, so it arrives as whatever
   they used: headings, lists, tables, code. The docs have their own scale;
   this is the same shapes at the size of the page they sit on. */
.markdown > * + * {
  margin-top: 16px;
}
.markdown h1,
.markdown h2,
.markdown h3 {
  margin-top: 28px;
  font-size: 19px;
}
.markdown ul,
.markdown ol {
  padding-left: 22px;
}
.markdown li + li {
  margin-top: 4px;
}
.markdown code {
  padding: 2px 5px;
  font-family: var(--font-mono);
  font-size: 13px;
  background: var(--color-surface-raised);
  border-radius: var(--radius-6);
}
.markdown pre {
  overflow-x: auto;
  padding: 14px 16px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-8);
}
.markdown pre code {
  padding: 0;
  background: none;
}
.markdown a {
  color: var(--color-moss-light);
  text-decoration: underline;
}
.markdown img {
  max-width: 100%;
}
.markdown table {
  width: 100%;
  border-collapse: collapse;
  font-size: 14px;
}
.markdown th,
.markdown td {
  padding: 8px 10px;
  text-align: left;
  border: 1px solid var(--color-border);
}
.markdown blockquote {
  padding-left: 14px;
  color: var(--color-text-muted);
  border-left: 3px solid var(--color-border-strong);
}

/* Publishing. The same card as a review's form, one column wider: this one is
   a description in markdown rather than a sentence about somebody else's. */
/* The icon a plugin ships, beside the name it is the face of. */
.listing-icon {
  vertical-align: -4px;
  margin-right: 10px;
}
.market-item-icon {
  vertical-align: -3px;
  margin-right: 8px;
}
.market-publish {
  margin-top: 24px;
}
.publish-form {
  display: grid;
  gap: 18px;
  max-width: 68ch;
  margin-top: 28px;
  padding: 24px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-8);
}
.publish-form label {
  display: grid;
  gap: 6px;
  font-size: 14px;
}
.publish-form input[type="text"],
.publish-form textarea {
  padding: 8px 10px;
  color: var(--color-text-primary);
  font: inherit;
  font-size: 14px;
  background: var(--color-bg);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-6);
}
.publish-form textarea {
  font-family: var(--font-mono, monospace);
}
.publish-form input[type="file"] {
  font-size: 14px;
}
.publish-form button {
  justify-self: start;
}
/* Taking a listing down, kept away from the form that publishes one. */
.publish-danger {
  max-width: 68ch;
  margin-top: 48px;
  padding: 20px 24px;
  border: 1px solid var(--color-danger, #c2410c);
  border-radius: var(--radius-8);
}
.publish-danger h2 {
  font-size: 17px;
}
.publish-danger p {
  margin: 8px 0 16px;
  color: var(--color-text-muted);
  font-size: 14px;
}
.publish-danger label {
  display: grid;
  gap: 6px;
  margin-bottom: 14px;
  font-size: 14px;
}
.publish-danger input {
  max-width: 32ch;
  padding: 8px 10px;
  color: var(--color-text-primary);
  font: inherit;
  font-size: 14px;
  background: var(--color-bg);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-6);
}
.button.danger {
  color: #fff;
  background: var(--color-danger, #c2410c);
  border-color: transparent;
}

.publish-manifest {
  max-width: 68ch;
  margin-top: 16px;
  color: var(--color-text-muted);
  font-size: 14px;
}
.publish-hint,
.publish-note {
  color: var(--color-text-muted);
  font-size: 13px;
}
/* A refusal reads as one. Same weight as the form, above it, so nobody
   resubmits without having seen why the last one did not take. */
.publish-failed {
  max-width: 68ch;
  margin-top: 24px;
  padding: 12px 14px;
  color: var(--color-text-primary);
  font-size: 14px;
  background: var(--color-surface);
  border: 1px solid var(--color-danger, #c2410c);
  border-left-width: 3px;
  border-radius: var(--radius-6);
}

/* Tokens ------------------------------------------------------------------ */

.tokens .token-form {
  margin-top: 28px;
}
.token-scopes {
  display: grid;
  gap: 14px;
  margin: 0;
  padding: 14px 16px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-8);
}
.token-scopes legend {
  padding: 0 6px;
  font-size: 14px;
}
/*
 * More specific than `.publish-form label`, which is a grid and was winning:
 * a one-column grid put each checkbox on its own row, centred above the words
 * it belongs to, which read as a decoration rather than as a control.
 */
.publish-form .token-scope {
  display: flex;
  flex-direction: row;
  gap: 10px;
  align-items: start;
  font-size: 14px;
  cursor: pointer;
}
.token-scope input[type="checkbox"] {
  /* Off the first line's baseline rather than the middle of two lines. */
  flex: none;
  width: 16px;
  height: 16px;
  margin-top: 2px;
  accent-color: var(--color-moss-light);
}
.token-scope strong {
  display: block;
  margin-bottom: 2px;
  color: var(--color-text-primary);
}
.token-scope span span {
  display: block;
  color: var(--color-text-muted);
  line-height: 1.5;
}

/* Shown once and never again, so it is the most legible thing on the page. */
.token-minted {
  max-width: 68ch;
  margin-top: 24px;
  padding: 20px 24px;
  background: var(--color-surface);
  border: 1px solid var(--color-moss-light);
  border-radius: var(--radius-8);
}
.token-minted p {
  margin: 8px 0 14px;
  color: var(--color-text-muted);
  font-size: 14px;
}
/* The token and its button on one row, the token taking what is left. */
.token-shown {
  display: flex;
  gap: 10px;
  align-items: start;
}
.token-shown .token-secret {
  flex: 1;
  min-width: 0;
}
.token-copy {
  flex: none;
}
/* Said rather than animated: the word changing is the whole feedback. */
.button.token-copied {
  color: var(--color-accent-foreground);
  background: var(--color-moss-light);
  border-color: transparent;
}

.token-secret {
  overflow-x: auto;
  margin: 0;
  padding: 12px 14px;
  color: var(--color-text-primary);
  font-family: var(--font-mono);
  font-size: 13px;
  background: var(--color-bg);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-6);
}

.token-list {
  margin-top: 40px;
}
.token-list ul {
  list-style: none;
  padding: 0;
}
.token {
  padding: 16px 0;
  border-bottom: 1px solid var(--color-border);
}
.token-head {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: baseline;
}
.token-name {
  color: var(--color-text-primary);
  font-weight: 600;
}
.token-hint {
  font-family: var(--font-mono);
  font-size: 13px;
  color: var(--color-text-muted);
}
.token-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  margin: 4px 0 10px;
  color: var(--color-text-muted);
  font-size: 13px;
}
.token-how {
  margin-top: 40px;
}
.token-how p {
  margin: 10px 0;
  color: var(--color-text-muted);
  font-size: 14px;
}

/* Releases ----------------------------------------------------------------- */

.listing-releases {
  margin-top: 32px;
}
/* What changed, an entry per version. The same rhythm as the releases list
   beside it, because they are two views of the same history: that one says
   when, this one says what. */
.changelog {
  margin-top: 12px;
  padding: 0;
  list-style: none;
}
.changelog-entry {
  padding: 16px 0;
  border-bottom: 1px solid var(--color-border);
}
.changelog-entry:last-child {
  border-bottom: none;
}
/* The version is a label on the entry, not a heading competing with the tab's
   own: it is an h3 so the page still reads in order to anything that follows
   headings, and it is sized like the word it is. */
.changelog-version {
  margin: 0 0 6px;
  color: var(--color-text-primary);
  font-size: 15px;
  font-weight: 600;
}
/* The note's own first paragraph sits against the version it belongs to. */
.changelog-entry .markdown > :first-child {
  margin-top: 0;
}

.release-list {
  list-style: none;
  padding: 0;
  margin-top: 12px;
}
.release {
  padding: 12px 0;
  border-bottom: 1px solid var(--color-border);
}
.release-head {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: baseline;
}
.release-version {
  color: var(--color-text-primary);
  font-weight: 600;
}
.release-when {
  color: var(--color-text-muted);
  font-size: 13px;
}
/* Which of these is the one you would install if you installed now. */
.release-current {
  padding: 1px 8px;
  color: var(--color-moss-light);
  font-size: 12px;
  border: 1px solid var(--color-moss-light);
  border-radius: var(--radius-full);
}
.release-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  margin-top: 4px;
  color: var(--color-text-muted);
  font-size: 13px;
}
.release-meta code {
  font-family: var(--font-mono);
}
/* The same number with different bytes, which is worth noticing. */
.release-changed {
  color: var(--color-danger, #c2410c);
}

/* A mark rather than a word, so it reads as somewhere else rather than as a
   fourth equal choice among the site's own pages. */
.ghost-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 7px 10px;
  color: var(--color-text-secondary);
}
.ghost-icon:hover {
  color: var(--color-text-primary);
}

/* Search ------------------------------------------------------------------- */

.market-search {
  display: flex;
  gap: 10px;
  margin-top: 24px;
}
.market-search input[type="search"] {
  flex: 1;
  max-width: 34ch;
  padding: 8px 12px;
  color: var(--color-text-primary);
  font: inherit;
  font-size: 14px;
  background: var(--color-surface);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-6);
}

/* A release anybody signed in can take, not only the newest one. */
.release-get {
  color: var(--color-moss-light);
  text-decoration: underline;
}

/* Tabs on a listing. The same shapes as the marketplace's tag filters,
   because they do the same job: they say where you are among a few places. */
.listing-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 18px;
  margin: 8px 0 24px;
  border-bottom: 1px solid var(--color-border);
}
.listing-tabs a {
  display: flex;
  gap: 7px;
  align-items: center;
  padding: 8px 2px;
  color: var(--color-text-muted);
  font-size: 14px;
  border-bottom: 2px solid transparent;
}
.listing-tabs a:hover {
  color: var(--color-text-primary);
}
.listing-tabs a.current {
  color: var(--color-text-primary);
  border-bottom-color: var(--color-moss-light);
}
/* A count somebody can read without opening the tab to find it empty. */
.tab-count {
  padding: 0 7px;
  color: var(--color-text-muted);
  font-size: 12px;
  background: var(--color-surface-raised);
  border-radius: var(--radius-full);
}
