/**
 * ProofDocs application-specific CSS overrides and custom components.
 *
 * This stylesheet extends the Falcon Bootstrap 5 theme with ProofDocs-specific
 * styles. pages/base.html loads it after theme.min.css and before the consent
 * library's cookieconsent.css.
 *
 * Accessibility notes:
 * - All animations and transitions respect prefers-reduced-motion (WCAG 2.3.3).
 * - Hover effects are gated behind @media (hover: hover) so touch devices do not
 *   get stuck in a hover state after tap (sticky-hover bug on iOS/Android).
 * - forced-colors disables decorative box-shadows and gradients so Windows High
 *   Contrast Mode can repaint affordances with system colors.
 */

/* Global custom properties: the badge hover tones Falcon keeps inside its .btn scopes,
   the sheet of a created document, the upward shadow Falcon has no token for, and the
   transition durations. Brand colours are Falcon's own variables. */
:root {
  /* Badge hover fills. These are not free values: each one is Falcon's own
     button hover shade for that variant, which the theme defines as
     --falcon-btn-hover-bg but only inside the .btn-<variant> scope — a .badge
     sits in no such scope and cannot read it, which is why the value is
     repeated here rather than referenced. Deriving it instead
     (color-mix(in srgb, var(--falcon-primary) 85%, black)) reproduces three of
     the four exactly but lands one channel off on success (178 vs 179, the
     browser rounds 178.5 down), so the literals stay. A fifth value existed for
     the secondary variant and was removed on 22.08.2026: no bg-secondary badge
     in this project sits inside an anchor, so the rule that read it never
     matched. They are pinned against
     theme.min.css by tests/test_theme_derived_values.py, so a theme upgrade
     that moves a shade cannot leave these silently behind. */
  --badge-primary-hover: #2569c3; /* .btn-primary  --falcon-btn-hover-bg */
  --badge-info-hover: #21a0d7; /* .btn-info     --falcon-btn-hover-bg */
  --badge-success-hover: #00b368; /* .btn-success  --falcon-btn-hover-bg */
  --badge-warning-hover: #d06d35; /* .btn-warning  --falcon-btn-hover-bg */

  /* The sheet of a created document is white in both modes, because the buyer reads it
     as the page they will print; its ink is the light-mode gray-1000 for the same
     reason, and the placeholder marks are the light warning tint under the sheet's ink. */
  --pd-paper-bg: #fff;
  --pd-paper-ink: #232e3c;
  --pd-placeholder-bg: #fde6d8;

  /* Upward shadow of the two fixed bottom bars (.sticky-cta-bar on the formular
     pages, .pd-sticky-cta on the reporting pages). Falcon's four box-shadow tokens
     all cast downward, so neither bar can use one; the value was therefore written
     out — and each of the two bars carried its own light and dark copy, four
     declarations for two distinct shadows. Two of them being verbatim duplicates is
     how the pair drifts: darkening one bar and forgetting the other. The token is
     redefined once for dark mode below, as Falcon redefines its own, so no component
     needs a dark rule of its own. */
  --pd-shadow-sticky: 0 -4px 16px rgba(20, 30, 60, 0.08);

  /* Transition durations. Nine declarations carried four different durations, and two
     of the differences were not decisions: .footer-brand faded in 0.15s beside
     .footer-link at 0.2s in the same footer row, and the demo hover of the former blog
     product boxes animated the same properties as .related-article-card at 0.3s against
     0.2s. Gleichartige Bewegungen must feel the same,
     so both were pulled onto the base value. The slow value survives for .badge alone,
     which is a colour cross-fade rather than a movement and reads better unhurried.
     The easing is `ease` throughout without a single exception and is part of the
     token, so a later change cannot move duration and curve apart. Every user of these
     sits inside @media (prefers-reduced-motion: no-preference), which is unchanged. */
  --pd-transition-base: 0.2s ease;
  --pd-transition-slow: 0.3s ease;
}

/* The theme's dark block ships three shadow tokens with an uncompiled SCSS variable,
   `rgba($black, .075)`, which no browser parses: every use falls back to none, so in dark
   mode .shadow-sm, the topic tiles, the sheet and the inset of the fields drew no shadow
   while the cards, on the valid --falcon-box-shadow, kept theirs (design run of
   16.10.2026). These are the values the theme's source meant, black at the same alpha. */
[data-bs-theme="dark"] {
  /* An 8 % shadow is invisible on the near-black page, so the bars cast a darker one. */
  --pd-shadow-sticky: 0 -4px 16px rgba(0, 0, 0, 0.5);
  --falcon-box-shadow-sm: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
  --falcon-box-shadow-lg: 0 1rem 4rem rgba(0, 0, 0, 0.175);
  --falcon-box-shadow-inset: inset 0 1px 2px rgba(0, 0, 0, 0.075);
}

/* Enable smooth scrolling behavior for better user experience. */
/* Respects prefers-reduced-motion for users with vestibular disorders (WCAG 2.3.3). */
@media (prefers-reduced-motion: no-preference) {
  html {
    scroll-behavior: smooth;
  }
}

/* Keep the sticky chrome out of the way when the browser scrolls something into view.
   Reserving space at the end of the document (further down this file) stops the last
   card from being covered, but it does nothing for the browser's own scroll-into-view:
   that stops as soon as the element touches the viewport edge, which is exactly where
   the fixed bar sits. Tabbing through the Arbeitszeugnisanalyse form at 768 px, nine
   stops were measured as 100 % hidden behind the bar at the moment they took focus —
   among them the upload field and both consent switches — which is a failure of WCAG 2.2
   SC 2.4.11 (Focus Not Obscured, AA). scroll-padding tells the browser where the usable
   viewport really ends; it also fixes the #activation anchor, which used to land under
   the navbar. The bottom values match the reserves used further down, so bar height and
   scroll padding cannot drift apart.

   The top value carries a second job that is easy to remove by accident. Every product
   badge on the home page links to /<produkt>/formular/#form, and the cost statement of
   each form page sits in the alert immediately above that anchor. Measured on
   16.09.2026 across four products and six widths from 320 to 1920 px: the jump leaves
   that statement on screen in all 24 cells.

   It does so because of two offsets, and this padding is only one of them — the figures
   are written out because an earlier version of this comment credited it with the whole
   effect and the measurement said otherwise. At 1440 px the price line lands at 100 px
   with both offsets, at 28 px with the theme's scroll-margin alone, at 7 px with this
   padding alone, and at **-65 px, off screen, with neither**. So either one carries it,
   barely, and removing both scrolls past the one sentence that answers what the product
   costs — on the most common entry into the funnel.

   The other offset is Falcon's ``scroll-margin-top: calc(--falcon-top-nav-height +
   1.5rem)`` in the compiled theme, which is a third-party value a theme update can
   change without anyone here noticing. That is the argument for keeping this one: it is
   the half of the margin this project controls. tests/test_css_accessibility_rules.py
   pins it. */
html {
  scroll-padding-top: 4.5rem;
}

html:has(.sticky-cta-bar) {
  scroll-padding-bottom: 4.5rem;
}

html:has(.pd-sticky-cta) {
  scroll-padding-bottom: 9rem;
}

/* The scroll padding has to follow the same breakpoint as the content padding
   below, or an anchor jump on the desktop reserves the mobile bar's height and
   leaves a visible gap. Measured on the locked reports (design run of 10.10.2026):
   the bar is 57 px from 992 px up, but 92 to 122 px between 768 and 991 px, where
   the price and button group leaves the guarantee line under 100 px and it wraps. */
@media (min-width: 992px) {
  html:has(.pd-sticky-cta) {
    scroll-padding-bottom: 4.5rem;
  }
}

/* The same correction for the form pages' bar, which the rule above had not
   received. `.sticky-cta-bar` is display:none from 992 px up, but :has() is
   structural and does not read display, so the 72 px stayed reserved for a bar
   that is never painted. Measured on the JTA form at 1280 and 1440 px:
   scrollIntoView({block:'nearest'}) on the last form row scrolled to 67 px
   instead of 0. The breakpoint is 992 px, not 768 px, because that is where
   this bar hides - the reserve below uses the same one. */
@media (min-width: 992px) {
  html:has(.sticky-cta-bar) {
    scroll-padding-bottom: 0;
  }
}

@media (max-width: 339.98px) {
  html:has(.sticky-cta-bar) {
    scroll-padding-bottom: 6rem;
  }
}

/* Override Falcon theme footer positioning to prevent content overlap. */
/* The theme uses absolute positioning with a fixed padding-bottom, which breaks with taller footers. */
/* Flexbox column layout ensures the footer always sits below the content regardless of height. */
/* The !important here beats Falcon's own rule and is legitimate. The value behind it
   is a custom property so that the reserves below (four since 10.10.2026) can set it
   by ordinary cascade: before, each of them had to beat this declaration with an
   !important of its own — six declarations, five values, one property, and the winner
   readable only from the line number rather than from the cascade. A further
   breakpoint can now be added without another !important. */
.content {
  display: flex;
  flex-direction: column;
  padding-bottom: var(--pd-content-pad-bottom, 0) !important;
}

.content > main {
  flex: 1 0 auto;
}

.footer {
  position: static !important;
  flex-shrink: 0;
}

/* The hamburger is a flex item of the top navigation with flex-shrink: 1 and no width
   floor of its own, so as soon as the row runs short it is the element that gives way:
   measured at 20 x 40 px at 320, 375 and 576-620 px, against 40 x 40 px everywhere else.
   Below 24 px it misses WCAG 2.2 SC 2.5.8 (AA), and the spacing exception does not apply
   because the logo link sits 4 px away — on a phone this is the only route into the
   navigation. The row has 17-26 px of slack in exactly those bands, so the 4 px this
   floor costs are affordable; the two size rules further down this file already trade
   the same slack for the logo and the theme toggle. */
.navbar-toggler {
  min-width: 24px;
}

/* Footer navigation links rendered as quiet pills that adopt the brand colour on hover and keyboard focus. */
.footer-link {
  display: inline-block;
  padding: 0.25rem 0.5rem;
  border-radius: var(--falcon-border-radius-lg);
  /* Fallback is #5e6e82, the token's own light value in theme.min.css and the one
     every --falcon-gray-700 fallback of this file carries. The #4d5969 that stood here
     was 8.4 % off: a theme update or a stylesheet that fails to load would have
     rendered this link in a tone nothing vouches for. */
  color: var(--falcon-gray-700, #5e6e82);
  text-decoration: none;
  line-height: var(--falcon-body-line-height);
}

/* The cookie preferences in the footer are a button and took the button face (Poppins);
   they read as one of the footer links. */
button.footer-link {
  font-family: inherit;
}

/* Focus stays ungated in both directions. A keyboard user exists on touch devices
   too, and prefers-reduced-motion must never remove a focus affordance — only its
   animation. */
/* The ink is Falcon's link colour on an 8 % tint of the brand blue (DES-01). */
.footer-link:focus-visible {
  color: rgb(var(--falcon-link-color-rgb));
  background-color: rgba(var(--falcon-primary-rgb), 0.08);
}

/* Hover behind (hover: hover) so a tap does not leave the link stuck in its hover
   state on iOS and Android, and the transition behind prefers-reduced-motion — the
   two guarantees the file header makes for every rule in this stylesheet. */
@media (hover: hover) {
  .footer-link:hover {
    color: rgb(var(--falcon-link-color-rgb));
    background-color: rgba(var(--falcon-primary-rgb), 0.08);
  }
}

@media (prefers-reduced-motion: no-preference) {
  .footer-link {
    transition:
      color var(--pd-transition-base),
      background-color var(--pd-transition-base);
  }
}

/* Footer brand mark in the baseline row; sits beside the copyright and cookie button. */
/* The vertical padding is load-bearing, not decoration: without it the link box is the
   bare height of its 18 px logo and its line, measured at 110 x 20 px on every page and
   every width, which is under the 24 px floor of WCAG 2.2 SC 2.5.8 (AA). Four pixels top
   and bottom lift it to 28 px; the baseline row is a wrapping flex row with room to
   spare, so nothing else moves. */
.footer-brand {
  color: var(--falcon-gray-800, #4d5969);
  padding: 0.25rem 0;
}

/* Same two gates as .footer-link above. */
@media (hover: hover) {
  .footer-brand:hover {
    opacity: 0.85;
  }
}

@media (prefers-reduced-motion: no-preference) {
  .footer-brand {
    transition: opacity var(--pd-transition-base);
  }
}

/* File upload drop zone component with dashed border styling. */
.filezone {
  border: 2px dashed var(--falcon-border-color);
  border-radius: var(--falcon-border-radius-lg);
  text-align: center;
  background-color: var(--falcon-body-bg);
}

/* Active state styling when files are dragged over the drop zone. Uses the
   theme-aware primary subtle background so the highlight visibly differs from the
   resting --falcon-body-bg in both light and dark mode. The former
   --falcon-input-bg variable was undefined, so the rule was invalid at
   computed-value time and the zone fell back to transparent (no drop feedback). */
/* :focus-within joins .dragover here because the zone had feedback for the pointer
   and none for the keyboard: tabbing to the file input inside it changed nothing on
   the zone itself, so the only upload control of the two analysis products gave a
   keyboard user no sign of where the focus had landed. Same declaration, same
   visual language - no new state is being invented, the existing one is extended to
   the second input method. The input's own focus ring is unaffected. */
.filezone.dragover,
.filezone:focus-within {
  background-color: var(--falcon-primary-bg-subtle);
}

/* The upload zone reads as a drop target at first sight: a cloud glyph above the label,
   the field itself no wider than its content needs and centred, the border turning to
   the brand colour under the pointer or a dragged file (design run of 20.10.2026). The
   glyph is drawn from the vendored Font Awesome font, so no markup changes and the
   label stays the zone's accessible name. */
.filezone::before {
  content: "\f382";
  flex: 0 0 100%;
  margin-bottom: 0.25rem;
  font-family: "Font Awesome 5 Free";
  font-weight: 900;
  font-size: 1.75rem;
  line-height: 1;
  color: var(--falcon-primary);
}

.filezone input[type="file"] {
  max-width: 34rem;
  margin-inline: auto;
}

.filezone.dragover,
.filezone:hover {
  border-color: var(--falcon-primary);
}

/* A chosen file turns the zone into a done step: a solid green border on the success
   tint, the cloud replaced by a check (custom.js enableDragAndDrop sets the class on
   every change of the field). */
.filezone.pd-filezone--done {
  border-style: solid;
  border-color: var(--falcon-success);
  background-color: var(--falcon-success-bg-subtle);
}

.filezone.pd-filezone--done::before {
  content: "\f058";
  color: var(--falcon-success);
}

@keyframes pd-pop {
  0% {
    opacity: 0;
    transform: scale(0.6);
  }

  70% {
    transform: scale(1.1);
  }

  100% {
    opacity: 1;
    transform: none;
  }
}

@media (prefers-reduced-motion: no-preference) {
  .filezone {
    transition:
      background-color var(--pd-transition-base),
      border-color var(--pd-transition-base);
  }

  .filezone.pd-filezone--done::before {
    animation: pd-pop var(--pd-transition-slow) ease-out;
  }
}

/* The native file selector button in the brand fill, like Falcon's buttons. */
input[type="file"]::file-selector-button {
  background-color: var(--falcon-primary);
  color: #fff;
}

/* The fill above wins over the theme's resting rule by specificity alone. It used to
   carry !important, which also beat the theme's hover shade, so the button had no hover
   state at all; it now darkens like every other primary button, at the theme hover
   rule's own specificity and later in the cascade (design run of 16.10.2026). The
   theme's hover rule is not behind (hover: hover), so the plain rule keeps the brand
   fill after a tap on a touch screen, where it turned #344050. */
.form-control:hover:not(:disabled):not([readonly])::file-selector-button {
  background-color: var(--falcon-primary);
}

@media (hover: hover) {
  .form-control:hover:not(:disabled):not([readonly])::file-selector-button {
    background-color: var(--badge-primary-hover);
  }
}

/* Resting look of a submit button whose consent switches are not both ticked.
   0.65 is stock Bootstrap's disabled opacity, but THIS theme fades a genuinely
   disabled button to 0.5 (--falcon-btn-disabled-opacity), so the two do not look
   alike and the value is not being aligned: the button here is still operable, and
   fading an operable control further than a dead one costs legibility for no gain.
   Wahrnehmbarkeit before Systemtreue. It deliberately omits
   pointer-events: none, because the button is no longer disabled: it stays in the
   tab order and in the accessibility tree so it can announce itself and explain the
   refusal (see initializeCheckboxToggle in custom.js). Suppressing pointer events
   here would silently restore the old behaviour for mouse users, who would click a
   dead control and receive nothing. */
.pd-consent-pending {
  opacity: 0.65;
  cursor: not-allowed;
}

/* Consent banner (vanilla-cookieconsent, vendors/cookieconsent/, since 08.10.2026).
   The library places itself at the maximum z-index; 1045 keeps the prompt above the
   sticky purchase bar and the navbar (1030) but below Bootstrap modals (1055) and
   tooltips (1080), so a consent prompt never hides a modal dialog, as the TermsFeed
   rules before it did. The site font replaces the library's system stack; `inherit`
   did not, because on a custom property it inherits the library's own value from
   :root. Since 16.10.2026 its buttons and corners are Falcon's too: the brand primary with
   white text, as every filled button of the site has stood since the owner restored the
   theme's colours (DES-01); both choices keep one weight, as equalWeightButtons asks.
   Set on #cc-main itself, so they win over the library's dark palette on the root. */
#cc-main {
  --cc-z-index: 1045;
  --cc-font-family: var(--falcon-body-font-family);
  --cc-modal-border-radius: var(--falcon-border-radius-lg);
  --cc-btn-border-radius: var(--falcon-border-radius);
  --cc-btn-primary-bg: var(--falcon-primary);
  --cc-btn-primary-color: #fff;
  --cc-btn-primary-border-color: var(--falcon-primary);
  --cc-btn-primary-hover-bg: var(--badge-primary-hover);
  --cc-btn-primary-hover-color: #fff;
  --cc-btn-primary-hover-border-color: var(--badge-primary-hover);
}

/* The library loads after this file, so these rules carry one more element to win.
   Its category switches measured 50 x 23 px, under the 24 px of WCAG 2.2 SC 2.5.8 with
   the section title too close for the spacing exception; the knob grows with them. */
html #cc-main .section__toggle,
html #cc-main .section__toggle-wrapper,
html #cc-main .toggle__icon,
html #cc-main .toggle__label,
html #cc-main .toggle__icon-circle {
  height: 24px;
}

html #cc-main .toggle__icon-circle {
  width: 24px;
}

html #cc-main .section__toggle:checked ~ .toggle__icon .toggle__icon-circle {
  transform: translateX(26px);
}

/* The prompt is 366 to 388 px high and did not scroll: on a phone in landscape its title
   started above the window (740 x 360). It now stays inside the window and scrolls. */
