/* =============================================================================
   a11y-target-size.css
   -----------------------------------------------------------------------------
   Remediation for WCAG 2.2:
     - 2.5.8 Target Size (Minimum)  - Level AA  - 24 x 24 CSS px   [REQUIRED]
     - 2.5.5 Target Size (Enhanced) - Level AAA - 44 x 44 CSS px   [OPTIONAL]
     - 1.4.1 Use of Color           - Level A                      [REQUIRED]
     - 1.4.4 Resize Text            - Level AA                     [SUPPORTING]
     - 2.5.3 Label in Name          - Level A   - needs MARKUP fix, see S7

   Scope:   bdo.at (Kentico Xperience 13 theme)
   Load:    LAST in the cascade, after the Tailwind build and all component CSS.
   Note:    Sections 1-6 are CSS only. Section 7 documents a template change
            that CSS cannot fix - it only ships the .sr-only helper it needs.

   Section 1 = target size, must-fix for EN 301 549 / EAA (AA).
   Section 2 = target size, cheap AAA wins.
   Section 3 = adjacent findings (focus visibility, reduced motion).
   Section 4 = coarse-pointer safety net.
   Section 5 = link identification, 1.4.1 - Level A, HIGHEST PRIORITY.
   Section 6 = fixed font sizes, AAA - low priority, read the comments first.
   Section 7 = Label in Name helper + markup instructions.

   Every override uses a single extra class or attribute for specificity so it
   beats Tailwind utilities without !important. If a rule does not apply,
   check the real class in DevTools first - Tailwind class strings in the
   audit output were truncated by the console.
   ============================================================================= */

:root {
  /* Single source of truth. Set to 24px if the design team rejects 44px;
     the AA success criterion is still met at 24px. */
  --a11y-target-size: 44px;
  --a11y-target-size-min: 24px;
}


/* =============================================================================
   SECTION 1 - REQUIRED (WCAG 2.5.8, Level AA)
   These elements are below 24px in at least one dimension AND sit too close
   to neighbouring targets to qualify for the spacing exception.
   ============================================================================= */

/* -----------------------------------------------------------------------------
   1.1  Mega-menu link lists  -  measured ~ N x 21px
   Selector target: a.animated-link.text-sm inside the header
   line-clamp-2 sets display:-webkit-box. Do NOT change `display` here or the
   two-line truncation breaks. padding-block works fine on -webkit-box.
   -------------------------------------------------------------------------- */
.header .animated-link.text-sm,
.header__sub-menu .animated-link.text-sm {
  padding-block: 11px;            /* 21 + 22 = 43px -> raise to 12px for 45px */
  box-sizing: content-box;
}

/* Remove the pre-existing vertical rhythm, otherwise each menu row grows by
   ~22px and the mega-menu overflows. Check which of these two applies. */
.header__sub-menu ul,
.header__sub-menu-two-levels-grid {
  gap: 0;
}
.header .animated-link.text-sm + .animated-link.text-sm {
  margin-top: 0;
}


/* -----------------------------------------------------------------------------
   1.2  Footer links  -  measured ~ N x 23px
   Kontakt / Standorte / AAB und BCR / Sitemap / Impressum / Jobs & Karriere
   Negative inline margin keeps the visual left edge exactly where it is.
   -------------------------------------------------------------------------- */
.footer .animated-link.text-white,
footer .animated-link.text-white {
  display: inline-flex;
  align-items: center;
  min-height: var(--a11y-target-size);
  padding-inline: 8px;
  margin-inline: -8px;
}

/* Guarantee horizontal separation so the enlarged hit areas cannot overlap. */
.footer nav ul,
footer nav ul {
  gap: 0 16px;
}


/* -----------------------------------------------------------------------------
   1.3  Header search icon  -  measured 20 x 20px
   Grows the hit area only; the glyph itself keeps its rendered size.
   -------------------------------------------------------------------------- */
.header a[aria-label="Search icon"],
.header a[aria-label*="Suche"] {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: var(--a11y-target-size);
  min-height: var(--a11y-target-size);
}


/* -----------------------------------------------------------------------------
   1.4  Swiper pagination bullets  -  measured 48 x 8px
   Width is fine, height is not. The pseudo-element enlarges the hit area
   without changing the visual design of the bullet.

   !! VERIFY AFTER DEPLOY !!
   A 44px tall hit area extends 18px above and below the bullet strip. If that
   overlaps slide content, the previous/next arrows, or a CTA button, the
   bullets will steal those clicks. In that case lower the height to
   var(--a11y-target-size-min) - 24px still satisfies AA.
   -------------------------------------------------------------------------- */
