/*
  QGIS2WebMap documentation - NIKA house style.

  The tokens below are NIKA's own, lifted from nikaplanet.com so the docs site
  and the company site are the same brand rather than two that resemble each
  other: plum-black ink, a near-white lilac page, amber in light and lime in
  dark. Space Grotesk sets headings, Inter sets text, JetBrains Mono sets the
  small structural labels.

  Two constraints shaped this file, and both are easy to break by accident:

  1. **The guides are rendered twice.** GitHub Pages renders them here, and the
     plugin's Help tab renders the very same Markdown with Qt (`QTextDocument`,
     HTML off - see `nika_onlymap_exporter/ui/main_dialog.py`). So every piece
     of chrome lives in a layout or in this stylesheet, never in a `.md` file.
     No Liquid, no HTML and no CSS classes in the Markdown itself.
  2. **Links between guides are written as `.md`.** GitHub Pages runs
     `jekyll-relative-links` by default, which rewrites them to `.html` at build
     time, so the same link works on the site, in the repository and in the
     Help tab. Layouts cannot rely on that - it only rewrites Markdown content -
     so nav links in layouts are real URLs.

  This replaces the earlier `_includes/head-custom.html`, which recoloured
  `jekyll-theme-minimal` from the outside. That was the right call while the aim
  was legibility; it is the wrong one now that the aim is NIKA's identity, since
  the parts that carry a brand - masthead, type scale, structure - are exactly
  the parts a theme override cannot reach.
*/

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

:root {
  color-scheme: light;

  --bg: #fbf9fc;
  --bg-2: #f4f0f5;
  --ink: #170d19;
  --ink-2: #544956;
  --ink-3: #807683;
  --rule: #d3cad5;
  --accent: #eba941;
  --accent-soft: #f5e1c8;

  /* Amber on a near-white page is a 1.9:1 contrast ratio, so it is never used
     for text. It underlines, marks and points; the ink does the reading. */
  --accent-ink: #8a5a00;
  --danger: #a3241b;
  --danger-soft: #f7e2e0;

  /* Its own token because the two themes need different strengths: the light
     `--accent-soft` is a pale amber that reads as an underline, while the dark
     one is a near-black olive that would vanish on the page. */
  --link-rule: var(--accent-soft);

  --font-title: "Space Grotesk", -apple-system, BlinkMacSystemFont, "Segoe UI",
    sans-serif;
  --font-sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --font-mono: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, monospace;

  --measure: 72ch;
  --shell: 1320px;

  /* The landing page's own column. Its own token because TWO things must agree
     on it: `.shell--wide`, and the hero's bleed calculation - the hero leans
     out of this column by however much room is left, and its figcaption leans
     back in by the same amount. When these two disagreed the caption sat at a
     different width from the text above it.

     Widened from 1080px so the hero stops looking pasted on. At 1920 the hero
     is ~1808px and the sections under it were 1016px - a 1.8x jump. Prose is
     unaffected: paragraphs carry their own `--measure` cap, so this widens the
     card grids and section blocks only. */
  --landing-col: 1400px;
  --radius: 10px;

  /* The masthead's vertical padding, as a token because two rules have to
     agree on it: the header's own padding, and the negative margin that lets a
     nav link reach past that padding to sit on the header's bottom border. */
  --masthead-pad-y: 0.7rem;
}

/* The OS preference is the default and the toggle overrides it. Both write the
   same custom properties, so there is one set of rules rather than a light copy
   and a dark copy that drift apart. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;

    --bg: #0e0511;
    --bg-2: #1e1021;
    --ink: #f5f2e7;
    --ink-2: #bcb7ab;
    --ink-3: #817683;
    --rule: #302333;
    --accent: #abf051;
    --accent-soft: #203501;
    --accent-ink: #abf051;
    --danger: #ff9a8f;
    --danger-soft: #3a1512;
    --link-rule: color-mix(in srgb, var(--accent) 38%, transparent);
  }
}

:root[data-theme="dark"] {
  color-scheme: dark;

  --bg: #0e0511;
  --bg-2: #1e1021;
  --ink: #f5f2e7;
  --ink-2: #bcb7ab;
  --ink-3: #817683;
  --rule: #302333;
  --accent: #abf051;
  --accent-soft: #203501;
  --accent-ink: #abf051;
  --danger: #ff9a8f;
  --danger-soft: #3a1512;
  --link-rule: color-mix(in srgb, var(--accent) 38%, transparent);
}

/* ---- Base -------------------------------------------------------------- */

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

html {
  scroll-behavior: smooth;
  /* Every in-page anchor lands under the sticky masthead without this. */
  scroll-padding-top: 5rem;
}

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

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

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

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  padding: 0.6rem 1rem;
  background: var(--ink);
  color: var(--bg);
  font: 600 14px/1 var(--font-sans);
  border-radius: 0 0 var(--radius) 0;
}

.skip-link:focus {
  left: 0;
}

/* ---- Masthead ---------------------------------------------------------- */

.masthead {
  position: sticky;
  top: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  /* Only ever separates the brand from the QGIS credit: the nav is pushed right
     by its own `margin-left: auto`, so widening this would not move it. Kept
     tight so the credit reads as attached to our mark rather than floating. */
  gap: 0.45rem;
  padding: var(--masthead-pad-y) clamp(1rem, 4vw, 2rem);
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: saturate(180%) blur(12px);
  border-bottom: 1px solid var(--rule);
}