html #cc-main .cm {
  max-height: calc(100vh - 1rem);
  max-height: calc(100dvh - 1rem);
  overflow-y: auto;
  overscroll-behavior: contain;
}

/* Apply pulse animations to CTA buttons for visual emphasis and user attention. */
/* The animation is gated behind prefers-reduced-motion (WCAG 2.3.3); the keyframes */
/* themselves stay outside the media query so the rule remains valid even if an external */
/* stylesheet later opts a single element into the animation. Two rounds of 2 s, then */
/* the button rests: running endlessly beside the report it needed a way to stop it */
/* (WCAG 2.2 SC 2.2.2, which exempts motion of 5 s or less). The pulsing buttons carry */
/* no shadow-sm: that utility is !important and outranked the animated ring. */
@media (prefers-reduced-motion: no-preference) {
  .pulse {
    animation: pulse-animation 2s 2;
  }
}

/* Pulse keyframes for every purchase CTA: scales up and emits a fading ring. The ring
   reads --pd-pulse-rgb, which the product colours below set, so a green or orange
   purchase button no longer pulses with a blue ring; without it the ring stays primary. */
@keyframes pulse-animation {
  0% {
    transform: scale(1);
    box-shadow: 0 0 0 0 rgba(var(--pd-pulse-rgb, var(--falcon-primary-rgb)), 0.7);
  }

  70% {
    transform: scale(1.05);
    box-shadow: 0 0 0 10px rgba(var(--pd-pulse-rgb, var(--falcon-primary-rgb)), 0);
  }

  100% {
    transform: scale(1);
    box-shadow: 0 0 0 0 rgba(var(--pd-pulse-rgb, var(--falcon-primary-rgb)), 0);
  }
}

.btn-success.pulse {
  --pd-pulse-rgb: var(--falcon-success-rgb);
}

.btn-warning.pulse {
  --pd-pulse-rgb: var(--falcon-warning-rgb);
}

.btn-danger.pulse {
  --pd-pulse-rgb: var(--falcon-danger-rgb);
}

.btn-secondary.pulse {
  --pd-pulse-rgb: var(--falcon-secondary-rgb);
}

.btn-info.pulse {
  --pd-pulse-rgb: var(--falcon-info-rgb);
}

/* Add smooth transition effect for badge background color changes. */
/* Respects prefers-reduced-motion for users with vestibular disorders (WCAG 2.3.3). */
@media (prefers-reduced-motion: no-preference) {
  .badge {
    transition: background-color var(--pd-transition-slow);
  }
}

/* Darken primary badge color on parent anchor hover for visual feedback. */
@media (hover: hover) {
  a:hover .badge.bg-primary {
    background-color: var(--badge-primary-hover) !important;
  }
}

/* Darken info badge color on parent anchor hover for visual feedback. */
@media (hover: hover) {
  a:hover .badge.bg-info {
    background-color: var(--badge-info-hover) !important;
  }
}

/* Darken success badge color on parent anchor hover for visual feedback. */
@media (hover: hover) {
  a:hover .badge.bg-success {
    background-color: var(--badge-success-hover) !important;
  }
}

/* Darken warning badge color on parent anchor hover for visual feedback. */
@media (hover: hover) {
  a:hover .badge.bg-warning {
    background-color: var(--badge-warning-hover) !important;
  }
}

/* Force checkbox and label side-by-side alignment on all screen sizes. A switch with a
   help text: crispy puts the text into the same flex row as a third column, where it
   touched the label ("Sprinterklausel" at 375 px), so the row wraps and the text takes
   its own line (design run of 10.10.2026). */
.form-switch .form-check {
  display: flex !important;
  flex-wrap: wrap;
  align-items: flex-start !important;
  padding-left: 0 !important;
}

/* Position the checkbox input correctly within the flex container. */
.form-switch .form-check .form-check-input {
  float: none !important;
  margin-left: 0 !important;
  margin-top: 0.1875rem;
  flex-shrink: 0;
}

/* The label text flows beside the checkbox, takes the rest of the first line and wraps
   inside it; with its automatic flex basis a long consent label fell below its switch
   once the row could wrap (design run of 10.10.2026). */
.form-switch .form-check .form-check-label {
  flex: 1 1 0;
  min-width: 0;
  margin-left: 0.5rem;
}

/* The consent switches of the product forms: their labels measured 23.2 px high from
   768 px up, below the 24 px of WCAG 2.2 SC 2.5.8 (design run of 10.10.2026). */
.form-switch .form-check-label {
  line-height: 1.5rem;
}

/* The help text of a switch, aligned with the label text: the 2em switch is measured in
   the field's font, the help text runs at 75 % of it, so 2em become 2.6667em there,
   plus the label's 0.5rem. */
.form-switch .form-check > .form-text {
  flex-basis: 100%;
  margin-left: calc(2.6667em + 0.5rem);
}

/* crispy-bootstrap5 gives the legend of a radio group `fs-6`, Bootstrap's smallest heading
   size (1rem). Falcon reverses the scale, its fs-6 is 1.728rem, so "Wer kündigt?" on the
   tool forms stood at 27.6 px beside 13.3 px labels (design run of 16.10.2026). The
   legend takes the face, size and weight Falcon gives every `label`; the !important
   answers the utility's. */
legend.form-label {
  font-family: var(--falcon-font-sans-serif);
  font-size: 0.8333333333rem !important;
  font-weight: 500;
  letter-spacing: 0.02em;
}

/* Sticky CTA bar on mobile for formular pages. */
/* Keeps the submit button visible at the bottom of the viewport on small screens. */
@media (max-width: 991.98px) {
  .sticky-cta-bar {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    z-index: 1030;
    /* The surface of the purchase bar (.pd-sticky-cta, bg-body-tertiary), its twin. */
    background: var(--falcon-tertiary-bg);
    border-top: 1px solid var(--falcon-border-color);
    padding: 0.75rem 1rem;
    box-shadow: var(--pd-shadow-sticky);
  }

  body:has(.sticky-cta-bar) .content {
    --pd-content-pad-bottom: 4.5rem;
  }
}

/* Related article cards: the movement (lift, arrow slide, transitions) behind
   prefers-reduced-motion and a hover-capable pointer, the state (frame and arrow colour)
   behind the pointer alone, so it no longer vanishes with reduced motion. The card sits
   inside the related-articles card and is set off by a hairline instead of a shadow; the
   8 % hover shadow of its own and its dark twin are gone (design runs of 16.10. and
   20.10.2026). */
@media (prefers-reduced-motion: no-preference) and (hover: hover) {
  .related-article-card {
    transition:
      transform var(--pd-transition-base),
      border-color var(--pd-transition-base);
  }

  .related-article-card:hover,
  .related-article-card:focus-within {
    transform: translateY(-2px);
  }

  .related-article-arrow {
    transition:
      transform var(--pd-transition-base),
      color var(--pd-transition-base);
  }

  .related-article-card:hover .related-article-arrow {
    transform: translateX(3px);
  }
}

/* In three columns of about 160 px (768 to 991 px) long compounds such as
   "Tätigkeitsbeschreibung" broke without a hyphen. */
.related-article-card h3 {
  -webkit-hyphens: auto;
  hyphens: auto;
}

/* Focus stays ungated, as for .pd-ratgeber-link: a keyboard user on a touch device
   keeps the accent frame. */
.related-article-card:focus-within {
  border-color: var(--falcon-primary) !important;
}

.related-article-card.related-article-card--warning:focus-within {
  border-color: var(--falcon-warning) !important;
}

@media (hover: hover) {
  .related-article-card:hover {
    border-color: var(--falcon-primary) !important;
  }

  .related-article-card.related-article-card--warning:hover {
    border-color: var(--falcon-warning) !important;
  }

  /* The arrow takes the card's brand colour on hover. */
  .related-article-card:hover .related-article-arrow {
    color: var(--falcon-primary) !important;
  }

  .related-article-card.related-article-card--warning:hover .related-article-arrow {
    color: var(--falcon-warning) !important;
  }
}

/* Ratgeber link rows on the homepage Top-Ratgeber card and the guide card of every */
/* product page: icon-led article links that replace the former bullet list and reuse the */
/* related-articles hover language (sliding arrow, subtle row tint) so the section sits */
/* naturally in the Falcon design. */
.pd-ratgeber-link {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.25rem 0.5rem;
  border-radius: var(--falcon-border-radius-lg);
  color: var(--falcon-gray-900);
}

/* Pin every icon to one fixed-width column so the link text starts at the same */
/* indent across all three columns. The fixed width is load-bearing: measured, the five */
/* icons in this list have five different intrinsic advances (12, 14, 16, 17 and 18 px), */
/* so without it the labels start at five different x positions. */
/* No !important: the earlier comment here claimed FontAwesome renders each glyph as an */
/* <svg class="svg-inline--fa"> whose own width rule had to be beaten. That was true of */
/* the SVG/JS delivery mode, which this project left on 19.08.2026 - it now loads the CSS */
/* plus webfont build, where svg.svg-inline--fa occurs 0 times in the DOM (measured) and */
/* nothing competes for width on this span. */
.pd-ratgeber-link__icon {
  width: 1.25rem;
  text-align: center;
  flex-shrink: 0;
}

/* The label between icon and arrow is a flex item, and a flex item's automatic minimum
   size keeps it from shrinking below its longest word. German compounds like
   "Kündigungsschutzklage" and "Standardformulierungen" therefore hold the row open, and
   the whole page scrolls sideways as soon as the type grows: measured on the homepage at
   375 px, the document overflowed by 10 px at a browser base font of 18 px and by 81 px
   at 24 px. min-width: 0 releases that floor and hyphens: auto lets the browser break the
   word properly instead of mid-syllable — the document is lang="de", so Chromium and
   Firefox apply real German hyphenation patterns. This is the same pair the
   .pd-overview-row rule further down this file already uses for the same reason. */
.pd-ratgeber-link > .flex-1 {
  min-width: 0;
  -webkit-hyphens: auto;
  hyphens: auto;
}

/* The same pair for the product pages, where a German compound in a narrow column
   reached past the viewport at 320 px (design run of 10.10.2026). The class also sits on
   the page heading of includes/headline.html, which nearly every page of the site uses,
   blog and legal texts included. Cases measured: a product name in the
   overview list ("Arbeitszeugniserstellung" pushed its price 46 px out), the headline of
   a report's overall assessment, the title of a next step ("Arbeitsunfähigkeitsbescheini-
   gung einreichen" reached 27 px past the window), a date in the timeline and a section
   title of a form. Hyphenation is limited to the narrowest band: set on
   every width it split ordinary words ("Ter-min", "un-serer") at 375 and 1440 px too.
   The band ends at 380 px, measured as the first width from which "Scheinselbständigkeits-
   prüfung-Bericht" and "Aufhebungsvertragserstellung" fit; below it they broke mid-word
   without a hyphen. hyphenate-limit-chars keeps the band to long words: without it the
   overall assessment split "Schrei-ben" and "End-termin" at 360 px. Where an engine has no
   German patterns (WebKit in the measurement harness), `anywhere` is the fallback that
   keeps a long compound inside the viewport; unlike break-word it also lowers the
   element's min-content width. */
.pd-hyphenate {
  min-width: 0;
}

/* A heading that opens with an icon hangs its second line under its text, as the topic
   card headers already do with their icon tile: written as an icon followed by text, a
   wrapped card title ran on under the icon (measured on 23 headings of the privacy
   policy, the product pages, a report and the home page at 375 px, design run of
   21.10.2026). Only headings with the icon as their one element child become flex
   containers, so a heading with a badge, a link or emphasis keeps its inline flow, and
   centred headings keep their alignment. */
:is(h2, h3, h4, h5, h6):has(> :is(.fas, .far, .fab):first-child):not(
    :has(> :nth-child(2)),
    .text-center,
    .d-flex,
    .d-inline,
    .d-inline-block
  ) {
  display: flex;
  align-items: baseline;
}

:is(h2, h3, h4, h5, h6):has(> :is(.fas, .far, .fab):first-child):not(
    :has(> :nth-child(2)),
    .text-center,
    .d-flex,
    .d-inline,
    .d-inline-block
  )
  > :first-child {
  flex-shrink: 0;
}

/* Headings on a phone carry the long German compounds of the product names
   ("Aufhebungsvertragsanalyse"), which a narrow column otherwise breaks mid-word without
   a hyphen ("analy se" in the purchase card, design run of 20.10.2026). Only words of
   twelve letters and more are hyphenated, so ordinary headings keep their lines. */
@media (max-width: 575.98px) {
  :is(h1, h2, h3, h4, h5, .h1, .h2, .h3, .h4, .h5) {
    -webkit-hyphens: auto;
    hyphens: auto;
    hyphenate-limit-chars: 12 5 5;
  }
}

@media (max-width: 379.98px) {
  .pd-hyphenate {
    -webkit-hyphens: auto;
    hyphens: auto;
    hyphenate-limit-chars: 12 5 5;
    overflow-wrap: anywhere;
  }
}

.pd-ratgeber-arrow {
  margin-left: auto;
  flex-shrink: 0;
}

/* Focus stays ungated, as for .footer-link: a keyboard user on a touch device or with
   reduced motion keeps the row tint. */
.pd-ratgeber-link:focus-visible {
  background-color: var(--falcon-tertiary-bg);
}

/* The tint and the arrow colour answer a hover-capable pointer, so they never stick
   after a tap; the transitions and the arrow slide additionally wait for
   prefers-reduced-motion: no-preference (WCAG 2.3.3). Until 16.10.2026 the state sat
   behind both gates and vanished entirely with reduced motion. */
@media (prefers-reduced-motion: no-preference) and (hover: hover) {
  .pd-ratgeber-link {
    transition: background-color var(--pd-transition-base);
  }

  .pd-ratgeber-arrow {
    transition:
      transform var(--pd-transition-base),
      color var(--pd-transition-base);
  }

  .pd-ratgeber-link:hover .pd-ratgeber-arrow {
    transform: translateX(3px);
  }
}

@media (hover: hover) {
  .pd-ratgeber-link:hover {
    background-color: var(--falcon-tertiary-bg);
  }

  .pd-ratgeber-link:hover .pd-ratgeber-arrow {
    color: var(--pd-ratgeber-accent, var(--falcon-primary)) !important;
  }
}

/* The arrow's hover colour follows the product or topic colour of its list. */
.pd-ratgeber-link--info {
  --pd-ratgeber-accent: var(--falcon-info);
}

.pd-ratgeber-link--warning {
  --pd-ratgeber-accent: var(--falcon-warning);
}

/* Reporting improvement block: the AI-suggested rewrite and the next step of a finding,
   on a green gradient that fades out to the right. No coloured edge: the owner rejected
   accent stripes on cards and boxes as generic (20.10.2026); colour comes from the
   surface, as on Falcon's illustrated cards. */
.pd-improvement-block {
  margin-top: 0.75rem;
  padding: 0.75rem 1rem;
  background: linear-gradient(
    110deg,
    rgba(var(--falcon-success-rgb), 0.14) 0%,
    rgba(var(--falcon-success-rgb), 0.04) 70%
  );
  border: 1px solid rgba(var(--falcon-success-rgb), 0.25);
  border-radius: var(--falcon-border-radius-lg);
}

/* Reporting hint block: subdued italic explanation under each improvement. */
.pd-hint-block {
  margin-top: 0.5rem;
  color: var(--falcon-gray-700);
  font-style: italic;
  font-size: 0.8333333333rem;
}

/* Footnote markers keep a floor, because their relative shrink compounds.
   The two <sup> in the project are the footnote pair of the activation CTA
   (products/ctas/activation.html), and the browser's own 0.75em applies to whatever
   the parent already is: measured
   on the report page, the marker beside the comparison price renders at 10px and the
   one on the citation line at 8.33px, because that line is already fs-11 (11.11px).
   8.33px is not readable, and the marker is the only thing tying the 226,10 € claim
   to the § 34 RVG source that backs it — an unreadable pointer leaves a price
   comparison looking unsupported on the conversion path. `max()` keeps the relative
   behaviour wherever it still works and only puts a floor under it; support is
   Chrome 79+, Safari 11.1+, Firefox 75+, and a browser without it falls back to the
   inherited 0.75em, which is today's rendering. */
sup,
sub {
  font-size: max(0.75em, 11px);
}

/* Reading pages: blog articles, the legal texts, help and about (redesign of
   15.10.2026). Running text is Falcon's body text at the body size, 1rem in the body
   colour, with the line height and rhythm of a long read; section headings are Falcon
   headings in the heading colour. The templates keep `mb-0` on their paragraphs so a
   paragraph inside a list item stays tight, which is why the spacing of the direct
   children of the card body carries !important here. The rhythm stops at a card nested
   in the text (a product box, a related article, a step card), which keeps its compact
   measures (design run of 20.10.2026). */
:is(body.is-blog-article, body.is-legal-page, body.pd-reading, .pd-prose)
  .card-body:not(.card .card .card-body)
  > p,
:is(body.is-blog-article, body.is-legal-page, body.pd-reading, .pd-prose)
  .card-body:not(.card .card .card-body)
  > ul,
:is(body.is-blog-article, body.is-legal-page, body.pd-reading, .pd-prose)
  .card-body:not(.card .card .card-body)
  > ol {
  line-height: 1.75;
}

:is(body.is-blog-article, body.is-legal-page, body.pd-reading, .pd-prose)
  .card-body:not(.card .card .card-body)
  > p {
  margin-bottom: 1.1rem !important;
}

/* The last block of a card leaves the bottom padding alone: a card ending in a paragraph
   stood 17.6 px deeper than one ending in a list (design run of 16.10.2026). */
:is(body.is-blog-article, body.is-legal-page, body.pd-reading, .pd-prose)
  .card-body:not(.card .card .card-body)
  > :last-child {
  margin-bottom: 0 !important;
}

:is(body.is-blog-article, body.is-legal-page, body.pd-reading, .pd-prose)
  .card-body:not(.card .card .card-body)
  > h2 {
  margin-top: 2.5rem;
  margin-bottom: 0.85rem !important;
  line-height: 1.35;
}

:is(body.is-blog-article, body.is-legal-page, body.pd-reading, .pd-prose)
  .card-body:not(.card .card .card-body)
  > :is(h2, h3):first-child {
  margin-top: 0;
}

:is(body.is-blog-article, body.is-legal-page, body.pd-reading, .pd-prose)
  .card-body:not(.card .card .card-body)
  > h3 {
  margin-top: 1.75rem;
  margin-bottom: 0.5rem;
  line-height: 1.4;
}

:is(body.is-blog-article, body.is-legal-page, body.pd-reading, .pd-prose)
  .card-body:not(.card .card .card-body)
  > ul,
:is(body.is-blog-article, body.is-legal-page, body.pd-reading, .pd-prose)
  .card-body:not(.card .card .card-body)
  > ol {
  margin-bottom: 1.25rem;
  padding-left: 1.35rem;
}

