@import url("./tokens.css");

* {
  box-sizing: border-box;
}

:root {
  /* Rendered height of the site header card. Feeds the hero's min-height, so a
     few pixels either way move the sliver of the next section showing under the
     fold and nothing else. */
  --site-header-h: 4.4rem;

  /* The gap above the sticky header at rest. The header is a card — it keeps a
     margin on both sides and one under it, and sitting flush against the top of
     the window was the only edge where it did not, which read as the page being
     cut off rather than as a card. Small on purpose: it is paid for out of the
     hero's height (see the min-height below), so every pixel here is a pixel
     off the one screenful, and it stays well under the gap to the card beneath
     so the two do not compete.

     The header still pins at `top: 0`, so this is the resting state only; once
     you scroll past it the card rises to the window edge. */
  --page-top: 0.75rem;
}

/* One ring for the whole site.
 *
 * Focus used to be styled a component at a time — twelve rules, three of which
 * replaced the ring with a hover-coloured background and `outline: none`, which
 * on these pale surfaces is no indicator at all. So the ring is declared once,
 * here, and components may only *move* it: change `outline-color` where it
 * lands on the accent gradient, or pull `outline-offset` negative to keep it
 * inside a pill. Nothing below may set `outline: none` on a focus state.
 *
 * Specificity is deliberately as low as it goes (0,1,0) so any component rule
 * that needs to reposition the ring already outranks it without !important.
 *
 * Note this is `:focus-visible`, not `:focus` — a mouse click on a card or a
 * button still gets no ring, which is why hover and focus must never share a
 * declaration block: they are different states with different audiences. */
:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}

body {
  margin: 0;
  min-height: 100vh;
  font-family: var(--font-sans);
  color: var(--text-base);
  background-color: #e9eefc;
  background-image: var(--gradient-body), var(--body-bg-image);
  background-size: cover;
  background-repeat: no-repeat;
  background-position: 50% 38%;
  background-attachment: fixed;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  padding: clamp(3rem, 8vw, 5.5rem) 0;
}

:root[data-theme="dark"] body {
  background-color: #0d1226;
}

body:has(.site-header) {
  padding-top: var(--page-top);
}

main {
  flex: 1;
  width: min(var(--max-width), 96vw);
  margin: 0 auto;
  /* No horizontal padding: `--max-width` is the content box, the same one the
     app shell and the auth pages use, and 96vw is the whole margin below it. A
     gutter here would inset the cards past the app's and break the alignment
     the shared header was introduced for. */
  padding: 0;
}

body:has(.site-header) main {
  padding-top: clamp(1.5rem, 4vw, 2.75rem);
}

/* The hero card sits 2rem below the header, the same inset the login card keeps
   from the top of its page. */
body[data-page="landing"] main {
  padding-top: 2rem;
}

.landing {
  position: relative;
  width: 100%;
  /* Grid tracks default to max-content, so one wide child stretched the whole
     column past the card and got clipped. */
  grid-template-columns: minmax(0, 1fr);
  border-radius: var(--radius-lg);
  padding: clamp(4rem, 11vw, 7.5rem) clamp(5rem, 12vw, 9.5rem);
  display: grid;
  grid-template-rows: auto 1fr auto;
  gap: clamp(1.5rem, 3vw, 2.6rem);
  background: linear-gradient(135deg, rgba(255, 255, 255, 0.96), rgba(238, 244, 255, 0.92));
  border: 1px solid var(--border-card);
  box-shadow: var(--shadow);
  backdrop-filter: blur(14px);
  overflow: hidden;
}

/* Interior marketing pages reuse the hero card, but they are not the landing
   page: the visitor arrived having already chosen what they wanted, so the
   card's job is to name the page, not to sell it.

   Measured at 1440x900 before this rule, the base inset above put the badge —
   the first pixel of text on the page — at y=235, and the 7.5rem floor under
   the card pushed the next section's heading to y=975 on about.html. Close to
   500px of the first screen was card padding, on pages whose content is the
   reason anyone opened them.

   Scoped to the pages the numbers were taken on. nra-reference.html joins them
   on the same evidence: measured at 1440, its `.landing` carried the same
   120px/120px inset and put the first row of the reference at y=1089 — a screen
   and a half of card on a page that exists only to be looked things up in.
   errors.html keeps the base inset (its own list starts higher); the landing
   page keeps its full-screen override below.

   The min-width guard is not decoration: `.landing` inside the max-width:720px
   block is a bare class, so an unguarded `body[data-page=…] .landing` outranks
   it and would drag this desktop inset onto phones. */
@media (min-width: 721px) {
  body[data-page="pricing"] .landing,
  body[data-page="learn-more"] .landing,
  body[data-page="about"] .landing,
  body[data-page="nra-reference"] .landing {
    padding: clamp(2.6rem, 5vw, 4rem) clamp(3rem, 8vw, 7rem)
      clamp(2.2rem, 4vw, 3.5rem);
    /* The base row gap sizes a full-screen hero. Here the rows are a badge, a
       headline and the page's own content — and on pricing four of these gaps
       stack between the title and the plan cards, so the gap buys back more
       height than its own value suggests. */
    gap: clamp(1.4rem, 2.4vw, 1.8rem);
  }

  /* A display size is a claim on attention, and an interior page has already
     been chosen. At the landing ramp's 4.7rem, "Цени, които са на сайта" ran
     two lines and 156px tall above the first price. Same face and rhythm, one
     step down the ramp. */
  body[data-page="pricing"] .landing__title,
  body[data-page="learn-more"] .landing__title,
  body[data-page="about"] .landing__title,
  body[data-page="nra-reference"] .landing__title {
    font-size: clamp(2.2rem, 4.2vw, 3.4rem);
  }
}

/* Sized to the login card (web-app AuthLayout), which is the other full-screen
   card in the product: it leaves 2rem of page above and below itself, insets its
   content by clamp(1.8rem, 4vw, 3.4rem), and centres that content as one stack
   so a tall window becomes margin around the block rather than air between its
   lines.

   The hero did none of that. Its min-height subtracted the body padding that
   `body:has(.site-header)` zeroes out plus a flat 8.5rem for a 3.55rem header,
   so the height it reserved described a page that no longer exists; and its own
   padding and gaps put the card 185px past the fold regardless, which the
   min-height then had no say over. Rows of `auto 1fr auto` did the rest — the
   badge pinned to the top edge and the beta line to the bottom, with the
   headline floating in whatever was left.

   Horizontal padding stays wider than the login card's: that card's text sits
   in a 700px half, this one runs the full 1360px width, and 3.4rem of inset
   against a 4rem headline reads as no margin at all. */
body[data-page="landing"] .landing {
  grid-template-rows: auto;
  align-content: center;
  padding: clamp(3.6rem, 7vw, 6.2rem) clamp(3rem, 8vw, 7rem)
    clamp(2.2rem, 4.2vw, 3.6rem);
  gap: clamp(1.9rem, 3.6vw, 3.1rem);
  /* Everything above the card: the gap over the header, the header, and the
     2rem under it. The trailing 2.5rem is deliberate slack — it leaves a sliver
     of the lanes section under the fold, which is what tells the reader there
     is more page. `--page-top` is subtracted rather than absorbed so that gap
     comes out of the card's own height and not out of the sliver: the card
     loses 12px, which is under 2% of it, and the spacing under the card is
     exactly what it was. */
  min-height: calc(100svh - var(--page-top) - var(--site-header-h) - 2rem - 2.5rem);
}

body[data-page="landing"] .landing__headline {
  gap: clamp(1.2rem, 2.3vw, 1.7rem);
  align-self: auto;
  margin-top: clamp(0.6rem, 1.7vw, 1.5rem);
}

/* The CTA pair reads as its own move, not the last line of the paragraph, so
   it gets more air above it than the stack's own rhythm gives. The extra sits
   on top of the headline gap; the plate behind the buttons (::before, inset
   -0.65rem) eats some of it, which is why it is worth more than it looks. */
body[data-page="landing"] .landing__actions {
  margin-top: clamp(1.1rem, 2.6vw, 2.2rem);
}

/* 13" laptops (~829px tall) run the hero a little over one screenful. Take it
   out of the stack, never the type: the title size is the thing you notice. */
@media (min-width: 721px) and (max-height: 920px) {
  body[data-page="landing"] main {
    padding-top: 1.5rem;
  }
  body[data-page="landing"] .landing {
    gap: clamp(1rem, 1.9vw, 1.25rem);
  }
  body[data-page="landing"] .landing__headline {
    gap: clamp(0.95rem, 1.8vw, 1.25rem);
  }
  /* Still bigger than the title was before, just short of the full ramp. */
  body[data-page="landing"] .landing__title {
    font-size: clamp(2.5rem, 5.2vw, 4.2rem);
  }
  body[data-page="landing"] .landing__actions {
    margin-top: clamp(0.8rem, 1.9vw, 1.5rem);
  }
  body[data-page="landing"] .footer-hint {
    margin-top: clamp(0.45rem, 1vw, 0.85rem);
  }
  /* The card's inset is the last thing to give, but a 13" laptop cannot hold
     the full ramp, three lines of subtitle and 4.9rem of padding on one
     screenful. Trimmed here rather than anywhere the reader would notice.

     `- var(--page-top)` pays for the gap above the header. On a window this
     short the card is taller than its own min-height, so subtracting the gap
     there does nothing and it would come out of the sliver under the card
     instead — the one piece of spacing that has a job. Taken off the top inset,
     it costs the card 12px of a 705px height. */
  body[data-page="landing"] .landing {
    padding-block: calc(clamp(2.7rem, 5.2vw, 4.3rem) - var(--page-top))
      clamp(1.7rem, 3.4vw, 2.7rem);
  }
  body[data-page="landing"] .landing__subtitle {
    font-size: clamp(1.1rem, 1.95vw, 1.4rem);
  }
}

/* The lanes section is the second screenful, and the hero deliberately leaves a
   sliver of it showing. Once you scroll to it, it should behave like the hero
   card does: one screen, content centred, nothing clipped by the sticky header.
   Same height formula, minus the header the card now scrolls under. */
body[data-page="landing"] #lanes {
  min-height: calc(100svh - var(--site-header-h) - 2rem - 2.5rem);
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: clamp(1.4rem, 2.8vw, 2.2rem);
  scroll-margin-top: calc(var(--site-header-h) + 1rem);
}

/* Same idea as the hero's tiers: on a shorter window the lanes give up inset
   and leading before they give up anything the reader needs. */
@media (min-width: 721px) and (max-height: 1000px) {
  body[data-page="landing"] #lanes {
    padding-block: clamp(1.6rem, 3.2vw, 2.5rem);
    gap: clamp(1rem, 2vw, 1.5rem);
  }
  body[data-page="landing"] #lanes .lp-lanes {
    gap: clamp(0.7rem, 1.5vw, 1.1rem);
  }
  body[data-page="landing"] #lanes .lp-lane {
    padding: 1.1rem 1.25rem 1.2rem;
    gap: 0.35rem;
  }
  body[data-page="landing"] #lanes .lp-lane__copy {
    font-size: 0.88rem;
    line-height: 1.48;
  }
}

@media (min-width: 721px) and (max-height: 880px) {
  body[data-page="landing"] #lanes {
    padding-block: clamp(1.2rem, 2.4vw, 1.9rem);
  }
  body[data-page="landing"] #lanes .lp-lane {
    padding: 0.9rem 1.1rem 1rem;
  }
  body[data-page="landing"] #lanes .lp-lane__copy {
    font-size: 0.83rem;
    line-height: 1.44;
  }
  body[data-page="landing"] #lanes .lp-section__title {
    font-size: clamp(1.5rem, 3vw, 2rem);
  }
}

/* A 13" laptop is ~720-780px tall, and at full type the hero runs about 80px
   over one screenful there. Take it out of the top of the type ramp and the
   gaps rather than the padding, so the card keeps the login card's inset
   instead of ending up with none. */