.masthead__brand {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  text-decoration: none;
  color: var(--ink);
  flex: 0 0 auto;
}

/* The brand lockup is scaled 1.5x off its original 30px/16px/9px. Ours is meant
   to dominate the QGIS credit outright, not sit in a fixed ratio with it. */
.masthead__mark {
  width: 45px;
  height: 45px;
  border-radius: 10px;
  display: block;
}

.masthead__name {
  font-family: var(--font-title);
  font-weight: 700;
  font-size: 24px;
  letter-spacing: -0.02em;
  line-height: 1.1;
}

/* Smaller than the credit's label so the two mono-caps lines sit in a clear
   order - ours is a sub-line of the name, theirs is a standalone caption. */
.masthead__by {
  display: block;
  font-family: var(--font-mono);
  font-size: 13.5px;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-3);
}

/* A credit, not a second brand. The rule on the left keeps it from reading as
   part of our own name, and the small mono caps file it as a caption rather
   than a nav item. */
.masthead__powered {
  display: flex;
  align-items: center;
  gap: 0.3rem;
  flex: 0 0 auto;
  padding-left: 0.5rem;
  border-left: 1px solid var(--rule);
}

/* `--ink-2`, not `--ink-3`: in mono caps at this size the dimmer token was
   legible in light mode and mud in dark, where the background is near-black and
   `-3` barely lifts off it. */
.masthead__powered-label {
  font-family: var(--font-mono);
  font-size: 9px;
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-2);
  white-space: nowrap;
}

/* `height: auto` because the source viewBox is cropped to the artwork and is no
   longer square - forcing a square box here would letterbox it and put back the
   padding the crop removed. */
.masthead__powered-mark {
  width: 16px;
  height: auto;
  display: block;
}

/* Three kinds of thing, three shapes, and that is the whole idea. Navigation
   is type. Actions are solid rectangles. The setting is an outlined square.
   An earlier pass made all six of them pills, which flattened the difference
   and, worse, borrowed the shape the sidebar uses at narrow widths - so the
   one place capsules meant something ("this list has collapsed into a row")
   stopped meaning it. */
.masthead__nav {
  display: flex;
  /* Stretch, not centre: the links need the header's full height to reach its
     bottom border. Their own flex box re-centres the text. */
  align-self: stretch;
  align-items: center;
  gap: 1.5rem;
  margin-left: auto;
}

.masthead__links {
  display: flex;
  align-self: stretch;
  gap: 1.4rem;
}

.masthead__actions {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

/* ---- Navigation: type, marked on the header's own edge -------------------
   The stylesheet's opening note is the rule here: the accent "underlines,
   marks and points; the ink does the reading". So these stayed words. What
   they gained is where the mark lands. Each link runs the full height of the
   masthead, padding included, so the current page's 2px accent sits directly
   on the hairline that divides the header from the page. The section you are
   in is notched into the chrome rather than badged inside it - which is also
   the only marker on the site that a sticky header could carry and a static
   one could not. */
.masthead__link {
  display: inline-flex;
  align-items: center;
  margin-block: calc(var(--masthead-pad-y) * -1);
  padding-block: var(--masthead-pad-y);
  font-size: 14.5px;
  font-weight: 500;
  color: var(--ink-2);
  text-decoration: none;
  white-space: nowrap;
  box-shadow: inset 0 -2px 0 transparent;
}

.masthead__link:hover {
  color: var(--ink);
  box-shadow: inset 0 -2px 0 var(--rule);
}

.masthead__link[aria-current="page"] {
  color: var(--ink);
  font-weight: 600;
  box-shadow: inset 0 -2px 0 var(--accent);
}

/* ---- Actions ------------------------------------------------------------
   Solid rectangles at the same 8px radius as the buttons on the landing page,
   so a masthead action and a page action are recognisably the same control.

   Both keep their platform's own colour rather than `--accent`. A recoloured
   Discord or GitHub mark stops being a recognisable one, and the company
   colour is better spent on the links next door, where it says something
   about us rather than about them. */
.masthead__action {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.45rem 0.8rem;
  border: 1px solid transparent;
  border-radius: 8px;
  font-size: 13.5px;
  font-weight: 600;
  /* Puts the label and the 16px mark on one optical centre line. Inherited
     line-height left the text a pixel low against the glyph - the sort of
     thing you see without being able to name. */
  line-height: 1;
  text-decoration: none;
  white-space: nowrap;
}

.masthead__action svg {
  flex: none;
  display: block;
}

.masthead__action--discord {
  background: #5865f2;
  color: #fff;
}

.masthead__action--discord:hover {
  background: #4752c4;
  color: #fff;
}

/* GitHub's own near-black in both themes. On the dark page that black is only
   a few steps off the background, so the hairline is what gives the control an
   edge; without it the label floats on nothing. */
.masthead__action--issues {
  background: #1f2328;
  color: #fff;
  border-color: rgba(255, 255, 255, 0.16);
}

.masthead__action--issues:hover {
  background: #32383f;
  color: #fff;
  border-color: rgba(255, 255, 255, 0.28);
}

.theme-toggle {
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  padding: 0;
  border: 1px solid var(--rule);
  border-radius: 8px;
  background: var(--bg-2);
  color: var(--ink-2);
  cursor: pointer;
}

.theme-toggle:hover {
  color: var(--ink);
  border-color: var(--accent);
}

.theme-toggle svg {
  width: 16px;
  height: 16px;
}

/* One button, two glyphs: the layout ships both and CSS reveals the one that
   describes the action rather than the state. */
.theme-toggle .icon-dark {
  display: block;
}

.theme-toggle .icon-light {
  display: none;
}

:root[data-theme="dark"] .theme-toggle .icon-dark {
  display: none;
}

:root[data-theme="dark"] .theme-toggle .icon-light {
  display: block;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .theme-toggle .icon-dark {
    display: none;
  }

  :root:not([data-theme="light"]) .theme-toggle .icon-light {
    display: block;
  }
}

/* ---- Shell ------------------------------------------------------------- */

/* Three columns on a wide screen: which guide you are in, the guide, and where
   you are inside it. The third collapses first, then the first. */
.shell {
  max-width: var(--shell);
  margin: 0 auto;
  padding: 0 clamp(1rem, 4vw, 2rem) 5rem;
  display: grid;
  grid-template-columns: 14rem minmax(0, 1fr) 15rem;
  gap: clamp(1.75rem, 4vw, 3rem);
  align-items: start;
}

/* `.shell.shell--wide` rather than `.shell--wide`: the narrow-screen rules
   below re-declare `.shell`'s columns, and at equal specificity the later rule
   wins. The landing page was picking up the guide layout's `14rem | 1fr`
   between 820px and 1180px, which put the whole page in the 14rem column. */
.shell.shell--wide {
  grid-template-columns: minmax(0, 1fr);
  max-width: var(--landing-col);
}

.sidebar {
  /* Static on purpose: it scrolls with the page. Sticky needed its own
     overflow once the list outgrew the viewport, and a nested scroll
     region inside a margin column is worse than scrolling past it. */
  padding-top: 3rem;
  font-size: 14.5px;
}


.sidebar__heading {
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--accent-ink);
  margin: 0 0 0.75rem;
}