/* The meta line of an article's header card is a list in a card body as well, but no
   running text: the spacing set every entry after the first 8 px lower than "Redaktion"
   (design run of 21.10.2026). */
:is(body.is-blog-article, body.is-legal-page, body.pd-reading, .pd-prose)
  .card-body:not(.card .card .card-body)
  > ul:not(.pd-page-header__meta)
  li
  + li,
:is(body.is-blog-article, body.is-legal-page, body.pd-reading, .pd-prose)
  .card-body:not(.card .card .card-body)
  > ol
  li
  + li {
  margin-top: 0.5rem;
}

:is(body.is-blog-article, body.is-legal-page, body.pd-reading, .pd-prose)
  .card-body:not(.card .card .card-body)
  > ul
  > li::marker,
:is(body.is-blog-article, body.is-legal-page, body.pd-reading, .pd-prose)
  .card-body:not(.card .card .card-body)
  > ol
  > li::marker {
  color: var(--falcon-primary);
  font-weight: 600;
}

:is(body.is-blog-article, body.is-legal-page, body.pd-reading, .pd-prose)
  .card-body:not(.card .card .card-body)
  > .table-responsive {
  margin-top: 0.75rem;
  margin-bottom: 1.5rem;
}

/* The wrapper carries the spacing; Bootstrap's own 1rem under the table added to it. */
:is(body.is-blog-article, body.is-legal-page, body.pd-reading, .pd-prose)
  .card-body:not(.card .card .card-body)
  > .table-responsive
  > .table {
  margin-bottom: 0;
}

/* On a phone a table keeps a readable width and scrolls in its wrapper, instead of
   squeezing its columns until a cell wraps into ten lines (design run of 20.10.2026). */
@media (max-width: 575.98px) {
  :is(body.is-blog-article, body.is-legal-page, body.pd-reading, .pd-prose)
    .card-body:not(.card .card .card-body)
    > .table-responsive
    > .table {
    min-width: 36rem;
  }

  /* A table of three or more columns carries running text in its last one; at 36rem that
     column wrapped into six lines per row. */
  :is(body.is-blog-article, body.is-legal-page, body.pd-reading, .pd-prose)
    .card-body:not(.card .card .card-body)
    > .table-responsive
    > .table:has(tr > :nth-child(3)) {
    min-width: 44rem;
  }

  /* The same for a bordered table outside a reading card: the cost comparisons of the
     Arbeitszeugnis- and Arbeitsvertragsanalyse pages squeezed "Kosten" to about 100 px,
     one word per line (design run of 21.10.2026). The stacked report tables are not
     bordered and keep their own phone layout. */
  .card-body:not(.card .card .card-body) > .table-responsive > .table.table-bordered {
    min-width: 36rem;
  }

  .card-body:not(.card .card .card-body)
    > .table-responsive
    > .table.table-bordered:has(tr > :nth-child(3)) {
    min-width: 44rem;
  }
}

/* The rule keeps Falcon's own colour (#d8e2ef at full opacity). An opacity of 0.12 on
   top of it measured about 1.03:1 against the card and hid the rule (design run of
   16.10.2026). */
:is(body.is-blog-article, body.is-legal-page, body.pd-reading, .pd-prose)
  .card-body:not(.card .card .card-body)
  > hr {
  margin-top: 1.75rem;
  margin-bottom: 1.75rem;
}

/* A sample letter or certificate in an article's note box: its paragraphs carry `mb-0`
   like every article paragraph, but the box is not a direct child of the card body, so
   the rhythm above never reached them and salutation, text and closing ran together as
   one block (design run of 20.10.2026). */
body.is-blog-article .pd-note > p:not(:last-child) {
  margin-bottom: 0.75rem !important;
}

/* A rule already separates the question that follows it; the heading's own top margin
   would double the gap (the help page's FAQ lists). */
:is(body.is-blog-article, body.is-legal-page, body.pd-reading, .pd-prose)
  .card-body:not(.card .card .card-body)
  > hr
  + :is(h2, h3) {
  margin-top: 0;
}

/* Column widths for the three recurring article table shapes. They used to be 19 */
/* inline `style="width: N%"` attributes across three articles, in five different */
/* distributions for what are really three layouts: a grade table went 8/15/77 in one */
/* article, 10/20/70 in the next and 10/15/75 in the third. Nothing rendered wrong, */
/* but the proportions were re-invented per article and a change on narrow screens */
/* meant editing every attribute by hand. Declaring them once also settles which */
/* distribution is the right one. */
/* Note (grade) | rating | example formulation. The example column carries the long */
/* prose and gets the room; the grade column holds a single digit. */
.pd-table-grades th:nth-child(1) {
  width: 10%;
}

.pd-table-grades th:nth-child(2) {
  width: 20%;
}

.pd-table-grades th:nth-child(3) {
  width: 70%;
}

/* Note (grade) | satisfaction formula. */
.pd-table-formula th:nth-child(1) {
  width: 10%;
}

.pd-table-formula th:nth-child(2) {
  width: 90%;
}

/* Criterion | three comparable roles, each of which needs the same room. */
.pd-table-compare th:nth-child(1) {
  width: 19%;
}

.pd-table-compare th:nth-child(n + 2) {
  width: 27%;
}

/* No reading measure on the long form, by owner decision of 03.10.2026. Running
   text in blog articles and on the legal pages spans the full width of its card,
   like the tables and CTAs beside it. A `max-width: 68ch` on the copy of both
   surfaces (K19-i1-02) was removed that day: it left a wide empty strip to the
   right of every paragraph on desktop. Guarded by tests/test_long_form_full_width.py,
   so a later design or accessibility pass does not bring it back. */

/* Tabular figures in tables and in the large display size. Measured on the pillar
   article: all 18 numeric table cells rendered with proportional figures, so the price
   and grade columns of the comparison tables did not line up vertically — a 1 is
   narrower than a 4, and the decimal points drift across the rows. Figures outside
   tables use .pd-figures. This is a font feature, not a size or colour change: nothing
   reflows, because tabular figures are the same advance width the layout already
   reserves for the widest digit. */
td,
th {
  font-variant-numeric: tabular-nums;
}

