/**
 * 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 and hover shadows Falcon has no token
   for, and the transition durations. Brand colours are Falcon's own variables. */
:root {
  --light-bg: #ffffff;

  /* 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. */
  --pd-shadow-sticky: 0 -4px 16px rgba(20, 30, 60, 0.08);
  --pd-shadow-sticky-dark: 0 -4px 16px rgba(0, 0, 0, 0.5);

  /* Hover lift of the related-article cards, in the same shape and for the same
     reason as the sticky pair above: an 8 % black shadow is invisible on the
     near-black dark-mode card, so the light and the dark value are two distinct
     shadows rather than one. Written out as a pair here so darkening one and
     forgetting the other is not possible — which is exactly the drift the comment
     on the sticky tokens warns about, and which these two values were still open
     to. */
  --pd-shadow-card-hover: 0 4px 12px rgba(0, 0, 0, 0.08);
  --pd-shadow-card-hover-dark: 0 4px 12px rgba(0, 0, 0, 0.45);

  /* 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 .demo-image-hover-* animated the
     exact same three properties as .related-article-card — transform, box-shadow,
     border-color — 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;
}

/* 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.2rem 0.55rem;
  border-radius: var(--falcon-border-radius-lg);
  /* Fallback is #5e6e82, the value this file measures at 5.21:1 further down and the
     one the second --falcon-gray-700 fallback already carried. The #4d5969 that stood
     here was 8.4 % off and backed by no measurement in this project: 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);
}

/* 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 the corrected link colour: the brand blue on its 8 % tint measured 3.36:1
   in light and 4.35:1 in dark mode (design run of 10.10.2026). */
.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, #344050);
  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 native file selector button in the brand fill, like Falcon's buttons. */
input[type="file"]::file-selector-button {
  background-color: var(--falcon-primary) !important;
  color: #fff !important;
}

/* 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. Its own button colours stay: the brand primary would put white text at about
   4:1, below the 4.5:1 WCAG AA asks for. */
#cc-main {
  --cc-z-index: 1045;
  --cc-font-family: var(--falcon-body-font-family);
}

/* 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;
}

/* Highlight active navigation links with primary brand color. */
.navbar-top .navbar-nav .nav-link.active {
  color: var(--falcon-primary) !important;
}

/* Apply hover and focus states to navigation links for better interactivity. */
.navbar-top .navbar-nav .nav-link.text-body:hover,
.navbar-top .navbar-nav .nav-link.text-body:focus {
  color: var(--falcon-nav-link-hover-color) !important;
}