.sidebar__heading + .sidebar__heading,
.sidebar ul + .sidebar__heading {
  margin-top: 2rem;
}

.sidebar ul {
  list-style: none;
  margin: 0;
  padding: 0;
  border-left: 1px solid var(--rule);
}

.sidebar li a {
  display: block;
  padding: 0.3rem 0 0.3rem 0.9rem;
  margin-left: -1px;
  border-left: 2px solid transparent;
  color: var(--ink-2);
  text-decoration: none;
}

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

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

/* ---- On this page ------------------------------------------------------- */

.toc {
  position: sticky;
  top: 4.5rem;
  padding-top: 3.4rem;
  font-size: 13.5px;
  line-height: 1.45;
  /* Its own scroller: a page with thirty headings must not push the sticky
     column taller than the viewport, or the foot of it becomes unreachable. */
  max-height: calc(100vh - 6rem);
  overflow-y: auto;
  /* Scrollable, but the scrollbar chrome is hidden rather than the overflow
     removed, so long pages still scroll without a visible bar down the side. */
  scrollbar-width: none;
}

.toc::-webkit-scrollbar {
  display: none;
}

.toc__heading {
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin: 0 0 0.7rem;
}

.toc ul {
  list-style: none;
  margin: 0;
  padding: 0;
  border-left: 1px solid var(--rule);
}

.toc a {
  display: block;
  padding: 0.28rem 0 0.28rem 0.8rem;
  margin-left: -1px;
  border-left: 2px solid transparent;
  color: var(--ink-3);
  text-decoration: none;
}

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

.toc a[aria-current="true"] {
  color: var(--ink);
  border-left-color: var(--accent);
}

/* Sub-sections indent and stay quieter, so the h2s remain the skeleton. */
.toc__item--h3 a {
  padding-left: 1.6rem;
  font-size: 12.5px;
}

/* ---- Prose ------------------------------------------------------------- */

.prose {
  padding-top: 3rem;
  max-width: var(--measure);
}

.prose > *:first-child {
  margin-top: 0;
}

.prose h1,
.prose h2,
.prose h3,
.prose h4 {
  font-family: var(--font-title);
  letter-spacing: -0.025em;
  line-height: 1.15;
  color: var(--ink);
  text-wrap: balance;
}

.prose h1 {
  font-size: clamp(2.1rem, 4.4vw, 2.9rem);
  font-weight: 700;
  margin: 0 0 1.5rem;
}

.prose h2 {
  font-size: 1.5rem;
  font-weight: 600;
  margin: 3.25rem 0 1rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--rule);
}

/* Several guides put a `---` between sections as well, which is right in a
   plain-text reading of the file and one rule too many here. The heading keeps
   its own. */
.prose hr + h2 {
  border-top: 0;
  padding-top: 0;
  margin-top: 0;
}

.prose h3 {
  font-size: 1.15rem;
  font-weight: 600;
  margin: 2.25rem 0 0.75rem;
}

.prose h4 {
  font-size: 1rem;
  font-weight: 600;
  margin: 1.75rem 0 0.5rem;
}

.prose p,
.prose li {
  color: var(--ink-2);
}

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

.prose a {
  color: var(--ink);
  text-decoration: none;
  border-bottom: 2px solid var(--link-rule);
  transition: border-color 0.15s ease;
}

.prose a:hover {
  border-bottom-color: var(--accent);
}

.prose ul,
.prose ol {
  padding-left: 1.2rem;
}

.prose li {
  margin: 0.35rem 0;
}

.prose li::marker {
  color: var(--ink-3);
}

.prose hr {
  height: 1px;
  border: 0;
  background: var(--rule);
  margin: 3rem 0;
}

