/* ──────────────────────────────────────────────────────────────────────────────
   TK Elevator (tenant `tke`) — tenant-scoped overrides.

   Loaded ONLY on tke pages, by the public tenant-board layout via
   `apps/web/lib/tenant-stylesheet.ts`. Nothing here reaches another customer.

   These rules were moved verbatim out of `packages/design-system/styles/globals.css`,
   which every tenant downloads. They are the accumulated pixel-parity and locale
   fixes for the rebuilt TKE careers site.

   CASCADE: this sheet is UNLAYERED and loads after the app bundle, so it outranks
   Tailwind's `@layer utilities` on cascade order alone. Inside `@layer base` these
   rules lost to every utility and each one needed `!important`; 35 of those markers
   are gone. Do NOT add `!important` here reflexively — reach for it only to beat
   another `!important` or an inline style, and say which in a comment. The flip side
   is that a deliberate utility-level opt-out no longer wins by itself: see the
   `[text-wrap:wrap]` rule below.

   SCOPING: rules must stay scoped to `[data-tenant="tke"]` or a builder-emitted
   `.tke-*` hook class. `data-cms-element-id` attributes exist ONLY in the editor
   overlay — a rule keyed on one silently does nothing on the published render
   (found the hard way, 2026-07-16).
   ────────────────────────────────────────────────────────────────────────────── */

/* TKE parity: the live careers site renders all text with grayscale
   antialiasing (`-webkit-font-smoothing: antialiased`), which yields lighter
   strokes. Our global default (`auto` = subpixel/standard AA) makes the same
   400-weight TKE Type look heavier than live. Match live for the tke tenant
   only (scoped to the tenant wrapper's `data-tenant`); also drop the global
   `optimizeLegibility` to live's `auto`. Other tenants keep the defaults. */
[data-tenant="tke"] {
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: auto;
}

/* Locale typography. English is the pixel-parity baseline and MUST render
   byte-identically, but longer translations orphan a word onto its own line in
   the CMS headings (e.g. de "Über unser Team", "Jede Geschichte zählt"). Scope
   orphan-avoidance to NON-English locales via the <html lang> attribute so
   English is never touched; other locales have no live reference, so a tidier
   wrap is a pure win. text-wrap:balance evens multi-line headings; the
   fit-content rule below collapses the near-miss orphans onto one line. */
@media (min-width: 768px) {
  html:not([lang="en"])
    [data-tenant="tke"]
    :is(.cms-rich-text, h1, h2, h3, h4) {
    text-wrap: balance;
  }
}
/* Long compound words (de "Bewerbungsprozess", "Produktionsstandorten") break
   instead of overflowing/clipping their box — only as a last resort when a word
   would otherwise not fit. Overrides the `break-normal` utility
   (overflow-wrap:normal) the hero/section headings carry for English parity.
   BOUNDED TO >=768: below that the NARROW VIEWPORTS block at the end of this file
   owns wrapping for every locale (and does it better — `hyphens: auto` puts in a
   hyphen instead of chopping mid-word). English is only the parity baseline at
   desktop widths; on a phone it needs the same help as everyone else. */
@media (min-width: 768px) {
  html:not([lang="en"])
    [data-tenant="tke"]
    :is(.cms-rich-text, h1, h2, h3, h4, p, li, blockquote) {
    overflow-wrap: anywhere;
  }
}
/* Explicit opt-out from the balance rule above. It was written for headings but
   `.cms-rich-text` also matches rich-text BODIES — balancing those sizes every line
   equally, so FAQ answers of different lengths ended up different widths and
   under-filled the panel. `FaqAnswer` (packages/cms-registry/src/primitives/
   faq-accordion.tsx) opts out with the `[text-wrap:wrap]` utility, which used to win
   because these rules lived in `@layer base` and every utility outranks that layer.
   This sheet is unlayered and now outranks utilities, so the opt-out has to be
   restored explicitly — otherwise the FAQ answers silently start balancing again.
   The selector mirrors the balance rule's prefix plus the opt-out class, so it wins
   on specificity (0,4,1 vs 0,3,1) rather than on source order. */