@media (min-width: 721px) and (max-height: 800px) {
  body[data-page="landing"] .landing {
    gap: clamp(0.9rem, 1.8vw, 1.35rem);
  }
  body[data-page="landing"] .landing__headline {
    gap: clamp(0.8rem, 1.6vw, 1.1rem);
  }
  body[data-page="landing"] .landing__title {
    font-size: clamp(2.1rem, 4.4vw, 3.1rem);
  }
  body[data-page="landing"] .landing__subtitle {
    font-size: clamp(1.05rem, 1.9vw, 1.3rem);
  }
  /* The extra air around the CTA is the first thing to give on a short screen —
     it is a nicety, whereas the card staying on one screenful is not. */
  body[data-page="landing"] .landing__actions {
    margin-top: clamp(0.4rem, 1vw, 0.8rem);
  }
  body[data-page="landing"] .footer-hint {
    margin-top: clamp(0.4rem, 0.9vw, 0.75rem);
  }
}

/* Under ~740px of height the hero cannot hold the full type ramp and still end
   on one screenful, so the title takes a second step down. Below that the card
   is allowed to run long — cramping it further would cost more than a scroll. */
@media (min-width: 721px) and (max-height: 740px) {
  body[data-page="landing"] .landing__title {
    font-size: clamp(1.95rem, 4vw, 2.7rem);
  }
  body[data-page="landing"] .landing {
    padding-block: clamp(2rem, 4vw, 3.1rem) clamp(1.5rem, 3vw, 2.4rem);
  }
  body[data-page="landing"] .footer-hint {
    margin-top: clamp(0.5rem, 1.2vw, 0.9rem);
  }
  body[data-page="landing"] .landing__headline {
    margin-top: 0;
  }
}


.landing::before {
  content: "";
  position: absolute;
  inset: -18% -10% -8% -18%;
  background: radial-gradient(120% 100% at 80% 30%, rgba(70, 104, 208, 0.22) 0%, rgba(70, 104, 208, 0.08) 42%, rgba(70, 104, 208, 0) 70%);
  z-index: 0;
  pointer-events: none;
}

.landing::after {
  content: "";
  position: absolute;
  inset: 0;
  background-image: var(--hero-wave-image);
  background-repeat: no-repeat;
  background-size: clamp(32rem, 68vw, 58rem) auto;
  background-position: 95% 60%;
  opacity: 0.46;
  z-index: 1;
  mix-blend-mode: screen;
  filter: drop-shadow(0 42px 90px rgba(70, 104, 208, 0.32));
  pointer-events: none;
  /* Thins over the text column rather than cutting away from it. Light does not
     need dark's hard stop — the dots are pale on a white card, so holding them
     at about a quarter strength behind the words keeps the card's texture while
     taking the noise off the type. Dark still cuts to nothing (see below). */
  -webkit-mask-image: linear-gradient(97deg, rgba(0, 0, 0, 0.12) 32%, rgba(0, 0, 0, 0.5) 58%, #000 78%);
  mask-image: linear-gradient(97deg, rgba(0, 0, 0, 0.12) 32%, rgba(0, 0, 0, 0.5) 58%, #000 78%);
}

.landing > * {
  position: relative;
  z-index: 2;
}

.landing__header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: 1rem;
}

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

.landing__lang {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.35rem;
  border-radius: calc(var(--radius) + 12px);
  border: 1px solid rgba(82, 104, 210, 0.25);
  background: rgba(255, 255, 255, 0.75);
  box-shadow: 0 20px 44px rgba(74, 94, 188, 0.18);
}
.landing__theme-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.6rem;
  height: 2.6rem;
  font-size: 1.05rem;
  line-height: 1;
  cursor: pointer;
  border-radius: calc(var(--radius) + 12px);
  border: 1px solid rgba(82, 104, 210, 0.25);
  background: rgba(255, 255, 255, 0.75);
  box-shadow: 0 20px 44px rgba(74, 94, 188, 0.18);
  transition: transform 0.15s ease, background 0.15s ease, border-color 0.15s ease;
}
.landing__theme-toggle:hover {
  transform: translateY(-1px);
  border-color: rgba(82, 104, 210, 0.45);
}

/* Fixed box, so swapping sun for moon cannot move the button — the emoji this
   replaced were two different characters with two different sets of metrics.
   `display: block` kills the inline baseline gap as well, in case the button
   ever stops being a flex container. */
.landing__theme-icon {
  display: block;
  color: var(--text-muted);
}
:root[data-theme="dark"] .landing__theme-toggle {
  background: var(--surface-card-muted);
}

.landing__lang-button {
  border: none;
  background: transparent;
  color: var(--text-muted);
  font-family: var(--font-controls);
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  font-size: 0.78rem;
  padding: 0.45rem 1.1rem;
  border-radius: 999px;
  cursor: pointer;
  transition: background 0.2s ease, color 0.2s ease, transform 0.2s ease;
}

.landing__lang-button:hover {
  transform: translateY(-1px);
  background: rgba(98, 118, 238, 0.12);
}

.landing__lang-button.is-active {
  background: var(--gradient-primary);
  color: var(--text-on-accent);
}

/* The ring was a half-transparent white here, which is invisible on the white
   pill it sits in — the pair only ever showed on the active button, and only
   because that one is filled with the blue gradient. So the inactive button
   takes the page ring, and the active one keeps a white ring for exactly the
   reason the old rule half-guessed at: it is the one thing on this page with an
   accent-coloured background. */
.landing__lang-button:focus-visible {
  outline-offset: 3px;
}

.landing__lang-button.is-active:focus-visible {
  outline-color: var(--focus-on-accent);
}

.landing__badge {
  font-family: var(--font-controls);
  font-size: 0.82rem;
  letter-spacing: 0.42em;
  text-transform: uppercase;
  color: var(--accent-600);
}

.landing__headline {
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  gap: clamp(1.3rem, 3vw, 2rem);
  max-width: clamp(20rem, 52vw, 44rem);
  padding-right: clamp(0.5rem, 2vw, 1.5rem);
  align-self: center;
}

.landing__title {
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(2.6rem, 5.9vw, 4.7rem);
  line-height: 1.04;
  letter-spacing: -0.015em;
  text-wrap: balance;
  color: rgba(34, 49, 118, 0.92);
}

.landing__title span[data-i18n="title_primary"] {
  display: block;
  color: rgba(34, 49, 118, 0.86);
}

.landing__title span[data-i18n="title_accent"] {
  display: block;
  margin-top: clamp(0.35rem, 1.2vw, 0.75rem);
  margin-bottom: 0.5rem;
  color: var(--accent-700);
}

.landing__subtitle {
  margin: 0;
  font-size: clamp(1.15rem, 2.2vw, 1.55rem);
  color: rgba(34, 49, 118, 0.7);
  letter-spacing: 0.01em;
  line-height: 1.4;
}

.landing__subtitle[data-i18n="subtitle"] {
  font-style: italic;
}

/* Held to roughly three lines. The hero wave rises through the right of the
   card, and a subtitle running the full headline width crossed into it; broken
   earlier it stays in the clear text column. */
body[data-page="landing"] .landing__subtitle {
  max-width: 36rem;
  font-weight: 300;
}

.landing__actions {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 1rem;
  position: relative;
  align-items: center;
  justify-content: flex-start;
  width: fit-content;
  max-width: 100%;
}

.landing__actions--end {
  justify-content: flex-start;
}

/* Mirrors the app's Button (web-app/src/components/ui.tsx): same radius,
   padding, shadow token, tracking and hover lift — the landing CTA and the
   app CTA must read as the same control. */
.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  padding: 0.625rem 1.25rem;
  border-radius: calc(var(--radius) + 6px);
  border: 1px solid transparent;
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 0.875rem;
  text-decoration: none;
  transition: transform 0.15s ease, box-shadow 0.15s ease, background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}

/* Sentence case, like every other control on these pages. The app's primary
   button still shouts in caps (web-app/src/components/ui.tsx); on the public
   pages the CTA sits inches from a ghost button and a compact header button
   that do not, and the odd one out read as an error. Bulgarian in caps is
   also harder to scan than English is. */
.button--primary {
  background: var(--gradient-primary);
  color: var(--text-on-accent);
  border-color: rgba(98, 118, 238, 0.45);
  box-shadow: var(--shadow-button);
  letter-spacing: 0.02em;
}

.button--primary:hover {
  transform: translateY(-1px);
  background: var(--gradient-primary-hover);
}

.button--primary:active {
  transform: translateY(1px);
}

/* The one surface the page ring cannot survive: --focus is a deep blue and the
   button is a deep-blue gradient, so outside the button the ring is lost on the
   white card and inside it is lost on the fill. White solves both, but only
   inset — a white ring drawn 2px *outside* the button lands on whatever card
   the CTA sits on, which on these pages is white. So it goes in, over the
   gradient, where it reads at 4.9:1 against the darkest stop (#385fd0). */
.button--primary:focus-visible {
  outline-color: var(--focus-on-accent);
  outline-offset: -3px;
}

/* The app's "secondary" look. */
.button--ghost {
  background: var(--surface-card);
  color: var(--accent-700);
  border-color: rgba(98, 118, 238, 0.32);
  box-shadow: 0 10px 24px rgba(74, 94, 188, 0.12);
}

/* Lifts like the primary does — it is the same control, one step quieter. The
   old hover was a 22%-alpha wash that only read as solid while the CTA plate
   sat behind it; on the hero card directly it went see-through. */
.button--ghost:hover {
  transform: translateY(-1px);
  background: color-mix(in srgb, var(--accent-500) 10%, var(--surface-card));
  border-color: rgba(98, 118, 238, 0.5);
  box-shadow: 0 14px 30px rgba(74, 94, 188, 0.18);
}

.button--ghost:active {
  transform: translateY(1px);
}

.landing__copy {
  display: flex;
  flex-direction: column;
  gap: 1.2rem;
  max-width: clamp(24rem, 46vw, 40rem);
  color: var(--text-base);
  position: relative;
}

.pricing-plans {
  display: grid;
  gap: clamp(1rem, 2vw, 1.5rem);
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
  align-items: stretch;
  position: relative;
}

.pricing-plan {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  padding: 1.6rem 1.8rem;
  border-radius: var(--radius-lg);
  background: rgba(255, 255, 255, 0.596);
  border: 1px solid rgba(196, 202, 236, 0.843);
  box-shadow: var(--shadow-soft);
  color: var(--text-base);
  text-decoration: none;
  cursor: pointer;
  transition: transform 0.15s ease, box-shadow 0.15s ease, border-color 0.15s ease;
  user-select: none;
}

.pricing-plan__cta {
  margin-top: auto;
  padding-top: 0.35rem;
  font-family: var(--font-controls);
  font-weight: 700;
  font-size: 0.82rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--accent-700);
}

.pricing-plan:hover {
  transform: translateY(-2px);
  box-shadow: 0 12px 32px rgba(82, 104, 210, 0.16);
  border-color: rgba(98, 118, 238, 0.45);
}

.pricing-plan:active {
  transform: translateY(0);
  box-shadow: var(--shadow-soft);
}

.pricing-plan:focus-visible {
  outline-offset: 3px;
}

.pricing-plan[data-disabled="true"] {
  cursor: wait;
  opacity: 0.7;
  pointer-events: none;
}

.pricing-plan--highlight {
  background: rgba(98, 118, 238, 0.1);
  border-color: rgba(98, 118, 238, 0.35);
  box-shadow: 0 22px 50px rgba(82, 104, 210, 0.22);
}

.pricing-plan__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
}

.pricing-plan__badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0.25rem 0.8rem;
  border-radius: 999px;
  background: rgba(98, 118, 238, 0.16);
  color: var(--accent-700);
  font-family: var(--font-controls);
  font-weight: 700;
  font-size: 0.7rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

.pricing-plan__title {
  margin: 0;
  font-family: var(--font-display);
  font-size: 1.5rem;
  color: var(--text-base);
}

.pricing-plan__price {
  margin: 0;
  font-family: var(--font-display);
  font-size: 1.9rem;
  letter-spacing: 0.03em;
  color: var(--accent-700);
}

.pricing-plan__copy {
  margin: 0;
  font-size: 0.98rem;
  line-height: 1.55;
  color: var(--text-muted);
}

/* The per-plan limits (companies, monthly generations, file size) as a quiet
   list — same voice as .pricing-plan__copy, one line per fact. */
.pricing-plan__list {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 0.45rem;
  font-size: 0.98rem;
  line-height: 1.55;
  color: var(--text-muted);
}

.pricing-plan__list li {
  padding-left: 1.1rem;
  position: relative;
}

.pricing-plan__list li::before {
  content: "·";
  position: absolute;
  left: 0.25rem;
  color: var(--accent-700);
  font-weight: 700;
}