.prose blockquote {
  margin: 1.75rem 0;
  padding: 1rem 1.25rem;
  border: 1px solid var(--rule);
  border-left: 3px solid var(--accent);
  border-radius: 0 var(--radius) var(--radius) 0;
  background: var(--bg-2);
}

.prose blockquote > *:first-child {
  margin-top: 0;
}

.prose blockquote > *:last-child {
  margin-bottom: 0;
}

.prose code {
  font-family: var(--font-mono);
  font-size: 0.86em;
  background: var(--bg-2);
  border: 1px solid var(--rule);
  border-radius: 5px;
  padding: 0.1em 0.35em;
}

.prose pre {
  background: var(--bg-2);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  padding: 1rem 1.15rem;
  overflow-x: auto;
  line-height: 1.6;
}

.prose pre code {
  background: none;
  border: 0;
  padding: 0;
  font-size: 13.5px;
}

/* Tables carry a lot of this documentation - every guide has at least one - so
   they get the same care as the prose rather than browser defaults. */
.table-scroll {
  overflow-x: auto;
  margin: 1.75rem 0;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
}

.prose table {
  border-collapse: collapse;
  width: 100%;
  font-size: 15px;
}

.prose th,
.prose td {
  text-align: left;
  vertical-align: top;
  padding: 0.6rem 0.9rem;
  border-bottom: 1px solid var(--rule);
}

.prose thead th {
  background: var(--bg-2);
  color: var(--ink);
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  white-space: nowrap;
}

.prose tbody tr:last-child td {
  border-bottom: 0;
}

.prose td {
  color: var(--ink-2);
}

.prose img {
  max-width: 100%;
  height: auto;
  display: block;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  margin: 1.75rem 0;
  background: var(--bg-2);
}

/* ---- Landing page ------------------------------------------------------ */

.hero {
  padding: clamp(3.5rem, 9vw, 6rem) 0 0;
}

.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin: 0 0 1.25rem;
}

.eyebrow::before {
  content: "";
  width: 1.75rem;
  height: 2px;
  background: var(--accent);
}

.hero h1 {
  font-family: var(--font-title);
  font-size: clamp(2.4rem, 6.5vw, 4.1rem);
  font-weight: 700;
  letter-spacing: -0.035em;
  /* Loose enough that the marker below has somewhere to sit. At 1.02 it landed
     across the descenders of the line it was marking. */
  line-height: 1.14;
  margin: 0 0 1.5rem;
  max-width: 16ch;
  text-wrap: balance;
}

.hero h1 em {
  font-style: normal;
  /* The one place the accent reads as itself: a marker under the phrase that
     names what the plugin actually does, not a wash over the whole line. It is
     drawn at the foot of each line box and cloned across the wrap, so a phrase
     spanning two lines gets two clean rules rather than one through the middle
     of the second. */
  background-image: linear-gradient(var(--accent), var(--accent));
  background-repeat: no-repeat;
  background-position: 0 100%;
  background-size: 100% 0.11em;
  /* An inline background box is font-size tall, not line-height tall, so its
     100% mark sits on the baseline and the rule ran through every descender.
     The padding pushes the box past them. */
  padding-bottom: 0.06em;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}

.hero__lede {
  font-size: clamp(1.05rem, 2.2vw, 1.25rem);
  line-height: 1.55;
  color: var(--ink-2);
  max-width: 52ch;
  margin: 0 0 2rem;
}

.hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  align-items: center;
}

.button {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.65rem 1.25rem;
  border-radius: 8px;
  font-size: 15px;
  font-weight: 600;
  text-decoration: none;
  border: 1px solid transparent;
}

.button--primary {
  background: var(--ink);
  color: var(--bg);
}

.button--primary:hover {
  background: var(--ink-2);
}

.button--ghost {
  /* Stronger than the hairline `--rule` used everywhere else: at button size on
     the dark theme that border disappears and the control reads as a flat
     rectangle rather than something to press. */
  border-color: color-mix(in srgb, var(--ink-3) 70%, transparent);
  color: var(--ink);
  background: transparent;
}

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

/* The one image on the landing page, and the only thing on it that is wider
   than the reading column - it earns that by being the only place the site
   shows what the plugin actually produces. */
.hero__figure {
  margin: clamp(2.5rem, 6vw, 3.5rem) 0 0;
}

.hero__figure img {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
}

/* ---- Landing hero composite -------------------------------------------- */

/* Two panes and a labelled arrow, assembled here rather than baked into one
   flat image. Three reasons that matters: the label gets the site's own type
   and accent instead of whatever a video encoder can draw; the halves can
   stack on a phone instead of becoming an unreadable band; and the moving half
   can be a video without having to carry the static half's pixels in every
   frame. */
/* The panes are not the same size. The dialog is the means and the map is the
   end, so the map gets the bigger frame - the row reads left to right as
   something growing into its result rather than as a symmetrical comparison,
   which is the shape of a different argument. */
/* The landing column is capped at 1080px for reading, which is narrower than
   this row wants to be. It leans out into the margin on both sides by however
   much room the viewport actually has, and by nothing at all once the window
   is no wider than the column - so it grows on a desktop without ever pushing
   a scrollbar onto a laptop. */