/* Mobile horizontal-scroll affordance for wide (3+ column) article tables. */
/* initializeScrollableTables() in custom.js tags any overflowing .table-responsive with */
/* .pd-scrollable and inserts a .pd-table-hint label before it; without this cue the */
/* rightmost column is silently clipped on phones. The right-edge mask fades the content so */
/* the clipping reads as "more to the right", and lifts once the user scrolls to the end. */
/* --falcon-gray-700, not -600: at 12px the 600 tone measures 3.95:1 against the card, */
/* below the 4.5:1 of WCAG 2.2 AA (1.4.3), and this label is the only cue that the */
/* rightmost table column is clipped. */
.pd-table-hint {
  display: none;
  margin-bottom: 0.25rem;
  font-size: 0.75rem;
  color: var(--falcon-gray-700, #5e6e82);
  text-align: right;
}

@media (max-width: 575.98px) {
  .pd-table-hint:has(+ .table-responsive.pd-scrollable) {
    display: block;
  }

  .table-responsive.pd-scrollable:not(.pd-scroll-end) {
    -webkit-mask-image: linear-gradient(to right, #000 86%, transparent 100%);
    mask-image: linear-gradient(to right, #000 86%, transparent 100%);
  }
}

/* Sticky bottom CTA bar shown on paid product reporting pages until activation. */
/* Positioning, theme-aware background (var(--falcon-tertiary-bg)) and top border come from */
/* the Bootstrap/Falcon utilities .fixed-bottom .bg-body-tertiary .border-top on the element. */
/* Only the upward shadow and iOS safe-area inset stay here — neither has a utility class. */
.pd-sticky-cta {
  box-shadow: var(--pd-shadow-sticky);
  padding-bottom: env(safe-area-inset-bottom);
}

/* Reserve room at the bottom of the main content so the sticky bar never covers the last card. */
/* 9rem matches the bar below 992 px, whose guarantee line also carries the AGB and privacy */
/* links: measured on the locked reports of 10.10.2026 (design run) it is 139 px from 320 */
/* to about 420 px, where the guarantee line wraps, 91 px from 430 px up, and 92 to 122 px */
/* between 768 and 991 px, where the price and button group squeezes the guarantee line; */
/* the earlier 7.5rem left 19 px of the last card covered, and a 4.5rem reserve from 768 px */
/* left the footer's brand link under the bar. From 992 px the "Einmalzahlung" line no */
/* longer wraps and the bar measures 57 px. */
body:has(.pd-sticky-cta) .content {
  --pd-content-pad-bottom: 9rem;
}

@media (min-width: 992px) {
  body:has(.pd-sticky-cta) .content {
    --pd-content-pad-bottom: 4.5rem;
  }
}

/* At exactly 320 px the form pages' sticky bar gains one more line and outgrows the
   space reserved for it, so the last content card stays covered no matter how far the
   visitor scrolls. Measured across 320-768 px: .sticky-cta-bar is 61 px from 340 px
   upwards but 85 px at 320 px (reserve 72 px), because the label of its one button (a
   link that jumps to the form) wraps to a second line. Raising the reserve by one line
   height in that band is the smaller change than shortening every product's label. The purchase bar of
   the locked reports needs no entry here: its 9rem reserve above already covers its
   139 px at 320 px. The 340 px boundary is the one the theme-toggle rule further down
   this file already uses. */
@media (max-width: 339.98px) {
  body:has(.sticky-cta-bar) .content {
    --pd-content-pad-bottom: 6rem;
  }
}

/* Up to 450 px of height (a phone in landscape, 400 % zoom) the bars stay in the page
   flow: fixed, the purchase bar and the sticky header left 48 px of a 320 x 256 window
   for the report (WCAG 2.2 SC 1.4.10). The button remains on the page, and the
   activation card carries the same purchase. */
@media (max-height: 450px) {
  .pd-sticky-cta.fixed-bottom,
  .sticky-cta-bar {
    position: static;
    box-shadow: none;
  }

  body:has(.pd-sticky-cta) .content,
  body:has(.sticky-cta-bar) .content {
    --pd-content-pad-bottom: 0;
  }
}

/* Links in running text: Falcon's colour, underlined on hover only. */
.card-body p a:not(.btn):not([class*="badge"]),
.card-body li a:not(.btn):not([class*="badge"]),
.form-check-label a:not(.btn) {
  text-underline-offset: 0.15em;
}

/* Focus indicator reinforcement (WCAG 2.4.7). */
/* Falcon and Bootstrap occasionally remove the native outline on buttons/links. */
/* :focus-visible only triggers for keyboard users — mouse clicks remain visually clean. */
/* One ring, drawn as an outline with a 2px offset. An earlier version of this comment */
/* promised a double ring of box-shadow plus outline; there is no box-shadow here, and */
/* the rule below this one deliberately clears any that Falcon leaves behind. The offset */
/* is what separates the ring from the control, so a second ring buys nothing. */
:focus-visible {
  outline: 2px solid var(--falcon-primary);
  outline-offset: 2px;
}

/* The bare :focus-visible rule above (specificity 0,1,0) loses to Falcon's own */
/* .nav-link:focus-visible{outline:0} (0,2,0) and .navbar .nav-link:focus-visible */
/* {box-shadow:none} (0,3,0) in theme.min.css, so every link in the vertical */
/* navigation and the top navbar was measurably focus-invisible — 11 consecutive */
/* tab stops on every page, directly after the skip link. Matching the higher */
/* specificity is the whole point of this rule; do not "simplify" it back into the */
/* selector above. Verify with getComputedStyle after a real Tab keypress, not after */
/* element.focus() — :focus-visible does not necessarily match on programmatic focus. */
/* .btn is in the same list for the same reason: Falcon's .btn:focus-visible{outline:0} */
/* (0,2,0) also beats the bare rule. Buttons were not invisible — the outline-* */
/* variants invert their colours on focus — but that state is identical to hover, so */
/* a keyboard user could not tell focus from a hovered button, and it departed from */
/* the 2px outline used everywhere else. */
.navbar .nav-link:focus-visible,
.navbar-vertical .nav-link:focus-visible,
.nav-link:focus-visible,
.btn:focus-visible {
  outline: 2px solid var(--falcon-primary);
  outline-offset: 2px;
  box-shadow: none;
}

/* The form controls were missing from the list above, for the same reason and with a
   worse outcome: .form-control:focus and .form-select:focus set outline: 0 (0,2,0) and
   beat the bare :focus-visible rule, and the box-shadow Bootstrap normally puts in its
   place resolves here to a fully transparent ring — measured on every field of every
   form, in all three engines, as `outline: 0px none` plus
   `rgba(0, 0, 0, 0) 0px 0px 0px 0px`, with the resting border colour unchanged. The
   result was a form whose focus was invisible from the first field on: the upload
   control of the two analysis products, every text field of the Arbeitszeugniserstellung
   and both consent switches (WCAG 2.2 SC 2.4.7, AA). Verified with real Tab presses, not
   element.focus() — :focus-visible does not necessarily match on programmatic focus. */
.form-control:focus-visible,
.form-select:focus-visible,
.form-check-input:focus-visible {
  outline: 2px solid var(--falcon-primary);
  outline-offset: 2px;
}

/* Skip link must rise above the sticky CTA (z-index 1030) when focused so keyboard users */
/* can always escape to the main content. Falcon's .visually-hidden-focusable handles */
/* hide/reveal; we only need to bump stacking. :focus-within covers the case where the */
/* anchor itself is not the focus target but a descendant is (defensive double-binding). */
/* The 1090 value intentionally sits just above Bootstrap's tooltip layer (1080) — */
/* a tooltip must never obscure the only keyboard escape route to the main content. */
.visually-hidden-focusable:focus,
.visually-hidden-focusable:focus-within {
  z-index: 1090;
}

/* Forced colors / Windows High Contrast Mode (WCAG 1.4.11). */
/* Strip decorative gradients and shadows so system colours can repaint affordances cleanly. */
/* Pulse animations are suppressed because the animated box-shadow conveys nothing without */
/* color (forced-colors removes shadows anyway, leaving only a meaningless scale tick). */
@media (forced-colors: active) {
  .pulse {
    animation: none !important;
  }

  /* .pd-improvement-block used to be listed here too. It sets no box-shadow
     anywhere in this file, so the declaration neutralised nothing.
     Counted on 20.10.2026, this file sets a real box-shadow outside the pulse
     keyframes in nine places: .sticky-cta-bar, .pd-sticky-cta, the two
     .form-range:focus-visible thumb rules, the deadline ring of the timeline (which
     gets an outline below), the sheet .pd-paper, .pd-topic-tile at rest and on
     hover, and the home hero pills on hover. Only the two bottom bars are cleared here,
     .pd-sticky-cta and its twin .sticky-cta-bar, because their upward shadow is the one
     that would otherwise be redrawn as a solid system colour and read as a second
     border above the top border each already carries. The deadline ring carries meaning and is replaced by the outline
     below; the decorative ones need no rule - forced-colors drops them by itself. The two
     .form-range thumb rules must NOT be added: they are the focus indicator of the
     three rating sliders, the one place where outline cannot be used (see their own
     comment), and clearing them would take the focus ring off the controls that
     decide the grades of a purchased certificate. */
  .pd-sticky-cta,
  .sticky-cta-bar {
    box-shadow: none !important;
  }

  /* The scale and the bars draw their meaning with background colours, which forced
     colours removes; a system-colour border keeps their extent, and the bar's value and
     the scale's marker are painted in the system text colour. */
  .pd-scale {
    border: 1px solid CanvasText;
  }

  /* The bar is drawn by hand here: forced colours painted track and value alike in
     Canvas, and the base rule's border: 0 further down this file beat a plain .pd-bar
     selector, so the bars vanished entirely (design run of 10.10.2026). The element
     selector outranks it. */
  progress.pd-bar {
    forced-color-adjust: none;
    background-color: Canvas;
    border: 1px solid CanvasText;
  }

  progress.pd-bar::-webkit-progress-bar {
    background-color: Canvas;
  }

  progress.pd-bar::-webkit-progress-value {
    background-color: CanvasText;
  }

  progress.pd-bar::-moz-progress-bar {
    background-color: CanvasText;
  }

  /* Scoped under .pd-scale: the base rule further down this file sets the marker's
     colour at one class and would win by order. */
  .pd-scale .pd-scale__marker {
    forced-color-adjust: none;
    background-color: CanvasText;
  }

  /* A ticked switch draws its state with its fill, which forced colours removed: on
     Canvas the white knob vanished and the two consent switches showed an empty frame
     when ticked. The system highlight carries the fill back. */
  .form-switch .form-check-input:checked {
    forced-color-adjust: none;
    background-color: Highlight;
    border-color: Highlight;
  }

  /* The ring marks the deadline among the dates; forced colours drop the shadow. */
  .pd-timeline__item--deadline .pd-timeline__dot {
    outline: 2px solid CanvasText;
    outline-offset: 1px;
  }

  /* Falcon draws the edge of a card and of a topic tile with shadow and fill only, and
     forced colours drop both: every card stood on Canvas without a boundary (design run
     of 16.10.2026). A one-pixel border in the system colour gives the edge back. */
  .card {
    --falcon-card-border-width: 1px;
  }

  .pd-topic-tile {
    border: 1px solid CanvasText;
  }

  :focus-visible {
    outline: 2px solid CanvasText;
  }
}

/* Print stylesheet for reports and blog articles. */
/* Users frequently print/save-as-PDF analysis reports for HR meetings or labour court */
/* filings — hide all interactive chrome (navbar, sticky CTA, footer, related articles) */
/* so the printed page contains only the substantive content. */
@media print {
  .navbar-top,
  .navbar-vertical,
  .footer,
  .pd-sticky-cta,
  .sticky-cta-bar,
  .related-articles,
  .pulse,
  .visually-hidden-focusable,
  #cc-main {
    display: none !important;
  }

  body,
  .content,
  .content > main,
  .card,
  .card-body {
    background: #ffffff !important;
    box-shadow: none !important;
    color: #000000 !important;
  }

  a {
    color: #000000 !important;
    text-decoration: underline;
  }

  /* Avoid orphan headings on page breaks. */
  h1,
  h2,
  h3,
  h4,
  h5,
  h6 {
    page-break-after: avoid;
    break-after: avoid;
  }

  /* Keep tables and lists together where possible. */
  table,
  ul,
  ol {
    page-break-inside: avoid;
    break-inside: avoid;
  }

  /* A card stretched to its row (h-100) kept the row's height when it moved to a new
     page and hid the end of its list under the next card; the number tiles, a bar with
     its label and a card head with nothing below it were cut across a page break
     (design run of 10.10.2026). The grid of the warning checks may break between its
     tiles, each tile stays whole. */
  .card.h-100 {
    height: auto !important;
  }

  .card-header {
    break-after: avoid;
  }

  .card-body > .row.g-2:not(:has(.pd-check-tile)),
  .card-body > div:has(> .pd-bar),
  .pd-check-tile {
    break-inside: avoid;
  }

  .card-body > .d-flex:has(+ .pd-bar) {
    break-after: avoid;
  }

  /* Each critical passage of the two original analyses stays whole; the card itself may
     break, so a long list does not leave the rest of a page empty above it. A card with a
     single passage stays whole, or its top edge stood alone at the foot of a page. */
  .card.border-danger .card-body > .border-danger,
  .card.border-danger:has(.card-body > .border-danger):not(
      :has(.card-body > .border-danger ~ .border-danger)
    ) {
    break-inside: avoid;
  }

  /* The findings start on a page of their own: their head and the AI note stood alone
     at the foot of a page with the first finding on the next (design run of
     10.10.2026), and no break-after held in Chromium, which split the two-line note
     instead. */
  .pd-findings {
    break-before: page;
  }

  .pd-paper__heading {
    break-after: avoid;
  }

  /* A letter's list may run across a page; the rule above for ul and ol would push a
     long one whole onto the next page. Its items stay whole. */
  .pd-paper__list {
    break-inside: auto;
  }

  .pd-paper__list > li {
    break-inside: avoid;
  }

  /* The next steps may run across a page, each step too; only a step's title stays with
     its text. A whole first step (124 px) did not fit at the foot of page 1, took the
     card head with it, and the block below then lost its last line to a page of its
     own (payslip report, design run of 10.10.2026). */
  .pd-steps {
    break-inside: auto;
  }

  .pd-steps__item > :first-child {
    break-after: avoid;
  }

  /* The document card starts on a page of its own, as the findings do: its title and AI
     note stood alone at the foot of a page, the letter on the next. */
  .card:has(> .card-body > .pd-paper:not(.pd-paper--preview)) {
    break-before: page;
  }

  .card:has(> .card-body > .pd-paper--preview) {
    break-inside: avoid;
  }

  .pd-paper--preview::after {
    display: none;
  }

  /* A finding may run across a page, its quote, wording and core sentence may not: kept
     whole, a finding of most of a page pushed the first one under "Prüfpunkte im
     Einzelnen" onto the next page and left the head alone on an empty one. The three
     parts (dd) may break between lines, at least two on either side: kept whole as
     well, they left up to 78 mm of a card empty above a part that would have fit. */
  .pd-quote,
  .pd-wording,
  .pd-finding > p {
    break-inside: avoid;
  }

  .pd-finding__parts > dd {
    orphans: 2;
    widows: 2;
  }

  .pd-finding__parts > dt,
  .pd-finding > p:has(+ .pd-quote),
  .pd-finding > p:has(+ .pd-finding__parts) {
    break-after: avoid;
  }

  /* Badges, step numbers, bars and the scale carry their meaning in a fill; printed
     without background graphics, the white badge text and step numbers vanished and
     the bars came out empty (design run of 10.10.2026). The icon tiles are listed for
     the same reason: a white glyph printed light grey on white (2.30:1). */
  .badge,
  .icon-item,
  .pd-steps__item::before,
  .pd-bar,
  .pd-scale,
  .pd-scale__marker,
  .pd-timeline__dot {
    -webkit-print-color-adjust: exact;
    print-color-adjust: exact;
  }

  /* Print improvement/hint side-bar blocks as plain readable paragraphs
       without the colored borders/backgrounds that confuse on paper. */
  .pd-improvement-block,
  .pd-hint-block {
    background: transparent !important;
    border-left: none !important;
    color: #000000 !important;
    padding-left: 0 !important;
  }
}

/* Compact top-nav product CTAs (Analysen / Erstellungen). Slimmer than a default
   button so the bar stays light: reduced vertical padding and a 34 px min-height
   that still satisfies the WCAG 2.5.8 (AA) 24 px target. On phones the labels are
   hidden (icon only), so the horizontal padding is tightened further. */
.pd-nav-cta {
  min-height: 34px;
  padding-top: 0.2rem;
  padding-bottom: 0.2rem;
}

@media (max-width: 575.98px) {
  .pd-nav-cta {
    min-height: 32px;
    padding-left: 0.5rem;
    padding-right: 0.5rem;
  }
}

/* The two product menus list the whole portfolio (09.10.2026), up to fourteen entries
   with their topic headers. Capped below the viewport height and scrolled inside, so
   the last entries stay reachable on a short laptop screen or a phone in landscape.
   Scoped under .navbar because the theme's `.navbar .dropdown-menu { overflow: visible }`
   otherwise wins on specificity and the entries spill out of the menu. */
.navbar .pd-nav-menu {
  max-height: 75vh;
  overflow-y: auto;
  overscroll-behavior: contain;
}

/* The product names in both menus start on one edge whatever the width of their icon,
   as in the product lists (fa-fw there; the menu entries live in includes/top.html). */
.pd-nav-menu .dropdown-item > .fas {
  width: 1.25em;
  text-align: center;
}

/* Below the sm breakpoint the "Analysen" menu, aligned to the end of its button, opened
   42 px past the left edge at 320 px and 28 px at 360 px, cutting off icons and topic
   headings (design run of 10.10.2026). In that range both menus span the window instead.
   The !important is required: Popper writes position, inset and transform as inline
   styles on the open menu. */
@media (max-width: 575.98px) {
  .navbar .pd-nav-menu.show {
    position: fixed !important;
    inset: 4rem 0.5rem auto 0.5rem !important;
    transform: none !important;
  }
}

/* A fixed bar at the bottom (the purchase bar of a locked report, 139 px at 320 px, or
   the bar of a form below 992 px, whose button jumps to the form) lies above the menus and covered their last
   entries, on phones upright and in landscape. Each menu stops short of the bar's
   reserve plus the 4rem the menu opens below; vh is the fallback for engines without
   dvh, which follows Safari's toolbar. */
body:has(.pd-sticky-cta) .navbar .pd-nav-menu.show {
  max-height: min(75vh, calc(100vh - 13rem));
  max-height: min(75dvh, calc(100dvh - 13rem));
}

@media (min-width: 992px) {
  body:has(.pd-sticky-cta) .navbar .pd-nav-menu.show {
    max-height: min(75vh, calc(100vh - 8.5rem));
    max-height: min(75dvh, calc(100dvh - 8.5rem));
  }
}

@media (max-width: 991.98px) {
  body:has(.sticky-cta-bar) .navbar .pd-nav-menu.show {
    max-height: min(75vh, calc(100vh - 10rem));
    max-height: min(75dvh, calc(100dvh - 10rem));
  }
}

/* D17-S3-001, D33-S3-001, D26-S4-001 of the design run: the vertical navigation ends at
   the bottom of the window, so a fixed bar covered its last links (Impressum, the whole
   group "Rechtlich" on a locked report), both in the menu behind the hamburger and in
   the sidebar from 1200 px, where tabbing put Blog and Impressum under the bar (WCAG 2.2
   SC 2.4.11). A scroll padding did not help: the container itself reached under the bar
   and had nothing to scroll. It now ends above the bar's reserve and scrolls inside. The
   !important answers the theme's own for the card navigation (.navbar-card, max-height
   with !important), which otherwise wins whatever the specificity. */
body:has(.pd-sticky-cta) .navbar-vertical .navbar-collapse .navbar-vertical-content {
  max-height: calc(100vh - var(--falcon-top-nav-height) - 9rem) !important;
  max-height: calc(100dvh - var(--falcon-top-nav-height) - 9rem) !important;
}

@media (min-width: 992px) {
  body:has(.pd-sticky-cta) .navbar-vertical .navbar-collapse .navbar-vertical-content {
    max-height: calc(100vh - var(--falcon-top-nav-height) - 4.5rem) !important;
    max-height: calc(100dvh - var(--falcon-top-nav-height) - 4.5rem) !important;
  }
}

@media (max-width: 991.98px) {
  body:has(.sticky-cta-bar) .navbar-vertical .navbar-collapse .navbar-vertical-content {
    max-height: calc(100vh - var(--falcon-top-nav-height) - 6rem) !important;
    max-height: calc(100dvh - var(--falcon-top-nav-height) - 6rem) !important;
  }
}

/* Up to 450 px of height the bars stand in the page flow (the rule "Up to 450 px of
   height" above), so the menus and the scroll position keep no room for them: at
   320 x 256 the reserves left both menus 43 to 48 px high. This sits after the menu
   rules because it has to win against them. */
@media (max-height: 450px) {
  html:has(.sticky-cta-bar),
  html:has(.pd-sticky-cta) {
    scroll-padding-bottom: 0;
  }

  body:has(.pd-sticky-cta) .navbar .pd-nav-menu.show,
  body:has(.sticky-cta-bar) .navbar .pd-nav-menu.show {
    max-height: 75vh;
    max-height: 75dvh;
  }

  body:has(.pd-sticky-cta) .navbar-vertical .navbar-collapse .navbar-vertical-content,
  body:has(.sticky-cta-bar) .navbar-vertical .navbar-collapse .navbar-vertical-content {
    max-height: calc(100vh - var(--falcon-top-nav-height) - 1rem) !important;
    max-height: calc(100dvh - var(--falcon-top-nav-height) - 1rem) !important;
  }
}

/* The menu behind the hamburger scrolled the page behind it once it reached its end. */
.navbar-vertical .navbar-vertical-content {
  overscroll-behavior: contain;
}

/* Theme toggle in the top navbar sized to the 44 px AAA touch target (WCAG 2.5.5) on every */
/* width outside the two narrow bands below. */
.pd-theme-toggle {
  min-width: 44px;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

/* The visible circle matches the 34 px of the menu buttons beside it, while the label
   keeps the 44 px target: the 5 px of padding stay clickable and the background is
   clipped to the content box, whose corners the 50 % radius still rounds into a circle
   (design run of 20.10.2026; at 44 px the circle stood larger than the main buttons). */
.pd-theme-toggle .theme-control-toggle-label {
  padding: 5px;
  background-clip: content-box;
}

/* The Falcon theme hides the toggle's checkbox with display: none and paints the */
/* two icon labels instead. display: none also removes the element from the tab */
/* order and from the accessibility tree, which left the light/dark switch usable */
/* by pointer only — it did not exist for keyboard or screen reader users at all */
/* (WCAG 2.1.1 Level A, 4.1.2 Level A). Hiding it visually instead keeps it */
/* focusable and operable with Space, while the icon labels keep rendering the */
/* visual state. The 1 px box plus pointer-events: none prevents it from */
/* intercepting clicks meant for the labels. */
.pd-theme-toggle .theme-control-toggle-input {
  display: block;
  position: absolute;
  width: 1px;
  height: 1px;
  margin: 0;
  padding: 0;
  border: 0;
  opacity: 0;
  pointer-events: none;
}

/* Keyboard focus lands on the invisible checkbox, so the ring has to be drawn on */
/* the visible labels next to it. */
/* The ring follows the label's own 50 % radius from the theme. */
.pd-theme-toggle .theme-control-toggle-input:focus-visible ~ .theme-control-toggle-label {
  outline: 2px solid var(--falcon-primary);
  outline-offset: 2px;
}

/* The Falcon table tokens are defined once without a dark-mode counterpart, so */
/* table cells kept the light-mode ink (#5e6e82) on the dark card background — */
/* measured at 3.22:1, below the 4.5:1 AA floor, while the surrounding body copy */
/* correctly remaps to #9da9bb. This affects every comparison table in the blog */
/* and the sentence table of the paid report. Both tokens are needed: striped */
/* rows resolve their colour through --falcon-table-striped-color, so remapping */
/* only the base token would leave every second row failing (measured: 38 of 90 */
/* cells still at 3.22:1). */
[data-bs-theme="dark"] table {
  --falcon-table-color: var(--falcon-body-color);
  --falcon-table-striped-color: var(--falcon-body-color);
}

/* The navigation row (hamburger + logo + two dropdowns + theme toggle) overshoots the */
/* viewport in two narrow bands. Measured with both size rules forced on and off across */
/* 320-768 px, the row needs the reduced toggle below 340 px and again between */
/* 576 px and 620 px, where Bootstrap's sm breakpoint widens me-sm-3 and reveals the */
/* dropdown labels. Everywhere else — including every common phone width from 360 px */
/* up — the toggle keeps its 44x44 px WCAG 2.5.5 (AAA) target. The two bands must be */
/* read together with the logo rule below: neither alone clears 320 px. */
/* The upper bound is 339.98px, not 340px: re-measured on 16.09.2026 with the rule */
/* forced off, the row overshoots by 6 px at 320 px and by 10 px at 576 px but by 0 px */
/* at 339, 340 and 341 px, so at exactly 340 px the toggle can keep its full target. */
/* That also closes a one-pixel disagreement: the form bar's reserve above breaks */
/* at 339.98px, so at 340px the control used to shrink while the space reserved for the */
/* bar did not. The responsive matrix measures 320 and 375 and never saw it. */
@media (max-width: 339.98px), (min-width: 576px) and (max-width: 620px) {
  .pd-theme-toggle {
    min-width: 30px;
    min-height: 32px;
  }
}

/* Below 375 px the 180 px logo leaves too little room for the rest of the navigation */
/* row: measured overflow is 52 px at 320 px, 32 px at 340 px and 12 px at 360 px with */
/* the toggle at full size. Scaling the logo reclaims exactly that, and the aspect */
/* ratio is preserved (180/36 = 130/26 = 5) so no layout shift is introduced. The bound */
/* is 374.98 px rather than 356 px because at 360 px the reduced toggle alone no longer */
/* applies — the two rules cover overlapping, not identical, ranges. */
@media (max-width: 374.98px) {
  .navbar-top .navbar-brand img {
    width: 130px;
    height: auto;
  }
}

/* The hamburger's 24 px floor above costs the row four pixels, and in two narrow bands
   the row has none to give: measured with the floor in place and the brand held at its
   documented width, the page overflowed by 1 px at 375 px and by 4 px at 576 px, while
   320 px, 600 px and 620 px still fit. Those four pixels are taken from the wordmark
   rather than from a control, and by a fixed amount rather than by letting flexbox
   decide — with `min-width: 0; flex-shrink: 1` on the brand the algorithm overshot to
   153 px at 375 px and 136 px at 600 px, a visible 15-24 % shrink of the logo at the
   default font size, which contradicts the two widths the project deliberately picked
   (180 px, and 130 px below 375 px). 172 px keeps eight pixels of headroom and is a
   4 % step, which is not perceptible beside the 28 % step the 130 px rule already makes.
   `min-height` guards the link's own hit area at the 24 px of WCAG 2.2 SC 2.5.8 (AA).
   The image deliberately carries no `max-width: 100%`: that declaration removes the
   flex item's automatic minimum size, and the wordmark then shrank on its own at every
   tight width — measured 112 px at 320 px, 152 px at 375 px and 124 px at 640 px, none
   of which any rule asked for. Its width stays under the explicit control of the two
   band rules instead. */
.navbar-top .navbar-brand {
  min-height: 24px;
}

@media (min-width: 375px) and (max-width: 430px), (min-width: 576px) and (max-width: 620px) {
  .navbar-top .navbar-brand img {
    width: 172px;
  }
}

/* Since 20.10.2026 the bar carries three area menus instead of two (docs/decision-log.md
   AREA-01), about 44 px more, and the theme toggle was pushed past the right edge on
   every phone (37 px at 390 px). The menu labels now appear from 768 px (top.html), the
   menus sit closer together below 576 px, and the wordmark keeps the 130 px of the
   narrowest band there; below 375 px it takes 96 px, the same 5:1 ratio. Measured without
   overflow from 320 px to 1440 px. */
@media (max-width: 575.98px) {
  .navbar-top .navbar-brand img {
    width: 130px;
    height: auto;
  }

  .navbar-top .dropdown.me-2 {
    margin-right: 0.25rem !important;
  }
}

@media (max-width: 374.98px) {
  .navbar-top .navbar-brand img {
    width: 96px;
  }
}

/* Stop spinning animations for users who prefer reduced motion (WCAG 2.3.3). */
/* FontAwesome's .fa-spin runs as a CSS animation; on long-running pages like the */
/* thanks page countdown (several minutes), the endless rotation can trigger vestibular */
/* discomfort. Suppressing it leaves the cog icon visible but stationary, which */
/* still communicates "in progress" alongside the live-region countdown text. */
@media (prefers-reduced-motion: reduce) {
  .fa-spin {
    animation: none !important;
  }

  /* The vendored theme animates the sidebar's width and labels, the hamburger lines,
     the theme toggle and the icon tiles without asking; the header's promise covers
     them only with this rule. */
  .navbar-vertical,
  .navbar-vertical *,
  .navbar-vertical *::before,
  .navbar-vertical *::after,
  .navbar-toggle-icon,
  .navbar-toggle-icon::before,
  .navbar-toggle-icon::after,
  .navbar-toggle-icon *,
  .navbar-toggle-icon *::before,
  .navbar-toggle-icon *::after,
  .toggle-line,
  .theme-control-toggle-label,
  .icon-item {
    transition: none !important;
  }
}

/* Falcon enlarges the tile of .icon-item-lg to 2.75rem but keeps the 0.875rem glyph of the
   base tile, so topic, guide and privacy icons sat small in their tiles; its own xl tile
   scales the glyph with the tile, and this follows it (design run of 20.10.2026). */
.icon-item.icon-item-lg {
  font-size: 1rem;
}

/* Stats cards on home.html: reduce minimum width so two columns fit comfortably on */
/* phones (375px viewport / 2 columns = ~180px effective width). The previous 12rem */
/* (192px) caused horizontal overflow on the smallest supported viewport. */
.pd-stat-card-min {
  min-width: 10rem;
}

/* The large coloured icon of a stat card, without a tile, as in July 2026 (DES-07). */
.pd-stat-icon {
  font-size: 2.25rem;
  line-height: 1;
}

/* On a phone the four key figures stand as rows, icon left; the icon column has one
   width, so the figures of all four rows start on one edge. */
@media (max-width: 575.98px) {
  .pd-stat-icon {
    flex-shrink: 0;
    width: 2.75rem;
    text-align: center;
  }
}

/* Links inside a table cell are the same defect as the article titles below, and
   they were reported twice before without being fixed: the internal cross-links in
   the comparison tables of the articles (329 tables) and the unlock links in the
   rating tables of the two analysis reports. Measured at 18 px high, and where the
   link is the whole content of its cell - which it is in these tables, the cell text
   and the link text are the same length - the inline exception of WCAG 2.2 SC 2.5.8
   (AA) does not cover it.
   The same mechanism as below: vertical padding on an inline element grows its hit
   box without growing its line box. Verified across three surfaces at 375 and
   1440 px that row heights, table heights and page height are byte-identical before
   and after, so the rule may match generously - a cell that holds text AND a link
   is unaffected either way, which is why CSS does not need to express "sole content
   of the cell" here. Minimum height 18 -> 26 px, count below 24 px: 18 -> 0. */
.card-body .table td a:not(.btn),
.card-body .table th a:not(.btn) {
  padding: 0.25rem 0;
}

/* The article title is the primary navigation target of the three category
   overviews, 140 rows in all, and it is the only content of its <h2> — so the
   inline exception of WCAG 2.2 SC 2.5.8 (AA) does not apply to it. Measured at
   375 and 1440 px it renders 23.0 px high: the inline box follows Open Sans's own
   ascent-plus-descent (1.4375 em at 16 px), which is why raising the h2's
   line-height would not move it. Vertical padding on the inline anchor lifts it to
   31 px and moves nothing else, because padding on an inline element does not grow
   its line box and the anchor carries no background. This mirrors what
   .footer-brand above does for the identical defect, with the same 0.25rem.
   Titles that wrap to two lines already measured 42 px and are unaffected. */
.pd-overview-row > h2 > a {
  padding: 0.25rem 0;
}

/* Below the sm breakpoint the title of an article row in the category overviews has to
   share the line with the icon tile and the chevron: min-width: 0 lets its column shrink
   below its min-content width, and hyphens: auto prefers proper German hyphenation over a
   mid-word break (the document is lang="de"). The row used to wrap and give the title a
   line of its own, for a category badge the row no longer carries; it then fell apart
   into icon, title and chevron on three lines (design run of 20.10.2026).

   Both declarations are scoped to this range on purpose. Applied unconditionally,
   min-width: 0 also shrank the two-column layout at 768-900 px, where the row fits at
   full width — it introduced word breaks there instead of preventing them. */
@media (max-width: 575.98px) {
  .pd-overview-row > h2.flex-grow-1 {
    min-width: 0;
    -webkit-hyphens: auto;
    hyphens: auto;
  }
}

/* At 320 px a col-6 is only ~146 px wide, so the 10rem (160 px) floor pushed the two
   stat cards 8 px past the viewport and produced the last remaining horizontal scroll
   bar on the site. Below 400 px the column width is the sensible constraint; the cards
   stay readable because their text is already set at the small fs-9 scale. */
@media (max-width: 400px) {
  .pd-stat-card-min {
    min-width: 0;
  }
}

/* Circular icon tile of the thanks page, previously an inline width/height pair.   */
/* 56 px has no step on Falcon's scale (sm 30px, lg 44px, xl 50px). Named after the */
/* pixel size.                                                                       */
.pd-icon-tile-56 {
  flex-shrink: 0;
  width: 56px;
  height: 56px;
}

/* WebKit propagates a <select>'s layout overflow to its ancestors: the closed control
   is laid out at its own width (303 px here) but the widest <option> — "10 oder weniger
   Mitarbeiter (Teilzeit anteilig)" on the Kündigungsanalyse form — still contributes to
   the scrollable area, which travels up through .form-floating, .card-body and .content
   until the document itself scrolls. Measured on the JTA form: 14 px of horizontal page
   scroll at 320 px and 29 px at 375 px in WebKit, 0 px in Chromium and Gecko, confirmed
   with a real window.scrollTo(400, 0) reporting scrollX = 29. Since every browser on iOS
   uses WebKit, that is every iPhone visitor of that form.
   Clipping the select itself is the narrowest fix that works: overflow never affects an
   element's own outline, so the focus ring stays intact, and the dropdown popup is drawn
   by the operating system and is likewise unaffected. Applying the same clip one level up
   on .form-floating also removes the overflow but would clip the focus ring of the field
   inside it, trading a layout defect for a WCAG 2.4.7 defect. */
select.form-select {
  overflow: hidden;
}

/* Falcon's own colours (owner decision of 15.10.2026, docs/decision-log.md DES-01).
   The accessibility runs of August to October 2026 had overridden the theme to reach
   contrast ratios: dark ink on the info, success, warning and secondary fills, darker
   text utilities, links and soft buttons, a darker primary and danger fill, darker form
   borders, labels and placeholders. The owner judged the result no longer Falcon and
   ordered the theme's original palette back; accessibility is a bonus here and does not
   change the design (global CLAUDE.md, Barrierefreiheit). The one colour rule this block
   keeps is the white glyph on a filled icon tile, which Falcon writes as `text-white` on
   the glyph and this project's templates had lost. */
.icon-item.bg-primary > .fas,
.icon-item.bg-info > .fas,
.icon-item.bg-success > .fas,
.icon-item.bg-warning > .fas,
.icon-item.bg-danger > .fas,
.icon-item.bg-secondary > .fas,
.icon-item.bg-info > .fab,
.icon-item.bg-success > .fab,
.icon-item.bg-warning > .fab {
  color: #fff;
}

/* Crispy adds form-control to every number widget, the range sliders included, which
   drew a text-field box around the track. A slider is not a text field. */
.form-range.form-control {
  height: 1.5rem;
  padding: 0;
  background-color: transparent;
  border: 0;
  box-shadow: none;
}

/* The range sliders of the Arbeitszeugniserstellung draw their focus as a ring around
   the thumb, which outline cannot reach. Invisible at rest. */
.form-range:focus-visible::-webkit-slider-thumb {
  box-shadow:
    0 0 0 2px var(--falcon-body-bg),
    0 0 0 4px var(--falcon-primary);
}

.form-range:focus-visible::-moz-range-thumb {
  box-shadow:
    0 0 0 2px var(--falcon-body-bg),
    0 0 0 4px var(--falcon-primary);
}

/* Report blocks of the portfolio products (products/blocks.py, 10.10.2026).
   Bars are native <progress> elements so their width is the element's value and no
   inline style is needed; each engine draws them, so both pseudo-elements are styled. */
.pd-bar {
  -webkit-appearance: none;
  appearance: none;
  display: block;
  width: 100%;
  height: 0.75rem;
  border: 0;
  border-radius: var(--falcon-border-radius-lg);
  background-color: var(--falcon-gray-200);
  overflow: hidden;
}

.pd-bar::-webkit-progress-bar {
  background-color: var(--falcon-gray-200);
  border-radius: var(--falcon-border-radius-lg);
}

.pd-bar::-webkit-progress-value {
  background-color: var(--pd-bar-color, var(--falcon-primary));
  border-radius: var(--falcon-border-radius-lg);
}

.pd-bar::-moz-progress-bar {
  background-color: var(--pd-bar-color, var(--falcon-primary));
  border-radius: var(--falcon-border-radius-lg);
}

.pd-bar--success {
  --pd-bar-color: var(--falcon-success);
}

.pd-bar--warning {
  --pd-bar-color: var(--falcon-warning);
}

.pd-bar--danger {
  --pd-bar-color: var(--falcon-danger);
}

.pd-bar--muted {
  --pd-bar-color: var(--falcon-gray-500);
}

/* The deadline calendar: a vertical line with one dot per date. A deadline gets a
   ring, a past date a muted dot, the next days a warning colour. */
.pd-timeline {
  position: relative;
  padding-left: 1.5rem;
}

.pd-timeline__item {
  position: relative;
  padding-bottom: 1rem;
}

/* The line is 2 px wide and centred on the 1rem dots, whose centre lies 0.5rem in and
   0.75rem down. Each item draws the segment from its own dot to the next one: drawn on
   the list, the line ran 17 px past the last dot at 1440 px and 152 px at 320 px, where
   the last date wraps under a note (design run of 10.10.2026). */
.pd-timeline__item:not(:last-child)::before {
  content: "";
  position: absolute;
  top: 0.75rem;
  bottom: -0.75rem;
  left: calc(-1rem - 1px);
  /* A border rather than a background, as .pd-steps draws its line: it prints without
     background graphics and stays visible under forced colours. */
  border-left: 2px solid var(--falcon-gray-300);
}

.pd-timeline__item:last-child {
  padding-bottom: 0;
}

.pd-timeline__dot {
  position: absolute;
  top: 0.25rem;
  left: -1.5rem;
  width: 1rem;
  height: 1rem;
  border-radius: 50%;
  background-color: var(--falcon-primary);
  border: 2px solid var(--falcon-card-bg, #fff);
}

.pd-timeline__item--past .pd-timeline__dot {
  background-color: var(--falcon-gray-500);
}

.pd-timeline__item--soon .pd-timeline__dot,
.pd-timeline__item--today .pd-timeline__dot {
  background-color: var(--falcon-warning);
}

.pd-timeline__item--deadline .pd-timeline__dot {
  box-shadow: 0 0 0 3px rgba(var(--falcon-danger-rgb), 0.35);
}

/* A scale between two poles with a marker, for the self-employment tendency. */
.pd-scale {
  position: relative;
  height: 0.75rem;
  border-radius: var(--falcon-border-radius-lg);
  background: linear-gradient(
    90deg,
    var(--falcon-success),
    var(--falcon-warning),
    var(--falcon-danger)
  );
}

.pd-scale__marker {
  position: absolute;
  top: -0.35rem;
  width: 0.25rem;
  height: 1.45rem;
  margin-left: -0.125rem;
  border-radius: var(--falcon-border-radius);
  background-color: var(--falcon-gray-1100);
}

/* Eleven marker positions in steps of ten percent; a class rather than an inline
   left offset, so the template carries no style attribute. */
.pd-scale__marker--0 {
  left: 0%;
}
.pd-scale__marker--10 {
  left: 10%;
}
.pd-scale__marker--20 {
  left: 20%;
}
.pd-scale__marker--30 {
  left: 30%;
}
.pd-scale__marker--40 {
  left: 40%;
}
.pd-scale__marker--50 {
  left: 50%;
}
.pd-scale__marker--60 {
  left: 60%;
}
.pd-scale__marker--70 {
  left: 70%;
}
.pd-scale__marker--80 {
  left: 80%;
}
.pd-scale__marker--90 {
  left: 90%;
}
.pd-scale__marker--100 {
  left: 100%;
}

/* Tiles of a requirement check, three to a row on wide screens. They carry the finding
   pattern below (.pd-finding with its rating modifier), so a rated point looks the same
   in every report; only the height and the closer padding of a tile differ. */
.pd-finding.pd-check-tile {
  height: 100%;
  margin-bottom: 0;
  padding: 0.5rem 1rem;
  background: linear-gradient(
    135deg,
    rgba(var(--pd-finding-rgb), 0.12) 0%,
    rgba(var(--pd-finding-rgb), 0.02) 60%
  );
  border: 1px solid rgba(var(--pd-finding-rgb), 0.3);
  border-radius: var(--falcon-border-radius-lg);
}

/* Product forms: a numbered heading above each group of questions. The number sits in a
   circle in the primary colour; the hint underneath is indented to the heading text. */
.pd-form-section {
  margin-top: 0.5rem;
}

.pd-form-section__number {
  display: inline-flex;
  flex-shrink: 0;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  border-radius: 50%;
  background: var(--falcon-primary-bg-subtle);
  color: var(--falcon-primary);
  font-weight: 600;
  font-size: 0.8333333333rem;
}

/* Points of a product page's method card: icon beside a short title and text. */
.pd-method-item {
  display: flex;
  gap: 1rem;
  padding: 1rem;
  border: 1px solid var(--falcon-border-color);
  border-radius: var(--falcon-border-radius-lg);
}

/* The text column may shrink and hyphenate: at 200 % zoom on a phone (about 188 px of
   layout width) "Leistungsbeurteilung" ran 90 px past its box (design run of 20.10.2026). */
.pd-method-item > div {
  min-width: 0;
  -webkit-hyphens: auto;
  hyphens: auto;
  overflow-wrap: break-word;
}

/* The checked points of an unpaid analysis: a plain numbered list with room per line. */
/* The points an unpaid analysis checked: one row each under a hairline, the number in a
   small primary circle as in the legal tables of contents, and the state (the "Kritisch"
   badge or the lock) at the right end of every row, so the marks of all rows stand in one
   column instead of after titles of different length (DES-17). role="list" keeps the
   list semantics that list-style: none removes in Safari. */
.pd-checked-list {
  padding-left: 0;
  list-style: none;
  counter-reset: pd-checked;
}

.pd-checked-list > li {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.5rem 0;
  border-bottom: 1px solid var(--falcon-border-color);
  counter-increment: pd-checked;
}

.pd-checked-list > li:last-child {
  border-bottom: 0;
}

.pd-checked-list > li::before {
  content: counter(pd-checked);
  display: inline-flex;
  flex: 0 0 1.5rem;
  align-items: center;
  justify-content: center;
  height: 1.5rem;
  border-radius: 50%;
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--falcon-primary);
  background-color: var(--falcon-primary-bg-subtle);
}

.pd-checked-list__title {
  flex: 1 1 auto;
  min-width: 0;
}

.pd-checked-list__state {
  flex: 0 0 auto;
}

/* Next steps of a paid analysis: numbered circles on a thin connecting line. */
.pd-steps {
  list-style: none;
  counter-reset: pd-step;
  padding-left: 0;
}

.pd-steps__item {
  position: relative;
  counter-increment: pd-step;
  padding: 0 0 1rem 3rem;
}

.pd-steps__item::before {
  content: counter(pd-step);
  position: absolute;
  top: 0;
  left: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  border-radius: 50%;
  background: var(--falcon-primary);
  color: #fff;
  font-weight: 600;
  font-size: 0.8333333333rem;
}

.pd-steps__item:not(:last-child)::after {
  content: "";
  position: absolute;
  top: 2.25rem;
  bottom: 0.25rem;
  left: calc(1rem - 1px);
  /* gray-300 like the timeline's line: --falcon-border-color is 5 % white in dark mode
     and left the line all but invisible there (design run of 16.10.2026). */
  border-left: 2px solid var(--falcon-gray-300);
}

.pd-steps__item:last-child {
  padding-bottom: 0;
}

/* One finding of an analysis or one graded sentence: a row of one list, as the graded
   sentences of the Arbeitszeugnisanalyse report of August 2026 stood in one striped
   table, the owner's benchmark. Neighbouring findings share a hairline, every second
   row is tinted, and only the first and last row of a run are rounded; the rating is
   carried by the badges in the row. No coloured edge: the owner rejected accent
   stripes as generic (20.10.2026, DES-16), tests/test_no_accent_stripes.py. */
.pd-finding {
  --pd-finding-rgb: var(--falcon-gray-500-rgb, 116, 129, 148);
  margin: 0;
  padding: 1rem 1.25rem;
  border: 1px solid var(--falcon-border-color);
}

.pd-finding + .pd-finding {
  border-top-width: 0;
}

.pd-finding:nth-child(even) {
  background-color: var(--falcon-tertiary-bg);
}

.pd-finding:first-child,
:not(.pd-finding) + .pd-finding {
  border-top-left-radius: var(--falcon-border-radius-lg);
  border-top-right-radius: var(--falcon-border-radius-lg);
}

.pd-finding:not(:has(+ .pd-finding)) {
  margin-bottom: 1rem;
  border-bottom-left-radius: var(--falcon-border-radius-lg);
  border-bottom-right-radius: var(--falcon-border-radius-lg);
}

/* The rating of a finding names its colour for the check tiles below. */
.pd-finding--danger {
  --pd-finding-rgb: var(--falcon-danger-rgb);
}

.pd-finding--warning {
  --pd-finding-rgb: var(--falcon-warning-rgb);
}

.pd-finding--success {
  --pd-finding-rgb: var(--falcon-success-rgb);
}

/* The three parts of a finding: small uppercase labels above each paragraph. */
.pd-finding__parts dt {
  margin-top: 0.5rem;
  color: var(--falcon-gray-700);
  font-size: 0.6944444444rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

/* A statute cited beside a label ("§ 1a KSchG") keeps its spelling: the label's capitals
   turned it into "§ 1A KSCHG", and the badge's 0.75em made it 9 px. */
.pd-finding__parts dt .badge {
  font-size: 0.6944444444rem;
  letter-spacing: 0;
  text-align: left;
  text-transform: none;
  /* A long citation ("§ 1 Abs. 3 Satz 1 Halbsatz 2 KSchG") overran 320 px by 17 px. */
  white-space: normal;
}

.pd-finding__parts dd {
  margin-bottom: 0;
  color: var(--falcon-gray-900);
}

/* A quotation from the uploaded document: a quiet surface with a hairline, no edge. */
.pd-quote {
  margin: 0 0 0.5rem;
  padding: 0.75rem 1rem;
  background: var(--falcon-tertiary-bg);
  border: 1px solid var(--falcon-border-color);
  border-radius: var(--falcon-border-radius-lg);
  color: var(--falcon-gray-1100);
}

/* The table of contents of the AGB and the privacy policy: numbered entries in small
   primary circles, a tinted surface under the pointer and on the section being read
   (custom.js initializeTocSpy sets .active). */
.terms-sidebar {
  counter-reset: pd-toc;
}

.pd-toc-link {
  counter-increment: pd-toc;
  display: flex;
  align-items: baseline;
  gap: 0.625rem;
  margin: 0 -0.625rem;
  padding: 0.375rem 0.625rem;
  color: var(--falcon-gray-700);
  font-weight: 500;
  border-radius: var(--falcon-border-radius);
}

.pd-toc-link::before {
  content: counter(pd-toc);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 1.375rem;
  height: 1.375rem;
  border-radius: 50%;
  background-color: var(--falcon-primary-bg-subtle);
  color: var(--falcon-primary);
  font-size: 0.6944444444rem;
  font-weight: 600;
  transform: translateY(-0.0625rem);
}

.pd-toc-link:hover,
.pd-toc-link.active {
  background-color: var(--falcon-primary-bg-subtle);
  color: var(--falcon-primary);
}

.pd-toc-link.active::before {
  background-color: var(--falcon-primary);
  color: #fff;
}

@media (prefers-reduced-motion: no-preference) {
  .pd-toc-link,
  .pd-toc-link::before {
    transition:
      background-color var(--pd-transition-base),
      color var(--pd-transition-base);
  }
}

/* "Das Wichtigste auf einen Blick" of an article (custom.js initializeKeyFacts): a tinted
   box with a check before every point, the summary a hurried reader reads first.
   The second selector matches the same list before the script runs: the class arrived
   after the first paint and moved the list by 20 px, a layout shift of 0.15 on a
   1350 px desktop (Lighthouse, conversion run of 21.10.2026). In the browser it matched
   exactly the script's list, or nothing, in all 139 published articles, and no article
   template opens with another h2.h5 followed by a list; :where() keeps its specificity
   at that of the class, so the cascade is unchanged. The class stays for the few
   articles whose heading is not the first h2. */
.pd-keyfacts,
.is-blog-article :where(h2.h5:first-of-type + ul) {
  padding: 1rem 1.25rem;
  list-style: none;
  background: linear-gradient(
    135deg,
    rgba(var(--falcon-primary-rgb), 0.09) 0%,
    rgba(var(--falcon-primary-rgb), 0.02) 70%
  );
  border: 1px solid rgba(var(--falcon-primary-rgb), 0.2);
  border-radius: var(--falcon-border-radius-lg);
}

.pd-keyfacts > li,
.is-blog-article :where(h2.h5:first-of-type + ul) > li {
  position: relative;
  padding-left: 1.75rem;
}

.pd-keyfacts > li + li,
.is-blog-article :where(h2.h5:first-of-type + ul) > li + li {
  margin-top: 0.5rem;
}

.pd-keyfacts > li::before,
.is-blog-article :where(h2.h5:first-of-type + ul) > li::before {
  content: "\f058";
  position: absolute;
  left: 0;
  top: 0.05em;
  font-family: "Font Awesome 5 Free";
  font-weight: 900;
  color: var(--falcon-primary);
}

/* ------------------------------------------------------------------------------------
   Signal cards (owner, 20.10.2026): a result that carries a rating (the verdict, a
   grade category, a count, a state) is a Falcon card on a corner illustration in the
   rating's colour, with a large figure or icon in that colour, as the
   Arbeitszeugnisanalyse report of August 2026 and the key figures of the home page do.
   They replace the coloured top and left stripes. The illustration is a class rather
   than an inline style, so every signal card picks it from one place:
   warm for danger and warning, green for success, blue for everything else.
   ------------------------------------------------------------------------------------ */
.pd-signal-bg,
.pd-signal-bg--primary,
.pd-signal-bg--info,
.pd-signal-bg--secondary {
  background-image: url("../img/icons/spot-illustrations/corner-2.875f8638a1a5.png");
}

.pd-signal-bg--danger,
.pd-signal-bg--warning {
  background-image: url("../img/icons/spot-illustrations/corner-1.dfdb6c51fda7.png");
}

.pd-signal-bg--success {
  background-image: url("../img/icons/spot-illustrations/corner-3.7df03b547acf.png");
}

/* A signal inside a card (the counts of a report): the same surface as a tile. */
.pd-signal-tile {
  position: relative;
  height: 100%;
  overflow: hidden;
  padding: 1rem 1.25rem;
  border: 1px solid var(--falcon-border-color);
  border-radius: var(--falcon-border-radius-lg);
}

/* On a phone a tile sets its figure beside its label; the figure takes a fixed width,
   so "10" and "2" leave their labels on one common edge. */
@media (max-width: 575.98px) {
  .pd-signal-tile .pd-signal-value {
    min-width: 3.25rem;
    text-align: center;
  }
}

/* The round icon of a signal card, a step larger than Falcon's icon-item. */
.pd-signal-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 3.5rem;
  height: 3.5rem;
  border-radius: 50%;
  font-size: 1.5rem;
}

/* The large figure of a signal card ("Noten Ø 1,9", "5"), Falcon's display face. */
.pd-signal-value {
  font-family: var(--falcon-font-sans-serif);
  font-size: clamp(2rem, 1.4rem + 1.6vw, 2.75rem);
  font-weight: 400;
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
}

/* A wording the buyer can copy: a quiet box with a dashed primary border. */
.pd-wording {
  margin-top: 1rem;
  padding: 0.75rem 1rem;
  border: 1px dashed rgba(var(--falcon-primary-rgb), 0.5);
  border-radius: var(--falcon-border-radius-lg);
  background: rgba(var(--falcon-primary-rgb), 0.04);
}

/* A wording that the model wrote as lines (a CV's list of tasks) keeps them, on the page
   and in what the copy button reads from it. */
.pd-wording > p {
  white-space: pre-line;
}

/* The created document drawn as a sheet of paper: white in both modes, because the
   buyer reads it as the letter or contract they will print. It takes the full width of
   its card (global rule: readable text is never narrowed to a reading measure). */
.pd-paper {
  position: relative;
  padding: 3rem;
  background: var(--pd-paper-bg);
  border: 1px solid var(--falcon-border-color);
  border-radius: var(--falcon-border-radius);
  box-shadow: var(--falcon-box-shadow-sm);
}

.pd-paper__text,
.pd-paper__text p,
.pd-paper__text li {
  color: var(--pd-paper-ink);
  line-height: 1.5;
}

.pd-paper__text p {
  margin-bottom: 1rem;
}

/* Paragraph or list, the last block leaves the bottom padding alone, as the first does
   at the top. */
.pd-paper__text > :last-child {
  margin-bottom: 0;
}

.pd-paper__text .pd-paper__heading {
  margin-top: 1.5rem;
  margin-bottom: 0.5rem;
  font-weight: 700;
}

/* The sheet's own padding is the top margin of its first block; a heading there would
   add its 1.5rem on top (measured 72 px of empty paper above the salary guide). */
.pd-paper__text > :first-child {
  margin-top: 0;
}

/* The list marks are text, not ::marker: copying and printing read the sheet's innerText,
   which carries no ::marker, and the numbers and dashes of the document went missing
   from both (design run of 10.10.2026). The marker box hangs in the indent. */
.pd-paper__list {
  margin-bottom: 1rem;
  padding-left: 1.5rem;
  list-style: none;
}

.pd-paper__list > li {
  text-indent: -1.5rem;
}

/* A list joined from items the text set apart keeps that space between them. */
.pd-paper__list--spaced > li + li {
  margin-top: 1rem;
}

.pd-paper__marker {
  display: inline-block;
  width: 1.25rem;
  text-indent: 0;
}

/* The unpaid preview fades out where the free part ends. The fade is decoration only:
   the server sends the free part and nothing more (CLAUDE.md > Invariants for Audit Runs). */
.pd-paper--preview {
  overflow: hidden;
}

.pd-paper--preview::after {
  content: "";
  position: absolute;
  right: 0;
  bottom: 0;
  left: 0;
  height: 5rem;
  background: linear-gradient(to bottom, rgba(255, 255, 255, 0), var(--pd-paper-bg));
  border-radius: 0 0 var(--falcon-border-radius) var(--falcon-border-radius);
}

/* Placeholders the buyer still fills in, marked in the sheet with the light values of
   the warning role (Falcon has no yellow); the sheet stays white in both modes, so the
   values are fixed rather than theme variables. The mark has no side padding: its own
   brackets are its edges, and a 4 px inset read as a space before the next comma
   ("[Ort] , [Datum]", design run of 10.10.2026). */
.pd-placeholder {
  padding: 0;
  border-radius: var(--falcon-border-radius);
  background: var(--pd-placeholder-bg);
  color: var(--pd-paper-ink);
}

@media (max-width: 575.98px) {
  .pd-paper {
    padding: 1.5rem 1rem;
  }
}

/* Below the sm breakpoint a three-column table of the report stacks each row into one
   block (label, value, rating) instead of hiding its last column behind a horizontal
   scroll; the rows keep one rule each, and the cells share one left edge. */
@media (max-width: 575.98px) {
  /* The column heads stay for screen readers: hidden with d-none, the stacked cells
     lost their column names (WCAG 2.2 SC 1.3.1). Visually hidden as .visually-hidden. */
  .pd-stack-table thead {
    position: absolute !important;
    width: 1px !important;
    height: 1px !important;
    padding: 0 !important;
    margin: -1px !important;
    overflow: hidden !important;
    clip: rect(0, 0, 0, 0) !important;
    white-space: nowrap !important;
    border: 0 !important;
  }

  .pd-stack-table tbody tr {
    padding: 0.5rem 0;
    border-bottom: 1px solid var(--falcon-border-color);
  }

  /* The theme indents the first and last cell of a row (.table tr th:first-child,
     1.25rem, specificity 0-2-2); in the stacked form every cell starts on the same edge. */
  .table.pd-stack-table tbody tr > :is(th, td) {
    padding: 0.25rem 0;
    border-bottom-width: 0;
  }

  /* Where two values of a row are amounts, the stacked cell names its column, or
     "366,63 €" and "358,25 €" could not be told apart (payslip comparison). */
  .pd-stack-table td[data-label]::before {
    content: attr(data-label) ": ";
    color: var(--falcon-gray-700);
  }

  /* The rating badge of a stacked row sits at the right of its title instead of on a
     line of its own, so every key term takes one line less; the title keeps clear of it. */
  .pd-stack-table tbody tr:has(> .pd-stack-table__badge) {
    position: relative;
  }

  .table.pd-stack-table tbody tr > .pd-stack-table__badge {
    position: absolute;
    top: 0.75rem;
    right: 0;
    padding: 0;
  }

  .table.pd-stack-table tbody tr:has(> .pd-stack-table__badge) > th {
    padding-right: 6.5rem;
  }
}

/* Every disclosure outside the legal tables of contents (the questions under the purchase
   card, the toggle of the original document) reads as one accordion row: the browser's
   triangle gives way to a chevron at the right that turns when the row opens, and
   neighbouring questions are divided by a hairline. */
details:not(.pd-toc) > summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.375rem 0;
  list-style: none;
  cursor: pointer;
}

details:not(.pd-toc) > summary::-webkit-details-marker {
  display: none;
}

details:not(.pd-toc) > summary::after {
  content: "\f078";
  flex-shrink: 0;
  font-family: "Font Awesome 5 Free";
  font-weight: 900;
  font-size: 0.75rem;
  color: var(--falcon-gray-500);
}

details[open]:not(.pd-toc) > summary::after {
  transform: rotate(180deg);
}

details:not(.pd-toc) + details:not(.pd-toc) {
  padding-top: 0.5rem;
  border-top: 1px solid var(--falcon-border-color);
}

@media (prefers-reduced-motion: no-preference) {
  details:not(.pd-toc) > summary::after {
    transition: transform var(--pd-transition-base);
  }

  details[open]:not(.pd-toc) > summary ~ * {
    animation: pd-fade-in var(--pd-transition-slow) both;
  }
}

/* The questions under the purchase card and the toggle of the original document on the
   two analysis reports ("Ihr ursprüngliches Arbeitszeugnis anzeigen") only changed the
   pointer on hover; they take the link ink like the footer links. */
@media (hover: hover) {
  details > summary:hover {
    color: rgb(var(--falcon-link-color-rgb));
  }
}

/* The leading icon of a link list keeps its fixed width: as a flex item it shrank from
   24 to 14.4 px beside a wrapping title, and the titles of one list started at
   different points. */
.list-group-item-action > .fas:first-child {
  flex-shrink: 0;
}

/* Dates and amounts that stand under one another outside a table take the tabular
   figures the tables already have (the td, th rule further up). */
.pd-figures {
  font-variant-numeric: tabular-nums;
}

/* On paper the sheet is the page: no frame, no inset, no shadow. The placeholders keep
   only their brackets, which survive printing without background graphics. */
@media print {
  .pd-paper {
    padding: 0;
    border: 0;
    box-shadow: none;
  }

  .pd-placeholder {
    background: none;
  }
}

/* Final pass of the design run, 12.10.2026. */

/* Headings break in balanced lines, so none ends with one word alone (112 of 815
   headings on 14 pages did; design run of 16.10.2026). The wording is untouched; running
   text keeps the browser's own breaking. The longhand leaves text-wrap-mode alone, so a
   heading set to nowrap stays unbroken. */
:is(h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6, .pd-faq__question) {
  text-wrap-style: balance;
}

/* Text selection in the brand blue in both modes; the theme's dark mode selected in
   the orange of the dismissal products. */
::selection,
[data-bs-theme="dark"] ::selection {
  background-color: var(--falcon-primary);
  color: #fff;
}

/* The theme draws the arrow of a select in #4d5969 in both modes: 2.53:1 on the dark
   field, and the arrow is what tells a select from a text field (WCAG 2.2 SC 1.4.11).
   gray-600 (#748194) measures above 4:1 there. */
[data-bs-theme="dark"] .form-select {
  --falcon-form-select-bg-img: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23748194' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e");
}

/* A badge is 0.75em of its parent, which put the verdict of a check at 10 px inside
   fs-10 text, below the smallest step of the scale (fs-11, 11.1 px). The floor lifts
   only those; a badge with a size class of its own keeps it. */
.content .badge {
  font-size: max(0.75em, 0.6944444444rem);
}

/* A field the visitor has left invalid, or that a refused submit found empty, shows it
   at the field and not only in the browser's passing bubble at the first one. */
.form-control:user-invalid,
.form-select:user-invalid,
.form-check-input:user-invalid {
  border-color: var(--falcon-danger);
}

/* The consent switches sat 24 px further in than every field above them: the column
   carries .form-switch, whose 2.5em indent is meant for the inner .form-check. Crispy
   renders the column as "col-md form-switch", so the selector matches any col class. */
.form-switch[class*="col"] {
  padding-left: calc(var(--falcon-gutter-x) * 0.5);
}

/* The 3 px accent of a card (border-3) reaches its buttons through the inherited
   --falcon-border-width and drew them with a 3 px frame. Their frame returns to 1 px;
   the padding takes the 2 px per side back, so the buttons keep their 40 px height
   (a target never shrinks in this run). */
.card.border-3 .btn:not(.btn-sm):not(.btn-lg) {
  --falcon-btn-border-width: 1px;
  --falcon-btn-padding-y: calc(0.3125rem + 2px);
}

/* Placeholder marks outside the white sheet (the list of placeholders, the summary,
   the notes and the wordings of a report) take the dark warning tint in dark mode; the
   sheet and its preview stay white and keep the light marks. */
[data-bs-theme="dark"] .pd-placeholder:not(.pd-paper .pd-placeholder) {
  --pd-placeholder-bg: var(--falcon-warning-bg-subtle);
  color: var(--falcon-warning-text-emphasis);
}

/* The printed report link wraps where it must: it is one long word. */
.pd-print-link {
  overflow-wrap: anywhere;
}

@media print {
  [data-report-link] {
    break-inside: avoid;
  }
}

/* The focus ring sits 2 px outside a control, and the navigation lists clip their
   overflow: on the sidebar links, the hamburger menu and the product menus only two
   horizontal lines of it were left. Inside those lists the ring is drawn inward. */
.navbar-vertical .nav-link:focus-visible,
.navbar .pd-nav-menu .dropdown-item:focus-visible {
  outline-offset: -2px;
}

/* The collapsed sidebar from 1200 px was fixed to the height of its container (h-100)
   while the theme clips the list, so with a mouse or by touch its lower links (Über uns,
   the guides, the legal pages) could not be reached; the content around it scrolls once
   the list takes its own height. */
@media (min-width: 1200px) {
  .navbar-vertical .navbar-collapse .navbar-vertical-content > #navbarVerticalNav {
    height: auto !important;
  }
}

/* The opened sidebar is 234 px wide, and the longer product names broke in the middle of
   a word without a hyphen ("Aufhebungsvertragsanaly-se"). */
.navbar-vertical .nav-link-text {
  -webkit-hyphens: auto;
  hyphens: auto;
  hyphenate-limit-chars: 12 5 5;
}

/* The consent library resets its buttons (all: initial; outline: revert), which left
   them without a visible ring in WebKit; they take the project's ring. The extra
   element wins against the library, which loads after this file. */
html #cc-main :focus-visible {
  outline: 2px solid var(--falcon-primary);
  outline-offset: 2px;
}