html:not([lang="en"]) [data-tenant="tke"] .cms-rich-text.\[text-wrap\:wrap\] {
  text-wrap: wrap;
}
/* The CMS section-heading boxes are centred and width-capped to English. A
   longer translation exceeds the cap by a little and orphans a word onto its
   own line ("Über unser Team", "Jede Geschichte zählt"). For non-English only,
   let the heading box shrink to its own content (fit-content) so it uses its
   natural width — the orphan collapses onto one line wherever the section has
   room, and English keeps its exact caps (scoped out by :not([lang=en])). */
html:not([lang="en"])
  [data-tenant="tke"]
  .relative.mx-auto:has(> [class*="cms-rich-text"]) {
  /* Matches every CMS section-heading wrap (dept `w-full`/`w-[39%]` and the
     centered `w-fit`/`w-[42%]` variants) — they're all `relative mx-auto` with
     a rich-text heading child; body blocks aren't `relative`.
     Overrides the Tailwind w-* utility on the same element. */
  width: fit-content;
  max-width: 100%;
}

/* ── TKE section-heading corner bracket, PINNED to the first line ──────────────
   Applies to EVERY section heading that has a corner bracket (both the gradient and
   the white variant), across all pages. Each is a `.relative` wrap whose FIRST child
   is the bracket (hook class `tke-corner-bracket`, emitted by `addHeadingBracket` +
   the working-at-tke inlined copy) and whose other child is the heading (a
   `.cms-rich-text` div, or an `h2` for local-career-sites).

   Model: make the heading `inline` so the bracket — an inline-block with ZERO net
   advance (its -38px right margin cancels its 38px width) at the start of the inline
   run — rides the FIRST line's start and hangs up-and-left into the corner, while the
   centred run stays centred. A uniform full width + 40px runway on both sides keeps
   every locale the same width AND guarantees the pinned bracket never clips
   off-screen (it lands at the wrap edge when the first line fills the width). Heroes
   are EXCLUDED — their two-bracket framing design is separate.

   The `html` prefix + `.relative` give (0,3,1) specificity so this beats the generic
   non-EN `.relative.mx-auto:has()` fit-content rule above, and the sheet's position
   beats the Tailwind width/padding/display/position/size utilities (incl. the
   bracket's own `-top-*`/`left-*`/`h-*`/`w-*` posClass). */
html [data-tenant="tke"] .relative:has(> .tke-corner-bracket) {
  width: 100%;
  max-width: none;
  padding-inline: 40px;
  text-align: center;
}
html
  [data-tenant="tke"]
  .relative:has(> .tke-corner-bracket)
  > :is(.cms-rich-text, h1, h2, h3, h4) {
  display: inline;
  padding-inline: 0;
  max-width: none;
}
html [data-tenant="tke"] .tke-corner-bracket {
  position: relative;
  display: inline-block;
  width: 38px;
  height: 38px;
  top: -2px;
  left: -40px;
  margin: -38px -38px 0 0;
  vertical-align: top;
}

/* Hero bottom-right corner bracket. It ships `invisible` so the client positioner
   (HeroBracketPositioner) can place it on the WRAPPED title's true right edge with
   no load-time jump. FAIL-SAFE: if the positioner never runs (JS disabled, or an
   editor re-render drops its inline reveal), reveal the bracket at its default
   box-corner position after a short delay so it is never permanently missing.
   (Animated values win over the `invisible` utility regardless of @layer order.) */
[data-tenant="tke"] .tke-hero-br {
  animation: tke-hero-br-reveal 1ms linear 1s forwards;
}
@keyframes tke-hero-br-reveal {
  to {
    visibility: visible;
  }
}