.hero-flow {
  /* NO upper cap, on instruction: this row is allowed to be wider than every
     other thing on the page. It was capped at 6.5rem, which held it to ~1288px
     on any monitor - and the one thing the composite has to do is let someone
     read the dialog it is showing them, which that width made impossible.
     It now takes the whole viewport less a 1.5rem gutter each side.

     `max(0px, ...)` rather than `clamp(...)` because the term goes NEGATIVE
     below 1080px + 3rem, and a negative bleed would push the row inward and
     then a positive figcaption margin would fight it. At or below the reading
     column the bleed is simply zero, which is the narrow-screen behaviour the
     stacked layout already assumes. */
  --hero-bleed: max(0px, calc((100vw - var(--landing-col)) / 2 - 1.5rem));
  margin-inline: calc(var(--hero-bleed) * -1);
}

.hero-flow__row {
  display: grid;
  grid-template-columns: 1.02fr auto 1.15fr;
  align-items: center;
  gap: clamp(0.5rem, 1.6vw, 1.25rem);
  /* Room for the corners the tilt throws outside the row's own box. */
  padding: 0.75rem 0;
}

/* Both panes are held to one aspect so the row has a flat top and bottom, and
   that aspect is the QGIS window's own. The two sources disagree on shape, so
   one of them gets cropped, and it must not be this one: trimming a screenshot
   of a window cuts through the panel text down its edge, which reads as a
   rendering fault rather than a crop. Trimming the map only loses map. */
.hero-flow__pane {
  position: relative;
  aspect-ratio: 1901 / 987;
  overflow: hidden;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: var(--bg-2);
  /* Tilted the same way a pair of prints would end up on a desk. Opposite
     directions rather than matching, so they read as two things put down
     rather than one graphic rotated. Kept under two degrees: past that the
     dialog's horizontals start to look like a mistake instead of a choice. */
  box-shadow: 0 12px 30px -18px rgb(0 0 0 / 45%);
}

.hero-flow__row > .hero-flow__pane:first-child {
  transform: rotate(-1.4deg);
}

.hero-flow__pane--live {
  transform: rotate(1deg);
}

.hero-flow__pane img,
.hero-flow__pane video {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Overrides `.hero__figure img`, which draws its own frame - here the frame
     belongs to the pane, or a cropped image would show two borders. */
  border: 0;
  border-radius: 0;
}

/* Names each half in one word, because "QGIS on the left, browser on the
   right" is the whole claim and the caption should not have to carry it. */
.hero-flow__tag {
  position: absolute;
  left: 0.6rem;
  bottom: 0.6rem;
  padding: 0.2rem 0.5rem;
  border-radius: 5px;
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  border: 1px solid var(--rule);
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-2);
}

.hero-flow__placeholder {
  position: absolute;
  right: 0.6rem;
  top: 0.6rem;
  padding: 0.2rem 0.5rem;
  border-radius: 5px;
  background: color-mix(in srgb, var(--accent) 88%, transparent);
  color: #1b1500;
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.04em;
}

.hero-flow__link {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5rem;
  color: var(--accent-ink);
  /* Above the panes, which the arrow's tail runs over. Both panes are
     transformed, so they each open a stacking context of their own and would
     otherwise paint on top of it. */
  position: relative;
  z-index: 2;
  /* Narrower than it was: the label sets happily on three short lines, and
     every pixel the gutter gives up goes to the two panes. */
  width: clamp(5rem, 8.5vw, 7.5rem);
}

.hero-flow__label {
  margin: 0;
  text-align: center;
  font-family: var(--font-mono);
  font-size: clamp(10px, 1.05vw, 12px);
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  line-height: 1.35;
  /* Ordinary ink, NOT the accent this element inherits from `.hero-flow__link`
     - the arrow still wants that colour, the sentence does not. A line that is
     entirely accented has nothing standing out in it. */
  color: var(--ink-2);
}

/* The two phrases carrying the claim. Colour and weight together, because at
   this size and letter-spacing colour alone is too quiet to separate them. */
.hero-flow__label em {
  color: var(--accent-ink);
  font-weight: 700;
  font-style: normal;
}

/* The settings named on their own line: the arrow says "export", this says
   which two dialog rows produced the right-hand pane. */
.hero-flow__label span {
  display: block;
  letter-spacing: 0.04em;
  text-transform: none;
  font-weight: 500;
  color: var(--ink-3);
  /* Two even lines rather than a full line and an orphaned word. */
  text-wrap: balance;
}

/* The tail starts inside the dialog rather than in the gap beside it, so the
   arrow reads as leaving that pane rather than as a symbol parked between two
   pictures. Widened and pulled left by the same amount, which keeps the tip
   where the gutter puts it. */
.hero-flow figcaption {
  margin-inline: var(--hero-bleed);
}

.hero-flow__arrow {
  display: block;
  width: calc(100% + 3.2rem);
  margin-left: -3.2rem;
  height: auto;
}

/* The caption runs the full width of the picture it belongs to. Capped to a
   reading measure it sat in the left half of a very wide image and read as a
   stray paragraph rather than as that image's label. */
.hero__figure figcaption,
.lead-figure figcaption {
  margin-top: 0.7rem;
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--ink-3);
}

/* A guide's lead image. Sized to its own pixels rather than stretched: the one
   in use is a 443px tab bar, and blown up to the column width it would be a
   blurry band. The script moves it below the `<h1>`; the margins here are for
   where it lands, not where it is emitted. */
.lead-figure {
  margin: 0 0 2rem;
}

.lead-figure--placed {
  margin: 0 0 2rem;
}

.lead-figure img {
  display: block;
  max-width: 100%;
  height: auto;
  border: 1px solid var(--rule);
  border-radius: 6px;
}