.swiper-pagination-bullet {
  position: relative;
}

.swiper-pagination-bullet::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  top: 50%;
  height: var(--a11y-target-size);
  transform: translateY(-50%);
}

/* Keep the arrows clickable where the enlarged bullet area reaches them. */
.swiper-btn__rounded {
  position: relative;
  z-index: 2;
}


/* -----------------------------------------------------------------------------
   1.5  Header meta bar  -  VERIFIED 2026-08-04 against the live DOM
   Ansprechpersonen / Standorte / Events / Presse - measured 117 x 20px.
   Real markup:
     ul.header__main-menu-list > li.header__main-menu-item > a.header__main-menu-link
   -------------------------------------------------------------------------- */
.header__main-menu-list {
  display: flex;
  align-items: center;
  gap: 4px;
}

.header__main-menu-item {
  margin: 0;
}

.header__main-menu-link {
  display: inline-flex;
  align-items: center;
  min-height: var(--a11y-target-size);
  padding-inline: 10px;
}


/* -----------------------------------------------------------------------------
   1.6  Language switch DE | EN  -  VERIFIED 2026-08-04, measured 18 x 12px
   Real markup:
     ul.header__cultures-list > li.header__cultures-item > a.header__languages-link
   Smallest targets on the page. See SECTION 7 for the Label in Name defect on
   these same two links - that one needs a markup change, not CSS.
   -------------------------------------------------------------------------- */
.header__cultures-list {
  display: flex;
  align-items: center;
  gap: 8px;
}

.header__cultures-item {
  margin: 0;
}

.header__languages-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 32px;
  min-height: var(--a11y-target-size);
}


/* -----------------------------------------------------------------------------
   1.7  Breadcrumbs  -  VERIFIED 2026-08-04 on a blog detail page
   Measured 32x20, 24x20, 51x20, 88x20 - width passes, height does not.
   Real markup:
     div.breadcrumbs > ul.breadcrumbs__list > li.breadcrumbs__list-item
       > div.pt-[1px] > a.animated-link

   Deliberately 24px, NOT 44px. Breadcrumbs sit in a thin bar directly under
   the header; forcing 44px there would add ~24px of vertical chrome above the
   fold on every page. 24px satisfies 2.5.8 (AA), which is the binding
   requirement. Record the AAA gap in the accessibility statement.
   -------------------------------------------------------------------------- */
.breadcrumbs__list {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0 4px;
}

.breadcrumbs__list-item {
  display: flex;
  align-items: center;
  margin: 0;
}

.breadcrumbs__list-item a {
  display: inline-flex;
  align-items: center;
  min-height: var(--a11y-target-size-min);
  padding-inline: 2px;
}


/* -----------------------------------------------------------------------------
   1.8  Footnote references inside running text  -  "1)" "2)" etc.
   Measured 7x23 to 13x23 in <p>, and 10x17 inside <sup>.

   NO SIZE FIX IS APPLIED, AND NONE IS REQUIRED.

   Both 2.5.8 (AA) and 2.5.5 (AAA) carry an explicit INLINE exception:
   a target in a sentence, or whose size is constrained by the line-height of
   surrounding non-target text, is exempt. These footnote markers sit mid
   sentence inside .insight-details__content, so they qualify.

   Forcing them larger would be actively harmful: vertical padding on an
   inline element does not push lines apart, so the enlarged hit areas would
   silently overlap the lines above and below and steal clicks from the body
   text and from neighbouring footnote markers.

   Cite the inline exception when the audit tool re-raises this. The only
   change below is a small horizontal breathing space, which helps pointer
   accuracy without affecting line layout.

   NOTE: these markers rely on "1)" being recognisable as a link. Section 5
   underlines them, which is what actually makes them usable.

   The [href] qualifier is load-bearing. Editorial content contains bare
   anchor targets such as <a id="eu1" name="eu1"></a> used as jump
   destinations. Those have no activation behaviour and are not targets, but
   without [href] the padding below would inflate them from 0x0 to 2x23 and
   they would start showing up as spurious target-size failures in audits.
   -------------------------------------------------------------------------- */