.pricing-callout {
  margin: 1.4rem 0 0;
  max-width: 62ch;
  color: var(--text-muted);
  font-size: 0.92rem;
  letter-spacing: 0.02em;
  position: relative;
}

.landing__copy strong {
  color: var(--accent-700);
}

.landing__copy::-webkit-scrollbar {
  width: 6px;
}

.landing__copy::-webkit-scrollbar-track {
  background: rgba(98, 118, 238, 0.1);
  border-radius: 999px;
}

.landing__copy::-webkit-scrollbar-thumb {
  background: rgba(98, 118, 238, 0.3);
  border-radius: 999px;
}

.footer-hint {
  font-size: 0.86rem;
  color: rgba(34, 49, 118, 0.7);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  position: relative;
}

/* A footnote about launch status, not a third call to action. Pushed clear of
   the buttons and set smaller and quieter than the card's own eyebrow, so the
   CTA pair keeps the bottom of the stack to itself. */
body[data-page="landing"] .footer-hint {
  margin-top: clamp(0.45rem, 1vw, 0.9rem);
  font-size: clamp(0.68rem, 1vw, 0.76rem);
  letter-spacing: 0.16em;
  color: rgba(34, 49, 118, 0.52);
}

:root[data-theme="dark"] body[data-page="landing"] .footer-hint {
  color: rgba(214, 224, 255, 0.48);
}

@media (max-width: 720px) {
  body {
    background-attachment: scroll;
    padding: clamp(1.5rem, 6vw, 3rem) 0;
  }

  .landing,
  body[data-page="landing"] .landing {
    gap: 2.5rem;
    padding: clamp(2.4rem, 10vw, 3.4rem);
    min-height: auto;
  }

  .landing::after {
    top: auto;
    right: clamp(1rem, 8vw, 2.5rem);
    bottom: clamp(1.5rem, 8vh, 3rem);
    left: auto;
    width: clamp(20rem, 72vw, 34rem);
    height: clamp(18rem, 70vw, 28rem);
    opacity: 0.6;
  }

  .landing__header {
    flex-direction: column;
    align-items: flex-start;
  }

  .landing__actions {
    width: 100%;
    display: flex;
    flex-direction: column;
    margin-top: 1.25rem;
    margin-bottom: 0;
    padding-top: 0;
  }

  .landing__actions--end {
    justify-content: center;
    align-items: stretch;
  }

  .landing__headline {
    align-self: auto;
  }

  /* "Съответстващ" is a single 12-character word: at the 2.5rem floor of the
     title ramp it is 323px wide inside a 262px column, so on a phone it ran
     off the card. Only this page's headline is long enough to hit it. */
  body[data-page="landing"] .landing__title {
    font-size: clamp(1.6rem, 7.6vw, 2.5rem);
  }

  .button {
    width: 100%;
    justify-content: center;
  }

  /* Every clamp() max-width above has a floor wider than a phone; below 720px
     the container is the only constraint that should apply. */
  .landing__headline,
  .landing__copy,
  .landing__lede,
  .pricing-plans,
  .pricing-callout {
    max-width: 100%;
    padding-right: 0;
  }
}

/* ===========================
   Marketing sections
   =========================== */

body[data-page="landing"],
body[data-page="learn-more"] {
  align-items: flex-start;
  padding-bottom: clamp(2rem, 6vw, 4rem);
}

main:has(.lp-section) {
  display: flex;
  flex-direction: column;
  gap: clamp(2.5rem, 5vw, 4rem);
}

/* Supporting copy, not a second headline: a step down in size and weight from
   the subtitle so the eye goes title -> subtitle -> CTA and reads this only if
   it wants the detail. Buys back a little height in the card as well. */
.landing__lede {
  margin: clamp(0.6rem, 1.4vw, 1rem) 0 0;
  font-size: clamp(0.94rem, 1.4vw, 1.04rem);
  font-weight: 330;
  line-height: 1.62;
  color: rgba(34, 49, 118, 0.72);
  max-width: 38rem;
}

.landing__actions--center {
  justify-content: center;
}

.lp-section {
  position: relative;
  width: 100%;
  border-radius: var(--radius-lg);
  padding: clamp(2.5rem, 5vw, 4rem) clamp(2rem, 6vw, 5rem);
  background: linear-gradient(135deg, rgba(255, 255, 255, 0.96), rgba(238, 244, 255, 0.92));
  border: 1px solid var(--border-card);
  box-shadow: var(--shadow);
  backdrop-filter: blur(14px);
}

.lp-section__header {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin-bottom: clamp(1.6rem, 3vw, 2.4rem);
}

.lp-section__title {
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(1.6rem, 3.2vw, 2.4rem);
  line-height: 1.1;
  color: rgba(34, 49, 118, 0.92);
}

.lp-section__title--center {
  text-align: center;
}

.lp-section__subtitle {
  margin: 0;
  font-size: clamp(1rem, 1.5vw, 1.1rem);
  color: var(--text-muted);
  max-width: 56ch;
}

/* Steps */
.lp-steps {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: clamp(1rem, 2vw, 1.6rem);
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
}

.lp-step {
  position: relative;
  padding: 1.4rem 1.6rem 1.6rem;
  border-radius: var(--radius);
  background: rgba(255, 255, 255, 0.78);
  border: 1px solid var(--border-card);
  box-shadow: var(--shadow-soft);
}

.lp-step__num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.2rem;
  height: 2.2rem;
  border-radius: 50%;
  background: var(--gradient-primary);
  color: var(--text-on-accent);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.1rem;
  margin-bottom: 0.8rem;
}

.lp-step__title {
  margin: 0 0 0.4rem;
  font-family: var(--font-display);
  font-size: 1.15rem;
  color: rgba(34, 49, 118, 0.92);
}

.lp-step__copy {
  margin: 0;
  font-size: 0.97rem;
  line-height: 1.55;
  color: var(--text-muted);
}

/* Modes */
.lp-modes {
  display: grid;
  gap: clamp(1rem, 2vw, 1.6rem);
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
}

.lp-mode {
  padding: 1.4rem 1.6rem 1.6rem;
  border-radius: var(--radius);
  background: rgba(98, 118, 238, 0.06);
  border: 1px solid rgba(98, 118, 238, 0.2);
  box-shadow: var(--shadow-soft);
}

.lp-mode__title {
  margin: 0 0 0.5rem;
  font-family: var(--font-display);
  font-size: 1.2rem;
  color: var(--accent-700);
}

.lp-mode__copy {
  margin: 0;
  font-size: 0.97rem;
  line-height: 1.55;
  color: var(--text-muted);
}

/* Trust */
.lp-section--trust .lp-section__title {
  margin-bottom: clamp(1.4rem, 3vw, 2rem);
  text-align: center;
}

.lp-trust {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: clamp(1rem, 2vw, 1.4rem);
  grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
}

.lp-trust__item {
  padding: 1.2rem 1.4rem;
  border-radius: var(--radius);
  background: rgba(255, 255, 255, 0.78);
  border: 1px solid var(--border-card);
  box-shadow: var(--shadow-soft);
}

.lp-trust__title {
  margin: 0 0 0.4rem;
  font-family: var(--font-display);
  font-size: 1.05rem;
  color: rgba(34, 49, 118, 0.92);
}

.lp-trust__copy {
  margin: 0;
  font-size: 0.93rem;
  line-height: 1.5;
  color: var(--text-muted);
}

/* Pricing teaser */
.lp-pricing-teaser {
  display: grid;
  gap: clamp(1rem, 2vw, 1.4rem);
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  margin-bottom: clamp(1.4rem, 3vw, 2rem);
}

.lp-pricing-teaser__card {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  padding: 1.4rem 1.6rem;
  border-radius: var(--radius);
  background: rgba(255, 255, 255, 0.78);
  border: 1px solid var(--border-card);
  box-shadow: var(--shadow-soft);
}

.lp-pricing-teaser__card--highlight {
  background: rgba(98, 118, 238, 0.1);
  border-color: rgba(98, 118, 238, 0.35);
  box-shadow: 0 22px 50px rgba(82, 104, 210, 0.18);
}

.lp-pricing-teaser__name {
  font-family: var(--font-display);
  font-size: 1.1rem;
  font-weight: 700;
  color: rgba(34, 49, 118, 0.92);
}

.lp-pricing-teaser__price {
  font-family: var(--font-display);
  font-size: 1.5rem;
  color: var(--accent-700);
}

.lp-pricing-teaser__copy {
  font-size: 0.93rem;
  line-height: 1.5;
  color: var(--text-muted);
}

/* FAQ */
.lp-faq {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}

.lp-faq__item {
  border: 1px solid var(--border-card);
  border-radius: var(--radius);
  background: rgba(255, 255, 255, 0.78);
  box-shadow: var(--shadow-soft);
  overflow: hidden;
}

.lp-faq__item[open] {
  border-color: rgba(98, 118, 238, 0.45);
}

.lp-faq__q {
  list-style: none;
  cursor: pointer;
  padding: 1rem 1.2rem;
  font-family: var(--font-display);
  font-size: 1.02rem;
  font-weight: 600;
  color: rgba(34, 49, 118, 0.92);
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
}

.lp-faq__q::-webkit-details-marker {
  display: none;
}

.lp-faq__q::after {
  content: "+";
  font-size: 1.4rem;
  color: var(--accent-700);
  line-height: 1;
  transition: transform 0.2s ease;
}

.lp-faq__item[open] .lp-faq__q::after {
  transform: rotate(45deg);
}

.lp-faq__a {
  padding: 0 1.2rem 1.1rem;
  font-size: 0.97rem;
  line-height: 1.6;
  color: var(--text-muted);
}

@media (max-width: 720px) {
  .lp-section {
    padding: 1.8rem 1.4rem;
  }

  .lp-faq__q {
    font-size: 0.97rem;
    padding: 0.9rem 1rem;
  }

  .lp-faq__a {
    padding: 0 1rem 1rem;
  }

  body[data-page="landing"],
  body[data-page="learn-more"] {
    padding-bottom: 2rem;
  }
}

/* Site footer (marketing pages) */
.site-footer {
  /* The same box as <main> and the header, rather than `width: 100%` capped at
     1100px: the footer sits outside <main>, so a percentage width was of the
     viewport, and under 1333px its rule ran wider than the cards above it. */
  width: min(var(--max-width), 96vw);
  margin: 2.5rem auto 1.5rem;
  padding: 1.4rem 1.6rem;
  text-align: center;
  font-size: 0.85rem;
  color: rgba(255, 255, 255, 0.72);
  border-top: 1px solid rgba(255, 255, 255, 0.12);
}

.site-footer__links {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.4rem 1.1rem;
  margin-bottom: 0.7rem;
}

.site-footer__links a {
  color: inherit;
  text-decoration: none;
  border-bottom: 1px solid rgba(255, 255, 255, 0.18);
  padding-bottom: 1px;
  transition: color 0.15s ease, border-color 0.15s ease;
}

.site-footer__links a:hover {
  color: #fff;
  border-color: rgba(255, 255, 255, 0.6);
}

/* The footer's own colours are overridden further down (`.site-footer__links a`
   in the light-mode block), but the `outline: none` that used to live here was
   not — so these links lost the ring in both themes and got a 1px underline
   colour change in its place. */
.site-footer__links a:focus-visible {
  color: #fff;
  border-color: rgba(255, 255, 255, 0.6);
}

.site-footer__copy {
  margin: 0;
  font-size: 0.78rem;
  opacity: 0.7;
}

@media (max-width: 720px) {
  .site-footer {
    margin: 1.6rem auto 1rem;
    padding: 1.1rem 1rem;
  }
  .site-footer__links {
    gap: 0.35rem 0.8rem;
  }
}

/* =========================================================================
   Dark theme surface overrides. Most colors come from tokens.css (which has a
   [data-theme="dark"] block), but several panels above hardcode white/near-
   white backgrounds; remap those to the dark glass surfaces here. Buttons and
   text already use tokens, so they adapt automatically.
   ========================================================================= */