/* TKE "schacht" (elevator-shaft) band — a light-grey vertical strip down the
   RIGHT edge of the whole page, behind all sections (set as the <main> content
   background, repeat-y at the right edge like live). Light/transparent bands
   reveal it; opaque dark bands paint over it, so it is absent on dark sections
   exactly as on live. schacht_heller.png is mostly transparent with the grey
   band on its right ~90px. Re-added 2026-07-24 at the customer's request,
   reversing the 2026-07-04 "no schacht band" decision. TKE-only via the
   builder-set class (see the (main) tenant layout). */
main.tke-schacht-shaft {
  background-image: url("/tke/schacht_heller.png");
  background-repeat: repeat-y;
  background-position: 100% 50%;
}

/* The shared TKE hero heading (`appendTkeHeroBand` / `appendTkeHomeHero`: the
   mono uppercase h1) is width-capped to the ENGLISH title (`max-w-[330px]
   md:max-w-[400px]`) so it wraps to live's exact 2-line shape ("TECHNICAL" /
   "SERVICES"). English MUST keep that cap byte-for-byte — the h1 fills to its
   max-width, so widening it would move the corner-bracket frame and break
   pixel parity. But a longer non-English word overflows that cap (de
   "TECHNISCHER" ≈ 450px > the 400px cap), and the global `overflow-wrap:
   anywhere` rule above then CHOPS it mid-word ("TECHNISCH" / "ER SERVICE").
   For non-English only, size the hero heading to its own content (fit-content,
   bounded by the hero container) so it wraps at word boundaries; drop the
   anywhere-chop back to `normal` and let `hyphens: auto` (the <html lang>
   dictionary) hyphenate cleanly ("TECH-" / "NISCHER") only when a single word
   truly can't fit (mobile). English is scoped out by :not([lang="en"]).
   Overrides the Tailwind max-w-* / break-* utilities on the same element. */
/* BOUNDED TO >=768: below that every locale gets this (and more) from the NARROW
   VIEWPORTS block — English hero titles overflow their EN-tuned cap on a phone too
   ("MANUFACTURING" ran 240px off-screen at 360, silently clipped by the band). */
@media (min-width: 768px) {
  html:not([lang="en"]) [data-tenant="tke"] h1.font-mono.uppercase {
    width: fit-content;
    overflow-wrap: normal;
    hyphens: auto;
    -webkit-hyphens: auto;
  }
}
/* fit-content up to the FULL hero container: a non-English title whose natural
   width still fits the container (e.g. de "TECHNISCHER SERVICE") sizes to itself
   and both corner brackets hug it. EXCEPTION — `.tke-hero-hug` (opt-in on pages
   whose translated title is LONGER than the container: es/de early-careers &
   hiring-process): there fit-content would fill the whole 970 container while the
   wrapped text stays narrow, leaving the bottom-right bracket stranded far from
   the text (a "stray bracket"). Those keep their per-page builder max-width so
   the box hugs the wrapped title and BOTH brackets sit at the same small offset. */
@media (min-width: 768px) {
  html:not([lang="en"])
    [data-tenant="tke"]
    h1.font-mono.uppercase:not(.tke-hero-hug) {
    max-width: 100%;
  }
}

/* TKE home "values" cards (`appendValues`). The mono uppercase card titles sit
   in a flex [icon + title] head capped to ~72% of the column — tuned to the
   English words (INTEGRITY … ONE TKE TEAM). A longer non-English word
   ("EXPECTATIVAS" ≈ 173px > the ~143px title box, "RENDIMIENTO") then hits the
   global `overflow-wrap:anywhere` above and CHOPS mid-word ("EXPECTATI/VAS").
   For non-English only, widen the head cap so the longest word fits and drop
   the chop back to word-boundary wrapping — matching live's CUSTOMER /
   EXPECTATIONS 2-line wrap. English keeps its exact 72% cap (scoped out).
   Targets the builder-emitted hook classes .tke-value-title / .tke-value-head
   (home.ts appendValues) — data-cms-element-id exists only in the editor. */