/* Apply pulse animations to CTA buttons for visual emphasis and user attention. */
/* Both variants are 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-info {
    animation: pulse-info-animation 2s 2;
  }
}

/* Pulse keyframes for the primary 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);
}

/* Pulse keyframes for the info CTA: scales up and emits a fading ring using the Falcon info RGB token. */
@keyframes pulse-info-animation {
  0% {
    transform: scale(1);
    box-shadow: 0 0 0 0 rgba(var(--falcon-info-rgb), 0.7);
  }

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

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

/* Demo image hover effect for primary-colored product GIFs. */
.demo-image-hover-primary {
  cursor: pointer;
}

/* Demo image hover effect for warning-colored product GIFs. */
.demo-image-hover-warning {
  cursor: pointer;
}

/* Apply hover transitions and transforms only when:
 *   1. the user has no motion preference (WCAG 2.3.3), AND
 *   2. the primary pointer is a real hover-capable device (mouse/trackpad).
 * On touch screens the :hover state stays "stuck" after a tap until the user
 * taps elsewhere, leaving the demo image visibly scaled — wrapping in
 * @media (hover: hover) suppresses that on phones and tablets. */
@media (prefers-reduced-motion: no-preference) and (hover: hover) {
  .demo-image-hover-primary {
    transition:
      transform var(--pd-transition-base),
      box-shadow var(--pd-transition-base),
      border-color var(--pd-transition-base);
  }

  .demo-image-hover-primary:hover {
    transform: scale(1.02) translateY(-2px);
    box-shadow: 0 12px 30px rgba(var(--falcon-primary-rgb), 0.2);
    border-color: var(--falcon-primary) !important;
  }

  .demo-image-hover-warning {
    transition:
      transform var(--pd-transition-base),
      box-shadow var(--pd-transition-base),
      border-color var(--pd-transition-base);
  }

  .demo-image-hover-warning:hover {
    transform: scale(1.02) translateY(-2px);
    box-shadow: 0 12px 30px rgba(var(--falcon-warning-rgb), 0.2);
    border-color: var(--falcon-warning) !important;
  }
}

/* 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;
  }
}

/* Hide Django-Daisy SVG icons in checkbox labels to maintain classic checkbox appearance. */
.toggle svg {
  display: none !important;
}

/* Ensure toggle labels do not create unwanted spacing or layout shifts. */
/* Using display:contents makes the toggle wrapper invisible to layout while keeping its children. */
.toggle {
  padding: 0 !important;
  margin: 0 !important;
  display: contents !important;
}

/* Reset toggle label styling to prevent DaisyUI interference with checkbox layout. */
.toggle::before,
.toggle::after {
  content: none !important;
  display: none !important;
}

/* Maintain proper alignment for checkboxes without toggle styling effects. */
.form-check .toggle {
  background: none !important;
  border: none !important;
  width: auto !important;
  height: auto !important;
}

/* Force checkbox and label side-by-side alignment on all screen sizes. */
.form-switch .form-check {
  display: flex !important;
  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;
}

/* Ensure the label text flows naturally beside the checkbox. */
.form-switch .form-check .form-check-label {
  margin-left: 0.5rem;
}

/* 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). It takes its own
   line, 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. The label 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 {
  flex-wrap: wrap;
}

.form-switch .form-check .form-check-label {
  flex: 1 1 0;
  min-width: 0;
}

.form-switch .form-check > .form-text {
  flex-basis: 100%;
  margin-left: calc(2.6667em + 0.5rem);
}

/* Shared base styles for product demo videos in CTA sections, to avoid inline style repetition. */
/* The explicit aspect-ratio reserves the box before anything is loaded. With             */
/* preload="none" the width/height attributes alone did not: Chrome treated the <video>   */
/* as unsized until its poster arrived, and the box then grew and pushed the cards below  */
/* it down (CLS 0.25 on a throttled mobile trace of the pillar article, 23.09.2026). All  */
/* three posters and videos are 960 x 600, hence 16 / 10.                                 */
.demo-video {
  border-width: 2px !important;
  width: 100%;
  height: auto;
  max-width: 100%;
  aspect-ratio: 16 / 10;
}

/* Primary-colored gradient background for analysis product demo videos. */
/* The light endpoint uses the Falcon emphasis-bg token (the card surface, white in light */
/* mode, dark navy in dark mode) so the wash adapts to the active theme instead of staying */
/* white. In light mode --falcon-emphasis-bg-rgb is 255,255,255, preserving the original look. */
.demo-video-primary {
  background: linear-gradient(
    135deg,
    rgba(var(--falcon-primary-rgb), 0.05) 0%,
    rgba(var(--falcon-emphasis-bg-rgb), 0.95) 100%
  );
}

/* Warning-colored gradient background for termination product demo videos. */
/* Same theme-aware light endpoint as .demo-video-primary (see note above). */
.demo-video-warning {
  background: linear-gradient(
    135deg,
    rgba(var(--falcon-warning-rgb), 0.05) 0%,
    rgba(var(--falcon-emphasis-bg-rgb), 0.95) 100%
  );
}

/* 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;
    background: var(--falcon-body-bg);
    border-top: 1px solid var(--falcon-border-color);
    padding: 0.75rem 1rem;
    box-shadow: var(--pd-shadow-sticky);
  }

  /* Stronger upward shadow in dark mode to keep the bar visually separated from the dark page. */
  [data-bs-theme="dark"] .sticky-cta-bar {
    box-shadow: var(--pd-shadow-sticky-dark);
  }

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

/* Related articles section styling for consistent visual integration with blog content. */
.related-articles {
  border-top: 1px solid var(--falcon-border-color);
}

/* Related articles header styling matching article heading conventions. */
.related-articles-header {
  padding-bottom: 0.75rem;
  border-bottom: 1px solid var(--falcon-border-color);
}

/* Related article card hover and transition effects for interactive feedback. */
/* Respects prefers-reduced-motion (WCAG 2.3.3) and is gated behind hover: hover so the */
/* effect does not stick on touch devices after a tap. */
@media (prefers-reduced-motion: no-preference) and (hover: hover) {
  .related-article-card {
    transition:
      transform var(--pd-transition-base),
      box-shadow var(--pd-transition-base),
      border-color var(--pd-transition-base);
  }

  .related-article-card:hover,
  .related-article-card:focus-within {
    transform: translateY(-2px);
    box-shadow: var(--pd-shadow-card-hover);
    border-color: var(--falcon-primary) !important;
  }

  /* An 8 % black shadow is invisible on the near-black dark-mode card background, */
  /* so the hover lift loses its depth cue. Matches the sticky-bar override above. */
  [data-bs-theme="dark"] .related-article-card:hover,
  [data-bs-theme="dark"] .related-article-card:focus-within {
    box-shadow: var(--pd-shadow-card-hover-dark);
  }

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

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

  /* The arrow slides and takes the card's brand colour on hover. */
  .related-article-card:hover .related-article-arrow {
    transform: translateX(3px);
    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.6rem;
  padding: 0.35rem 0.55rem;
  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;
}

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

/* 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;
}

.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);
}

/* Hover affordances are gated behind hover-capable pointers and motion preference */
/* so the tint and arrow slide never stick after a tap on touch devices (WCAG 2.3.3). */
@media (prefers-reduced-motion: no-preference) and (hover: hover) {
  .pd-ratgeber-link {
    transition: background-color var(--pd-transition-base);
  }

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

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

  .pd-ratgeber-link:hover .pd-ratgeber-arrow {
    transform: translateX(3px);
    color: var(--falcon-primary) !important;
  }

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

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

/* Reporting improvement block: green-tinted highlight for AI-suggested rewrites and for
   the next step of a finding. */
.pd-improvement-block {
  margin-top: 0.75rem;
  padding: 0.75rem 0.875rem;
  background: rgba(var(--falcon-success-rgb), 0.08);
  border-left: 3px solid var(--falcon-success);
  border-radius: var(--falcon-border-radius-lg);
}

/* Slightly stronger green tint in dark mode so the success accent stays readable on a dark surface. */
[data-bs-theme="dark"] .pd-improvement-block {
  background: rgba(var(--falcon-success-rgb), 0.14);
}

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

/* Footnote markers keep a floor, because their relative shrink compounds.
   The six <sup> in the project are the footnote pair of the three activation CTAs,
   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. */
:is(body.is-blog-article, body.is-legal-page, body.pd-reading, .pd-prose) .card-body > p,
:is(body.is-blog-article, body.is-legal-page, body.pd-reading, .pd-prose) .card-body > ul,
:is(body.is-blog-article, body.is-legal-page, body.pd-reading, .pd-prose) .card-body > ol {
  line-height: 1.75;
}

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

:is(body.is-blog-article, body.is-legal-page, body.pd-reading, .pd-prose) .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
  > :is(h2, h3):first-child {
  margin-top: 0;
}

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

:is(body.is-blog-article, body.is-legal-page, body.pd-reading, .pd-prose) .card-body > ul li + li,
:is(body.is-blog-article, body.is-legal-page, body.pd-reading, .pd-prose) .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
  > ul
  > li::marker,
:is(body.is-blog-article, body.is-legal-page, body.pd-reading, .pd-prose)
  .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
  > .table-responsive {
  margin-top: 0.75rem;
  margin-bottom: 1.5rem;
}

:is(body.is-blog-article, body.is-legal-page, body.pd-reading, .pd-prose) .card-body > hr {
  margin-top: 1.75rem;
  margin-bottom: 1.75rem;
  opacity: 0.12;
}

/* 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
  > 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. It is the same substitution .form-text already */
/* makes for the same reason. */
.pd-table-hint {
  display: none;
  margin-bottom: 0.35rem;
  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);
}

/* Stronger upward shadow in dark mode to keep the sticky bar visually separated from the dark page. */
[data-bs-theme="dark"] .pd-sticky-cta {
  box-shadow: var(--pd-shadow-sticky-dark);
}

/* 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,
  [data-bs-theme="dark"] .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,
  .pulse-info {
    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, this file sets a real box-shadow in twelve places: the two
     .demo-image-hover-* hovers, .sticky-cta-bar and its dark twin,
     .related-article-card:hover/:focus-within and its dark twin, .pd-sticky-cta
     and its dark twin, the two .form-range:focus-visible thumb rules, the sheet
     .pd-paper and the deadline ring of the timeline, which gets an outline below.
     Only .pd-sticky-cta is cleared here, and the reason is that its shadow is the
     one that would otherwise be redrawn as a solid system colour and read as a
     second border above the .border-top the include already carries. The deadline
     ring carries meaning and is replaced by the outline below; the seven 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 {
    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;
  }

  .demo-video-primary,
  .demo-video-warning {
    background: Canvas !important;
  }

  :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,
  .pulse-info,
  .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 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. */
.pd-theme-toggle .theme-control-toggle-input:focus-visible ~ .theme-control-toggle-label {
  outline: 2px solid var(--falcon-primary);
  outline-offset: 2px;
  border-radius: var(--falcon-border-radius-sm);
}

/* 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;
  }
}

/* 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 (up to 60s), 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;
  }
}

/* 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;
}

/* 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 article rows in the category overviews cannot hold title
   and category badge side by side: at 320 px the title column measures ~106 px, less
   than a single long word, and the badge was pushed 51 px past the viewport. Letting
   the row wrap moves the badge under the title and gives the title the full line;
   min-width: 0 additionally allows the column to shrink below its min-content width,
   and hyphens: auto prefers proper German hyphenation over a mid-word break (the
   document is lang="de", so Chromium and Firefox apply real hyphenation patterns).

   All three 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 {
    flex-wrap: wrap;
  }

  .pd-overview-row > h2.flex-grow-1 {
    min-width: 0;
    flex-basis: 100%;
    -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 tiles on the blog overview, the home product cards, the related-  */
/* articles cards and the thanks page. Three fixed sizes, previously repeated as    */
/* nine inline width/height pairs. Falcon's own .icon-item scale does not carry     */
/* these values (sm 30px, lg 44px, xl 50px), so pulling them onto it would resize   */
/* every tile visibly for no stated reason — the values stay, only the inline style */
/* goes. Named after the pixel size.                                               */
.pd-icon-tile-40,
.pd-icon-tile-56 {
  flex-shrink: 0;
}

.pd-icon-tile-40 {
  width: 40px;
  height: 40px;
}

.pd-icon-tile-56 {
  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). Everything below draws the
   theme's tokens unchanged. The one rule left 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;
}

/* 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;
}

/* 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: rgba(var(--falcon-primary-rgb), 0.12);
  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 checked points of an unpaid analysis: a plain numbered list with room per line. */
.pd-checked-list {
  padding-left: 1.25rem;
}

.pd-checked-list > li {
  padding: 0.25rem 0;
}

/* An icon that belongs to the word before it: Font Awesome sets .fas inline-block, and
   a line may break before an inline-block even after a no-break space. */
.pd-inline-icon {
  display: inline;
}

/* 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);
  border-left: 2px solid var(--falcon-border-color);
}

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

/* One finding of a paid analysis: a card-like block whose left edge carries the rating
   colour, as the Arbeitszeugnisanalyse marks a graded sentence. The colour comes from a
   modifier of its own; the border-* utility it used to take is !important in Bootstrap
   and needed six !important declarations to be overridden again. */
.pd-finding {
  padding: 1rem;
  margin-bottom: 1rem;
  border: 1px solid var(--falcon-border-color);
  border-left-width: 4px;
  border-left-color: var(--falcon-gray-400);
  border-radius: var(--falcon-border-radius-lg);
}

.pd-finding--danger {
  border-left-color: var(--falcon-danger);
}

.pd-finding--warning {
  border-left-color: var(--falcon-warning);
}

.pd-finding--success {
  border-left-color: var(--falcon-success);
}

/* 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.02em;
  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. */
.pd-quote {
  margin: 0 0 0.5rem;
  padding: 0.5rem 1rem;
  border-left: 3px solid var(--falcon-gray-400);
  background: var(--falcon-tertiary-bg);
  border-radius: 0 var(--falcon-border-radius-lg) var(--falcon-border-radius-lg) 0;
  color: var(--falcon-gray-1100);
}

/* A wording the buyer can copy: a quiet box with a dashed primary border. */
.pd-wording {
  margin-top: 1rem;
  padding: 0.5rem 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 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. */

/* 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;
}

/* 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;
}

/* A required field left empty names its problem at the field, not only in the browser's
   passing bubble at the first one (custom.js, initializeRequiredFieldMessages). */
.pd-required-error {
  font-size: 0.8333333333rem;
}

/* ------------------------------------------------------------------------------------
   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: Falcon's light display weight on wide screens,
   stepped down so its two lines do not break into four on a phone. */
.pd-hero-title {
  font-size: clamp(1.75rem, 1.2rem + 2vw, 2.75rem);
  font-weight: 300;
  line-height: 1.2;
  color: var(--falcon-gray-1000, #0b1727);
}

/* The topic picker beside the hero: a tinted panel of tiles that jump to the topic
   cards further down the page. */
.pd-topic-picker {
  background-color: rgba(var(--falcon-primary-rgb), 0.04);
  border: 1px solid rgba(var(--falcon-primary-rgb), 0.12);
}

.pd-topic-tile {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  height: 100%;
  min-height: 3.5rem;
  padding: 0.6rem 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, #232e3c);
  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);
  background-color: rgba(var(--falcon-primary-rgb), 0.1);
  color: var(--falcon-primary);
}

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

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

.pd-topic-tile__count {
  font-size: 0.75rem;
  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.78rem;
    hyphens: manual;
  }
}

/* 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);
  }
}

@media (prefers-reduced-motion: no-preference) {
  .pd-topic-tile {
    transition:
      color var(--pd-transition-base),
      box-shadow var(--pd-transition-base);
  }
}

/* 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;
}

.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.8333rem;
  font-weight: 600;
  color: var(--falcon-gray-900, #232e3c);
  hyphens: auto;
  overflow-wrap: anywhere;
}

/* Two lines of the tagline; the rest is on the product page. */
.pd-product-row__tagline {
  display: -webkit-box;
  overflow: hidden;
  font-size: 0.75rem;
  color: var(--falcon-gray-700, #5e6e82);
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
}

.pd-product-row__price {
  flex-shrink: 0;
  font-size: 0.8333rem;
  font-weight: 600;
  color: var(--falcon-gray-900, #232e3c);
  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;
  border-left: 1px solid var(--falcon-border-color);
  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;
}

@media (hover: hover) {
  .pd-product-row__link:hover {
    background-color: rgba(var(--falcon-primary-rgb), 0.04);
  }

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

/* The step icons of "So funktioniert's", Falcon's round feature icons. */
.pd-step-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 3.5rem;
  height: 3.5rem;
  border-radius: 50%;
  font-size: 1.25rem;
}

/* 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.75rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--falcon-gray-900, #232e3c);
}

.footer-nav .list-unstyled .footer-link {
  margin-left: -0.55rem;
  font-size: 0.8333rem;
}

/* ------------------------------------------------------------------------------------
   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). */
.pd-page-header__body {
  padding: 1.5rem 1.25rem;
}

@media (min-width: 992px) {
  .pd-page-header__body {
    padding: 2rem 2.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);
}

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

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

/* The facts under a product's tagline (products/product_header.html). */
.pd-facts > li {
  display: inline-flex;
  align-items: center;
  color: var(--falcon-gray-800);
}

.pd-how-it-works {
  line-height: 1.6;
}

/* 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: 1rem 1.125rem;
  border-radius: var(--falcon-border-radius-lg);
  background-color: var(--falcon-tertiary-bg);
  border: 1px solid var(--falcon-border-color);
}

/* 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: 0.9375rem;
  font-weight: 600;
  line-height: 1.45;
}

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

/* The three steps of a product page (includes/steps.html): numbered circles joined by a
   line from 768 px, stacked with a line down the side below. */
.pd-process__step {
  position: relative;
}

.pd-process__number {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.5rem;
  height: 2.5rem;
  margin-bottom: 0.75rem;
  border-radius: 50%;
  background-color: var(--falcon-primary);
  color: #fff;
  font-family: var(--falcon-headings-font-family, Poppins, sans-serif);
  font-weight: 600;
  text-decoration: none;
  box-shadow: 0 0 0 0.35rem rgba(var(--falcon-primary-rgb), 0.12);
}

.pd-process__label {
  font-size: 0.6944444444rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--falcon-gray-600);
}

@media (min-width: 768px) {
  .pd-process__step:not(:last-child)::after {
    content: "";
    position: absolute;
    top: 1.25rem;
    left: calc(var(--bs-gutter-x, 1.5rem) * 0.5 + 3.5rem);
    right: calc(var(--bs-gutter-x, 1.5rem) * -0.5 + 1rem);
    height: 2px;
    background: linear-gradient(
      90deg,
      rgba(var(--falcon-primary-rgb), 0.35),
      rgba(var(--falcon-primary-rgb), 0.08)
    );
  }
}

/* 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 from 1200 px. */
.pd-activation__panel {
  background-color: var(--falcon-tertiary-bg);
  border-top: 1px solid var(--falcon-border-color);
}

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

/* Below 1400 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;
}

.pd-activation__price {
  font-family: var(--falcon-headings-font-family, Poppins, sans-serif);
  font-size: 2.25rem;
  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 1.125rem;
  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);
}

.pd-hub-list__item .pd-overview-row {
  transition: background-color var(--pd-transition-base);
}

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

@media (min-width: 768px) {
  .pd-hub-list__item:nth-child(odd) {
    border-right: 1px solid var(--falcon-border-color);
  }
}

/* The three category cards of the blog overview lift slightly on hover, as Falcon's
   feature cards do. */
.pd-category-card {
  transition:
    box-shadow var(--pd-transition-base),
    transform var(--pd-transition-base);
}

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

/* On a phone the page header's H1 and lead shrink one step, so the first screen shows
   the header and the start of the content rather than the header alone. */
@media (max-width: 575.98px) {
  .pd-page-header h1 {
    font-size: 1.375rem;
  }

  /* Falcon's .fs-9 on the lead carries !important. */
  .pd-page-header__lead {
    font-size: 0.9375rem !important;
  }
}

/* The product box of an article in a newer blog category (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);
}

.pd-blog-cta__link {
  transition: background-color var(--pd-transition-base);
}

.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, the generated letter
   in a sheet-like box, and the next steps as three equal columns. */
.pd-tool-result {
  background-color: var(--falcon-tertiary-bg);
  border: 1px solid var(--falcon-border-color);
}

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

.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-letter {
  padding: 1.5rem;
  border: 1px solid var(--falcon-border-color);
  border-radius: var(--falcon-border-radius-lg);
  background-color: var(--falcon-card-bg, #fff);
  line-height: 1.7;
}

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

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

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