:root[data-theme="dark"] .landing {
  background: linear-gradient(135deg, rgba(26, 33, 64, 0.92), rgba(20, 26, 56, 0.86));
  border-color: var(--border-card);
}
:root[data-theme="dark"] .landing__lang {
  background: var(--surface-card-muted);
}
:root[data-theme="dark"] .pricing-plan,
:root[data-theme="dark"] .lp-step,
:root[data-theme="dark"] .lp-trust__item,
:root[data-theme="dark"] .lp-pricing-teaser__card,
:root[data-theme="dark"] .lp-faq__item {
  background: var(--surface-card);
  border-color: var(--border-card);
}
:root[data-theme="dark"] .lp-section {
  background: var(--surface-card-muted);
  border-color: var(--border-card);
}
:root[data-theme="dark"] .pricing-plan--highlight {
  background: rgba(98, 118, 238, 0.18);
  border-color: rgba(120, 150, 240, 0.45);
}
/* Headings/body inks are hardcoded brand-navy for the light glass card; on the
   dark card that navy is nearly invisible (e.g. the hero title). Remap the ink
   to the light-text tokens — the accent spans already use tokens and adapt. */
:root[data-theme="dark"] .landing__title,
:root[data-theme="dark"] .landing__title span[data-i18n="title_primary"],
:root[data-theme="dark"] .lp-section__title,
:root[data-theme="dark"] .lp-step__title,
:root[data-theme="dark"] .lp-trust__title,
:root[data-theme="dark"] .lp-pricing-teaser__name,
:root[data-theme="dark"] .lp-faq__q {
  color: var(--text-base);
}
:root[data-theme="dark"] .landing__subtitle,
:root[data-theme="dark"] .landing__lede,
:root[data-theme="dark"] .footer-hint {
  color: var(--text-muted);
}
/* The decorative wave (.landing::after) uses mix-blend screen, so on the dark
   card its dots turn bright and land on top of the hero text. This used to be
   answered with a scrim behind the text column, which read as a rounded
   rectangle around the headline — a patch you could see. Cut the wave short
   instead: it fades in only past where the text column ends, so nothing is
   covering anything. The stop positions are percentages of the card, and the
   text column ends at ~63% of it (`.landing__headline` max-width), so the ramp
   runs from there to clear of it.

   Light keeps the full wave: there the dots are pale on a white card and read
   as texture under the text rather than over it. */
:root[data-theme="dark"] .landing::after {
  opacity: 0.34;
  filter: drop-shadow(0 42px 90px rgba(6, 12, 38, 0.5));
  -webkit-mask-image: linear-gradient(97deg, transparent 58%, rgba(0, 0, 0, 0.45) 72%, #000 84%);
  mask-image: linear-gradient(97deg, transparent 58%, rgba(0, 0, 0, 0.45) 72%, #000 84%);
}

/* ── Error catalog (errors.html) ────────────────────────────────────────────
   Reuses the lp-section shell and the shared tokens; the only new shapes are
   the filter bar and the code row. Rows are rendered from
   assets/error_catalog.json, which is generated by
   scripts/build_error_catalog.py — never hand-edited. */

/* The coverage cards on errors.html: six categories, kept to three columns so
   they read as two even rows rather than a 4+2 split. */
#coverage .lp-deliver {
  grid-template-columns: repeat(3, minmax(0, 1fr));
}

@media (max-width: 900px) {
  #coverage .lp-deliver {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 600px) {
  #coverage .lp-deliver {
    grid-template-columns: 1fr;
  }
}

.ec-toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
  align-items: center;
  margin-bottom: 1.1rem;
}

.ec-search {
  flex: 1 1 16rem;
  min-width: 12rem;
  padding: 0.62rem 0.85rem;
  font: inherit;
  font-family: var(--font-body);
  color: var(--text-base);
  background: var(--surface-card);
  border: 1px solid var(--border-field);
  border-radius: var(--radius);
}

.ec-search:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 1px;
  border-color: var(--accent-500);
}

.ec-filter {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 0.3rem;
  padding: 0.22rem;
  background: var(--surface-card-muted);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius);
}

.ec-filter__btn {
  padding: 0.4rem 0.7rem;
  font: inherit;
  font-family: var(--font-controls);
  font-size: 0.88rem;
  color: var(--text-muted);
  background: transparent;
  border: 0;
  border-radius: calc(var(--radius) - 2px);
  cursor: pointer;
}

.ec-filter__btn:hover { color: var(--text-base); }

/* How many codes the chip would show. The number is the argument: a group is
   only worth naming if something is behind it. */
.ec-filter__count {
  margin-left: 0.4em;
  font-variant-numeric: tabular-nums;
  font-size: 0.86em;
  opacity: 0.62;
}

.ec-filter__btn.is-active .ec-filter__count { opacity: 0.8; }

.ec-filter__btn.is-active {
  color: var(--text-on-accent);
  background: var(--gradient-primary);
}

.ec-count {
  font-size: 0.9rem;
  color: var(--text-quiet);
  margin-bottom: 0.8rem;
}

.ec-list {
  display: grid;
  gap: 0.55rem;
}

.ec-item {
  border: 1px solid var(--border-card);
  border-radius: var(--radius);
  background: rgba(255, 255, 255, 0.78);
  box-shadow: var(--shadow-soft);
  overflow: hidden;
}

.ec-item[open] { border-color: rgba(98, 118, 238, 0.45); }

.ec-item__head {
  list-style: none;
  min-width: 0;
  cursor: pointer;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.55rem;
  padding: 0.8rem 1rem;
}

.ec-item__head::-webkit-details-marker { display: none; }

/* Metadata inside the open panel, not the headline of the row. It is an anchor
   for a link or a support thread — never something the product asks anyone to
   read — so it sits at the weight of the section label beside it. */
.ec-item__code {
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--text-quiet);
  word-break: break-all;
}