html:not([lang="en"]) [data-tenant="tke"] .tke-value-title {
  overflow-wrap: normal;
}
@media (min-width: 1025px) {
  html:not([lang="en"]) [data-tenant="tke"] .tke-value-head {
    max-width: 92%;
  }
}

/* Non-English dept INTRO heading centering (`appendDeptIntro`, e.g.
   business-finance "The minds behind smart decisions"). At desktop the 1080
   container fits the German title on one centred line, but the longer es/pt/fr
   titles wrap and — via the fit-content section-heading rule above — fill the
   container left-aligned, so they read as shifted left next to German's centred
   single line. Give es/pt/fr a slightly smaller heading from 1140 (where the
   container is the full 1080, `min-[1140px]:px-0`) so they also fit one centred
   line. German already fits (left as-is); English is the parity baseline (scoped
   out). Below 1140 every locale wraps to the gutter, so no reduction is needed —
   they are already consistent there. Targets the intro heading via the
   builder-emitted hook class .tke-dept-intro-heading (dept-template
   appendDeptIntro) — data-cms-element-id attributes exist ONLY in the editor
   overlay, so the earlier [data-cms-element-id="dept-intro-section"] scope
   never matched on the published render (found 2026-07-16: /es/business-
   finance @1280 rendered 52px). The hook sits on the rich-text heading
   itself, so the spotlight / "Every story counts" / join headings that share
   the class string are untouched (the user asked to leave those). */
@media (min-width: 1140px) {
  html:is([lang="es"], [lang="pt"], [lang="fr"])
    [data-tenant="tke"]
    .tke-dept-intro-heading {
    font-size: 48px;
    line-height: 48px;
  }
}

/* Home-hero title (`appendTkeHomeHero`: the centred mono uppercase h1 framed by
   two corner brackets). de/es/pt keep the short English "ARE YOU THE ONE?" tagline
   (byte-identical to EN — untouched); only fr ("Serez-vous notre prochain talent ?")
   and zh ("你，就是我们要找的人吗？") translate it to something long enough to WRAP.
   When a non-EN title wraps, the shared dept-hero rule above (width: fit-content,
   written for the LEFT-pinned dept hero) grows this CENTRED home title to ~full
   width and left-pins it, so the corner brackets hang off both screen edges (fr's
   top-left bracket sat at x=-35 across 768–1440, clipped by the section's
   overflow-hidden). Scope a fix to fr/zh only: a smaller font (fr stacked to 7
   lines at 375) and, from 768, a width-capped centred block so the brackets frame
   the title on-screen at every width. English + de/es/pt are scoped out.
   Targets the builder-emitted hook class .tke-home-hero-title (_hero.ts
   appendTkeHomeHero, home hero h1 ONLY — the dept hero h1 shares
   font-mono/uppercase but not the hook) — data-cms-element-id attributes
   exist ONLY in the editor overlay, so the earlier
   [data-cms-element-id="home-hero-section"] scope never matched on the
   published render (found 2026-07-16). .font-mono.uppercase are kept in the
   selector for SPECIFICITY, not scoping: the max-width here must out-rank
   the shared non-EN hero rule above (h1.font-mono.uppercase, 0-4-2, whose
   `max-width: 100%` would otherwise win and let the title grow full-width, hanging
   the brackets off-screen again). */
/* The <768 branch this rule used to carry (fr/zh at 48px) is gone: the narrow type
   scale at the end of this file sizes the home hero for every locale. */
@media (min-width: 768px) {
  html:is([lang="fr"], [lang="zh"])
    [data-tenant="tke"]
    h1.tke-home-hero-title.font-mono.uppercase {
    /* ≥768 (centred title): 56px in a width-capped block wraps fr/zh to a tidy
       2-line frame that the corner brackets sit around, on-screen at every width. */
    font-size: 56px;
    line-height: 60px;
    max-width: min(calc(100vw - 160px), 600px);
    text-align: center;
  }
}