.insight-details__content p > a[href],
.insight-details__content sup > a[href],
.rich-text__wrapper p > a[href],
.rich-text__wrapper sup > a[href] {
  padding-inline: 1px;
}


/* =============================================================================
   SECTION 2 - OPTIONAL (WCAG 2.5.5, Level AAA)
   These already pass AA. Cheap to fix, good for the accessibility statement.
   Delete this whole section if AAA is explicitly out of scope.
   ============================================================================= */

/* Filter dropdowns - Type / Bereich / Service / Branche - measured N x 43px.
   One pixel short. */
.filter-container__select-btn {
  min-height: var(--a11y-target-size);
}

/* Carousel arrows - measured 40 x 40px. */
.swiper-btn__rounded {
  width: var(--a11y-target-size);
  height: var(--a11y-target-size);
}

/* Tertiary buttons - "Mehr Erfahren", "Alle Events & Webinare" - 26/28px. */
.btn--tertiary {
  display: inline-flex;
  align-items: center;
  min-height: var(--a11y-target-size);
}

/* Two-level sub-menu grid items - measured N x 36px. */
.header__sub-menu-two-levels-grid-item,
.header__sub-menu-two-levels-grid-item--active {
  display: flex;
  align-items: center;
  min-height: var(--a11y-target-size);
}

/* Mega-menu titles Blog / Topics - measured 29 x 61px: height fine, width not. */
.header__mega-menu-title {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: var(--a11y-target-size);
}

/* Top-level nav links - measured ~ N x 27px. */
.header .animated-link.hover\:text-cta-blue {
  display: inline-flex;
  align-items: center;
  min-height: var(--a11y-target-size);
}


/* =============================================================================
   SECTION 3 - ADJACENT FINDINGS (not target size)
   Included because they surfaced in the same audit and are trivial to fix.
   ============================================================================= */

/* 3.1  swiper-btn__rounded.opacity-0
   The carousel arrows are invisible but remain in the tab order, so keyboard
   users land on a control they cannot see.
   -> WCAG 2.4.7 Focus Visible (AA).
   CSS makes the focused arrow visible again. The cleaner fix is to add the
   `inert` attribute in JS while the arrows are hidden - do that if you can
   touch the Swiper init. */
.swiper-btn__rounded.opacity-0:focus-visible {
  opacity: 1;
}

/* 3.2  Consistent, visible focus indicator on every enlarged target.
   Prevents the enlarged padding from swallowing the default outline. */
.header a:focus-visible,
.footer a:focus-visible,
footer a:focus-visible,
.swiper-pagination-bullet:focus-visible,
.swiper-btn__rounded:focus-visible,
.filter-container__select-btn:focus-visible,
.btn--tertiary:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 2px;
}

/* 3.3  Reduced motion - the enlarged targets inherit existing transitions. */
@media (prefers-reduced-motion: reduce) {
  .swiper-pagination-bullet,
  .swiper-btn__rounded,
  .btn--tertiary {
    transition: none;
  }
}


/* =============================================================================
   SECTION 4 - COARSE POINTER SAFETY NET
   Touch devices are where target size actually hurts. Belt and braces for any
   interactive element the selectors above missed.
   Keep this scoped to coarse pointers so it cannot disturb the desktop layout.
   ============================================================================= */

@media (pointer: coarse) {
  .header a,
  .header button,
  .footer a,
  footer a,
  .btn {
    min-height: var(--a11y-target-size-min);
  }
}