/* The signature. The plugin's promise is that nothing is dropped silently: it
   classifies every property of your project before you export and shows you the
   verdict. That vocabulary is the product, so it opens the site - a real legend
   with the plugin's own five words, not an invented graphic. */
/* The verdicts are a `.section` now, so the heading rule and the spacing come
   from there. All that is left here is the report itself. */

.verdicts__list {
  margin: 0;
  max-width: 58ch;
}

.verdict {
  display: grid;
  grid-template-columns: 1.1rem 8.5rem minmax(0, 1fr);
  align-items: baseline;
  gap: 0 0.9rem;
  padding: 0.6rem 0;
  border-bottom: 1px solid var(--rule);
}

.verdict:last-child {
  border-bottom: 0;
}

/* The key square, in the column of its own, so the five words line up down the
   page the way they line up down the Fidelity tab's Result column. */
.verdict::before {
  content: "";
  width: 9px;
  height: 9px;
  border-radius: 2px;
  background: var(--dot, var(--ink-3));
  /* `baseline` alignment on an empty box puts it on the line's bottom edge; a
     nudge sits it with the x-height of the word beside it. */
  transform: translateY(-0.1em);
}

.verdict[data-tone="kept"] {
  --dot: var(--accent);
}

.verdict[data-tone="changed"] {
  --dot: var(--ink-2);
}

.verdict[data-tone="blocked"] {
  --dot: var(--danger);
}

.verdict dt {
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink);
  white-space: nowrap;
}

.verdict dd {
  margin: 0;
  font-size: 14.5px;
  line-height: 1.5;
  color: var(--ink-2);
}

@media (max-width: 560px) {
  .verdict {
    grid-template-columns: 1.1rem minmax(0, 1fr);
    row-gap: 0.15rem;
  }

  .verdict dd {
    grid-column: 2;
  }
}

.section {
  margin-top: clamp(3rem, 6vw, 4.5rem);
}

/* The landing page's own prose sits in a `.section`, which already spaces it.
   Without this it inherits the guide pages' top padding as well and opens with
   a hole. */
.section.prose {
  padding-top: 0;
}

/* Same rule-above-the-heading as `.prose h2`, so the landing page and the
   guides are structured by one device rather than two. */
.section__title {
  font-family: var(--font-title);
  font-size: 1.6rem;
  font-weight: 600;
  letter-spacing: -0.025em;
  margin: 0 0 0.5rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--rule);
}

.section.prose > h2:first-child {
  margin-top: 0;
}

.section__lede {
  color: var(--ink-2);
  max-width: 60ch;
  margin: 0 0 1.75rem;
}

/* 13.5rem so the four-card Reference row fits on one line at full width
   instead of stranding the fourth card on a row of its own. */
.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(13.5rem, 1fr));
  gap: 0 2rem;
}

/* Unfilled and open on three sides. The page already spends its contrast on the
   verdict legend above; a grid of filled, lifting, rounded boxes underneath it
   would compete with that and is the shape every documentation index has. What
   is left is the top rule, which turns accent on hover - the same signal the
   masthead and sidebar use for "you are here". */
.card {
  display: block;
  padding: 1.1rem 0 0.4rem;
  border-top: 2px solid var(--rule);
  text-decoration: none;
  color: inherit;
  transition: border-color 0.15s ease;
}

.card:hover {
  border-top-color: var(--accent);
}

.card:hover h3 {
  color: var(--accent-ink);
}

.card__step {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.14em;
  color: var(--ink-3);
}

.card h3 {
  font-family: var(--font-title);
  font-size: 1.05rem;
  font-weight: 600;
  letter-spacing: -0.015em;
  margin: 0.35rem 0 0.4rem;
  color: var(--ink);
  transition: color 0.15s ease;
}

.card p {
  margin: 0;
  font-size: 14.5px;
  line-height: 1.5;
  color: var(--ink-2);
}

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

.site-footer {
  border-top: 1px solid var(--rule);
  background: var(--bg-2);
  padding: 2.5rem clamp(1rem, 4vw, 2rem);
}

.site-footer__inner {
  max-width: var(--shell);
  margin: 0 auto;
  display: flex;
  flex-wrap: wrap;
  gap: 1rem 2.5rem;
  align-items: baseline;
  font-size: 14px;
  color: var(--ink-3);
}

.site-footer a {
  color: var(--ink-2);
  text-decoration: none;
  border-bottom: 1px solid transparent;
}

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

.site-footer nav {
  display: flex;
  flex-wrap: wrap;
  gap: 1.25rem;
}

.site-footer__legal {
  flex-basis: 100%;
  font-size: 12.5px;
  line-height: 1.6;
  color: var(--ink-3);
  margin: 0;
}

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

/* The contents list is the first thing to go: it is an aid, and the guide it
   indexes needs the width more. */
@media (max-width: 1180px) {
  .shell {
    grid-template-columns: 14rem minmax(0, 1fr);
  }

  .toc {
    display: none;
  }
}