.ec-item__summary {
  /* Shares the line with the badges now that the code has left it, and drops
     to its own line when the row is too narrow to hold both. */
  flex: 1 1 16rem;
  min-width: 0;
  font-size: 0.92rem;
  color: var(--text-muted);
  /* One line collapsed. The full text lives in the open panel, so without the
     clamp the row and the panel say exactly the same thing twice. */
  display: -webkit-box;
  -webkit-line-clamp: 1;
  line-clamp: 1;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.ec-badge {
  font-family: var(--font-controls);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  padding: 0.16rem 0.5rem;
  border-radius: 999px;
  border: 1px solid transparent;
  white-space: nowrap;
}

/* The row badge says what happens to a file carrying this, not how loudly the
   emitter shouted. Red is reserved for the two states that stop a filing. */
.ec-badge--blocks    { color: #8c2033; background: rgba(198, 58, 82, 0.13); border-color: rgba(198, 58, 82, 0.28); }
.ec-badge--invalid   { color: #8c2033; background: rgba(198, 58, 82, 0.13); border-color: rgba(198, 58, 82, 0.28); }
.ec-badge--attention { color: #8a5410; background: rgba(203, 132, 32, 0.15); border-color: rgba(203, 132, 32, 0.3); }
.ec-badge--repair   { color: #1d6349; background: rgba(38, 148, 106, 0.14); border-color: rgba(38, 148, 106, 0.3); }
.ec-badge--source   { color: var(--text-muted); background: var(--surface-elevated); border-color: var(--border-soft); }

/* Open, the panel below already carries the full text — keeping the clamped
   preview above it just says the same sentence twice. */
.ec-item[open] .ec-item__summary {
  display: none;
}

.ec-item__body {
  padding: 0 1rem 1rem;
  display: grid;
  /* Grid tracks default to min-content, so a long unbreakable code or xpath
     pushed the panel wider than the phone viewport. */
  grid-template-columns: minmax(0, 1fr);
  gap: 0.7rem;
}

.ec-field__label {
  font-family: var(--font-controls);
  font-size: 0.74rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-quiet);
  margin-bottom: 0.2rem;
}

.ec-field__value {
  font-size: 0.95rem;
  color: var(--text-base);
  line-height: 1.55;
  overflow-wrap: anywhere;
}

.ec-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.9rem;
  font-size: 0.84rem;
  color: var(--text-quiet);
  border-top: 1px solid var(--border-divider);
  padding-top: 0.6rem;
}

.ec-cta {
  justify-self: start;
  font-size: 0.88rem;
  font-weight: 700;
  color: var(--accent-700);
  text-decoration: none;
}

.ec-cta:hover { text-decoration: underline; }

.ec-empty {
  padding: 2rem 1rem;
  text-align: center;
  color: var(--text-muted);
}

@media (max-width: 640px) {
  .ec-toolbar { gap: 0.5rem; }
  /* Four severity labels are wider than a phone at Bulgarian word lengths
     ("Предупреждение"), so they wrap onto two rows rather than pushing the
     page sideways. */
  .ec-filter { width: 100%; }
  .ec-filter__btn { flex: 1 1 auto; }
}

:root[data-theme="dark"] .ec-item {
  background: var(--surface-card);
  border-color: var(--border-card);
}

/* Inherits `--text-quiet` from `.ec-meta` in both themes now. The override
   here dated from when the code was the headline of the row; leaving it in
   made the code brighter than the section label sitting next to it. */

:root[data-theme="dark"] .ec-badge--blocks    { color: #ffb3c0; background: rgba(198, 58, 82, 0.22); }
:root[data-theme="dark"] .ec-badge--invalid   { color: #ffb3c0; background: rgba(198, 58, 82, 0.22); }
:root[data-theme="dark"] .ec-badge--attention { color: #f4cf95; background: rgba(203, 132, 32, 0.22); }
:root[data-theme="dark"] .ec-badge--repair  { color: #93dcbe; background: rgba(38, 148, 106, 0.24); }

/* =========================================================================
   Shared site header — the same markup on all nine pre-auth pages. There is
   no templating step for web/, so the block is hand-copied and must stay
   byte-identical; everything that differs between pages is done here in CSS,
   never in the markup.
   ========================================================================= */

/* The signed-in app heads its pages with a floating card — rounded, bordered,
   surface-panel, soft shadow — holding the brand lockup and a pill nav. The
   marketing pages now use the same object instead of a full-width bar, so the
   chrome a visitor sees before signing up is the chrome they keep after. It
   sits in the same gutter as <main>, so card edges line up down the page.

   Sticky at top:0 — it starts flush with the viewport edge, so sticking costs
   no jump, and the CTA stays reachable through the long page. The glass then
   earns its keep: content blurs under the card as it passes beneath. */
.site-header {
  position: sticky;
  top: 0;
  z-index: 40;
  width: min(var(--max-width), 96vw);
  margin: 0 auto;
  padding: 0;
}

/* The card's surface — border, glass, shadow, blur — lives here rather than on
   `.site-header__inner`, one layer behind the row it frames. Everything on the
   inner (brand, links, CTA) has to stay fully opaque at every scroll position,
   and a single element cannot be both the plate that fades and the content that
   does not. Split, the whole surface is one `opacity` (see the scroll-driven
   rule below) and the row above it is untouched.

   Not on `.site-header__inner::after`, which would have been the smaller move:
   the inner would have had to clip with `overflow: hidden`, which would have
   eaten the drop shadow. `.site-header` does not clip, and with `padding: 0` its
   box is the card's box exactly.

   The blue glow is a background layer here rather than its own element. It used
   to be `.site-header__inner::before`, a box hanging outside the row and cut
   back to the card's shape by `overflow: hidden` on the row. That clip caught
   the CTA's drop shadow too, and once the plate faded to nothing at the top of
   the page the clipped shadow was the only thing left drawing the card — a
   glow that stopped dead along a rounded rectangle that was not there. As a
   background layer it is clipped by the plate's own radius, the row clips
   nothing, and the CTA's shadow is simply a shadow. The geometry is the old
   box's, resolved against the card: its ellipse was 60%x100% at 20% 50% of a
   box spanning -12%..45% of the width and -60%..160% of the height, which is
   34.2%x220% at -0.6% 50% of the card. */
.site-header::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: var(--radius-lg);
  border: 1px solid rgba(255, 255, 255, 0.68);
  /* Frosted glass rather than a flat panel: a diagonal wash from white into the
     page's blue, over a saturating blur so the hero's gradient shows through and
     shifts as the card moves against it. The inset highlight is the lit top edge
     that makes it read as glass instead of a tinted rectangle. */
  background:
    radial-gradient(
      34.2% 220% at -0.6% 50%,
      rgba(84, 125, 235, 0.22) 0%,
      rgba(84, 125, 235, 0.08) 45%,
      rgba(84, 125, 235, 0) 72%
    ),
    linear-gradient(
      135deg,
      rgba(255, 255, 255, 0.94) 0%,
      rgba(242, 246, 255, 0.82) 52%,
      rgba(230, 238, 255, 0.74) 100%
    );
  box-shadow:
    0 20px 48px -14px rgba(50, 72, 160, 0.3),
    0 2px 10px rgba(50, 72, 160, 0.07),
    inset 0 1px 0 rgba(255, 255, 255, 0.9);
  backdrop-filter: blur(20px) saturate(155%);
  -webkit-backdrop-filter: blur(20px) saturate(155%);
  pointer-events: none;
}

.site-header__inner {
  position: relative;
  display: flex;
  align-items: center;
  /* Named so the CTA can cancel it. The CTA used to live inside
     .site-header__actions and inherit that group's 0.5rem gap; it had to move
     out to stay in the bar when the rest of the row folds into the menu, and
     the negative margin below puts the spacing back exactly where it was. Every
     band that retunes this gap sets the variable, not `gap`. */
  --header-gap: clamp(0.6rem, 1.8vw, 1.5rem);
  gap: var(--header-gap);
  padding: 0.8rem 1.1rem;
}

/* A brand-coloured bloom in the corner behind the mark, so the glass has a
   light source instead of an even tint. Sits under the content. */
.site-header__inner > * {
  position: relative;
  z-index: 1;
}

/* The wrapper that becomes the menu below 900px. Above it, `display: contents`
   makes it disappear from the layout entirely: the nav and the actions stay
   direct flex children of .site-header__inner, keeping their own auto margins
   and the row exactly as it was measured. Verified by measurement, not by
   reasoning — see tests/e2e/site-header-menu.spec.js, which asserts every box
   in the desktop bar is where it was before the wrapper existed. */
.site-header__menu {
  display: contents;
}

/* The CTA left .site-header__actions so it can stay in the bar while the rest
   of the row folds away. As a sibling it now sits after the inner row's gap
   rather than the actions group's 0.5rem, so take the difference back.

   `width: auto` undoes the `.button { width: 100% }` that the 720px block
   applies to every button on the page. Inside the actions group that rule was
   harmless — the CTA was one flex item among several and simply shrank — but as
   a direct child of a wrapping row it claimed a row of its own and put 42px
   back on the header it is meant to shorten. A control in the bar is never
   full-width. */
.site-header__cta {
  margin-inline-start: calc(0.5rem - var(--header-gap));
  width: auto;
}

/* Hidden until the collapsed band turns it on, which only happens once JS has
   marked the header — a menu button that cannot open anything is worse than a
   tall header. See the collapsed block further down. */
.site-header__burger {
  display: none;
}

:root[data-theme="dark"] .site-header::before {
  border-color: rgba(140, 165, 240, 0.22);
  background:
    radial-gradient(
      34.2% 220% at -0.6% 50%,
      rgba(124, 158, 250, 0.2) 0%,
      rgba(124, 158, 250, 0.07) 45%,
      rgba(124, 158, 250, 0) 72%
    ),
    linear-gradient(
      135deg,
      rgba(34, 45, 92, 0.86) 0%,
      rgba(25, 34, 72, 0.78) 52%,
      rgba(20, 28, 62, 0.72) 100%
    );
  box-shadow:
    0 20px 48px -14px rgba(2, 6, 24, 0.6),
    inset 0 1px 0 rgba(255, 255, 255, 0.09);
}

/* At the top of the page the header card has nothing to sit over: the hero
   starts below it, so the plate is a panel drawn against a page that is already
   a panel — two surfaces, one behind the other, for no reason. Once you scroll
   it does have a job, because the hero then passes underneath it.

   So the surface follows the scroll. At the top it is not there at all — no
   glass, no border, no shadow, just the brand, the links and the CTA sitting on
   the page — and it is solid again by 40px, which is a few pixels before the
   hero's top edge reaches the card's underside (12px gap + 70px header vs the
   hero at 106px down: they meet at 36px of scroll). Nothing on the inner is
   animated; the row is at full strength the whole way.

   Scroll-driven, like the hairline below, so there is no listener. Where that
   is unsupported the plate simply stays solid — today's header, which is the
   right thing to degrade to. */
@keyframes saftix-header-plate {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

@supports (animation-timeline: scroll()) {
  .site-header::before {
    animation: saftix-header-plate linear both;
    animation-timeline: scroll(root block);
    animation-range: 0 40px;
  }
}

/* An open menu brings its surface back whatever the scroll position. The panel
   is a row inside this card, so on a phone at the top of the page the links
   would otherwise unfold onto the hero with nothing behind them. */
.site-header[data-nav="open"]::before {
  animation: none;
  opacity: 1;
}

/* A surface that appears and disappears under the reader is exactly the kind of
   change this preference is asking about. Solid throughout instead. */
@media (prefers-reduced-motion: reduce) {
  .site-header::before {
    animation: none;
    opacity: 1;
  }
}

/* Reading-progress hairline, pinned above everything at the top edge.
   Driven by the scroll timeline, so there is no scroll listener and no work on
   the main thread. Browsers without scroll-driven animations simply never grow
   the bar past scaleX(0) — it stays invisible rather than showing a full one. */
.scroll-progress {
  position: fixed;
  inset: 0 0 auto 0;
  height: 2px;
  z-index: 60;
  pointer-events: none;
}

.scroll-progress__bar {
  height: 100%;
  transform: scaleX(0);
  transform-origin: 0 50%;
  background: linear-gradient(
    90deg,
    rgba(78, 123, 238, 0.75) 0%,
    rgba(124, 92, 240, 0.82) 45%,
    rgba(168, 85, 247, 0.82) 78%,
    rgba(192, 132, 252, 0.72) 100%
  );
  box-shadow: 0 0 6px rgba(124, 92, 240, 0.28);
}

@keyframes saftix-scroll-progress {
  from {
    transform: scaleX(0);
  }
  to {
    transform: scaleX(1);
  }
}

@supports (animation-timeline: scroll()) {
  .scroll-progress__bar {
    animation: saftix-scroll-progress linear;
    animation-timeline: scroll(root block);
  }
}

@media (prefers-reduced-motion: reduce) {
  .scroll-progress {
    display: none;
  }
}

.site-header__brand {
  display: inline-flex;
  align-items: center;
  gap: 0.75rem;
  text-decoration: none;
  flex: 0 0 auto;
}

/* Name over tagline, exactly as the app header stacks them. */
.site-header__lockup {
  display: flex;
  flex-direction: column;
  line-height: 1.18;
  min-width: 0;
}

.site-header__tagline {
  font-size: 0.76rem;
  color: var(--text-muted);
  white-space: nowrap;
}

/* The header shows the bare glyph, not the framed tile the favicon uses: the
   frame exists so the mark can fill a fixed square on a background we do not
   control, and neither applies here. Without it the CTA is the only filled
   blue object in the bar. The glyph is 50:39, so the box is not square. */
.site-header__mark {
  content: url("brand/saftix-mark.svg");
  width: 2.375rem;
  height: 1.85rem;
  object-fit: contain;
  display: block;
}

/* Theme is set by a data-theme attribute on <html>, not prefers-color-scheme.
   The gradient's dark stop (#2f54c4) goes muddy on the dark header, so dark
   uses the flat #9cbdfc file — already --accent-600's dark value. */
:root[data-theme="dark"] .site-header__mark {
  content: url("brand/saftix-mark-on-dark.svg");
}

.site-header__wordmark {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.12rem;
  letter-spacing: -0.01em;
  color: var(--text-base);
}

/* Pill group, matching the app's tab rail: rounded-full track in the muted
   card surface, each link a pill inside it. Centred by auto margins so the
   brand and the actions sit at the two ends. */
.site-header__nav {
  display: inline-flex;
  align-items: center;
  gap: 0.15rem;
  margin-inline: auto;
  padding: 0.3rem;
  border-radius: 999px;
  border: 1px solid var(--border-divider);
  background: var(--surface-card-muted);
  min-width: 0;
  flex: 0 1 auto;
}

.site-header__nav a {
  font-family: var(--font-controls);
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--text-muted);
  text-decoration: none;
  padding: 0.42rem 0.8rem;
  border-radius: 999px;
  white-space: nowrap;
  transition: color 0.15s ease, background 0.15s ease;
}

.site-header__nav a:hover {
  color: var(--text-base);
  background: var(--surface-card);
}

/* Keyboard focus keeps the hover tint *and* the ring — the tint alone is a
   1.06:1 change against the pill it sits in, which is not an indicator. The
   offset goes negative so the ring is drawn inside the link's own pill instead
   of overlapping its neighbours in a row with a 0.15rem gap. */
.site-header__nav a:focus-visible {
  color: var(--text-base);
  background: var(--surface-card);
  outline-offset: -2px;
}

.site-header__actions {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  flex: 0 0 auto;
  margin-inline-start: auto;
}

.site-header__login {
  font-family: var(--font-controls);
  font-size: 0.92rem;
  font-weight: 500;
  color: var(--text-muted);
  text-decoration: none;
  padding: 0.4rem 0.6rem;
  border-radius: var(--radius);
  white-space: nowrap;
  transition: color 0.15s ease, background 0.15s ease;
}

.site-header__login:hover {
  color: var(--text-base);
  background: var(--surface-elevated);
}

.site-header__login:focus-visible {
  color: var(--text-base);
  background: var(--surface-elevated);
  outline-offset: -2px;
}

/* The lang pill and theme toggle are lifted straight from the hero so the two
   controls stay one component; only the scale changes in the bar. */
.site-header .landing__lang {
  padding: 0.2rem;
  box-shadow: none;
}

.site-header .landing__lang-button {
  padding: 0.32rem 0.62rem;
  letter-spacing: 0.12em;
  font-size: 0.72rem;
}

.site-header .landing__theme-toggle {
  width: 2.1rem;
  height: 2.1rem;
  font-size: 0.92rem;
  box-shadow: none;
}

.button--compact {
  padding: 0.5rem 0.95rem;
  font-size: 0.78rem;
  box-shadow: 0 10px 22px rgba(74, 94, 188, 0.22);
  white-space: nowrap;
}

/* Below the desktop bar the nav drops to its own full-width row rather than
   squeezing the brand and the CTA off the screen. The ceiling is set by the
   widest point at which the six-link row still cannot be made to fit on one
   line — see the intermediate band near the end of this file, which picks up
   at the next pixel.

   That row wraps; it used to scroll sideways with the scrollbar hidden. A
   hidden scrollbar is not an affordance: with five links the row happened to
   fit and nobody noticed, and the sixth pushed „За нас" out past the pill's
   edge with nothing to say so — clipped and unclickable across 621–661px, and
   still hanging outside the pill up to 698px. Wrapping cannot do that, and it
   costs nothing at the widths where the row already fits, because flex only
   wraps once it must. */
@media (max-width: 1160px) {
  .site-header__inner {
    flex-wrap: wrap;
    row-gap: 0.35rem;
  }

  .site-header__nav {
    order: 3;
    flex: 1 0 100%;
    margin-inline-start: 0;
    flex-wrap: wrap;
    row-gap: 0.15rem;
  }
}

@media (max-width: 620px) {
  .site-header__inner {
    padding: 0.55rem 1rem;
    --header-gap: 0.4rem;
    row-gap: 0.5rem;
  }

  /* Without the script the CTA is a sibling of this group rather than its last
     child, so it takes the row below instead of the far end of this one — 42px
     more header at 360px than the old markup produced. That is the degraded
     path only (JS off, or the moment before the module runs); with the script
     running this whole row is inside the menu and the CTA is up in the bar. */
  .site-header__actions {
    order: 2;
    flex: 1 0 100%;
    margin-inline-start: 0;
    justify-content: space-between;
  }

  .site-header__wordmark {
    font-size: 1rem;
  }

  .site-header__login {
    padding: 0.35rem 0.4rem;
    font-size: 0.86rem;
  }

  .button--compact {
    padding: 0.55rem 0.8rem;
    font-size: 0.72rem;
  }

  .site-header__nav a {
    font-size: 0.86rem;
    padding: 0.25rem 0.1rem;
  }

  .site-header__nav {
    flex-wrap: wrap;
    row-gap: 0;
    column-gap: 0.85rem;
  }
}

/* ---------------------------------------------------------------------------
   The collapsed header (phones and small tablets).

   What it replaces, measured 2026-08-20 in Chromium on pricing.html:

     500x667  header 165px sticky — 25% of the screen — nav on two rows,
              each link 79x25, against the 44px a finger needs
     360x640  header 190px — 30% of the screen — nav on three rows
     768x1024 header 111px, brand and actions on one row, nav on a second

   A quarter of a phone screen permanently spent on chrome, and links too small
   to hit reliably. So under 900px the row folds into a disclosure: brand, the
   one CTA, and a menu button; everything else moves into a panel that opens on
   its own row inside the same glass card.

   Two things gate this.

   The 900px bound sits below the 1160px stacked breakpoint on purpose. Between
   901 and 1160 the header keeps its two-row stacked layout, which is what
   tests/test_site_header_layout.py pins and what the 1161-1380 band above hands
   off to. Nothing in that chain moves.

   The `[data-nav]` attribute is written by landing.js. Without JS none of this
   applies and the header renders exactly as it does today — tall, but every
   link reachable. A disclosure whose button does nothing would be worse than
   the thing it replaces, so it never appears unless the script that runs it
   has.

   The panel is a flex item on its own row rather than an absolutely positioned
   overlay. That was originally forced — .site-header__inner carried
   `backdrop-filter`, which made it the containing block for absolutely
   positioned descendants, and clipped them with `overflow: hidden`, so a
   dropdown anchored there was invisible. Both have since moved to
   `.site-header::before` and the clip is gone, but growing the card was always
   the better answer anyway: the menu reads as the header opening rather than as
   a second surface floating under it.
   --------------------------------------------------------------------------- */
@media (max-width: 900px) {
  .site-header[data-nav] .site-header__inner {
    flex-wrap: wrap;
    row-gap: 0.5rem;
  }

  /* Brand | CTA | menu. The auto margin replaces the negative one the CTA uses
     to sit tight against the login link on desktop. */
  .site-header[data-nav] .site-header__cta {
    margin-inline-start: auto;
    order: 1;
  }

  .site-header[data-nav] .site-header__burger {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    order: 2;
    /* 44px, the smallest comfortable tap target. */
    min-height: 2.75rem;
    padding: 0 0.85rem;
    border-radius: 999px;
    border: 1px solid var(--border-divider);
    background: var(--surface-card-muted);
    color: var(--text-base);
    font-family: var(--font-controls);
    font-size: 0.85rem;
    font-weight: 600;
    line-height: 1;
    cursor: pointer;
    transition: background 0.15s ease, border-color 0.15s ease;
  }

  .site-header[data-nav] .site-header__burger:hover {
    background: var(--surface-card);
    border-color: var(--border-strong);
  }

  /* The panel: last in the row, full width, and only in flow while open.
     `display: none` when closed keeps it out of the tab order and out of the
     accessibility tree without a second attribute to keep in step. */
  .site-header[data-nav] .site-header__menu {
    display: none;
    order: 3;
    flex: 1 0 100%;
    flex-direction: column;
    gap: 0.35rem;
    padding-top: 0.35rem;
    /* The card is sticky at top:0, so a menu taller than the screen would run
       off the bottom with no way to reach the end of it. */
    max-height: calc(100svh - 8rem);
    overflow-y: auto;
  }

  .site-header[data-nav="open"] .site-header__menu {
    display: flex;
  }

  /* The nav pill becomes a list. Nothing wraps, nothing scrolls sideways, and
     every link is a full-width row — which is also the only shape in which six
     Bulgarian labels fit a 360px screen without abbreviating any of them. */
  .site-header[data-nav] .site-header__nav {
    /* The stacked bands below 1160px and 620px give these two `order` values
       for their place in the header row. Inside the panel those orders still
       apply and put the settings above the links — which also puts the first
       thing Tab reaches four rows below the first thing the eye reaches. Reset
       both so the panel follows the markup: where to go, then how to see it. */
    order: 0;
    flex: 0 0 auto;
    flex-direction: column;
    align-items: stretch;
    gap: 0.15rem;
    margin-inline: 0;
    padding: 0.35rem;
    border-radius: var(--radius-lg);
  }

  .site-header[data-nav] .site-header__nav a {
    display: flex;
    align-items: center;
    min-height: 2.75rem;
    padding: 0.5rem 0.85rem;
    font-size: 0.95rem;
    border-radius: var(--radius);
  }

  /* Language, theme and the login link share the row under the divider: they
     are the settings of the page, not places to go. */
  .site-header[data-nav] .site-header__actions {
    order: 1;
    flex: 0 0 auto;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-inline-start: 0;
    justify-content: flex-start;
    padding-top: 0.5rem;
    margin-top: 0.15rem;
    border-top: 1px solid var(--border-divider);
  }

  .site-header[data-nav] .site-header__login {
    display: inline-flex;
    align-items: center;
    min-height: 2.75rem;
    margin-inline-start: auto;
    padding-inline: 0.9rem;
    font-size: 0.95rem;
    border-radius: var(--radius);
    background: var(--surface-elevated);
  }

  .site-header[data-nav] .landing__lang-button {
    min-height: 2.75rem;
    padding-inline: 0.95rem;
    font-size: 0.78rem;
  }

  .site-header[data-nav] .landing__theme-toggle {
    width: 2.75rem;
    height: 2.75rem;
  }

  /* The tagline is the first decoration to go on a phone, exactly as it is in
     the 1161-1380 band — the wordmark already says who we are, and the two
     lines of lockup are what make the bar taller than its tallest control. */
  .site-header[data-nav] .site-header__tagline {
    display: none;
  }
}

/* The icon carries the state; the label names the thing and never changes, so
   the button does not resize under the finger that just pressed it. Which state
   it is in is `aria-expanded`'s job, and the glyph's. */
.site-header__burger-x {
  display: none;
}

.site-header__burger[aria-expanded="true"] .site-header__burger-bars {
  display: none;
}

.site-header__burger[aria-expanded="true"] .site-header__burger-x {
  display: inline;
}

/* Stroke weight is drawn from the brand mark rather than picked: the mark is a
   7-unit stroke in a 39-unit-tall box (18% of its height) with round caps and
   joins, so the icon keeps the caps and the joins and takes 3 units in a 24-unit
   box. Not the full 18% — three parallel bars at that weight close their own
   gaps at 20px — but heavy enough that the two marks read as one family. */
.site-header__burger-icon {
  flex: 0 0 auto;
  color: var(--accent-600);
}

/* The footer sat on white-ish text over a light page — invisible in light mode
   wherever the backdrop is pale. Put it on the text tokens instead. */
.site-footer {
  color: var(--text-muted);
  border-top-color: var(--border-divider);
}

.site-footer__links a {
  border-bottom-color: var(--border-strong);
}

.site-footer__links a:hover,
.site-footer__links a:focus-visible {
  color: var(--accent-600);
  border-color: var(--accent-500);
}

/* =========================================================================
   The four lanes (index.html). Four structurally equal cards — four equal
   answers to "what are you holding today".
   ========================================================================= */

.lp-lanes {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: clamp(1rem, 2vw, 1.5rem);
  /* One row of three. The routes are the three things a visitor can be holding —
     documents, an export, a finished file — so the row is the whole answer with
     nothing left over. (It was two-by-two when a fourth card stated the free
     check; that was a price, not a route, and it left the grid's last cell
     visibly short.) */
  grid-template-columns: repeat(3, minmax(0, 1fr));
}

/* Was 720px, when the grid was two columns. Three columns run out of width
   sooner: measured, they are 368px wide at a 1440px viewport, 243px by 1000px
   (card 436px tall), and 218px by 900px (card 494px tall) — a ribbon of copy in
   a column taller than it is wide. 1000px is where that stops being worth it.
   Three does not halve, so a middle two-column step would only put the orphan
   back — go straight to one column. */
@media (max-width: 1000px) {
  .lp-lanes {
    grid-template-columns: 1fr;
  }
}

.lp-lane {
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
  padding: 1.5rem 1.7rem 1.7rem;
  border-radius: var(--radius);
  background: rgba(255, 255, 255, 0.78);
  border: 1px solid var(--border-card);
  box-shadow: var(--shadow-soft);
}

.lp-lane__eyebrow {
  font-family: var(--font-controls);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--accent-600);
}

.lp-lane__title {
  margin: 0;
  font-family: var(--font-display);
  font-size: 1.22rem;
  color: var(--text-base);
}

.lp-lane__copy {
  margin: 0;
  font-size: 0.97rem;
  line-height: 1.6;
  color: var(--text-muted);
}

.lp-lane__link {
  margin-top: auto;
  padding-top: 0.5rem;
  align-self: flex-start;
  font-family: var(--font-controls);
  font-size: 0.86rem;
  font-weight: 700;
  color: var(--accent-600);
  text-decoration: none;
}

.lp-lane__link:hover {
  text-decoration: underline;
}

/* "Какво получавате" / "Какво не правим" */
.lp-deliver {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: clamp(1rem, 2vw, 1.4rem);
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
}

/* On /errors these six cards are the filter: each one opens the group of codes
   that backs the claim it makes. They only carry this affordance on that page,
   where errors.js finds the `data-layer-link` attribute. */
.lp-deliver__item--link {
  cursor: pointer;
  transition: border-color 140ms ease, transform 140ms ease;
}

.lp-deliver__item--link:hover {
  border-color: rgba(98, 118, 238, 0.5);
  transform: translateY(-1px);
}

/* The lift is shared with hover, the ring is not: a 55%-alpha blue on a white
   card was the faintest indicator on the site. The page ring replaces it. */
.lp-deliver__item--link:focus-visible {
  border-color: rgba(98, 118, 238, 0.5);
  transform: translateY(-1px);
}

.lp-deliver__item--link .lp-deliver__title::after {
  /* Non-breaking, so the arrow never wraps to a line of its own under a title
     that happens to fill its column. */
  content: "\00a0→";
  color: var(--text-quiet);
}

@media (prefers-reduced-motion: reduce) {
  .lp-deliver__item--link { transition: none; }
  .lp-deliver__item--link:hover,
  .lp-deliver__item--link:focus-visible { transform: none; }
}

.lp-deliver__item {
  padding: 1.2rem 1.4rem;
  border-radius: var(--radius);
  background: rgba(255, 255, 255, 0.78);
  border: 1px solid var(--border-card);
  box-shadow: var(--shadow-soft);
}

.lp-deliver__item--negative {
  background: var(--chip-warning);
  border-color: var(--warning);
}

.lp-deliver__title {
  margin: 0 0 0.4rem;
  font-family: var(--font-display);
  font-size: 1.05rem;
  color: var(--text-base);
}

.lp-deliver__copy {
  margin: 0;
  font-size: 0.93rem;
  line-height: 1.55;
  color: var(--text-muted);
}

.lp-trust__link {
  display: inline-block;
  margin-top: 0.5rem;
  font-family: var(--font-controls);
  font-size: 0.84rem;
  font-weight: 700;
  color: var(--accent-600);
  text-decoration: none;
}

.lp-trust__link:hover {
  text-decoration: underline;
}

.lp-note {
  margin: clamp(1.2rem, 2.5vw, 1.8rem) 0 0;
  font-size: 0.9rem;
  line-height: 1.55;
  color: var(--text-quiet);
}

.lp-section__cta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.8rem;
  align-items: center;
  margin-top: clamp(1.4rem, 3vw, 2rem);
}

/* Free tier, stated above the paid table because it is a real tier. */
.pricing-free {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.6rem 1.2rem;
  margin: 0 0 1.2rem;
  padding: 1.1rem 1.4rem;
  border-radius: var(--radius);
  background: var(--surface-elevated);
  border: 1px solid var(--accent-400);
  position: relative;
}

.pricing-free__title {
  flex: 1 0 100%;
  margin: 0;
  font-family: var(--font-display);
  font-size: 1.1rem;
  color: var(--text-base);
}

.pricing-free__copy {
  margin: 0;
  flex: 1 1 16rem;
  font-size: 0.93rem;
  line-height: 1.55;
  color: var(--text-muted);
}

.pricing-free__link {
  font-family: var(--font-controls);
  font-size: 0.86rem;
  font-weight: 700;
  color: var(--accent-600);
  text-decoration: none;
  white-space: nowrap;
}

.pricing-free__link:hover {
  text-decoration: underline;
}

.pricing-annual-note {
  margin: 0 0 0.4rem;
  max-width: 62ch;
  font-size: 0.92rem;
  color: var(--text-muted);
  position: relative;
}

@media (max-width: 720px) {
  .pricing-annual-note {
    max-width: 100%;
  }
}

:root[data-theme="dark"] .lp-lane,
:root[data-theme="dark"] .lp-deliver__item,
:root[data-theme="dark"] .pricing-free {
  background: var(--surface-card);
  border-color: var(--border-card);
}

:root[data-theme="dark"] .pricing-free {
  border-color: var(--accent-600);
}

:root[data-theme="dark"] .lp-deliver__item--negative {
  background: var(--chip-warning);
  border-color: var(--warning);
}

:root[data-theme="dark"] .lp-lane__title,
:root[data-theme="dark"] .lp-deliver__title,
:root[data-theme="dark"] .pricing-free__title,
:root[data-theme="dark"] .site-header__wordmark {
  color: var(--text-base);
}

/* =========================================================================
   Legal pages (privacy, terms, aup, billing-terms, subprocessors). They used
   to load an assets/style.css that does not exist and rendered unstyled. They
   are now on this sheet, on the same shell and the same language switch as
   everything else. Their *text* is untouched.
   ========================================================================= */

.legal {
  width: 100%;
  max-width: 52rem;
  margin: 0 auto;
  border-radius: var(--radius-lg);
  padding: clamp(1.8rem, 4vw, 3rem) clamp(1.4rem, 4vw, 3rem);
  background: linear-gradient(135deg, rgba(255, 255, 255, 0.96), rgba(238, 244, 255, 0.92));
  border: 1px solid var(--border-card);
  box-shadow: var(--shadow);
  backdrop-filter: blur(14px);
}

.legal h1 {
  margin: 0 0 0.35rem;
  font-family: var(--font-display);
  font-size: clamp(1.6rem, 3.4vw, 2.1rem);
  line-height: 1.15;
  color: var(--text-base);
}

.legal h2 {
  margin: 2rem 0 0.5rem;
  font-family: var(--font-display);
  font-size: 1.14rem;
  line-height: 1.3;
  color: var(--text-base);
}

.legal h3 {
  margin: 1.4rem 0 0.4rem;
  font-family: var(--font-display);
  font-size: 1rem;
  color: var(--text-base);
}

.legal p,
.legal li {
  font-size: 0.96rem;
  line-height: 1.65;
  color: var(--text-muted);
}

.legal p {
  margin: 0 0 0.8rem;
}

.legal ul,
.legal ol {
  margin: 0 0 0.9rem;
  padding-inline-start: 1.3rem;
}

.legal li {
  margin-bottom: 0.35rem;
}

.legal strong {
  color: var(--text-base);
}

.legal em {
  color: var(--text-quiet);
  font-style: normal;
}

.legal a {
  color: var(--accent-600);
  text-decoration: underline;
  text-underline-offset: 2px;
}

.legal code {
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  font-size: 0.9em;
  padding: 0.1rem 0.35rem;
  border-radius: calc(var(--radius) - 4px);
  background: var(--surface-elevated);
  color: var(--text-base);
}

/* Tables are the widest thing on these pages; they scroll inside their own
   box rather than pushing the page sideways on a phone. */
.legal__table {
  overflow-x: auto;
  margin: 0 0 1rem;
}

.legal table {
  width: 100%;
  min-width: 30rem;
  border-collapse: collapse;
  font-size: 0.92rem;
}

.legal th,
.legal td {
  text-align: left;
  vertical-align: top;
  padding: 0.55rem 0.75rem;
  border: 1px solid var(--border-divider);
  color: var(--text-muted);
}

.legal th {
  background: var(--surface-elevated);
  font-family: var(--font-controls);
  font-weight: 600;
  color: var(--text-base);
}

.legal .callout {
  margin: 1.1rem 0;
  padding: 0.85rem 1.1rem;
  border-radius: var(--radius);
  background: var(--surface-elevated);
  border-inline-start: 3px solid var(--accent-500);
  font-size: 0.92rem;
  color: var(--text-muted);
}

.legal footer {
  margin-top: 2rem;
  padding-top: 1rem;
  border-top: 1px solid var(--border-divider);
  font-size: 0.9rem;
  color: var(--text-quiet);
}

/* The language switch is the shared BG/EN pill in the header; these two blocks
   are what it shows and hides. */
.legal [data-legal-lang] {
  display: none;
}

.legal [data-legal-lang].is-active {
  display: block;
}

:root[data-theme="dark"] .legal {
  background: var(--surface-card-muted);
  border-color: var(--border-card);
}

.lp-about {
  max-width: 46rem;
  margin: 0 auto;
  color: var(--text-muted);
  font-size: 1.04rem;
  line-height: 1.7;
  text-align: center;
}

.pricing-limits {
  margin: 1.4rem auto 0;
  text-align: center;
  font-size: 0.92rem;
  color: var(--text-muted);
}

.pricing-limits a {
  color: var(--accent-700);
  font-weight: 600;
  text-decoration: none;
}

.pricing-limits a:hover {
  text-decoration: underline;
}

/* ── Beta access request ──────────────────────────────────────────────────
 *
 * The dialog behind every "Заявете достъп" CTA. It replaced a mailto: link,
 * which handed the visitor a half-written message and no way to send it if
 * the machine has no mail client configured — most accountants read mail in a
 * browser tab.
 *
 * Built on native <dialog>: showModal() gives the focus trap, the inert
 * background and Esc-to-close for free, and landing.js only intercepts the
 * CTA when the browser actually supports it — everywhere else the mailto:
 * fallback in the href still fires.
 *
 * Everything here is token-driven, so the dark theme comes along with the
 * page; only the two surfaces that mix their own alpha need an override.
 */
.beta-dialog {
  width: min(46rem, calc(100vw - 2rem));
  max-height: min(92vh, 54rem);
  padding: 0;
  border: 1px solid var(--border-card);
  border-radius: var(--radius-lg);
  background: var(--surface-panel);
  color: var(--text-base);
  box-shadow: var(--shadow);
  overflow: hidden;
}

.beta-dialog::backdrop {
  background: rgba(11, 20, 56, 0.52);
  backdrop-filter: blur(3px);
}

:root[data-theme="dark"] .beta-dialog::backdrop {
  background: rgba(4, 8, 26, 0.68);
}

.beta-dialog[open] {
  animation: beta-dialog-in 0.18s ease-out;
}

@keyframes beta-dialog-in {
  from {
    opacity: 0;
    transform: translateY(8px) scale(0.985);
  }
}

@media (prefers-reduced-motion: reduce) {
  .beta-dialog[open] {
    animation: none;
  }
}

.beta-dialog__panel {
  display: flex;
  flex-direction: column;
  max-height: min(92vh, 54rem);
}

/* The form is the flex child that stretches; its field list is what scrolls,
   which keeps the heading and the send button in view on a phone. */
.beta-dialog__form {
  display: flex;
  flex-direction: column;
  min-height: 0;
}

.beta-dialog__head {
  position: relative;
  padding: 1.5rem clamp(1.2rem, 3vw, 2rem) 1.1rem;
  border-bottom: 1px solid var(--border-divider);
  background: var(--surface-card-muted);
}

.beta-dialog__eyebrow {
  display: block;
  font-family: var(--font-controls);
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--accent-600);
}

.beta-dialog__title {
  margin: 0.45rem 0 0;
  padding-inline-end: 2.5rem;
  font-family: var(--font-display);
  font-size: clamp(1.3rem, 2.6vw, 1.6rem);
  line-height: 1.2;
  color: var(--text-base);
}

.beta-dialog__lede {
  margin: 0.5rem 0 0;
  max-width: 34rem;
  font-size: 0.95rem;
  line-height: 1.55;
  color: var(--text-muted);
}

/* The plan the visitor clicked, carried into the message so the reply can
   answer the question they actually asked. */
.beta-dialog__plan {
  display: none;
  margin-top: 0.75rem;
  padding: 0.28rem 0.7rem;
  border-radius: 999px;
  background: var(--chip-info);
  border: 1px solid rgba(98, 118, 238, 0.3);
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--accent-700);
}

.beta-dialog__plan.is-visible {
  display: inline-block;
}

.beta-dialog__close {
  position: absolute;
  top: 0.9rem;
  inset-inline-end: 0.9rem;
  width: 2.1rem;
  height: 2.1rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border-radius: 50%;
  border: 1px solid var(--border-soft);
  background: var(--surface-card);
  color: var(--text-muted);
  font-size: 1.05rem;
  line-height: 1;
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease, transform 0.15s ease;
}

.beta-dialog__close:hover {
  transform: translateY(-1px);
  color: var(--text-base);
  background: var(--surface-elevated);
}

.beta-dialog__close:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
}

.beta-dialog__body {
  flex: 1 1 auto;
  min-height: 0;
  padding: 1.3rem clamp(1.2rem, 3vw, 2rem) 1.3rem;
  overflow-y: auto;
}

.beta-form__grid {
  display: grid;
  gap: 0.9rem 1rem;
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
}

.beta-form__field {
  display: flex;
  flex-direction: column;
  gap: 0.32rem;
  min-width: 0;
}

.beta-form__field--wide {
  grid-column: 1 / -1;
}

.beta-form__label {
  font-family: var(--font-controls);
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--text-base);
}