/* =============================================================================
   SECTION 5 - LINK IDENTIFICATION
   WCAG 1.4.1 Use of Color - Level A - 1,437 occurrences on 263 pages.
   HIGHEST PRIORITY OF THE WHOLE FILE.

   Colour alone must not be the only thing distinguishing an in-text link from
   its surrounding body copy. The .animated-link pattern reveals its underline
   on hover only, so at rest there is no non-colour cue.

   Technique used: G182 (visible non-colour distinction = underline).
   The alternative, G183, requires >= 3:1 contrast between link colour and the
   surrounding text colour. cta-blue against the dark-grey body text almost
   certainly fails that, so underlining is the reliable route.

   SCOPE MATTERS. This criterion applies to links "surrounded by text".
   Navigation, buttons, cards, tag chips and breadcrumbs are NOT in scope and
   must stay un-underlined or the design falls apart.

   VERIFIED 2026-08-04 by crawling a sample across all page-type segments.
   Exactly two editorial content wrappers exist, and both are React-rendered
   (they are NOT present in the server-side HTML, so DevTools on a live page
   is the only reliable way to inspect them):

     .insight-details__content   - blog / tax-news / accounting-news detail
                                   pages. 660 blog + 130 topics URLs in the
                                   sitemap. This is the bulk of the 1,437.
     .rich-text__wrapper         - editorial content pages (ueber-bdo, etc.)

   Offending links carry NO class at all - they are inserted through the
   Kentico rich-text editor, so they miss the "underline" utility class that
   the React components apply. Colour comes from a stylesheet rule instead.

   WHY UNDERLINE AND NOT THE CONTRAST ROUTE (G183):
     link colour  #0062B8  (rgb 0 98 184)
     body colour  #333333  (rgb 51 51 51)
     contrast ratio between the two = 2.07:1
   G183 needs >= 3:1 against the surrounding text, so it fails. Underlining
   is the only viable technique without changing the brand link colour.
   (Against the white background the link still measures 6.1:1, so 1.4.3
   Contrast Minimum is fine - this is purely a 1.4.1 issue.)
   ============================================================================= */

.insight-details__content a:not(.btn):not([class*="btn--"]):not([role="button"]),
.rich-text__wrapper a:not(.btn):not([class*="btn--"]):not([role="button"]) {
  text-decoration: underline;
  text-underline-offset: 0.2em;
  text-decoration-thickness: max(1px, 0.0625em);
  text-decoration-skip-ink: auto;
}

/* Hover must stay meaningful. Thickening rather than toggling on/off keeps a
   hover affordance while the resting state already carries the cue. */
.insight-details__content a:not(.btn):hover,
.rich-text__wrapper a:not(.btn):hover {
  text-decoration-thickness: max(2px, 0.125em);
}

/* The .animated-link pseudo-underline would now double up with the real one
   inside content areas. Suppress it there; it stays intact in nav and footer. */
.insight-details__content .animated-link::after,
.rich-text__wrapper .animated-link::after {
  display: none;
}

/* Already compliant, left here as documentation:
   contact-person bylines carry a literal "underline" utility class and
   compute to text-decoration: underline. No rule needed. */

/* EXPLICITLY OUT OF SCOPE - do not let a broad selector leak in here. */
.header a,
.footer a,
footer a,
.breadcrumb a,
.card a,
.teaser a,
.btn,
[class*="btn--"] {
  text-decoration: none;
}


/* =============================================================================
   SECTION 6 - FIXED FONT SIZES
   WCAG 1.4.4 Resize Text (AA) is already met via browser page zoom; the audit
   tool reports this against the AAA-adjacent "absolute units" check.
   1,265 occurrences over 325 pages - LOW PRIORITY, and largely NOT a theme bug.

   Tailwind emits rem (text-sm = 0.875rem), so the build is not the source.
   The px/pt values almost certainly come from inline styles pasted into the
   Kentico rich-text editor out of Word or Outlook, plus possibly the UserWay
   overlay (see the data-uw-* attributes in the DOM).

   THE REAL FIX IS CONTENT CLEANUP, NOT CSS:
     1. Remove the font-size control from the RTE toolbar configuration.
     2. Run a one-off cleanup over existing page content to strip
        style="font-size:...", mso-* declarations and <font> tags.
   The rules below are a stopgap until that happens.

   Diagnostic (console):
     [...document.querySelectorAll('[style*="font-size"]')]
       .map(el => ({ tag: el.tagName, size: el.style.fontSize,
                     html: el.outerHTML.slice(0,80) }))
       .filter(o => /px|pt|cm|in|mm/.test(o.size))
   ============================================================================= */

/* Respect the user's browser default instead of pinning the root. */
html {
  font-size: 100%;
}

/* Neutralise pasted inline font sizes inside editorial content only.
   !important is justified here: it overrides inline styles that should never
   have been authored. Do NOT widen this selector beyond content wrappers -
   it would flatten deliberate type scales in components. */
.insight-details__content [style*="font-size"],
.rich-text__wrapper [style*="font-size"] {
  font-size: inherit !important;
}

/* Legacy <font size> tags from very old imported content. */
.insight-details__content font[size],
.rich-text__wrapper font[size] {
  font-size: inherit !important;
}