@media (max-width: 820px) {
  .shell {
    grid-template-columns: minmax(0, 1fr);
    gap: 0;
  }

  /* Side by side on a phone, each pane is about 160px wide and the dialog
     becomes a grey smudge. Stacked, both stay readable and the arrow turns a
     quarter-turn to keep pointing at the thing it produces. */
  .hero-flow__row {
    grid-template-columns: minmax(0, 1fr);
    gap: 0.75rem;
  }

  /* Stacked in a single narrow column, the tilt costs width the panes cannot
     spare and the two rotations fight each other. */
  .hero-flow__row > .hero-flow__pane:first-child,
  .hero-flow__pane--live {
    transform: none;
  }

  .hero-flow__link {
    flex-direction: row;
    width: auto;
    gap: 0.75rem;
  }

  .hero-flow__label {
    text-align: right;
  }

  .hero-flow__arrow {
    width: clamp(4.5rem, 22vw, 7rem);
    /* Nothing to overlap once the panes are stacked. */
    margin-left: 0;
    transform: rotate(58deg);
  }

  /* Stacked, the guide list was a full phone screen of links standing between
     the reader and the page they asked for. Same links, laid out as a wrapped
     row of chips: about three lines instead of a screen, and still the first
     thing under the masthead so it is reachable without scrolling to the foot.
     The group headings go - with everything on one row they label nothing. */
  .sidebar {
    position: static;
    padding: 1.5rem 0 0;
    border-bottom: 1px solid var(--rule);
    padding-bottom: 1.25rem;
  }

  .sidebar__heading {
    display: none;
  }


  .sidebar ul {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    border-left: 0;
  }

  .sidebar ul + ul {
    margin-top: 0.4rem;
  }

  .sidebar li a {
    padding: 0.3rem 0.7rem;
    margin-left: 0;
    border: 1px solid var(--rule);
    border-radius: 999px;
    font-size: 13.5px;
  }

  .sidebar li a[aria-current="page"] {
    border-color: var(--accent);
    border-left-color: var(--accent);
    color: var(--ink);
  }

  .prose {
    padding-top: 2rem;
  }

  .masthead {
    gap: 0.75rem;
  }

  .masthead__nav {
    gap: 0.6rem;
  }

  /* The guide links are all in the sidebar chip row just below; repeating them
     in a wrapping masthead costs a third of the first screen. They go at the
     same width the sidebar collapses into that row, which is also the width
     where the two actions would otherwise wrap to a second line. */
  .masthead__links {
    display: none;
  }

  .masthead__action {
    font-size: 13px;
    padding: 0.42rem 0.7rem;
  }
}

@media (max-width: 560px) {
  body {
    font-size: 16px;
  }

  /* Only the labels go, not the buttons: the two marks are recognisable on
     their own and stay tappable, where wrapped text would push the masthead
     to two rows. `aria-label` on each keeps them named for a screen reader. */
  .masthead__action {
    gap: 0;
    padding: 0.4rem 0.55rem;
    font-size: 0;
  }

  /* Same reasoning: at this width the credit pushes the brand and the actions
     onto separate lines. Nothing legal is lost - the footer's trademark and
     no-endorsement note is on every page and is not hidden here. */
  .masthead__powered {
    display: none;
  }
}

@media print {
  .masthead,
  .sidebar,
  .theme-toggle,
  .skip-link {
    display: none;
  }

  .shell {
    display: block;
  }
}

/* ---- Demo pages -------------------------------------------------------- */

/* Each demo is a guide-shaped page: sidebar left, the map in the middle
   with its story and export recipe beneath, and the action rail where a
   guide keeps its contents list. The heading IS the map's title, and the
   map loads with the page. */

/* The demo pages alone take the wide treatment: the map is the page, so
   it gets the width the guides give to reading comfort. The LEFT edge and
   sidebar column match the guide pages exactly - the sidebar must not
   move when crossing between a guide and a demo; only the right side
   reaches further out. */
.shell.demo-page {
  max-width: 1460px;
  margin-left: max(calc((100% - 1320px) / 2), 0px);
  margin-right: auto;
  grid-template-columns: 14rem minmax(0, 1fr) 11rem;
}

@media (max-width: 1180px) {
  .shell.demo-page {
    grid-template-columns: 14rem minmax(0, 1fr);
  }
}

.demo-main {
  min-width: 0;
}

.demo-main__head {
  padding: 0.9rem 0 0.7rem;
}

.demo-main__head .eyebrow {
  margin-bottom: 0.3rem;
}

.demo-main__title {
  font-family: var(--font-title);
  font-size: clamp(1.6rem, 3vw, 2.3rem);
  font-weight: 700;
  letter-spacing: -0.03em;
  line-height: 1.12;
  margin: 0;
  text-wrap: balance;
}

/* The map's frame. As tall as the viewport allows while the heading and a
   line of the strip below stay reachable - the map is the page. */
.demo__stage {
  position: relative;
  height: calc(100dvh - 16.5rem);
  min-height: 420px;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--bg-2);
}

.demo__frame {
  display: block;
  width: 100%;
  height: 100%;
  border: 0;
}

/* A control hint pinned over the stage (only maps that need one declare it).
   It overlays the live iframe too, so it must not eat the mouse. */
.demo__tip {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  bottom: 0.75rem;
  margin: 0;
  padding: 0.35rem 0.7rem;
  border-radius: 999px;
  border: 1px solid var(--rule);
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  font-family: var(--font-mono);
  font-size: 11.5px;
  letter-spacing: 0.06em;
  color: var(--ink-2);
  pointer-events: none;
  z-index: 3;
}

/* The strip under the stage: what this map shows and whose data it is. */
.demo__provenance {
  padding-top: 0.75rem;
}

.demo__lede {
  font-size: 14.5px;
  line-height: 1.5;
  color: var(--ink-2);
  max-width: 90ch;
  margin: 0 0 0.5rem;
}