/* Flip-card BACK descriptions (technical-services "The people who keep
   cities moving"; .tke-flipcard-desc set by the builder). The 650px card face
   holds the EN text at 18px/27 at every width, but non-English runs ~25%
   longer and outgrows the face wherever the 3-up carousel squeezes cards
   below ~350px (de overflowed by up to +134 at 1025 and +242 at 375). Step
   non-English down to 16px/24 below 1200 — the same bound where the card
   label drops 32px→24px — so it fits; any residual worst case top-aligns and
   scrolls (auto-margin centring + overflow-y-auto on the face) instead of
   clipping. English is the parity baseline (scoped out). Overrides the
   text-[18px]/leading-[27px] utilities. */
@media (min-width: 768px) and (max-width: 1199.98px) {
  html:not([lang="en"]) [data-tenant="tke"] .tke-flipcard-desc {
    font-size: 16px;
    line-height: 24px;
  }
}

/* Non-English header nav labels are longer and overflow the desktop row in the
   1200-1359 band (es "Empleos" ran ~138px past the edge). Keep the hamburger
   there for non-English so nothing clips; English keeps its 1200 breakpoint
   (scoped out). Overrides the min-[1200px] flex/hidden utilities. */
@media (min-width: 1200px) and (max-width: 1359.98px) {
  html:not([lang="en"]) [data-tenant="tke"] .tke-nav-desktop {
    display: none;
  }
  html:not([lang="en"]) [data-tenant="tke"] .tke-nav-mobile {
    display: flex;
  }
}

/* ══════════════════════════════════════════════════════════════════════════════
   NARROW VIEWPORTS (< 768px) — EVERY LOCALE
   ══════════════════════════════════════════════════════════════════════════════
   The rebuild reproduced the live Elementor site pixel-for-pixel, including what
   it got wrong on a phone: the live site also rendered a 68px hero at 375, so the
   parity gate — which only ever asked "does this match live?" — could never flag
   any of this. Measured on the deployed site at 320/360/375/414 across de/en/fr/es
   (tools/tke-parity/narrow-audit.mjs), 13 pages: 299 words too wide for their box
   at 320, 194 at 360, 73 at 414. It degrades continuously; there is no cliff at
   400, so this band is bounded at the md breakpoint rather than at a phone width.

   ALL LOCALES, deliberately. Every earlier fix here is scoped `:not([lang="en"])`
   because English was frozen for pixel parity — but that freeze only ever made
   sense against the live desktop reference. On a phone English breaks the same way
   (`/en/manufacturing` at 360 rendered "Manufacturing" 530px wide from x=70, i.e.
   240px off-screen, silently clipped by the hero's overflow-hidden). Below md,
   text is text: one set of rules for everyone. Desktop parity is untouched because
   this whole block is inside a max-width media query, not because of a selector.

   WHAT IS LEFT HERE IS POLICY, NOT PER-COMPONENT DECISIONS. The type scale, band
   heights, bracket sizing, image ratios and the rest moved into the builders as
   responsive class pairs (#131) — the spec now says what it renders. These four
   remain because they are cross-cutting rules that would be wrong to repeat in 600
   class strings, plus one exception: the dept team panel needs a spec restructure
   (next/image `fill` is a boolean prop, not a responsive one).
   ────────────────────────────────────────────────────────────────────────────── */