.beta-form__req {
  color: var(--error);
}

.beta-form__input,
.beta-form__select,
.beta-form__textarea {
  width: 100%;
  padding: 0.6rem 0.8rem;
  font: inherit;
  font-family: var(--font-body);
  font-size: 0.95rem;
  color: var(--text-base);
  background: var(--surface-card);
  border: 1px solid var(--border-field);
  border-radius: var(--radius);
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.beta-form__textarea {
  min-height: 5.5rem;
  resize: vertical;
}

.beta-form__input:focus-visible,
.beta-form__select:focus-visible,
.beta-form__textarea:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 1px;
  border-color: var(--accent-500);
}

.beta-form__input[aria-invalid="true"],
.beta-form__select[aria-invalid="true"] {
  border-color: var(--error);
  box-shadow: 0 0 0 1px var(--error);
}

.beta-form__error {
  display: none;
  font-size: 0.82rem;
  color: var(--error);
}

.beta-form__error.is-visible {
  display: block;
}

/* Off-screen rather than display:none — a bot that respects the latter would
   walk straight past the trap. */
.beta-form__honeypot {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.beta-dialog__alert {
  display: none;
  margin-top: 1rem;
  padding: 0.7rem 0.9rem;
  border-radius: var(--radius);
  background: var(--chip-error);
  border: 1px solid rgba(224, 85, 97, 0.35);
  font-size: 0.9rem;
  line-height: 1.5;
  color: var(--text-base);
}

.beta-dialog__alert.is-visible {
  display: block;
}

.beta-dialog__alert a {
  color: var(--accent-700);
  font-weight: 600;
}

.beta-dialog__foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.9rem;
  padding: 1.1rem clamp(1.2rem, 3vw, 2rem) 1.4rem;
  border-top: 1px solid var(--border-divider);
  background: var(--surface-card-muted);
}