/* =============================================================================
   SECTION 7 - LABEL IN NAME  (WCAG 2.5.3, Level A)
   CSS CANNOT FIX THIS. Listed here so the finding stays with its siblings.

   Reported: visible text "DE", accessible name "german".
   VERIFIED 2026-08-04, the live markup is:

     <a class="header__languages-link" href="/de-at/home-at" aria-label="German">
       <span class="hidden lg:flex">de</span>
       <span class="flex normal-case lg:hidden">German</span>
     </a>
     <a class="header__languages-link" href="/en-gb/home-en" aria-label="English">
       <span class="hidden lg:flex">en</span>
       <span class="flex normal-case lg:hidden">English</span>
     </a>

   On desktop the visible text is "DE" (uppercased via CSS from "de"), while
   the accessible name is "German" - which does not contain "de". A speech
   input user saying "click DE" hits nothing.

   Note the aria-label is also English on a German-language site.

   FIX - preferred, drop aria-label entirely and let the spans do the work:
     <a class="header__languages-link" href="/de-at/home-at" lang="de" hreflang="de">
       <span class="hidden lg:flex">de</span>
       <span class="flex normal-case lg:hidden">Deutsch</span>
     </a>

   FIX - alternative, keep aria-label but lead with the visible string:
     <a class="header__languages-link" href="/de-at/home-at"
        hreflang="de" aria-label="DE - Deutsch">...</a>

   ALSO IN THE SAME COMPONENT
     <a href="/de-at/search?searchtext=" aria-label="Search icon">
     "icon" does not belong in an accessible name, and it should be German.
     -> aria-label="Suche"
     (The target size rule in section 1.3 already matches this element and is
      confirmed working; only the name is wrong.)

   The .sr-only utility ships with Tailwind. This is a fallback in case the
   build purges it or the header sits outside the Tailwind content globs.
   ============================================================================= */

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

/* Skip links and similar: hidden until focused. */
.sr-only-focusable:focus,
.sr-only-focusable:focus-visible {
  position: static;
  width: auto;
  height: auto;
  margin: 0;
  overflow: visible;
  clip: auto;
  clip-path: none;
  white-space: normal;
}


/* =============================================================================
   VERIFICATION
   Paste in the console after deploy. Should return an empty array for AA.

   [...document.querySelectorAll('a,button,input,select,[role="button"],[role="link"],[tabindex]:not([tabindex="-1"])')]
     .map(el => {
       const r = el.getBoundingClientRect();
       const a = el.querySelector(':scope > ::after') ? null : null;
       const cs = getComputedStyle(el, '::after');
       const h = Math.max(r.height, parseFloat(cs.height) || 0);
       const w = Math.max(r.width,  parseFloat(cs.width)  || 0);
       return { el, w, h };
     })
     .filter(o => o.w && o.h && (o.w < 24 || o.h < 24));

   Note: getBoundingClientRect() does NOT include pseudo-element hit areas, so
   the swiper bullets will still show as 48x8 in a naive audit. That is a false
   positive - the ::after rule above is a valid technique under 2.5.8. Document
   it in the accessibility statement so the next auditor does not re-raise it.

   -----------------------------------------------------------------------------
   Section 5 - in-text links without a non-colour cue. Should return [].

   [...document.querySelectorAll('.insight-details__content a, .rich-text__wrapper a')]
     .filter(a => !a.closest('.btn, [class*="btn--"], nav'))
     .filter(a => getComputedStyle(a).textDecorationLine === 'none')

   -----------------------------------------------------------------------------
   Section 6 - remaining absolute font sizes inside content. Should return [].

   [...document.querySelectorAll('.insight-details__content *, .rich-text__wrapper *')]
     .filter(el => /px|pt|cm|in|mm/.test(el.style.fontSize || ''))

   -----------------------------------------------------------------------------
   Section 7 - accessible name must contain the visible label. Should return [].

   [...document.querySelectorAll('a[aria-label], button[aria-label]')]
     .filter(el => {
       const visible = (el.innerText || '').trim().toLowerCase();
       const name = (el.getAttribute('aria-label') || '').toLowerCase();
       return visible && !name.includes(visible);
     })
     .map(el => ({ visible: el.innerText.trim(),
                   name: el.getAttribute('aria-label'), el }));
   ============================================================================= */