@media (max-width: 767.98px) {
  /* ── 1. Hyphenate instead of chopping ────────────────────────────────────
     `overflow-wrap: anywhere` (the >=768 non-English rule) breaks a word at an
     arbitrary letter with no hyphen — "Innovatore/n", "Flexibilitä/t". At phone
     widths that is the single most visible defect in the customer's screenshots.
     `hyphens: auto` uses the <html lang> dictionary and only breaks where the
     language allows, with a hyphen; `break-word` stays as the last resort for a
     word no dictionary can split (URLs, "Fluggastbrücken" in a 180px card). */
  [data-tenant="tke"]
    :is(.cms-rich-text, h1, h2, h3, h4, h5, h6, p, li, dd, dt) {
    hyphens: auto;
    -webkit-hyphens: auto;
    overflow-wrap: break-word;
    /* Only hyphenate a word of 10+ characters, and never leave a stub: 4 before
       the break, 3 after. Without this the hyphenator splits "Generation" the
       moment the line is tight. */
    hyphenate-limit-chars: 12 4 3;
    /* `text-wrap: balance` is bounded to >=768 for the same reason: equalising
       line lengths in a 280px column just means hyphenating more. */
    text-wrap: auto;
  }
  /* Unbreakable strings — the legal pages quote raw URLs and agency names that no
     dictionary splits ("http://tools.google.com/dlpage/gaoptout" is 338px wide in
     a 300px column). Only these may break at an arbitrary character. */
  [data-tenant="tke"] :is(p, li, dd) a,
  [data-tenant="tke"] .cms-rich-text a {
    overflow-wrap: anywhere;
  }

  /* ── 2. The corner-bracket runway ─────────────────────────────────────────
     At 360 a section heading had 220px of text width: 360 − 2×30px container
     gutter − 2×40px corner-bracket runway. That is ~4 characters per line at 52px.
     16px gutters and a 24px runway return 60px — a third more text width — before
     the type scale even applies. */
  [data-tenant="tke"] .relative:has(> .tke-corner-bracket) {
    padding-inline: 24px;
  }

  /* ── 3. The dept "who we are / who we're looking for" panel ─────────────
     The body copy is an `absolute bottom-0` overlay pinned inside a 500px
     `overflow-hidden` box, so a longer translation grows UPWARD and is clipped from
     the TOP — the reader arrives mid-sentence. Measured up to 348px of German and
     213px of ENGLISH cut off (this is one of the customer's screenshots). Below md
     the overlay stops being an overlay: the photo keeps its height, the text flows
     underneath it on the same dark background. */
  [data-tenant="tke"] .relative.h-full.min-h-\[500px\] {
    height: auto;
    min-height: 0;
  }
  /* The photo is a `fill` <img> (absolutely positioned by next/image), so it must
     be pulled into flow too — otherwise it stretches to whatever height the text
     needs and sits behind it. 240px keeps it a photo rather than a strip. */
  [data-tenant="tke"] .relative.h-full.min-h-\[500px\] > img {
    /* !important is load-bearing here (one of the few places it is): next/image's
       `fill` writes `position:absolute; height:100%` as an INLINE style, which no
       author rule can outrank without it. */
    position: relative !important;
    height: 240px !important;
  }
  /* `position: relative`, NOT `static`: the overlay carries `z-10` to sit above the
     photo, and z-index is ignored on a static box — the image would paint over the
     text and the panel would look like a photo with no caption. */
  [data-tenant="tke"]
    .relative.h-full.min-h-\[500px\]
    > .absolute.inset-x-0.bottom-0 {
    position: relative;
    padding-top: 20px;
    background: #434343;
  }

  /* ── 4. Touch targets ─────────────────────────────────────────────────────
     WCAG 2.5.8 asks for 24px minimum and 44px is the practical floor on a phone.
     The footer's seven stacked nav links are 24px tall on all 16 pages, the social
     icons 28px, the "Mehr erfahren" links 27px. Padding only — nothing moves on
     desktop, and the visual density barely changes because these are already
     stacked in a column. */
  [data-tenant="tke"] footer a,
  [data-tenant="tke"] .tke-elevator-scroll button {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
  }
  /* Standalone controls — the builders render every real button/CTA/chip as a
     flex box, while a link inside prose stays inline. Keying on that keeps the
     44px floor off inline text links, which must not become blocks. */
  [data-tenant="tke"] :is(a, button):is(.flex, .inline-flex) {
    min-height: 44px;
  }
}