.beta-dialog__privacy {
  flex: 1 1 16rem;
  margin: 0;
  font-size: 0.82rem;
  line-height: 1.5;
  color: var(--text-quiet);
}

.beta-dialog__privacy a {
  color: var(--accent-700);
  font-weight: 600;
  text-decoration: none;
}

.beta-dialog__privacy a:hover {
  text-decoration: underline;
}

.beta-dialog__actions {
  display: flex;
  align-items: center;
  gap: 0.6rem;
}

.beta-dialog__submit[aria-busy="true"] {
  background: var(--gradient-primary-disabled);
  box-shadow: none;
  cursor: progress;
  pointer-events: none;
}

/* Confirmation. It replaces the form rather than sitting under it, so the
   answer to "did that go through?" is the only thing on screen. */
.beta-dialog__done {
  display: none;
  padding: 2.2rem clamp(1.2rem, 3vw, 2rem) 2.4rem;
  text-align: center;
}

.beta-dialog.is-done .beta-dialog__done {
  display: block;
}

.beta-dialog.is-done .beta-dialog__form,
.beta-dialog.is-done .beta-dialog__lede,
.beta-dialog.is-done .beta-dialog__plan {
  display: none;
}

.beta-dialog__done-mark {
  width: 3rem;
  height: 3rem;
  margin: 0 auto 0.9rem;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--chip-success);
  color: var(--success);
  font-size: 1.5rem;
  line-height: 1;
}