/* What the map is about, in the brand's text-safe accent (amber-ink in
   light, lime in dark - raw amber fails contrast on the light page). */
.demo__lede em {
  font-style: normal;
  font-weight: 600;
  color: var(--accent-ink);
}

.demo__compare-note {
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--ink-3);
  margin: 0 0 0.5rem;
}

.demo__credits {
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--ink-3);
  margin: 0;
}

/* The export recipe: the dialog settings the .qgz cannot carry. */
.demo__recipe {
  margin-top: 1.5rem;
  padding-top: 1rem;
  border-top: 1px solid var(--rule);
  max-width: var(--measure);
}

.demo__recipe-heading {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin: 0 0 0.6rem;
}

.demo__recipe-lede {
  font-size: 13.5px;
  line-height: 1.55;
  color: var(--ink-2);
  margin: 0 0 0.9rem;
}

.demo__recipe-lede em {
  font-style: normal;
  font-weight: 600;
  color: var(--ink);
}

.demo__recipe-list {
  margin: 0;
}

.demo__recipe-row {
  display: grid;
  grid-template-columns: 14rem minmax(0, 1fr);
  gap: 1rem;
  padding: 0.45rem 0;
  border-top: 1px solid var(--rule);
}

.demo__recipe-row dt {
  font-family: var(--font-mono);
  font-size: 11.5px;
  letter-spacing: 0.06em;
  color: var(--ink-3);
  padding-top: 0.1rem;
}

.demo__recipe-row dd {
  margin: 0;
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--ink);
}

/* The setting the row exists for - the dialog value to actually pick. */
.demo__recipe-row dd strong {
  font-weight: 600;
  color: var(--accent-ink);
}

/* The markdown body of the page, after the recipe. */
.demo-recipes__notes {
  margin-top: 1.5rem;
  padding-top: 1rem;
  border-top: 1px solid var(--rule);
  max-width: var(--measure);
  font-size: 13.5px;
  line-height: 1.55;
  color: var(--ink-2);
}

.demo-recipes__notes h2 {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin: 0 0 0.6rem;
}

.demo-recipes__notes p {
  margin: 0 0 0.7rem;
}

.demo-recipes__notes a {
  color: var(--ink);
}

/* ---- The action rail --------------------------------------------------- */

/* Where a guide keeps its contents list: just the four actions, nothing
   else. One filled button - the install CTA. */
.demo-rail {
  position: sticky;
  top: 4.5rem;
  padding-top: 4.1rem;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  align-self: start;
}

.demo-rail .button {
  justify-content: center;
  padding: 0.5rem 0.5rem;
  font-size: 13px;
}

.demo-rail__install {
  margin-top: 0.9rem;
}

/* ---- Compare with QGIS ------------------------------------------------- */

/* The stage splits: the left pane (QGIS's own rendering, pre-drawn tiles)
   clips against a draggable divider over the live export. */

.demo__compare-toggle {
  position: absolute;
  right: 0.75rem;
  /* Clear of the runtime's own "Built with OnlyMap" badge in that corner. */
  bottom: 3.4rem;
  padding: 0.45rem 0.9rem;
  border-radius: 999px;
  border: 1px solid var(--rule);
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  z-index: 3;
}

.demo__compare-toggle:hover {
  border-color: var(--accent);
}

.demo__compare-pane {
  position: absolute;
  inset: 0;
  z-index: 1;
}

.demo__compare-pane .demo__frame {
  position: absolute;
  inset: 0;
}

.demo__divider {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
  width: 0;
  z-index: 2;
  cursor: ew-resize;
}

/* A generous grab area around the visible hairline. */
.demo__divider::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: -12px;
  width: 24px;
}

.demo__divider-handle {
  position: absolute;
  top: 0;
  bottom: 0;
  left: -1px;
  width: 2px;
  background: var(--accent);
}

/* The knob that makes the divider read as draggable - a hairline alone
   disappears against a busy map. */
.demo__divider-handle::after {
  content: "\25C2\2009\25B8";
  position: absolute;
  top: 50%;
  left: 1px;
  transform: translate(-50%, -50%);
  display: grid;
  place-content: center;
  width: 2.1rem;
  height: 2.1rem;
  border-radius: 50%;
  border: 1px solid var(--rule);
  background: var(--bg);
  color: var(--ink);
  font-size: 13px;
  letter-spacing: 0;
  box-shadow: 0 1px 6px rgb(0 0 0 / 0.25);
}

.demo__divider-label {
  position: absolute;
  top: 0.75rem;
  padding: 0.25rem 0.6rem;
  border-radius: 999px;
  border: 1px solid var(--rule);
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-2);
  white-space: nowrap;
  pointer-events: none;
}

.demo__divider-label--left {
  right: 0.6rem;
}

.demo__divider-label--right {
  left: 0.6rem;
}

/* While the divider is being dragged the iframes must not eat the pointer. */
.demo__stage--dragging .demo__frame {
  pointer-events: none;
}

/* ---- Small screens ------------------------------------------------------ */

@media (max-width: 1180px) {
  /* The rail follows the toc out of the third column; as a wrapped row it
     stays reachable right under the recipe. */
  .demo-rail {
    position: static;
    padding-top: 0;
    flex-direction: row;
    flex-wrap: wrap;
  }
}

@media (max-width: 820px) {
  .demo__stage {
    height: auto;
    aspect-ratio: 4 / 3;
    min-height: 0;
  }

  .demo__compare-toggle {
    display: none;
  }
}