/* ------------------------------------------------------------------------------------
   Navigation and home page of the portfolio redesign (14.10.2026).
   The layout follows the Falcon originals the theme ships: the vertical card navigation
   with its collapse toggle, the round feature icons and the multi-column footer of the
   landing page. The top navigation keeps its two product menus (owner, 15.10.2026).
   Every product of the catalogue gets the same weight; colours stay the theme's own.
   ------------------------------------------------------------------------------------ */

/* The big heading of the home page, stepped down so its two lines do not break into
   four on a phone. Its weight is 400: poppins.css carries no 300 face, so the "light
   display weight" this rule asked for was never drawn (design run of 16.10.2026). */
.pd-hero-title {
  font-size: clamp(1.75rem, 1.2rem + 2vw, 2.75rem);
  font-weight: 400;
  line-height: 1.2;
  color: var(--falcon-gray-1000, #232e3c);
}

/* The two verbs of the hero headline carry the brand's blue running into its light blue,
   the one gradient on the page; the text stays solid primary where background-clip is
   unknown. Under forced colours the system colour replaces both. */
.pd-hero-accent {
  color: var(--falcon-primary);
}

@supports (-webkit-background-clip: text) or (background-clip: text) {
  .pd-hero-accent {
    background-image: linear-gradient(
      90deg,
      var(--falcon-primary) 0%,
      var(--falcon-info) 50%,
      var(--falcon-primary) 100%
    );
    background-size: 200% 100%;
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
  }
}

/* The topic picker under the centred hero: a row of tiles, no panel of its own, that
   jump to the topic cards further down the page (DES-07). */
.pd-topic-picker {
  margin-top: 0.5rem;
}

.pd-topic-tile {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  height: 100%;
  min-height: 3.5rem;
  padding: 0.5rem 0.75rem;
  border-radius: var(--falcon-border-radius-lg);
  background-color: var(--falcon-card-bg, #fff);
  box-shadow: var(--falcon-box-shadow-sm);
  color: var(--falcon-gray-900, #344050);
  text-decoration: none;
}

.pd-topic-tile__icon {
  display: inline-flex;
  flex-shrink: 0;
  align-items: center;
  justify-content: center;
  width: 2.25rem;
  height: 2.25rem;
  border-radius: var(--falcon-border-radius-lg);
  background-color: var(--falcon-primary-bg-subtle);
  color: var(--falcon-primary);
}

.pd-topic-tile__text {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.pd-topic-tile__name {
  font-size: 0.8333333333rem;
  font-weight: 600;
  line-height: 1.2;
  -webkit-hyphens: auto;
  hyphens: auto;
  overflow-wrap: anywhere;
}

.pd-topic-tile__count {
  font-size: 0.6944444444rem;
  color: var(--falcon-gray-700, #5e6e82);
}

.pd-topic-tile:focus-visible {
  outline: 2px solid var(--falcon-primary);
  outline-offset: 2px;
}

/* Below 576 px two tiles share a row of about 160 px: the icon goes above the name, so
   "Aufhebungsvertrag" keeps its line instead of breaking into three. */
@media (max-width: 575.98px) {
  .pd-topic-tile {
    flex-direction: column;
    align-items: flex-start;
    gap: 0.5rem;
    padding: 0.75rem;
  }

  .pd-topic-tile__name {
    font-size: 0.75rem;
    -webkit-hyphens: manual;
    hyphens: manual;
  }
}

/* Between 768 and 991 px four tiles share a row of about 144 px, narrower than two on a
   phone: the icon goes above the name there as well (design run of 16.10.2026). */
@media (min-width: 768px) and (max-width: 991.98px) {
  .pd-topic-tile {
    flex-direction: column;
    align-items: flex-start;
    gap: 0.5rem;
    padding: 0.75rem;
  }
}

/* Hover behind (hover: hover) so a tap leaves no stuck state, the movement behind
   prefers-reduced-motion, as everywhere in this file. */
@media (hover: hover) {
  .pd-topic-tile:hover {
    color: var(--falcon-primary);
    box-shadow: var(--falcon-box-shadow);
  }
}

/* The topic card's product list: one row per product, the whole row a link, the
   example report a second, separate link at its end (a link cannot contain a link). */
.pd-product-row {
  display: flex;
  align-items: stretch;
  border-top: 1px solid var(--falcon-border-color);
}

.pd-product-row:first-child {
  border-top: 0;
}

.pd-product-row__link {
  display: flex;
  flex: 1 1 auto;
  align-items: flex-start;
  gap: 0.75rem;
  min-width: 0;
  padding: 0.75rem 1.25rem;
  color: inherit;
  text-decoration: none;
}

/* A row without an example report (the tools and the template) keeps the example
   column's 2.75rem free, so its "kostenlos" ends on the line of the prices above and
   below it instead of 44 px further right (design run of 16.10.2026). Only from 576 px:
   on a phone the reserve took a third of the row and broke "Brutto-Netto-Rechner" into
   syllables. */
@media (min-width: 576px) {
  .pd-product-row__link:only-child {
    padding-right: 4rem;
  }
}

.pd-product-row__icon {
  flex-shrink: 0;
  padding-top: 0.1rem;
}

.pd-product-row__body {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  min-width: 0;
}

.pd-product-row__name {
  font-size: 0.8333333333rem;
  font-weight: 600;
  color: var(--falcon-gray-900, #344050);
  -webkit-hyphens: auto;
  hyphens: auto;
  overflow-wrap: anywhere;
}

.pd-product-row__kind {
  margin-left: 0.25rem;
}

/* On a phone the kind label goes under every name, not only under the long ones, so the
   rows of a card share one shape, and the price moves down to the line of the label: beside
   the name it took about 100 px and broke "Aufhebungsvertragsanalyse" in the middle of the
   word. A row without an example report ends 2.75rem further right, so its price keeps
   the line of the others (design run of 20.10.2026). */
@media (max-width: 575.98px) {
  .pd-product-row__kind {
    display: table;
    margin-top: 0.25rem;
    margin-left: 0;
  }

  .pd-product-row__link {
    position: relative;
  }

  .pd-product-row__price {
    position: absolute;
    right: 1.25rem;
    bottom: 0.75rem;
  }

  .pd-product-row__link:only-child .pd-product-row__price {
    right: 4rem;
  }
}

/* Between 992 and 1199 px the two topic columns are narrow as well, and the longest name,
   "Arbeitslosengeld-Dauer-Rechner", pushed its label onto a line of its own while every
   other row stayed on one; there every label goes under its name. */
@media (min-width: 992px) and (max-width: 1199.98px) {
  .pd-product-row__kind {
    display: table;
    margin-top: 0.25rem;
    margin-left: 0;
  }
}

.pd-product-row__price {
  flex-shrink: 0;
  font-size: 0.8333333333rem;
  font-weight: 600;
  color: var(--falcon-gray-900, #344050);
  white-space: nowrap;
}

/* 44 px wide and as tall as the row: the touch target of WCAG 2.5.5. */
.pd-product-row__example {
  display: flex;
  flex-shrink: 0;
  align-items: center;
  justify-content: center;
  width: 2.75rem;
  color: var(--falcon-gray-700, #5e6e82);
  text-decoration: none;
}

.pd-product-row__link:focus-visible,
.pd-product-row__example:focus-visible {
  outline: 2px solid var(--falcon-primary);
  outline-offset: -2px;
}

/* The row tint of every link list in the project (hub lists, blog boxes, guide links):
   Falcon's tertiary background, eased in like them (design run of 16.10.2026). */
@media (prefers-reduced-motion: no-preference) {
  .pd-product-row__link,
  .pd-product-row__name,
  .pd-product-row__example {
    transition:
      background-color var(--pd-transition-base),
      color var(--pd-transition-base);
  }
}

@media (hover: hover) {
  .pd-product-row__link:hover {
    background-color: var(--falcon-tertiary-bg);
  }

  .pd-product-row__link:hover .pd-product-row__name,
  .pd-product-row__example:hover {
    color: var(--falcon-primary);
  }
}

/* Footer columns: the headings of Falcon's landing footer, and the pill links of the
   footer lined up with their heading instead of indented by their own padding. */
.pd-footer-heading {
  margin-bottom: 0.5rem;
  font-size: 0.6944444444rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--falcon-gray-900, #344050);
}

/* A column is about 130 px wide at 320 px, and "Kündigungsschutzklage" did not fit:
   the link, an inline-block that does not wrap a single word, pushed every page 9 px
   past the window, at 400 % zoom as well (design run of 16.10.2026). Below 576 px the
   link is held to its column, and a long compound breaks with a hyphen;
   hyphenate-limit-chars keeps short words whole, as .pd-hyphenate does. From 576 px the
   link may run into the gutter as before: held to its column there, "Aufhebungsvertrag"
   broke on the desktop, where it fits. */
.footer-nav .list-unstyled .footer-link {
  margin-left: -0.5rem;
  font-size: 0.8333333333rem;
}

@media (max-width: 575.98px) {
  .footer-nav .list-unstyled .footer-link {
    max-width: 100%;
    -webkit-hyphens: auto;
    hyphens: auto;
    hyphenate-limit-chars: 12 5 5;
    overflow-wrap: anywhere;
  }
}

/* Between 992 and 1199 px the four link columns are narrowest, and the two longest
   compounds, "Nebenkostenabrechnung" and "Kündigungsschutzklage", ran through the whole
   gutter until they touched the next column (measured at 1024 and 1180 px, design run of
   21.10.2026). In that band a word of twenty letters and more is held to its column and
   breaks with a hyphen; shorter ones such as "Aufhebungsvertrag" stay whole, and every
   other width keeps the words whole in the gutter, where they fit. */
@media (min-width: 992px) and (max-width: 1199.98px) {
  .footer-nav .list-unstyled .footer-link {
    max-width: 100%;
    -webkit-hyphens: auto;
    hyphens: auto;
    hyphenate-limit-chars: 20 8 8;
  }
}

/* ------------------------------------------------------------------------------------
   Design system of 15.10.2026: Falcon's own look, carried through every page.
   Colours, radii and shadows are the theme's tokens; the rules below only add the
   compositions Falcon has no class for.
   ------------------------------------------------------------------------------------ */

/* The page header of nearly every page (includes/headline.html): the compact card of
   July 2026 (DES-07), with the padding of every card below it, so the header text starts
   on the same left edge as the content (owner, 20.10.2026: one spacing grid). */
.pd-page-header__body {
  padding: 1.25rem;
}

.pd-page-header__lead {
  color: var(--falcon-gray-700);
  line-height: 1.6;
}

.pd-page-header__meta > li + li::before {
  content: "·";
  margin-right: 0.75rem;
  color: var(--falcon-gray-400);
}

/* Below 992 px the entries wrap, and a separator would open each new line; the icons of
   the entries separate them there. On a phone the words before the values ("Redaktion:",
   "Veröffentlicht:", "Aktualisiert:") stay for screen readers only, so the four entries
   take two lines instead of four (design run of 20.10.2026). */
@media (max-width: 575.98px) {
  .pd-page-header__label {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
  }
}

@media (max-width: 991.98px) {
  .pd-page-header__meta > li + li::before {
    content: none;
  }
}

/* A small capital line above a heading, as Falcon sets section labels. */
.pd-eyebrow {
  font-size: 0.6944444444rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--falcon-primary);
}

.pd-eyebrow a {
  color: inherit;
  text-decoration: none;
}

/* The facts under a tool's lead line (tools/tool.html). */
.pd-facts > li {
  display: inline-flex;
  align-items: center;
  color: var(--falcon-gray-800);
}

/* On a phone the four facts of a tool header stand two by two instead of flowing into
   three ragged lines (design run of 20.10.2026); the d-flex utility it overrides carries
   !important. */
@media (max-width: 575.98px) {
  .pd-facts {
    display: grid !important;
    grid-template-columns: 1fr 1fr;
  }
}

/* The order summary beside the form; it follows the visitor down the form from 1200 px,
   below the sticky top navigation. */
@media (min-width: 1200px) {
  .pd-sticky-aside {
    position: sticky;
    top: calc(var(--falcon-top-nav-height, 4.3125rem) + 1rem);
  }
}

.pd-order-aside__price {
  background-color: var(--falcon-tertiary-bg);
  border: 1px solid var(--falcon-border-color);
}

/* Two lines of a text, the rest cut with an ellipsis. */
.pd-clamp-2 {
  display: -webkit-box;
  overflow: hidden;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
}

/* A quiet note box: the free preview and the lawyer note of the product pages. */
.pd-note {
  padding: 0.75rem 1rem;
  border-radius: var(--falcon-border-radius-lg);
  background-color: var(--falcon-tertiary-bg);
  border: 1px solid var(--falcon-border-color);
}

/* The four product pills of the home hero: one under the other on a phone, two by two
   up to 1539 px and in one row from there. Four pills need about 985 px and the hero
   column offers 784 px between 1200 and 1539 px, where a flex row broke them three and
   one (design run of 20.10.2026). The grid gives the pills of a column one width. */
.pd-hero-products {
  display: grid;
  grid-template-columns: minmax(0, 20rem);
  justify-content: center;
}

/* At 320 px "Arbeitszeugniserstellung" lacked 3 px and broke onto a second line. */
@media (max-width: 575.98px) {
  .pd-hero-products .btn {
    padding-inline: 0.75rem;
  }
}

@media (min-width: 768px) {
  .pd-hero-products {
    grid-template-columns: repeat(2, auto);
  }
}

@media (min-width: 1540px) {
  .pd-hero-products {
    grid-template-columns: repeat(4, auto);
  }
}

/* The verdict of a report is a sentence of up to forty words; at h5 it ran over ten lines
   on a phone and outweighed the summary under it. */
@media (max-width: 575.98px) {
  .pd-verdict__headline {
    font-size: 1rem;
    line-height: 1.4;
  }
}

/* The four trust points under the home hero broke three and one between 576 and 991 px;
   there they stand two by two (design run of 20.10.2026). The d-flex utility it
   overrides carries !important. */
@media (min-width: 576px) and (max-width: 991.98px) {
  .pd-hero-trust {
    display: grid !important;
    grid-template-columns: repeat(2, max-content);
    justify-content: center;
  }
}

/* A checkbox of a tool form brought the bottom margin of its field group on top of the
   row gap, and three one-line options stood as far apart as labelled fields. */
#rechner .mb-3:has(> .form-check) {
  margin-bottom: 0 !important;
}

/* The table of contents of the privacy policy and the terms below 992 px, where the sticky
   column beside the text is hidden: a closed card above the first section that opens on
   tap, without script (design run of 20.10.2026). */
.pd-toc > summary {
  cursor: pointer;
  list-style: none;
}

.pd-toc > summary::-webkit-details-marker {
  display: none;
}

.pd-toc:not([open]) > summary {
  border-bottom: 0;
}

.pd-toc[open] > summary .fa-chevron-down {
  transform: rotate(180deg);
}

/* Questions and answers as Falcon sets them in its FAQ pages: the question in the heading
   face and colour, the answer in body text, a hairline between them. */
.pd-faq__item {
  padding: 1rem 0;
  border-bottom: 1px solid var(--falcon-border-color);
}

.pd-faq__item:first-child {
  padding-top: 0;
}

.pd-faq__item:last-child {
  padding-bottom: 0;
  border-bottom: 0;
}

.pd-faq__question {
  margin-bottom: 0.4rem;
  font-size: 1rem;
  font-weight: 600;
  line-height: 1.45;
}

.pd-faq__answer {
  margin-bottom: 0;
  font-size: 0.8333333333rem;
  line-height: 1.65;
}

/* The purchase card of an unpaid report (products/ctas/activation.html): the right half
   is a tinted panel, divided from the benefits by a hairline once the two halves stand
   side by side. That happens at Falcon's xxl breakpoint, 1540 px (col-xxl-7/-5); the
   rule switched at 1400 px until 16.10.2026, so between 1400 and 1539 px the stacked
   panel lost its top rule (design run). */
.pd-activation__panel {
  background-color: var(--falcon-tertiary-bg);
  border-top: 1px solid var(--falcon-border-color);
}

@media (min-width: 1540px) {
  .pd-activation__panel {
    border-top: 0;
    border-left: 1px solid var(--falcon-border-color);
  }
}

/* Below 1540 px the panel runs the full card width; its price, button and notes keep
   the width of a purchase box instead of stretching across it. */
.pd-activation__panel > .card-body > * {
  width: 100%;
  max-width: 30rem;
  margin-left: auto;
  margin-right: auto;
}

/* From 1540 px the panel is about 380 px wide and the fixed button text broke as
   "Zahlungspflichtig für 24,99 € / freischalten", the verb alone on the second line.
   Balanced lines keep the wording and split it evenly (design run of 16.10.2026). */
.pd-activation__panel .btn-lg {
  text-wrap: balance;
}

.pd-activation__price {
  font-family: var(--falcon-font-sans-serif);
  font-size: 2.0736rem;
  font-weight: 600;
  line-height: 1.1;
  color: var(--falcon-gray-1000);
  font-variant-numeric: tabular-nums;
}

/* The guarantee line of the purchase card: a shield tile beside its text. */
.pd-guarantee {
  display: flex;
  align-items: flex-start;
  gap: 1rem;
  padding: 1rem;
  border-radius: var(--falcon-border-radius-lg);
  background-color: rgba(var(--falcon-success-rgb), 0.06);
  border: 1px solid rgba(var(--falcon-success-rgb), 0.2);
}

/* The article list of a blog category overview: one card, rows divided by hairlines
   like Falcon's list groups, two columns from 768 px. The whole row is the link
   (stretched-link), the row tints on hover. */
.pd-hub-list__item {
  border-bottom: 1px solid var(--falcon-border-color);
}

/* The last row of the list, and from 768 px the last row of each of its two columns,
   carries no rule under it: the card's edge already closes the list. */
.pd-hub-list__item:last-child {
  border-bottom: 0;
}

@media (min-width: 768px) {
  .pd-hub-list__item:nth-child(odd):nth-last-child(2) {
    border-bottom: 0;
  }
}

/* Hover and transition behind the two gates every other hover in this file passes:
   (hover: hover) and prefers-reduced-motion: no-preference (design run of 16.10.2026). */
@media (prefers-reduced-motion: no-preference) {
  .pd-hub-list__item .pd-overview-row {
    transition: background-color var(--pd-transition-base);
  }
}

@media (hover: hover) {
  .pd-hub-list__item .pd-overview-row:hover {
    background-color: var(--falcon-tertiary-bg);
  }
}

/* The last item of an odd list stands alone in its row: no rule beside its empty half
   (one tool in a topic of the tool overview, design run of 16.10.2026). */
@media (min-width: 768px) {
  .pd-hub-list__item:nth-child(odd):not(:last-child) {
    border-right: 1px solid var(--falcon-border-color);
  }
}

/* On a phone the one header set at h3 size, the purchase confirmation
   (products/purchase.html), steps down to 1.375rem. Every other header is an h5 and
   needs no rule. */
@media (max-width: 575.98px) {
  .pd-page-header__body h1.h3 {
    font-size: 1.375rem;
  }
}

/* The product box of every blog article (includes/blog_cta.html): the category's pitch
   on a tinted panel, its products as hairline rows beside it. */
.pd-blog-cta__intro {
  background-color: var(--falcon-tertiary-bg);
  border-bottom: 1px solid var(--falcon-border-color);
}

@media (min-width: 992px) {
  .pd-blog-cta__intro {
    border-bottom: 0;
    border-right: 1px solid var(--falcon-border-color);
  }
}

.pd-blog-cta__item + .pd-blog-cta__item {
  border-top: 1px solid var(--falcon-border-color);
}

/* On a phone the icon tile left a text column of about 145 px, and names such as
   "Arbeitszeugnisanalyse" broke in the middle of the word; the row drops the decorative
   tile there and hyphenates (design run of 20.10.2026). */
@media (max-width: 575.98px) {
  .pd-blog-cta__link > .icon-item {
    display: none;
  }

  .pd-blog-cta__link {
    -webkit-hyphens: auto;
    hyphens: auto;
  }
}

@media (prefers-reduced-motion: no-preference) {
  .pd-blog-cta__link {
    transition: background-color var(--pd-transition-base);
  }
}

@media (hover: hover) {
  .pd-blog-cta__link:hover {
    background-color: var(--falcon-tertiary-bg);
  }
}

/* The free tools (templates/tools/tool.html): the main figure of a result on a tinted
   panel, its lines as label and value pairs divided by hairlines, and the next steps as
   three equal columns. A generated letter is drawn on the .pd-paper sheet the created
   documents of the reports use (design run of 16.10.2026). */
.pd-tool-result {
  background-color: var(--falcon-tertiary-bg);
  border: 1px solid var(--falcon-border-color);
}

.pd-tool-result__value {
  font-family: var(--falcon-font-sans-serif);
  font-size: 1.728rem;
  font-weight: 600;
  line-height: 1.2;
  color: var(--falcon-gray-1000);
}

/* A copy button that has just copied turns green and shows a check in place of its copy
   symbol for the 2.5 s its label says "kopiert" (custom.js sets .pd-copied). */
.btn.pd-copied {
  color: var(--falcon-success) !important;
}

.pd-copied > .fa-copy::before {
  content: "\f00c";
}

@media (prefers-reduced-motion: no-preference) {
  .pd-copied > .fa-copy {
    animation: pd-pop var(--pd-transition-slow) ease-out;
  }
}

/* Button rows that sit side by side where they fit. A row's width depends on the page (a
   narrow column on the thanks page, the full report width elsewhere), so a container query
   on .pd-cq rather than the viewport decides between a button's long and short label. The
   long label stays readable to a screen reader when it is hidden; the short one is
   aria-hidden and may be absent, which leaves the icon alone. */
.pd-cq {
  container-type: inline-size;
}

.pd-label-short {
  display: none;
}

@container (max-width: 44.999rem) {
  .pd-label-long {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
  }

  .pd-label-short {
    display: inline;
  }

  .pd-report-link .fa-envelope {
    margin-inline-end: 0 !important;
  }
}

/* The same pair for a single button that only runs out of room in a phone-wide form,
   such as "Weitere Angaben machen (freiwillig)": its own container and a far smaller
   threshold, so a tablet still shows the full label. */
.pd-cq-xs {
  container-type: inline-size;
}

.pd-label-short-xs {
  display: none;
}

@container (max-width: 21.999rem) {
  .pd-label-long-xs {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
  }

  .pd-label-short-xs {
    display: inline;
  }
}

/* The icon tile that opens a banner alert (example report, payment state, deadlines)
   takes 56 px of a phone's width with its margin and squeezed the sentence beside it
   into a narrow column. On a phone it shrinks to 28 px; colour and glyph keep the
   meaning, and the text gains a fifth of the line. */
@media (max-width: 575.98px) {
  .alert.d-flex > .icon-item:first-child {
    width: 1.75rem;
    height: 1.75rem;
    margin-right: 0.625rem !important;
  }

  .alert.d-flex > .icon-item:first-child > .fas {
    font-size: 0.8333rem !important;
  }
}

/* The ways back of a status page (404, 500, expired report, failure) sit side by side
   where they fit; on a phone, where they wrap anyway, each fills its row, so the stack
   reads as one column of equal buttons instead of three centred widths. */
@media (max-width: 575.98px) {
  .pd-actions > .btn {
    flex: 1 1 auto;
    padding-inline: 0.5rem;
  }
}

/* On the narrowest phones (below 360 px, the first iPhone SE) button labels step down by
   a size, so "Arbeitszeugnis prüfen lassen" and its siblings keep one line. */
@media (max-width: 359.98px) {
  .btn {
    font-size: 0.875rem;
  }

  .btn-sm {
    font-size: 0.8125rem;
  }
}

/* A full-width button on a phone needs no side padding of its own: the width already
   frames it, and Falcon's 1rem a side pushed labels such as "Kündigungsschreiben
   erstellen" onto a second line. */
@media (max-width: 575.98px) {
  .btn.w-100 {
    padding-inline: 0.5rem;
  }
}

/* The report-link card keeps field, copy and mail on one row; the field gives way first. */
.pd-report-link .input-group {
  flex-wrap: nowrap;
}

.pd-report-link .input-group > .form-control {
  min-width: 6rem;
}

/* The step indicator of the thanks page: done steps carry a green check, the running one
   its spinner and the heading colour, the open one a pale ring. */
.pd-thanks-steps__item {
  color: var(--falcon-gray-700);
  white-space: nowrap;
}

.pd-thanks-steps__item--active {
  font-weight: 600;
  color: var(--falcon-gray-1000);
}

/* On a phone the three steps stand as three columns, the symbol above its label, instead
   of breaking two and one. The flex and margin utilities they override carry !important. */
@media (max-width: 575.98px) {
  .pd-thanks-steps {
    display: grid !important;
    grid-template-columns: repeat(3, 1fr);
  }

  .pd-thanks-steps__item {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.25rem;
    white-space: normal;
  }

  .pd-thanks-steps__item > [class*="fa-"] {
    margin-right: 0 !important;
    font-size: 1rem;
  }
}

@media (prefers-reduced-motion: no-preference) {
  .pd-thanks-steps {
    animation: pd-fade-in var(--pd-transition-slow) 0.1s both;
  }
}

/* A figure that counts up keeps the width of its digits, so it does not jitter while it
   runs (custom.js initializeCountUp). */
.pd-tool-result__value,
[data-pd-countup] {
  font-variant-numeric: tabular-nums;
}

/* A fresh result comes in with a short fade instead of standing there at once. */
@media (prefers-reduced-motion: no-preference) {
  .pd-tool-result {
    animation: pd-fade-in var(--pd-transition-slow) both;
  }
}

.pd-tool-rows__item {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  column-gap: 1rem;
  padding: 0.5rem 0;
  border-bottom: 1px solid var(--falcon-border-color);
}

.pd-tool-rows__item > dd:first-of-type {
  text-align: right;
}

.pd-tool-rows__note {
  grid-column: 1 / -1;
}

.pd-tool-step {
  border-bottom: 1px solid var(--falcon-border-color);
}

/* In three columns of about 200 px (768 to 991 px) "Aufhebungsvertragsanalyse" ran past
   the card; the step names hyphenate on every width (design run of 20.10.2026). */
.pd-tool-step .pd-hyphenate {
  -webkit-hyphens: auto;
  hyphens: auto;
}

@media (min-width: 768px) {
  .pd-tool-step {
    border-bottom: 0;
  }

  .pd-tool-step + .pd-tool-step {
    border-left: 1px solid var(--falcon-border-color);
  }
}

/* ------------------------------------------------------------------------------------
   Motion of the July design (owner, 20.10.2026, DES-13): cards rise into view as the
   page scrolls, the home hero fades in once, and lifted surfaces answer the pointer.
   Everything waits for prefers-reduced-motion: no-preference, and every element rests
   fully visible: the scroll-driven rise needs animation-timeline, which Firefox does
   not implement yet, so there the cards simply stand. A card already in view at load is
   drawn complete once 30 % of it has entered; one cut by the bottom edge of the first
   screen shows part of the rise until the page is scrolled.
   ------------------------------------------------------------------------------------ */
@keyframes pd-rise {
  from {
    opacity: 0.001;
    transform: translateY(1rem);
  }

  to {
    opacity: 1;
    transform: none;
  }
}

@keyframes pd-sheen {
  from {
    background-position: 0% 50%;
  }

  to {
    background-position: 100% 50%;
  }
}

@keyframes pd-fade-in {
  from {
    opacity: 0.001;
    transform: translateY(0.5rem);
  }

  to {
    opacity: 1;
    transform: none;
  }
}

@media screen and (prefers-reduced-motion: no-preference) {
  @supports (animation-timeline: view()) {
    #content > .card,
    #content > article > .card,
    #content > .row > [class*="col"] > .card,
    #content > section > .row > [class*="col"] > .card,
    #content > section.row > [class*="col"] > .card,
    .pd-topic-grid__item > .card {
      animation: pd-rise linear both;
      animation-timeline: view();
      animation-range: entry 0% entry 30%;
    }

    /* The icon of a signal card or tile pops in a moment after its card has risen. */
    .pd-signal-icon,
    .pd-signal-tile .fas {
      animation: pd-pop linear both;
      animation-timeline: view();
      animation-range: entry 20% entry 70%;
    }
  }

  /* The gradient of the headline's verbs wanders slowly across them and back. */
  .pd-hero-accent {
    animation: pd-sheen 8s ease-in-out infinite alternate;
  }

  .pd-hero-title,
  section[aria-labelledby="home-hero-heading"] .col-xl-10 > p,
  .pd-hero-products,
  .pd-topic-picker {
    animation: pd-fade-in var(--pd-transition-slow) both;
  }

  section[aria-labelledby="home-hero-heading"] .col-xl-10 > p {
    animation-delay: 0.08s;
  }

  .pd-hero-products {
    animation-delay: 0.16s;
  }

  .pd-topic-picker {
    animation-delay: 0.24s;
  }

  /* Every other page opens the same way: the lines of its header card (eyebrow, title,
     lead, byline) fade in one after the other, as the home hero does. */
  .pd-page-header__body > * {
    animation: pd-fade-in var(--pd-transition-slow) both;
  }

  .pd-page-header__body > :nth-child(2) {
    animation-delay: 0.06s;
  }

  .pd-page-header__body > :nth-child(3) {
    animation-delay: 0.12s;
  }

  .pd-page-header__body > :nth-child(n + 4) {
    animation-delay: 0.18s;
  }
}

/* The hero pills and the topic tiles lift a little under the pointer, the one elevation
   step Falcon uses for hover (its box-shadow). The stat cards are not links and stay
   still. Behind (hover: hover), so a tap leaves no stuck state, and behind no-preference
   for the movement. */
@media (hover: hover) and (prefers-reduced-motion: no-preference) {
  .pd-hero-products .btn,
  .pd-topic-tile {
    transition:
      color var(--pd-transition-base),
      transform var(--pd-transition-base),
      box-shadow var(--pd-transition-base);
  }

  .pd-hero-products .btn:hover,
  .pd-topic-tile:hover {
    transform: translateY(-2px);
    box-shadow: var(--falcon-box-shadow);
  }
}

/* Interaction polish (owner, 20.10.2026): every control answers the pointer the same way.
   Filled buttons lift by a pixel with Falcon's small shadow, outlined Falcon buttons lift
   without changing their own ring shadow, and rows that link somewhere take the tinted
   surface. Pressing returns a button to its place. Behind (hover: hover) and the
   no-preference query like the rest of the motion. */
@media (hover: hover) and (prefers-reduced-motion: no-preference) {
  #content :is(.btn-primary, .btn-info, .btn-success, .btn-warning, .btn-danger, .btn-secondary),
  #content [class*="btn-falcon-"] {
    transition:
      color var(--pd-transition-base),
      background-color var(--pd-transition-base),
      border-color var(--pd-transition-base),
      box-shadow var(--pd-transition-base),
      transform var(--pd-transition-base);
  }

  #content
    :is(.btn-primary, .btn-info, .btn-success, .btn-warning, .btn-danger, .btn-secondary):not(
      .disabled,
      :disabled
    ):hover {
    transform: translateY(-1px);
    box-shadow: var(--falcon-box-shadow-sm);
  }

  #content [class*="btn-falcon-"]:not(.disabled, :disabled):hover {
    transform: translateY(-1px);
  }

  #content .btn:active {
    transform: none;
  }

  .pd-product-row__link:hover {
    background-color: var(--falcon-tertiary-bg);
  }
}

/* The top bar turns to frosted glass once the page scrolls (Falcon adds
   .navbar-glass-shadow then): the content passes under it blurred instead of being cut
   by an opaque band. Only where backdrop-filter works; elsewhere Falcon's own surface
   stays. */
@supports (backdrop-filter: blur(1px)) {
  .navbar-top.navbar-glass-shadow {
    background-color: color-mix(in srgb, var(--falcon-bg-navbar-glass) 78%, transparent);
    -webkit-backdrop-filter: saturate(180%) blur(10px);
    backdrop-filter: saturate(180%) blur(10px);
  }
}

@keyframes pd-slide-up {
  from {
    transform: translateY(100%);
  }

  to {
    transform: none;
  }
}

@keyframes pd-drift {
  0%,
  100% {
    transform: translate3d(0, 0, 0);
  }

  50% {
    transform: translate3d(0, -0.5rem, 0);
  }
}

@media screen and (prefers-reduced-motion: no-preference) {
  .navbar-top {
    transition:
      box-shadow var(--pd-transition-base),
      background-color var(--pd-transition-base);
  }

  /* The purchase bars come up from the bottom edge instead of appearing at once. */
  .pd-sticky-cta,
  .sticky-cta-bar {
    animation: pd-slide-up var(--pd-transition-slow) ease-out both;
  }

  /* The corner illustration behind the home hero drifts slowly, a quiet sign of life
     that never draws the eye from the text. */
  section[aria-labelledby="home-hero-heading"] > .bg-holder {
    animation: pd-drift 14s ease-in-out infinite;
  }

  /* The large code of the error pages floats the same way, a little faster. */
  .pd-error-code {
    animation: pd-drift 6s ease-in-out infinite;
  }
}

/* An arrow in a link or button moves a few pixels in its own direction under the pointer,
   the cue that the control leads somewhere. The rows that animate their arrow already
   (.pd-ratgeber-arrow, .related-article-arrow) keep their own rules. */
@media (hover: hover) and (prefers-reduced-motion: no-preference) {
  :is(a, .btn) > .fa-arrow-right,
  :is(a, .btn) > .fa-arrow-down {
    transition: transform var(--pd-transition-base);
  }

  :is(a, .btn):hover > .fa-arrow-right {
    transform: translateX(3px);
  }

  :is(a, .btn):hover > .fa-arrow-down {
    transform: translateY(2px);
  }

  /* A card that leads somewhere as a whole lifts like the topic tiles. */
  .pd-lift {
    transition:
      transform var(--pd-transition-base),
      box-shadow var(--pd-transition-base);
  }

  .pd-lift:hover {
    transform: translateY(-2px);
    box-shadow: var(--falcon-box-shadow-lg, var(--falcon-box-shadow));
  }
}

/* The menus of the top bar open with a short fade and drop instead of appearing at once,
   and the plus of a fold button turns into a cross while its part stands open. */
@media (prefers-reduced-motion: no-preference) {
  .navbar-top .dropdown-menu.show {
    animation: pd-fade-in var(--pd-transition-base) both;
  }

  [data-bs-toggle="collapse"] > .fa-plus {
    transition: transform var(--pd-transition-base);
  }
}

[data-bs-toggle="collapse"][aria-expanded="true"] > .fa-plus {
  transform: rotate(45deg);
}

/* A thin bar along the top edge of an article fills as the reader scrolls. It is driven
   by the scroll position itself (animation-timeline: scroll()), so it costs no script;
   where the browser lacks scroll timelines, Firefox today, the bar stays hidden. */
.pd-reading-progress {
  display: none;
}

@keyframes pd-progress {
  to {
    transform: scaleX(1);
  }
}

@supports (animation-timeline: scroll()) {
  .pd-reading-progress {
    position: fixed;
    top: 0;
    left: 0;
    z-index: 1031;
    display: block;
    width: 100%;
    height: 3px;
    background-color: var(--falcon-primary);
    transform: scaleX(0);
    transform-origin: 0 50%;
    pointer-events: none;
    animation: pd-progress linear both;
    animation-timeline: scroll(root block);
  }
}

@media print {
  .pd-reading-progress {
    display: none !important;
  }
}

/* The topic cards of the home page and /leistungen/ as two balanced columns from 992 px:
   a topic with three products no longer stands as tall as its neighbour with nine, with
   white space under its rows (DES-12). Reading order runs down the first column. */
/*
 * The topic cards: two columns of about equal height from 992 px, balanced on the
 * server (products.views.topic_columns). Below that the columns dissolve and each card
 * takes its place in the topic order again from its inline order.
 */
.pd-topic-grid {
  display: flex;
  flex-direction: column;
}

.pd-topic-grid__col {
  display: contents;
}

.pd-topic-grid__item {
  margin-bottom: 1rem;
}

@media (min-width: 992px) {
  .pd-topic-grid {
    flex-direction: row;
    align-items: flex-start;
    gap: 1rem;
  }

  .pd-topic-grid__col {
    display: block;
    flex: 1 1 0;
    min-width: 0;
  }
}

/* A card inside a card body, the product box of an article above all, draws no second
   shadow: it is set off by a hairline, as Falcon nests panels (DES-14). */
#content .card .card-body .card {
  box-shadow: none;
  border: 1px solid var(--falcon-border-color);
}

/* On reading pages the FAQ answers keep the size of the text they close; .pd-prose marks
   the same on a page that is not a reading page as a whole (the blog overview). */
:is(body.is-blog-article, body.is-legal-page, body.pd-reading, .pd-prose) .pd-faq__answer {
  font-size: 1rem;
  line-height: 1.7;
}

/* A testimonial: a large quotation mark set faintly into the top corner, the kind badge
   and the quote left-aligned, the author under a hairline as on a signed letter. */
.pd-quote-card {
  position: relative;
  overflow: hidden;
}

.pd-quote-card::after {
  content: "\f10e";
  position: absolute;
  top: 0.75rem;
  right: 1rem;
  font-family: "Font Awesome 5 Free";
  font-weight: 900;
  font-size: 2.25rem;
  line-height: 1;
  color: rgba(var(--falcon-primary-rgb), 0.12);
  pointer-events: none;
}

/* The "Nach oben" button (custom.js initializeBackToTop): a round primary button in the
   bottom right corner that fades and rises in once a long page is scrolled. Hidden, it
   takes no clicks and no focus. */
.pd-to-top {
  position: fixed;
  right: 1rem;
  bottom: 1rem;
  z-index: 1020;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.75rem;
  height: 2.75rem;
  border: 0;
  border-radius: 50%;
  color: #fff;
  background-color: var(--falcon-primary);
  box-shadow: var(--falcon-box-shadow);
  opacity: 0;
  visibility: hidden;
  transform: translateY(0.5rem);
}

.pd-to-top--shown {
  opacity: 1;
  visibility: visible;
  transform: none;
}

/* Scrolled to the end, the button sat on the footer's last line and covered the
   "Cookies" button wherever the page is narrower than its container plus the button,
   from the phone up to 1280 px and again just above 1540 px (design run of 21.10.2026).
   The reserve lifts that line above the button's 3.75 rem. A product page's bar at the
   bottom edge exists below 992 px only: there the bar takes the button's place and
   keeps its own, larger reserve; from 992 px, and where the bar joins the page flow,
   the page has the button like any other. */
body:has(> .pd-to-top):not(:has(.sticky-cta-bar)) .content {
  --pd-content-pad-bottom: 3rem;
}

@media (min-width: 992px) {
  body:has(> .pd-to-top) .content {
    --pd-content-pad-bottom: 3rem;
  }
}

@media (max-width: 991.98px) and (min-height: 450.02px) {
  body:has(.sticky-cta-bar) > .pd-to-top {
    display: none;
  }
}

/* Up to 450 px of height the product page's bar stands in the page flow (see the bars
   above), so the button returns there and brings its reserve along. */
@media (max-height: 450px) {
  body:has(> .pd-to-top) .content {
    --pd-content-pad-bottom: 3rem;
  }
}

.pd-to-top:hover {
  background-color: color-mix(in srgb, var(--falcon-primary) 85%, #000);
}

.pd-to-top:focus-visible {
  outline: 2px solid var(--falcon-primary);
  outline-offset: 3px;
}

@media (prefers-reduced-motion: no-preference) {
  .pd-to-top {
    transition:
      opacity var(--pd-transition-base),
      transform var(--pd-transition-base),
      visibility var(--pd-transition-base),
      background-color var(--pd-transition-base);
  }
}

@media print {
  .pd-to-top {
    display: none;
  }
}

/* The reading progress of a blog article: a thin primary line along the top edge of the
   window that grows with the scroll position. Drawn only where scroll-driven animation
   exists; elsewhere the article simply has none. */
@supports (animation-timeline: scroll()) {
  body.is-blog-article::after {
    content: "";
    position: fixed;
    top: 0;
    left: 0;
    z-index: 1031;
    width: 100%;
    height: 3px;
    background-image: linear-gradient(90deg, var(--falcon-primary), var(--falcon-info));
    transform-origin: 0 50%;
    animation: pd-read-progress linear both;
    animation-timeline: scroll(root);
    pointer-events: none;
  }

  @keyframes pd-read-progress {
    from {
      transform: scaleX(0);
    }

    to {
      transform: scaleX(1);
    }
  }
}

@media print {
  body.is-blog-article::after {
    display: none;
  }
}

/* Conversion of the product forms (20.10.2026, docs/decision-log.md FORM-06 to FORM-10).
   The fixed jump bar under a form page slides away while the form is on screen
   (custom.js, initializeStickyFormBar), so it never covers the consents or the submit
   button. The promises beside the submit button sit in one column on a phone and beside
   the button from 992 px up, on the button's centre line. */
.sticky-cta-bar {
  transition:
    transform var(--pd-transition-base),
    visibility var(--pd-transition-base);
}

.sticky-cta-bar.pd-sticky-cta-bar--hidden {
  transform: translateY(110%);
  visibility: hidden;
}

@media (prefers-reduced-motion: reduce) {
  .sticky-cta-bar {
    transition: none;
  }
}

.pd-form-trust li {
  line-height: 1.35;
}