.beta-dialog__done-title {
  margin: 0;
  font-family: var(--font-display);
  font-size: 1.25rem;
  color: var(--text-base);
}

.beta-dialog__done-copy {
  margin: 0.6rem auto 1.3rem;
  max-width: 30rem;
  font-size: 0.95rem;
  line-height: 1.6;
  color: var(--text-muted);
}

@media (max-width: 30rem) {
  .beta-dialog__foot {
    flex-direction: column;
    align-items: stretch;
  }

  .beta-dialog__privacy {
    flex: 0 0 auto;
  }

  .beta-dialog__actions {
    justify-content: flex-end;
  }
}

/* The page behind a modal must not scroll under it. The open header menu is the
   same promise: it covers the page it belongs to, and a page that scrolls away
   underneath an open menu leaves the reader somewhere they did not ask to be.
   One rule for both so there is one thing to get right. */
html.beta-dialog-open,
html.beta-dialog-open body,
html.site-nav-open,
html.site-nav-open body {
  overflow: hidden;
}

/* ---------------------------------------------------------------------------
   nra-reference.html — the НАП requirement справочник.
   Reuses the catalogue primitives (.ec-item, .ec-badge, .ec-filter) so the two
   published reference pages read as one product. What is new here is the
   identifier: on errors.html a code is metadata, but on this page it is the
   thing being looked up — it is printed on the rejection notice the reader is
   holding — so it sits in the summary line and is styled to be found.
--------------------------------------------------------------------------- */

.nr-id {
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--accent-700);
  background: rgba(28, 63, 166, 0.08);
  border: 1px solid rgba(28, 63, 166, 0.16);
  border-radius: calc(var(--radius) - 4px);
  padding: 0.1rem 0.4rem;
  white-space: nowrap;
}

[data-theme="dark"] .nr-id {
  color: var(--accent-400);
  background: rgba(122, 162, 255, 0.12);
  border-color: rgba(122, 162, 255, 0.24);
}

.nr-item[hidden] { display: none; }

/* The summary text has to be allowed to shrink next to a badge and a fixed-width
   identifier, or a long requirement pushes the row past the viewport. */
.nr-item .ec-item__summary { flex: 1 1 14rem; min-width: 0; }

.ec-field { min-width: 0; }

/* Which of the three files a requirement applies to, and what we do about it. */
/* Auto width, not 100%: three short cells stretched across the panel read as
   three unrelated columns rather than one line about one file. */
.nr-modes {
  width: auto;
  border-collapse: collapse;
  font-size: 0.88rem;
}

.nr-modes th,
.nr-modes td {
  text-align: left;
  padding: 0.3rem 1.4rem 0.3rem 0;
  border-bottom: 1px solid var(--border-divider);
  vertical-align: top;
  color: var(--text-base);
}

.nr-modes th { font-weight: 600; white-space: nowrap; }
.nr-modes td:last-child { color: var(--text-muted); }
.nr-modes tr:last-child th,
.nr-modes tr:last-child td { border-bottom: 0; }

.nr-paths {
  margin: 0;
  padding-left: 1.1rem;
  display: grid;
  gap: 0.25rem;
}

.nr-paths code {
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  font-size: 0.78rem;
  color: var(--text-quiet);
  word-break: break-all;
}

/* The per-mode totals band above the list. */
.nr-modes-grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 1rem;
  grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
}

.nr-mode {
  border: 1px solid var(--border-card);
  border-radius: var(--radius);
  background: var(--surface-card);
  box-shadow: var(--shadow-soft);
  padding: 1.1rem 1.2rem;
}

.nr-mode__name {
  font-family: var(--font-display);
  font-size: 1.05rem;
  margin: 0 0 0.5rem;
  color: var(--text-base);
}

.nr-mode__figure {
  font-family: var(--font-display);
  font-size: 1.9rem;
  font-weight: 700;
  line-height: 1.1;
  margin: 0 0 0.35rem;
  color: var(--text-base);
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.45rem;
}

.nr-mode__figure span {
  font-family: var(--font-body);
  font-size: 0.88rem;
  font-weight: 400;
  color: var(--text-muted);
}

.nr-mode__line {
  margin: 0 0 0.2rem;
  font-size: 0.9rem;
  color: var(--text-muted);
}

/* Zero unmet mandatory requirements is the claim this page is making; if the
   build ever produces a non-zero it should read as a warning, not as a stat. */
.nr-mode__line--clear { color: var(--success); font-weight: 600; }
.nr-mode__line--gap { color: var(--error); font-weight: 600; }

.lp-section__note {
  font-size: 0.9rem;
  color: var(--text-quiet);
  margin: 1.1rem 0 0;
  max-width: 46rem;
}

/* The coverage claim: three figures that add up to the total. The middle one is
   the admission, so it is styled as an amber note rather than hidden. */
.nr-cover-grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 1rem;
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
}

.nr-cover {
  border: 1px solid var(--border-card);
  border-left-width: 3px;
  border-radius: var(--radius);
  background: var(--surface-card);
  box-shadow: var(--shadow-soft);
  padding: 1.1rem 1.2rem;
}

.nr-cover--checked { border-left-color: var(--success); }
.nr-cover--stated { border-left-color: var(--warning); }
.nr-cover--schema { border-left-color: var(--border-strong); }

.nr-cover__figure {
  font-family: var(--font-display);
  font-size: 2.1rem;
  font-weight: 700;
  line-height: 1.05;
  margin: 0 0 0.3rem;
  color: var(--text-base);
}

.nr-cover__name {
  margin: 0;
  font-size: 0.92rem;
  color: var(--text-muted);
  line-height: 1.45;
}

/* What the reader still has to do themselves, kept visually distinct from the
   requirement text above it so the two are not mistaken for one statement. */
.nr-gap {
  border-left: 2px solid var(--warning);
  padding-left: 0.7rem;
}

.nr-gap .ec-field__value {
  font-size: 0.9rem;
  color: var(--text-muted);
}

/* The header between the stacked layout (≤1160px) and a comfortable desktop.
   In that band the nav keeps its full-size links while the brand keeps its
   tagline, so the nav — which may shrink but whose links may not wrap here —
   overflows its own pill and slides underneath the language toggle. The
   failure is silent: nothing looks broken, the links are simply unclickable.

   Measured 2026-08-20 in Chromium over every page in both languages, after
   „Наръчник" made the nav six links. The bar is that no link may extend past
   the pill that holds it — one hanging over the edge is the same failure a few
   pixels early, and it is the part you can see. With the tagline showing the
   row clears the pill only from 1372px up; with the tagline dropped and the
   spacing below tightened, from 1153px up. So the band runs 1161–1380px and
   the stacked layout takes everything under it, each bound keeping ~8px of
   slack on the measurement. Bulgarian binds; the English labels are narrower.

   1366px therefore sits inside the band and shows no tagline. That is not a
   choice — at 1366px there is no room for the tagline and six links at once.

   The tagline goes first because it is the only decorative thing competing:
   the wordmark already says who we are. The two gaps come next and are close to
   free — the nav is centred by auto margins, which reabsorb whatever the gaps
   give up until the row is genuinely full. Tightening the link padding covers
   the rest of the band. */
@media (min-width: 1161px) and (max-width: 1380px) {
  .site-header__tagline {
    display: none;
  }

  .site-header__inner {
    --header-gap: 0.85rem;
  }

  .site-header__nav {
    gap: 0;
  }

  .site-header__nav a {
    padding-inline: 0.5rem;
  }

  .site-header__login {
    padding-inline: 0.4rem;
  }
}

/* ==========================================================================
   SFX-16 · Error catalogue: expand affordance, the code in the closed row,
   and a legend for the two badge vocabularies.

   Appended rather than folded into the .ec-* block above, and scoped to
   #ec-list / #ec-legend throughout: nra-reference.html reuses .ec-item,
   .ec-item__head, .ec-item__code and .ec-badge verbatim across 1.2 MB of
   static markup, and none of it should move because this page grew a „+".
   ========================================================================== */

/* The rows are <details>, but .ec-item__head turns the disclosure marker off
   and put nothing in its place — 132 cards with no sign they open. This is the
   same „+" as .lp-faq__q, which is in the „За списъка" section of this very
   page, so the two disclosures on one screen now open the same way. */
#ec-list .ec-item__toggle {
  flex: 0 0 auto;
  font-size: 1.15rem;
  line-height: 1;
  color: var(--accent-700);
  opacity: 0.75;
  transition: transform 0.2s ease, opacity 0.2s ease;
}

#ec-list .ec-item[open] .ec-item__toggle {
  transform: rotate(45deg);
  opacity: 1;
}

/* Hover only — the keyboard already gets the global :focus-visible ring, and
   hover and focus must not share a block (see the note at the top of this
   file). The whole row is the control, so the tell brightens from anywhere
   on it, not just from the glyph. */
#ec-list .ec-item__head:hover .ec-item__toggle {
  opacity: 1;
}

/* Trailing and right-aligned, a notch below the 0.78rem it had inside the
   panel: 132 of them stacked in one column read as a lot more type than one
   did at the foot of an open row, and the sentence has to win the row.
   `margin-left: auto` does nothing while the sentence beside it is growing to
   fill the row; it earns its place when the row is open (the sentence is
   hidden) or when a long code wraps to a line of its own — both times it keeps
   the codes in one column instead of scattering them mid-row.
   `flex: 0 0 auto` makes a long code take its own line rather than break in
   half; break-all is inherited as the last resort on a narrow phone. */
#ec-list .ec-item__head .ec-item__code {
  flex: 0 0 auto;
  margin-left: auto;
  font-size: 0.72rem;
  letter-spacing: 0.01em;
}

/* The badges on a row come from two different vocabularies — what the file is
   fit for, and where the correction is made — and nothing on the row said so.
   Sits between the filters and the tally: after the controls that change the
   list, before the list it explains.
   One line per axis rather than both on one line. Side by side they do not fit
   at any real width — the five Bulgarian badge labels run to about 1100px — so
   the shared line only ever wrapped, and it wrapped mid-axis, which orphaned
   „Изисква данни от счетоводството" on a line of its own under nothing. */
.ec-legend {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.4rem;
  margin-bottom: 0.7rem;
}

/* Each axis is one unit: its name, then its badges. */
.ec-legend__axis {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.35rem;
}

.ec-legend__name {
  font-family: var(--font-controls);
  font-size: 0.8rem;
  color: var(--text-quiet);
}

/* Below this the „Къде се поправя" badges (596px of Bulgarian) stop fitting
   beside their heading, and a badge wrapped to its own line sits at almost the
   same distance from its heading as from the next axis — the grouping the
   legend exists to show goes ambiguous. Under 820px the heading takes the full
   width instead and its badges drop underneath it, which is unambiguous at any
   width; the gap between axes grows so the two blocks stay apart. */
@media (max-width: 820px) {
  .ec-legend { gap: 0.6rem; }
  .ec-legend__name { flex: 0 0 100%; }
}

@media (prefers-reduced-motion: reduce) {
  #ec-list .ec-item__toggle { transition: none; }
}

/* The NRA element chips on a catalogue entry (Приложение №2 ids — MF.C.3,
   SD.MG.27…), rendered by errors.js from the catalogue's `nra_refs`. Scoped
   to #ec-list — the id only errors.html carries — so nra-reference.html's
   reuse of the .ec-* class primitives (its list is id="nr-list") never picks
   these up. The look is the neutral badge (.ec-badge--source tokens,
   .ec-badge radius) in the code's monospace (.ec-item__code) — no colours of
   its own. Lives here rather than inline: the static pages' CSP forbids
   inline <style>. */
#ec-list .ec-refs {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.35rem;
}
#ec-list .ec-ref {
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.01em;
  color: var(--text-muted);
  background: var(--surface-elevated);
  border: 1px solid var(--border-soft);
  border-radius: 999px;
  padding: 0.1rem 0.5rem;
  text-decoration: none;
  white-space: nowrap;
}
#ec-list .ec-ref:hover {
  color: var(--accent-700);
  border-color: var(--accent-700);
}
