/* ==========================================================================
   Vireolin - Blade shell
   ==========================================================================

   Loaded AFTER vireolin.css and theme.css. It carries the small amount of CSS
   that the SPA produced from inline styles and from the handful of custom
   rules its build prepended to the bundle, plus the fixes for the defects that
   are baked into that CSS.

   Nothing here redefines Vuetify components - every class name the markup
   uses (d-flex, pa-5, text-h5, v-row, v-col, ...) is resolved by vireolin.css,
   so the rendered result stays pixel-identical to the Vue app.


   Defects fixed
   -------------
   1. The bundle declares `.bg-transparent` twice. The second declaration wins,
      so the header was *always* frosted white (#ffffffb3) and turned white in
      dark mode. The app bar bound `bg-transparent` to `isScrolled`, i.e. the
      opposite of the intent. Replaced by `.v-app-bar` + `.v-app-bar--scrolled`
      below: transparent over the hero, frosted once you scroll.

   2. `.nav-link { color: var(--v-theme-text) }` assigns an "r, g, b" triple to
      `color`, which is invalid, so the declaration was dropped and the links
      inherited whatever the toolbar happened to use. Corrected to
      `rgb(var(--v-theme-text))`.

   3. `.v-main { padding-top: 72px }` did not match the real app-bar height.
      `v-app-bar` carries `pa-5` (20px) around a 64px toolbar, so the bar is
      104px tall and 32px of content stayed hidden behind it. Both now derive
      from --v-app-bar-height.


   Tailwind is intentionally not used on the public site: the design is built
   from Vuetify's utility class names, and Tailwind's preflight would reset the
   very baseline the bundle relies on.

   ========================================================================== */

/* --------------------------------------------------------------------------
   Custom properties
   -------------------------------------------------------------------------- */

:root {
    --v-app-bar-height: 104px;
    /* v-main offsets itself by the bar height; 72px in the bundle. */
    --v-shell-content-offset: var(--v-app-bar-height);

    /*
     * The logo colour, verbatim. Measured from public/assets/images/
     * Vireolin-HKsZ1aiY.png (mean of the gold cluster, 29985 px) and identical
     * to the value the legacy stylesheet documents as "the logo gold #E2A52C"
     * (--v-copper-500, vireolin-website/public/css/style.css).
     *
     * --v-brand-gold-ink is the SAME hue at the lightness that is legible as
     * text on a light surface. Raw #E2A52C scores 2.18:1 on white and 2.00:1
     * on the theme's #F5F5F5 surface; WCAG AA wants 4.5:1 for text under 18pt.
     * Darkening along the same hue (40deg, unchanged) to #8A5F07 gives
     * 5.64:1 / 5.18:1 - recognisably the logo gold, actually readable.
     *
     * Which one a label uses is decided per surface, never per component:
     * `.v-btn-brand` and `.v-eyebrow` read --v-btn-brand-fg, which is the ink
     * variant by default and the raw gold inside the dark containers
     * (.v-hero, .v-footer), where #E2A52C scores 7.97:1.
     */
    --v-brand-gold: #e2a52c;
    --v-brand-gold-ink: #8a5f07;
    --v-btn-brand-fg: var(--v-brand-gold-ink);

    /*
     * Companion "r, g, b" triples. Every legacy alpha is written as
     * rgba(247,245,241,.25) in the original stylesheet, and `rgba()` only
     * accepts numbers - `rgba(#f7f5f1, .25)` is invalid and the declaration is
     * dropped at computed-value time, which silently renders a 0px border
     * rather than an error. So each of the three tones above also exists as a
     * triple, and the alpha variants use that one. Same convention Vuetify's own
     * `--v-theme-*` variables follow.
     */
    --v-brand-gold-rgb: 226, 165, 44;
    --v-paper-100-rgb: 247, 245, 241;

    /*
     * Legacy footer ink. The footer is the one region rebuilt to the legacy
     * design (vireolin-website/public/css/style.css, `.site-footer`), which is
     * a warm near-black gradient rather than the theme's surface, so it needs
     * the legacy's own neutrals rather than --v-theme-surface.
     */
    --v-ink-950: #14120e;
    --v-ink-900: #1d1a15;
    --v-paper-100: #f7f5f1;

    /*
     * Gold detail drawn *inside* a surface card - the home page's numbered
     * badges and challenge icons. On the light theme the card is a pale
     * surface, so it wants the ink variant; on the dark theme the same card
     * sits on near-black and the ink fails, while the raw gold clears it. The
     * `.v-theme--dark` class lives on #app, so the override just below reaches
     * every card without the components having to know the theme.
     */
    --v-card-accent: var(--v-brand-gold-ink);

    /*
     * Elevation ink, as an "r, g, b" triple like the rest of the tokens.
     *
     * The sheets are deliberately flat - a hairline border stands in for
     * elevation - but a card that MOVES on hover (the service cards lift 3px)
     * has to land somewhere, and a border that only recolours reads as a
     * highlight rather than as lift. The shadow is therefore the legacy's warm
     * near-black (--v-ink-950's family), not the theme's pure black: a cold
     * shadow on a page whose footer, bullets and buttons are all warm gold
     * reads as a different material. Dark theme points it at black, where a
     * warm shadow would glow instead of recede.
     */
    --v-shadow-ink: 20, 18, 14;
}

.v-theme--dark {
    --v-card-accent: var(--v-brand-gold);
    --v-shadow-ink: 0, 0, 0;
}

.v-theme--dark .home-why__callout {
    background: linear-gradient(145deg,
            rgb(var(--v-theme-surface-bright)) 0%,
            rgb(var(--v-theme-surface)) 70%);
}

.v-theme--dark .home-group-card:hover {
    box-shadow: 0 14px 28px -18px rgba(0, 0, 0, 0.75);
}

.v-theme--dark .home-cta::before,
.v-theme--dark .home-cta::after {
    background: radial-gradient(ellipse at center,
            rgba(var(--v-brand-gold-rgb), 0.55) 0%,
            rgba(var(--v-brand-gold-rgb), 0) 72%);
}

/* --------------------------------------------------------------------------
   Button height

   Fourth bundle defect, and the reason the button work below could not be
   judged on colour alone: `.v-btn` in vireolin.css sets no height, and neither
   `min-height` nor the `height` it needs. `.v-btn--density-default` does declare
   `height: calc(var(--v-btn-height) + 0px)`, but `--v-btn-height` is only ever
   set by a `.v-btn--size-*` class, and those classes set `padding: 0 Npx` with
   no vertical component and no height of their own.

   So every button on the site collapsed to its line box: 19px for a
   `--size-large` hero call to action, 13px for a `--size-small` shortcut. They
   were still correct in colour and still clickable, which is presumably why
   nothing caught it.

   `min-height` reads the same `--v-btn-height` the size classes already publish
   and falls back to Vuetify's own 36px default for the buttons that carry no
   size class (the icon buttons in the app bar, which were 20x19). Vertical
   only: no width moves, so the app bar's intrinsic-width arithmetic in
   "When the inline bar stops fitting" is unaffected.
   -------------------------------------------------------------------------- */

.v-btn {
    min-height: var(--v-btn-height, 36px);
}

/* --------------------------------------------------------------------------
   Brand buttons and eyebrows

   One ghost treatment for every non-primary action on the public site, so
   "Learn More", "Contact Us", "All Services", the catalogue filter chips and
   the footer CTA stop being four different buttons and read as one family.

     rest            logo-gold text, no fill, a hairline in the same gold
     hover / focus   the filled primary the buttons already used, so the hover
                     state is the pre-existing design rather than a new one
     active          stays filled, so a click does not flicker back to ghost

   The hairline is an inset box-shadow, not a border. A border would grow the
   box by 2px in both axes, and the app bar's two breakpoints are computed from
   the intrinsic width of its contents (see "When the inline bar stops
   fitting"); a class that silently changes every button's width is exactly the
   kind of thing that reopens that arithmetic. An inset shadow draws the same
   line inside the existing box and leaves layout untouched.

   `.v-btn-brand` also overrides `text-primary` and `bg-primary` deliberately,
   with `!important`: the whole point is that the resting state is no longer a
   filled primary, and a `!important` utility in the class list cannot be undone
   by the per-page class list this rule is fighting.
   -------------------------------------------------------------------------- */

.v-btn-brand {
    position: relative;
    box-shadow: inset 0 0 0 1px rgba(var(--v-theme-primary), 0.45) !important;
    background-color: transparent !important;
    color: var(--v-btn-brand-fg) !important;
    text-decoration: none;
    transition:
        color 0.18s ease-in-out,
        background-color 0.18s ease-in-out,
        box-shadow 0.18s ease-in-out;
}

.v-btn-brand:hover,
.v-btn-brand:focus-visible,
.v-btn-brand:active {
    background-color: rgb(var(--v-theme-primary)) !important;
    color: rgb(var(--v-theme-on-primary)) !important;
    box-shadow:
        inset 0 0 0 1px rgb(var(--v-theme-primary)),
        0 6px 18px -8px rgba(var(--v-theme-primary), 0.65) !important;
}

/* On the photo hero and in the dark footer the raw logo gold clears 7.9:1, so
   those regions re-point the label at it. All three selectors are containers,
   not buttons, which keeps the choice with the surface.

   `.home-hero` is the public home page's photo hero. It was missing from this
   list, so its two buttons fell back to --v-brand-gold-ink (#8A5F07), a dark
   brown label drawn over a dark photo scrim - legible on white, muddy and
   nearly invisible here. The container is `home-hero`, not `v-hero`, so the
   dark-surface choice has to name it. */
.v-hero,
.v-footer,
.home-hero {
    --v-btn-brand-fg: var(--v-brand-gold);
}

/*
   Eyebrows: "Komplettgruppe", "Über uns", section kickers. These were
   `.home-badge` - a filled gold chip reading as a button, which is not what a
   kicker is. Plain gold text, no fill, no border, no padding, so it reads as a
   label rather than as something to click.
*/
.v-eyebrow {
    display: inline-block;
    padding: 0;
    border: 0;
    background: none;
    border-radius: 0;
    color: var(--v-btn-brand-fg);
    font-size: 0.9rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    text-decoration: none;
    box-shadow: none;
}

/* A focus ring is still required on an interactive element; a borderless chip
   loses the affordance entirely without one. */
.v-btn-brand:focus-visible {
    outline: 2px solid var(--v-btn-brand-fg);
    outline-offset: 3px;
}

/* --------------------------------------------------------------------------
   Document / application frame
   Mirrors <VApp>: .v-application > .v-application__wrap
   -------------------------------------------------------------------------- */

html,
body {
    margin: 0;
    padding: 0;
}

body.v-shell-locked {
    overflow: hidden;
}

.v-application {
    display: flex;
    background: rgb(var(--v-theme-background));
    color: rgba(var(--v-theme-on-background), var(--v-high-emphasis-opacity));
}

.v-application__wrap {
    backface-visibility: hidden;
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    max-width: 100%;
    min-height: 100vh;
}

.v-main {
    flex: 1 0 auto;
    max-width: 100%;
    padding-top: var(--v-shell-content-offset);
    transition: 0.2s cubic-bezier(0.4, 0, 0.2, 1);
    transition-property: padding-top, padding-right, padding-bottom, padding-left;
}

/* --------------------------------------------------------------------------
   App bar
   -------------------------------------------------------------------------- */

/* `.v-app-bar.v-toolbar { background: rgb(var(--v-theme-surface)) }` in
   vireolin.css is specificity (0,2,0). A bare `.v-app-bar` rule here is
   (0,1,0) and loses, whatever the load order -- which is how the header ended
   up painting `color: #fff` (the `.v-app-bar--over-hero` rules below) onto an
   *opaque* surface: white text on #f5f5f5, i.e. an invisible header at the top
   of the home page that only appeared after the first scroll added
   `.v-app-bar--scrolled`. Both selectors are therefore re-stated at (0,2,0). */
.v-app-bar,
.v-app-bar.v-toolbar {
    display: flex;
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 10;
    height: var(--v-app-bar-height);
    padding-top: 20px;
    padding-bottom: 20px;
    background-color: rgb(var(--v-theme-surface));
    color: rgba(var(--v-theme-on-surface), var(--v-high-emphasis-opacity));
    transition: background-color 0.3s ease-in-out, color 0.3s ease-in-out,
        backdrop-filter 0.3s ease-in-out, box-shadow 0.3s ease-in-out;
}

.v-app-bar--scrolled,
.v-app-bar--scrolled.v-toolbar {
    background-color: rgba(255, 255, 255, 0.7);
    -webkit-backdrop-filter: blur(6px);
    backdrop-filter: blur(6px);
}

.v-app-bar--scrolled.v-theme--dark,
.v-theme--dark .v-app-bar--scrolled {
    background-color: rgba(30, 30, 30, 0.7);
}

/* `.v-app-bar--over-hero` is a no-op on purpose.

   The bundle's design had the bar float on top of the home hero picture, so it
   went transparent and white. That never worked here: `.v-main` reserves
   `--v-shell-content-offset` (see the `.v-main` rule above), so page content
   always *starts below* the bar and no hero is ever behind it. The only thing
   the class did in the port was force white text and an inverted-white logo
   over the opaque surface above. The class is kept on the element so the
   original markup contract survives, but it paints nothing.

   To get the overlay look back, the hero has to actually reach under the bar:
   drop `.v-main`'s padding for pages that open with `.home-hero`, set the bar
   back to `transparent` above, and re-enable these three rules. */
.v-app-bar--over-hero:not(.v-app-bar--scrolled) {
    color: rgba(var(--v-theme-on-surface), var(--v-high-emphasis-opacity));
}

.v-app-bar--over-hero:not(.v-app-bar--scrolled) .nav-link {
    color: rgb(var(--v-theme-text));
}

.v-app-bar--over-hero:not(.v-app-bar--scrolled) .v-logo {
    filter: none;
}

/* `.v-app-bar:not(.v-toolbar--absolute)` in the bundle reserves room for the
   scrollbar; a fixed bar already spans the viewport, so this is dropped. */

/* --------------------------------------------------------------------------
   Logo
   -------------------------------------------------------------------------- */

.v-logo {
    width: 130px;
    height: auto;
    object-fit: cover;
    transition: filter 0.3s ease-in-out;
}

/* --------------------------------------------------------------------------
   Desktop navigation
   -------------------------------------------------------------------------- */

/* `.links-center { position: absolute; left: 50%; translateX(-50%) }` took the
   nav out of flow, so nothing stopped the right-hand cluster from growing
   underneath it: at 1026px the three admin shortcuts (567px of label text on
   their own) pushed the cluster to 763px and it overlapped the centred nav by
   492px. The bar is now a three-column grid -- logo | nav | actions -- where
   the columns cannot overlap and the nav can be squeezed instead. */
.v-app-bar__inner {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    align-items: center;
    gap: 8px;
    width: 100%;
    min-width: 0;
}

.links-center {
    /* vireolin.css ships `.links-center { position: absolute; left: 50%;
       transform: translate(-50%) }` too. Both selectors are (0,1,0) and the
       shell loads last, so re-declaring is enough to win -- but every one of
       those four properties has to be reset, otherwise the nav keeps floating
       out of flow (and the leftover `transform` still shifts a static box). */
    position: static;
    left: auto;
    right: auto;
    transform: none;
    justify-self: center;
    min-width: 0;
}

.nav-link {
    position: relative;
    color: rgb(var(--v-theme-text));
    text-transform: none;
    font-size: 16px;
    /* Never let a squeezed centre column wrap a nav link onto two lines. */
    white-space: nowrap;
}

/* Header shortcut buttons.

   The five admin shortcuts carry their label text in the bar, and the bar has a
   finite width, so at some point the labels have to go. They go to the icon
   only; the anchor keeps `aria-label` and `title`, so the shortcut is still
   named for a screen reader and still legible on hover.

   The inline `font-size`/`me-1` that used to sit on the icons moved here so the
   spacing collapses with the label instead of leaving a dangling 4px gap.

   What the breakpoint is NOT is Vuetify's `lg` (1280). At 1280 the labels come
   back and the bar does not fit - see the block further down for the numbers
   and for what that overflow did. */

.v-tool-icon {
    font-size: 18px;
}

.v-tool-label {
    margin-inline-start: 4px;
}

@media (max-width: 1984.98px) {
    .v-tool-label {
        display: none;
    }
}

/* --------------------------------------------------------------------------
   When the inline bar stops fitting.

   Two independent widths, and conflating them is what produced the original
   bug:

   1. 1985px - wide enough for logo + nav + actions WITH all five admin
      shortcut labels. Measured per locale with the labels forced visible and
      the bar at `width: max-content`; German is the worst case at 1951
      (Spanish 1940, French 1843, Italian 1831, Turkish 1773, English 1743,
      Arabic 1342). See `test_the_breakpoint_is_wide_enough_for_every_admin_
      label_set`, which recomputes this rather than trusting the number.

   2. 1385px - wide enough for the same bar with the labels COLLAPSED, which
      is the state every viewport between the two breakpoints is actually in.
      German again, at 138 + 561 + 639 + 16 = 1354.

   The bar only fits in flow above 1354, but Vuetify's `d-md-flex` puts the nav
   on screen from 960. Between the two, `minmax(0, 1fr)` shrinks the centre
   column and the nav - which is 561px of content in a 191px box - spills 177px
   over the logo on one side and 177px over the actions on the other. Measured,
   not inferred: at a 985px viewport the nav's left edge was at -39 against a
   logo ending at 138.

   So the nav is not Vuetify's `md` breakpoint, and neither is `lg` (1280, still
   74px short). Below 1385 the bar drops to the hamburger, which is where a
   reader would expect the menu to be anyway - the inline nav is a luxury that
   needs real width, not a default.

   `.v-bar-narrow` carries the hamburger and the mobile account menu, so both
   come back at exactly the width the inline nav goes away.
   --------------------------------------------------------------------------- */

@media (max-width: 1383.98px) {
    .links-center {
        display: none !important;
    }

    .v-bar-narrow {
        display: inline-flex !important;
    }

    /* The desktop account menu, as opposed to the nav, the CTA and the
       shortcuts - those still fit at 960px and are wanted on the hamburger
       row. This one has a `v-bar-narrow` twin, so it has to stand down at the
       same width or both account icons render at once. */
    .v-bar-wide {
        display: none !important;
    }
}

.nav-link::after {
    content: '';
    position: absolute;
    left: 0;
    bottom: -2px;
    width: 0%;
    height: 2px;
    background-color: rgb(var(--v-theme-primary));
    transition: width 0.3s ease;
}

.nav-link:hover::after,
.nav-link.is-active::after {
    width: 100%;
}

/* --------------------------------------------------------------------------
   The request CTA

   It is the only control in the bar whose purpose is to be pressed, so it is
   the only one that moves: a ring spreads out of it every 2.6s and it lifts a
   pixel on hover.

   The ring lives on ::after, not on the button's own box-shadow. Vuetify sets
   an elevation shadow there, and animating the same property would either
   stomp the elevation or be stomped by it - which is how the first attempt at
   this ended up as a button that blinked.

   `overflow` is not set on the button, so the ring is drawn outside the box
   and needs `z-index: -1` with `isolation` on the parent to sit behind the
   label instead of over it.
   -------------------------------------------------------------------------- */

.v-bar-cta {
    position: relative;
    isolation: isolate;
    transition:
        transform 0.18s ease-in-out,
        box-shadow 0.18s ease-in-out;
}

.v-bar-cta::after {
    content: '';
    position: absolute;
    inset: 0;
    z-index: -1;
    border-radius: inherit;
    pointer-events: none;
    box-shadow: 0 0 0 0 rgba(var(--v-theme-primary), 0);
    animation: v-bar-cta-pulse 2.6s ease-out infinite;
}

@keyframes v-bar-cta-pulse {
    0% {
        box-shadow: 0 0 0 0 rgba(var(--v-theme-primary), 0.5);
    }

    70% {
        box-shadow: 0 0 0 12px rgba(var(--v-theme-primary), 0);
    }

    100% {
        box-shadow: 0 0 0 0 rgba(var(--v-theme-primary), 0);
    }
}

.v-bar-cta:hover,
.v-bar-cta:focus-visible {
    transform: translateY(-1px);
    box-shadow: 0 6px 18px -8px rgba(var(--v-theme-primary), 0.65);
}

/* Hover lifts; the ring is the resting affordance, and running both at once
   reads as two ideas competing. */
.v-bar-cta:hover::after,
.v-bar-cta:focus-visible::after {
    animation: none;
    box-shadow: 0 0 0 0 rgba(var(--v-theme-primary), 0);
}

@media (prefers-reduced-motion: reduce) {
    .v-bar-cta::after {
        animation: none;
    }

    .v-bar-cta:hover,
    .v-bar-cta:focus-visible {
        transform: none;
    }
}

/* --------------------------------------------------------------------------
   Theme toggle
   -------------------------------------------------------------------------- */

.theme-icon {
    transition: transform 0.3s ease-in-out;
}

.theme-icon:hover {
    transform: rotate(20deg);
}

/* --------------------------------------------------------------------------
   Mobile navigation
   -------------------------------------------------------------------------- */

.v-mobile-nav {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 100;
    visibility: hidden;
}

.v-mobile-nav.is-open {
    visibility: visible;
}

.v-mobile-nav__scrim {
    position: absolute;
    inset: 0;
    background-color: rgba(0, 0, 0, 0.5);
    opacity: 0;
    transition: opacity 0.2s ease-in-out;
}

.v-mobile-nav.is-open .v-mobile-nav__scrim {
    opacity: 1;
}

.v-mobile-nav__panel {
    position: absolute;
    top: 0;
    bottom: 0;
    inset-inline-end: 0;
    width: min(320px, 84vw);
    display: flex;
    flex-direction: column;
    background-color: rgb(var(--v-theme-surface));
    color: rgba(var(--v-theme-on-surface), var(--v-high-emphasis-opacity));
    transform: translateX(100%);
    transition: transform 0.2s cubic-bezier(0.4, 0, 0.2, 1);
    box-shadow: 0 0 24px rgba(0, 0, 0, 0.24);
    overflow-y: auto;
}

.v-locale--is-rtl .v-mobile-nav__panel {
    transform: translateX(-100%);
}

.v-mobile-nav.is-open .v-mobile-nav__panel {
    transform: translateX(0);
}

.v-mobile-nav__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 16px;
}

.v-mobile-nav__links {
    padding: 8px 8px 24px;
}

.v-mobile-nav__link {
    display: flex;
    align-items: center;
    min-height: 48px;
    padding: 0 16px;
    border-radius: 8px;
    font-size: 16px;
    text-decoration: none;
    color: rgba(var(--v-theme-on-surface), var(--v-high-emphasis-opacity));
}

.v-mobile-nav__link:hover,
.v-mobile-nav__link:focus-visible,
/* The drawer lists the languages too, and marks the current one the same way
   the desktop locale menu does. */
.v-mobile-nav__link.is-active {
    background-color: rgba(var(--v-theme-on-surface), var(--v-hover-opacity));
}

.v-mobile-nav__divider {
    height: 1px;
    margin: 8px 16px;
    background-color: rgba(var(--v-theme-on-surface), var(--v-border-opacity));
}

/* --------------------------------------------------------------------------
   Account dropdown
   -------------------------------------------------------------------------- */

.v-account-menu {
    position: absolute;
    top: calc(100% + 8px);
    inset-inline-end: 0;
    min-width: 220px;
    padding: 8px 0;
    border-radius: 8px;
    background-color: rgb(var(--v-theme-surface));
    color: rgba(var(--v-theme-on-surface), var(--v-high-emphasis-opacity));
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.16);
    visibility: hidden;
    opacity: 0;
    transform: translateY(-8px);
    transition: opacity 0.15s ease-in-out, transform 0.15s ease-in-out,
        visibility 0.15s;
}

.v-account-menu.is-open {
    visibility: visible;
    opacity: 1;
    transform: translateY(0);
}

.v-account-menu__item {
    display: flex;
    align-items: center;
    width: 100%;
    padding: 10px 16px;
    border: 0;
    background: none;
    font: inherit;
    font-size: 15px;
    text-align: start;
    text-decoration: none;
    color: inherit;
    cursor: pointer;
}

.v-account-menu__item:hover,
.v-account-menu__item:focus-visible {
    background-color: rgba(var(--v-theme-on-surface), var(--v-hover-opacity));
}

/* The desktop bar positions these absolutely; give the wrapper a context so
   the dropdown does not escape the bar. */
.v-app-bar__account {
    position: relative;
}

/* --------------------------------------------------------------------------
   Language switcher
   -------------------------------------------------------------------------- */

.v-locale-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    height: 40px;
    padding: 0 12px;
    border: 1px solid rgba(var(--v-theme-on-surface), var(--v-border-opacity));
    border-radius: 4px;
    font-size: 14px;
    color: inherit;
    background: transparent;
    cursor: pointer;
}

.v-locale-btn:hover {
    background-color: rgba(var(--v-theme-on-surface), var(--v-hover-opacity));
}

.v-locale-menu {
    position: absolute;
    top: calc(100% + 8px);
    inset-inline-end: 0;
    min-width: 180px;
    padding: 8px 0;
    border-radius: 8px;
    background-color: rgb(var(--v-theme-surface));
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.16);
    visibility: hidden;
    opacity: 0;
    transform: translateY(-8px);
    transition: opacity 0.15s ease-in-out, transform 0.15s ease-in-out,
        visibility 0.15s;
}

.v-locale-menu.is-open {
    visibility: visible;
    opacity: 1;
    transform: translateY(0);
}

.v-locale-menu__item {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    padding: 9px 16px;
    border: 0;
    background: none;
    font: inherit;
    font-size: 15px;
    text-align: start;
    color: rgba(var(--v-theme-on-surface), var(--v-high-emphasis-opacity));
    text-decoration: none;
    cursor: pointer;
}

.v-locale-menu__item:hover,
.v-locale-menu__item.is-active {
    background-color: rgba(var(--v-theme-on-surface), var(--v-hover-opacity));
}

.v-locale-menu__flag {
    font-size: 18px;
    line-height: 1;
}

/* --------------------------------------------------------------------------
   Footer

   A copy of the legacy design, not an adaptation of it:
   vireolin-website/templates/footer.html and the `.site-footer` block in
   vireolin-website/public/css/style.css (lines 506-538) plus its two
   responsive steps.

   The one thing carried over rather than copied is the colour scheme. The
   legacy is dark in both themes because it had one theme; this site has a light
   and a dark theme, and a footer that flips with them would be a different
   design on half the visits. The legacy's warm near-black is used literally, so
   the footer reads the same at every setting.

   `--v-ink-950`/`--v-ink-900`/`--v-paper-100` are the legacy's own neutrals,
   declared in the tokens block at the top of this file. Everything with an
   alpha in them is the legacy's `rgba(247,245,241,·)` expressed against
   --v-paper-100 so the intent survives if the paper tone is ever changed.
   -------------------------------------------------------------------------- */

.footer {
    /* border-image on a solid background paints the gradient across the top
       edge only - the legacy's `border-image: … 1`. */
    border-top: 3px solid transparent;
    border-image: linear-gradient(90deg, #f0c976 0%, #c9941e 100%) 1;
    background-image: linear-gradient(180deg, var(--v-ink-900) 0%, var(--v-ink-950) 100%);
    background-color: var(--v-ink-950);
    color: var(--v-paper-100);
    transition: background-color 0.3s ease-in-out, color 0.3s ease-in-out;
}

.footer a {
    text-decoration: none;
}

/* `pa-10` was the Vuetify padding utility. The legacy used 76px here; the
   footer was then reported as "almost half the screen", so the block was
   tightened without changing its structure - the columns, divider and bottom
   row are all still the legacy's. */
.footer__inner {
    padding-top: 40px;
}

.footer__top {
    display: grid;
    grid-template-columns: 1.6fr 1.3fr 1.2fr 1fr;
    gap: 26px;
    padding-bottom: 32px;
    border-bottom: 1px solid rgba(var(--v-paper-100-rgb), 0.14);
}

/* -- brand ---------------------------------------------------------------- */

.footer__wordmark {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    color: #fff;
    font-size: 1.15rem;
    font-weight: 700;
}

.footer__mark {
    width: 30px;
    height: 30px;
}

.footer__about {
    margin: 14px 0 16px;
    max-width: 34ch;
    color: rgba(var(--v-paper-100-rgb), 0.68);
    font-size: 0.92rem;
}

/* The brand column has no rules of its own in the legacy either - it is a grid
   cell holding a wordmark, a paragraph and the social row, all three of which
   are styled above. Kept as an explicit rule so the class reads as an
   intentional hook rather than as a leftover, and so the column stays a
   block-level box under RTL the way the other three are. */
.footer__brand {
    min-width: 0;
}

/* Circular buttons, not bare glyphs: the legacy's `.footer-social a` is a 34px
   circle with a 15px icon inside, and the ring is what makes the row read as a
   set rather than as four loose links. */
.footer__social {
    display: flex;
    gap: 10px;
    margin-top: 16px;
}

.footer__social a {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    border: 1px solid rgba(var(--v-paper-100-rgb), 0.25);
    border-radius: 50%;
    color: rgba(var(--v-paper-100-rgb), 0.85);
    transition:
        border-color 0.15s ease-in-out,
        color 0.15s ease-in-out,
        background-color 0.15s ease-in-out;
}

.footer__social a:hover,
.footer__social a:focus-visible {
    border-color: var(--v-brand-gold);
    background-color: rgba(var(--v-brand-gold-rgb), 0.12);
    color: #fff;
}

.footer__social .mdi {
    font-size: 15px;
    vertical-align: middle;
}

/* The Xing profile ships as an inline SVG (no glyph in the bundled icon font),
   matched to the 15px of the font icons beside it. */
.footer__social svg {
    width: 15px;
    height: 15px;
    fill: currentColor;
}

/* -- column headings ------------------------------------------------------ */

/* The mono uppercase treatment is the legacy's own `.footer-col h4`
   (`--font-mono`, .82rem, .08em tracking, 55% paper). It is what separates a
   column label from a heading, so it is reproduced rather than approximated
   with the theme's `text-h5` + gold, which is what this used to be. */
.footer__heading {
    margin: 0 0 14px;
    color: rgba(var(--v-paper-100-rgb), 0.55);
    font-family: var(--v-font-mono, 'IBM Plex Mono', 'Courier New', monospace);
    font-size: 0.82rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    line-height: 1.4;
    text-transform: uppercase;
}

.footer__col ul {
    padding: 0;
    margin: 0;
    list-style: none;
}

.footer__col li {
    margin-bottom: 7px;
}

.footer__col a {
    color: rgba(var(--v-paper-100-rgb), 0.85);
    font-size: 0.92rem;
    transition: color 0.15s ease-in-out;
}

.footer__col a:hover,
.footer__col a:focus-visible {
    color: #fff;
    text-decoration: underline;
}

/* -- navigation and services ---------------------------------------------- */

.footer__nav {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0 28px;
}

/* The legacy caps this and scrolls. Without a cap a site with thirty services
   turns the footer into a full-page list, so the cap stays - but the
   scrollbar itself is hidden (the list still scrolls by wheel/trackpad). */
.footer__services {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 2px 24px;
    max-height: 178px;
    overflow-y: auto;
    overflow-x: hidden;
    scrollbar-width: none; /* Firefox */
    -ms-overflow-style: none; /* legacy Edge / IE */
}

.footer__services::-webkit-scrollbar {
    display: none;
}

/* A grid item's default `min-width: auto` floors it at the width of its
   longest unbreakable word, so one long German service name (ein-
   bruchmeldeanlagen, videoüberwachungstechnik) grew the grid past the column
   and produced a horizontal scrollbar. `min-width: 0` lets the track shrink and
   `overflow-wrap: anywhere` lets the word break inside it instead. */
.footer__services li {
    min-width: 0;
    margin: 0;
}

.footer__services a {
    display: inline-block;
    padding: 3px 0;
    color: rgba(var(--v-paper-100-rgb), 0.78);
    font-size: 0.86rem;
    line-height: 1.35;
    overflow-wrap: anywhere;
}

.footer__services a:hover,
.footer__services a:focus-visible {
    color: #fff;
}

/* -- contact column ------------------------------------------------------- */

/* `address` is italic by default, which reads as emphasis rather than as an
   address, so the style is reset - as it is in the legacy. */
.footer__contact {
    display: flex;
    flex-direction: column;
    margin: 0;
    color: rgba(var(--v-paper-100-rgb), 0.85);
    font-style: normal;
    font-size: 0.92rem;
    line-height: 1.7;
}

.footer__contact a {
    color: rgba(var(--v-paper-100-rgb), 0.85);
}

.footer__contact a:hover,
.footer__contact a:focus-visible {
    color: #fff;
    text-decoration: underline;
}

.footer__contact-name {
    font-weight: 700;
    color: #fff;
}

.footer__col-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    margin-top: 16px;
}

/* -- bottom row ----------------------------------------------------------- */

.footer__bottom {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 16px 0;
    color: rgba(var(--v-paper-100-rgb), 0.6);
    font-size: 0.82rem;
}

.footer__legal {
    display: flex;
    flex-wrap: wrap;
    gap: 22px;
    padding: 0;
    margin: 0;
    list-style: none;
}

.footer__legal a {
    color: rgba(var(--v-paper-100-rgb), 0.75);
}

.footer__legal a:hover,
.footer__legal a:focus-visible {
    color: #fff;
    text-decoration: underline;
}

/* -- responsive ----------------------------------------------------------- */

/* The legacy's two steps: 1.6/1.3/1.2/1 -> 1fr 1fr -> 1fr. Their breakpoints
   are 1080px and 760px; both are copied rather than re-derived, because the
   column widths they were chosen for are the ones above. */
@media (max-width: 1079.98px) {
    .footer__top {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

@media (max-width: 759.98px) {
    .footer__inner {
        padding-top: 32px;
    }

    .footer__top {
        grid-template-columns: 1fr;
        gap: 20px;
        padding-bottom: 26px;
    }

    .footer__nav,
    .footer__services {
        grid-template-columns: 1fr;
    }
}

/* Keeps the MDI glyph on the text baseline next to a wrapped paragraph. */
.footer .mdi {
    vertical-align: middle;
}

/* --------------------------------------------------------------------------
   Utility classes the SPA relied on Vue bindings for
   -------------------------------------------------------------------------- */

.is-hidden {
    display: none !important;
}

.u-visually-hidden {
    position: absolute !important;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* Skip link: visible only when focused. */
.skip-link {
    position: absolute;
    top: -100px;
    inset-inline-start: 8px;
    z-index: 200;
    padding: 10px 16px;
    border-radius: 0 0 8px 8px;
    background-color: rgb(var(--v-theme-primary));
    color: rgb(var(--v-theme-on-primary));
    text-decoration: none;
}

.skip-link:focus {
    top: 0;
}

/* --------------------------------------------------------------------------
   Right-to-left
   The markup is written with logical classes only, so the flip itself is
   handled here rather than by duplicating every template.
   -------------------------------------------------------------------------- */

.v-locale--is-rtl {
    direction: rtl;
}

.v-locale--is-rtl .v-mobile-nav__panel,
.v-locale--is-rtl .v-account-menu,
.v-locale--is-rtl .v-locale-menu {
    text-align: right;
}

/* Vuetify's own RTL rules ship in the bundle; this only covers the app-bar
   gradient and the icon pairs the SPA styled by hand. */
.v-locale--is-rtl .mr-2 {
    margin-right: 0 !important;
    margin-left: 8px;
}

.v-locale--is-rtl .mr-3 {
    margin-right: 0 !important;
    margin-left: 16px;
}

.v-locale--is-rtl .text-right {
    text-align: left !important;
}

/* --------------------------------------------------------------------------
   Reduced motion
   The bundle ships AOS and initialises it with defaults
   (offset 120, duration 400, easing ease, once false).
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
    html,
    body,
    .v-application,
    .v-card,
    .v-app-bar,
    .v-footer {
        transition: none !important;
    }

    [data-aos] {
        transition-duration: 0.01ms !important;
        animation-duration: 0.01ms !important;
    }

    [data-aos].aos-animate {
        transition-duration: 0.01ms !important;
    }
}
/* --------------------------------------------------------------------------
   Public home page
   The SPA rendered these blocks with Vuetify layout primitives; the values
   below come from the bundle's own measurements so the Blade markup lines up
   the same way.
   -------------------------------------------------------------------------- */

/* Long-form copy stops at a readable measure. The SPA got this from
   v-container + max-width on the paragraph, which does not exist here. */
.home-measure {
    max-width: 60ch;
    margin-inline: auto;
}

/* 1. Hero --------------------------------------------------------------- */

.home-hero {
    position: relative;
    overflow: hidden;
}

.home-hero__scrim {
    position: absolute;
    inset: 0;
    /* The photo is a pale sky shot, so the light theme needs a real scrim
       for white text to clear contrast. The bundle layered the same
       gradient over the background-image.

       The gold wash at the bottom edge is the one addition: it seats the
       photo on the page's brand colour instead of letting it fade to
       whatever the picture happens to end on, and it gives the two hero
       buttons a slightly warmer floor to sit above. It stays under 0.3
       alpha so it tints rather than covers. */
    background:
        linear-gradient(180deg,
            rgba(0, 0, 0, 0.5) 0%,
            rgba(0, 0, 0, 0.28) 50%,
            rgba(0, 0, 0, 0.58) 100%),
        linear-gradient(0deg,
            rgba(var(--v-brand-gold-rgb), 0.28) 0%,
            rgba(var(--v-brand-gold-rgb), 0) 38%);
}

/* The kicker rule above the headline: a short gold bar, the same gesture the
   footer opens with (border-image gradient), so the first thing on the page
   and the last thing share one mark. Decorative - the eyebrow already carries
   the same words as text, so this adds no information and stays aria-hidden. */
.home-hero__content::before {
    content: '';
    display: block;
    width: 3.5rem;
    height: 3px;
    margin: 0 auto 1.5rem;
    border-radius: 2px;
    background: linear-gradient(90deg, #f0c976 0%, var(--v-brand-gold) 60%, #c9941e 100%);
    box-shadow: 0 0 14px rgba(var(--v-brand-gold-rgb), 0.55);
}

.home-hero__content {
    position: relative;
    z-index: 1;
    padding: 0 1.5rem;
    max-width: 60rem;
    /* The headline is centre-set and long in German and Turkish; balance keeps
       a two-line title from leaving a single orphan word on the second line. */
    text-wrap: balance;
}

.home-hero__title {
    font-size: clamp(2.15rem, 5.4vw, 4.25rem);
    font-weight: 700;
    line-height: 1.06;
    /* Roboto's default tracking is set for body copy; at display size it
       loosens the counters and the headline stops reading as one shape. */
    letter-spacing: -0.02em;
    color: #fff;
    text-shadow: 0 2px 12px rgba(0, 0, 0, 0.42);
    text-wrap: balance;
}

.home-hero__subtitle {
    margin-top: 1.25rem;
    margin-inline: auto;
    max-width: 46ch;
    font-size: clamp(1.02rem, 2vw, 1.3rem);
    line-height: 1.55;
    color: rgba(255, 255, 255, 0.92);
    text-shadow: 0 1px 8px rgba(0, 0, 0, 0.4);
}

/* 2. Stat cards --------------------------------------------------------- */

.home-stats {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 1rem;
    width: 100%;
}

.home-stats__item {
    flex: 0 0 auto;
    width: 100%;
    max-width: 20rem;
}

/* `hover-scale` in the bundle: the card lifts on hover. Cards in this sheet
   are flat by design: a hairline border stands in for elevation. The
   `--v-shadow-key-*` tokens these rules once used are never defined, so the
   `box-shadow` declarations were silently dropped - hence the borders. */
.home-stats__card {
    height: 100%;
    border: 1px solid rgba(var(--v-border-color), var(--v-border-opacity));
    border-radius: 0.5rem;
    transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}

.home-stats__card:hover {
    transform: scale(1.03);
}

/* 3. Services section --------------------------------------------------- */

/* Superseded by `.v-eyebrow`, which is the same intent stated as a component:
   a gold kicker with no fill. Kept as an alias so a `.home-badge` left in a
   view cannot reintroduce the filled chip that made a section title look like
   a button. */
.home-badge,
.home-cta__badge {
    background-color: transparent;
    border: 0;
    border-radius: 0;
    padding: 0;
    color: var(--v-btn-brand-fg);
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

.home-services__grid {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 2rem;
    width: 100%;
    max-width: 72rem;
    margin-inline: auto;
    padding: 0 1.5rem;
}

.home-services__features {
    flex: 1 1 22rem;
}

.home-services__media {
    flex: 1 1 20rem;
}

.home-services__image {
    max-width: 100%;
    height: auto;
    border-radius: 0.75rem;
}

.home-feature {
    background-color: rgb(var(--v-theme-surface));
    border: 1px solid rgba(var(--v-border-color), var(--v-border-opacity));
    border-radius: 0.5rem;
}

/* 4. Stage carousel ----------------------------------------------------- */

.home-carousel {
    position: relative;
    width: 100%;
    max-width: 72rem;
    margin-inline: auto;
    padding: 0 1.5rem 3rem;
}

.home-carousel__viewport {
    position: relative;
    overflow: hidden;
    border-radius: 0.5rem;
}

/* Only the active slide is in flow; the others are stacked and faded. This is
   what v-carousel did with its slide-x-transition, minus the transform. */
.home-carousel__slide {
    display: none;
}

.home-carousel__slide.is-active {
    display: block;
    animation: home-carousel-slide 0.4s ease;
}

.home-carousel__slide.is-leaving {
    display: block;
    position: absolute;
    inset: 0;
    opacity: 0;
    transition: opacity 0.4s ease;
}

@keyframes home-carousel-slide {
    from {
        opacity: 0;
        transform: translateX(24px);
    }

    to {
        opacity: 1;
        transform: translateX(0);
    }
}

.home-carousel__image {
    display: block;
    width: 100%;
    height: 18rem;
    object-fit: cover;
}

.home-carousel__caption {
    padding: 1.5rem;
    background-color: rgb(var(--v-theme-surface));
}

.home-carousel__dots {
    display: flex;
    justify-content: center;
    gap: 0.5rem;
    margin-top: 1.5rem;
}

.home-carousel__dot {
    width: 0.75rem;
    height: 0.75rem;
    padding: 0;
    border: none;
    border-radius: 50%;
    background-color: rgba(var(--v-border-color), 0.35);
    cursor: pointer;
    transition: background-color 0.2s ease, transform 0.2s ease;
}

.home-carousel__dot.is-active {
    background-color: rgb(var(--v-theme-primary));
    transform: scale(1.25);
}

/* 2. Why Vireolin? ------------------------------------------------------ */
/* Editorial split: a sticky intro column beside the section's condensed
   four-sentence statement (`home.whyText1..4`). The opening sentence is set as
   a lead, and the closing onboarding offer becomes a callout panel carrying
   the section's CTA, so the action sits beside the text that motivates it.
   Replaces the legacy split's four numbered cards. */

.home-why__layout {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.25fr);
    gap: 3.5rem;
    align-items: start;
    max-width: 72rem;
    margin-inline: auto;
    padding-inline: 1.5rem;
}

.home-why__intro {
    position: sticky;
    top: calc(var(--v-app-bar-height) + 1.5rem);
}

.home-why__statement {
    max-width: 42rem;
}

.home-why__statement > p {
    margin-bottom: 1.15rem;
    line-height: 1.75;
    color: rgba(var(--v-theme-on-surface), 0.85);
}

.home-why__lead {
    font-size: 1.25rem;
    line-height: 1.6;
    font-weight: 500;
    color: rgb(var(--v-theme-on-surface));
    text-wrap: balance;
}

.home-why__callout {
    position: relative;
    display: flex;
    align-items: flex-start;
    gap: 1.1rem;
    margin-top: 2rem;
    padding: 1.5rem;
    border: 1px solid rgba(var(--v-border-color), var(--v-border-opacity));
    border-radius: 0.5rem;
    background: linear-gradient(145deg,
            rgb(var(--v-theme-surface-bright, 255, 255, 255)) 0%,
            rgb(var(--v-theme-surface)) 70%);
    overflow: hidden;
    box-shadow: 0 18px 30px -22px rgba(var(--v-shadow-ink), 0.6);
    transition: transform 0.25s ease, box-shadow 0.25s ease;
}

.home-why__callout:hover {
    transform: translateY(-2px);
    box-shadow: 0 22px 34px -24px rgba(var(--v-shadow-ink), 0.8);
}

/* The gold leading edge is the site's "key tile" gesture (see
   `.about-value-tile`), held open here: the callout is always an offer, not
   something you hover to reveal. */
.home-why__callout::before {
    content: "";
    position: absolute;
    inset-block: 0;
    inset-inline-start: 0;
    width: 3px;
    background: linear-gradient(180deg, var(--v-brand-gold) 0%, #c9941e 100%);
}

.home-why__callout-icon {
    flex: none;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 2.75rem;
    height: 2.75rem;
    border-radius: 50%;
    background-color: rgba(var(--v-theme-primary), 0.12);
    color: var(--v-card-accent);
    box-shadow: inset 0 0 0 1px rgba(var(--v-theme-primary), 0.35);
    font-size: 1.4rem;
}

.home-why__callout-icon .mdi {
    display: inline-flex;
}

.home-why__callout-body {
    flex: 1 1 auto;
    min-width: 0;
}

.home-why__callout-text {
    margin-bottom: 1rem;
    font-weight: 600;
    line-height: 1.6;
    color: rgb(var(--v-theme-on-surface));
}

/* 3. Challenges --------------------------------------------------------- */
/* The six problems as a bulleted list beside a supporting image. The list
   carries the content; the image fills the opposite column at the same
   height, so the two read as one balanced block. */

.challenges-split {
    display: grid;
    grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr);
    gap: 3rem;
    align-items: stretch;
    max-width: 72rem;
    margin-inline: auto;
}

.challenges-list {
    display: grid;
    gap: 1.4rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

/* The bullet: a gold disc in the site's accent. */
.challenge-item {
    position: relative;
    padding: 1rem 1.25rem 1rem 2.6rem;
    border: 1px solid transparent;
    border-radius: 0.5rem;
    transition: background-color 0.25s ease, border-color 0.25s ease, transform 0.25s ease;
}

.challenge-item::before {
    content: "";
    position: absolute;
    inset-inline-start: 1.1rem;
    top: 1.25rem;
    width: 0.6rem;
    height: 0.6rem;
    border-radius: 50%;
    background: radial-gradient(circle, #f0c976 0%, var(--v-brand-gold) 100%);
    box-shadow: 0 0 0 6px rgba(var(--v-brand-gold-rgb), 0.08);
}

.challenge-item:hover {
    background-color: rgb(var(--v-theme-surface));
    border-color: rgba(var(--v-border-color), var(--v-border-opacity));
    transform: translateX(4px);
}

.challenge-item__title {
    font-size: 1.0625rem;
    font-weight: 700;
    line-height: 1.45;
    margin-bottom: 0.15rem;
}

.challenge-item__text {
    margin: 0;
    font-size: 0.9375rem;
    line-height: 1.6;
    color: rgba(var(--v-theme-on-surface), 0.72);
}

/* The image is absolutely positioned so the column simply matches the list's
   height; the mobile breakpoint gives it its own aspect ratio instead. */
.challenges-media {
    position: relative;
    min-height: 16rem;
    border-radius: 0.75rem;
    overflow: hidden;
}

.challenges-media img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* 4. Services grid ------------------------------------------------------ */

.home-groups {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
    gap: 1rem;
    max-width: 72rem;
    margin-inline: auto;
    padding-inline: 1.5rem;
}

.home-group-card {
    position: relative;
    display: block;
    border: 1px solid rgba(var(--v-border-color), var(--v-border-opacity));
    border-radius: 0.5rem;
    text-decoration: none;
    color: inherit;
    overflow: hidden;
    transition:
        transform 0.25s ease,
        border-color 0.25s ease,
        box-shadow 0.25s ease;
}

/* The gold edge that grows in from the top on hover. It is the one piece of
   brand colour these cards get while resting they are plain surfaces, and the
   rule reads as "this tile is live" without the whole card having to change
   fill. Drawn as a pseudo-element rather than a border so it cannot push the
   1px hairline the grid's geometry already assumes. */
.home-group-card::before {
    content: '';
    position: absolute;
    inset: 0 0 auto;
    height: 3px;
    background: linear-gradient(90deg, #f0c976 0%, var(--v-brand-gold) 55%, #c9941e 100%);
    transform: scaleX(0);
    transform-origin: left;
    transition: transform 0.3s ease;
}

.home-group-card .mdi {
    transition: transform 0.25s ease, color 0.25s ease;
}

.home-group-card:hover {
    transform: translateY(-4px);
    border-color: rgba(var(--v-theme-primary), 0.5);
    box-shadow: 0 14px 28px -18px rgba(var(--v-shadow-ink), 0.55);
}

.home-group-card:hover::before,
.home-group-card:focus-visible::before {
    transform: scaleX(1);
}

.home-group-card:hover .mdi {
    transform: translateY(-2px) scale(1.06);
}

/* Keyboard users get the same two signals as the pointer, plus the outline
   the fill-less tile would otherwise lose. */
.home-group-card:focus-visible {
    outline: 2px solid var(--v-brand-gold-ink);
    outline-offset: 2px;
}

/* 5. Process ------------------------------------------------------------ */

.home-process__strip {
    display: grid;
    grid-template-columns: repeat(5, minmax(0, 1fr));
    gap: 2rem 1.5rem;
    max-width: 72rem;
    margin-inline: auto;
    padding: 0;
    list-style: none;
}

.home-process__step {
    position: relative;
}

.home-process__num {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 1.9rem;
    height: 1.9rem;
    margin-bottom: 0.9rem;
    border-radius: 50%;
    background: radial-gradient(circle, #f0c976 0%, var(--v-brand-gold) 100%);
    color: #fff;
    box-shadow:
        inset 0 0 0 1px rgba(255, 255, 255, 0.25),
        0 8px 16px -10px rgba(var(--v-shadow-ink), 0.9);
    font-size: 0.82rem;
    font-weight: 700;
}

/* The connector line between steps on wider viewports. It reads as a flow
   rather than as five isolated cards - the site is about process, so
   showing the pipeline is the point. Only drawn when there's room to do it
   without creating a tangled mess. */
@media (min-width: 960px) {
    .home-process__strip {
        position: relative;
    }

    .home-process__strip::before {
        content: '';
        position: absolute;
        top: 0.95rem;
        left: calc(1.5rem + 0.95rem);
        right: calc(1.5rem + 0.95rem);
        height: 1px;
        background: linear-gradient(90deg,
                rgba(var(--v-brand-gold-rgb), 0.5) 0%,
                rgba(var(--v-border-color), 0.16) 100%);
    }

    .home-process__step {
        position: relative;
        z-index: 1;
    }
}

/* The dark sections need their horizontal gutter; the grids above cap their
   own width but do not pad, so the padding lives on the section. */
.home-challenges,
.home-process {
    padding-inline: 1.5rem;
}

@media (max-width: 959px) {
    .home-why__layout {
        grid-template-columns: minmax(0, 1fr);
        gap: 2rem;
    }

    .home-why__intro {
        position: static;
    }

    .home-process__strip {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    /* Stacked, the split collapses to one column and the image has no list to
       match, so it takes its own aspect ratio. */
    .challenges-split {
        grid-template-columns: minmax(0, 1fr);
        gap: 2rem;
    }

    .challenges-media {
        min-height: 0;
        aspect-ratio: 3 / 2;
    }
}

@media (max-width: 599px) {
    .home-process__strip {
        grid-template-columns: minmax(0, 1fr);
    }
}

/* 6. Call to action ----------------------------------------------------- */

.home-cta {
    background: linear-gradient(180deg,
            rgba(var(--v-theme-surface), 0) 0%,
            rgba(var(--v-theme-surface), 0.92) 28%,
            rgba(var(--v-theme-surface), 0.92) 72%,
            rgba(var(--v-theme-surface), 0) 100%);
    position: relative;
}

.home-cta::before,
.home-cta::after {
    content: '';
    position: absolute;
    left: 50%;
    width: min(72rem, 88vw);
    height: 1px;
    transform: translateX(-50%);
    background: radial-gradient(ellipse at center,
            rgba(var(--v-brand-gold-rgb), 0.45) 0%,
            rgba(var(--v-brand-gold-rgb), 0) 70%);
}

.home-cta::before {
    top: 0;
}

.home-cta::after {
    bottom: 0;
}

.home-cta__heading {
    position: relative;
    text-wrap: balance;
}

.home-cta__heading::after {
    content: '';
    display: block;
    width: 3rem;
    height: 3px;
    margin: 1rem auto 0;
    border-radius: 2px;
    background: linear-gradient(90deg, #f0c976 0%, var(--v-brand-gold) 60%, #c9941e 100%);
}

@media (max-width: 960px) {
    .home-hero__content {
        max-width: none;
    }
}

/* RTL: the carousel enters from the other side, matching v-locale--is-rtl. */
.v-locale--is-rtl .home-carousel__slide.is-active {
    animation-name: home-carousel-slide-rtl;
}

@keyframes home-carousel-slide-rtl {
    from {
        opacity: 0;
        transform: translateX(-24px);
    }

    to {
        opacity: 1;
        transform: translateX(0);
    }
}

/* --------------------------------------------------------------------------
   About / contact / services pages
   -------------------------------------------------------------------------- */

.page-about,
.page-contact,
.page-services,
.page-service-detail {
    width: 100%;
    max-width: 72rem;
    margin-inline: auto;
    padding-inline: 1.5rem;
}

.about-story {
    max-width: 56rem;
    margin-inline: auto;
}

.about-values__grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
    gap: 1.25rem;
}

.about-value-card {
    border: 1px solid rgba(var(--v-border-color), var(--v-border-opacity));
    border-radius: 0.5rem;
}

/* Values & vision: a split block - a sticky intro column beside a 2x2 grid
   of icon tiles. Deliberately not the centred card wall the Positioning
   section below uses; two identical card sections back to back read as one
   section twice. Mirrors the home page's `.home-why` rhythm so the pattern
   feels familiar, and inherits RTL from logical properties throughout. */
.about-values-split {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.25fr);
    gap: 3.5rem;
    align-items: start;
}

.about-values-split__intro {
    position: sticky;
    top: calc(var(--v-app-bar-height) + 1.5rem);
}

/* Left-aligned inside the split; the centred mobile treatment comes from the
   single-column breakpoint below. */
.about-values-split__intro .v-eyebrow,
.about-values-split__intro h2,
.about-values-split__intro p {
    text-align: start;
}

.about-values-split__grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1rem;
}

.about-value-tile {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    padding: 1.5rem;
    border: 1px solid rgba(var(--v-border-color), var(--v-border-opacity));
    border-radius: 0.5rem;
    background: rgb(var(--v-theme-surface));
    overflow: hidden;
    transition: transform 0.25s ease, border-color 0.25s ease;
}

/* Gold leading edge on hover - the site-wide "key tile" gesture (it was the
   legacy home page's card treatment), kept as a pseudo-element so the
   resting card is unchanged. */
.about-value-tile::before {
    content: "";
    position: absolute;
    inset-block: 0;
    inset-inline-start: 0;
    width: 3px;
    background: linear-gradient(180deg, var(--v-brand-gold) 0%, #c9941e 100%);
    transform: scaleY(0);
    transform-origin: top;
    transition: transform 0.25s ease;
}

.about-value-tile:hover {
    transform: translateY(-3px);
    border-color: rgba(var(--v-theme-primary), 0.5);
}

.about-value-tile:hover::before {
    transform: scaleY(1);
}

.about-value-tile__icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 2.75rem;
    height: 2.75rem;
    margin-bottom: 0.9rem;
    border-radius: 50%;
    background: rgba(var(--v-theme-primary), 0.12);
    color: var(--v-card-accent);
    box-shadow: inset 0 0 0 1px rgba(var(--v-theme-primary), 0.35);
}

@media (max-width: 959px) {
    .about-values-split {
        grid-template-columns: minmax(0, 1fr);
        gap: 2rem;
    }

    .about-values-split__intro {
        position: static;
        text-align: center;
    }

    .about-values-split__intro .v-eyebrow,
    .about-values-split__intro h2,
    .about-values-split__intro p {
        text-align: center;
    }
}

@media (max-width: 599px) {
    .about-values-split__grid {
        grid-template-columns: minmax(0, 1fr);
    }
}

.about-location {
    max-width: 34rem;
    margin-inline: auto;
}

/* Contact ---------------------------------------------------------------- */

.contact-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr));
    gap: 2rem;
    align-items: start;
}

.contact-label {
    display: block;
    margin-bottom: 0.35rem;
    font-size: 0.875rem;
    color: rgba(var(--v-theme-on-surface), 0.72);
}

.contact-input {
    display: block;
    width: 100%;
    padding: 0.55rem 0.75rem;
    /* Matches Vuetify's outlined field: 1px currentColor at low alpha, and a
       2px primary border once focused. */
    border: 1px solid rgba(var(--v-border-color), var(--v-border-opacity));
    border-radius: 0.25rem;
    background-color: transparent;
    color: rgb(var(--v-theme-on-surface));
    font: inherit;
    line-height: 1.5;
}

.contact-input:focus {
    outline: none;
    border-color: rgb(var(--v-theme-primary));
    box-shadow: 0 0 0 1px rgb(var(--v-theme-primary));
}

.contact-input.is-invalid {
    border-color: rgb(var(--v-theme-error));
}

textarea.contact-input {
    resize: vertical;
    min-height: 7rem;
}

.contact-error {
    margin-top: 0.3rem;
    font-size: 0.75rem;
    color: rgb(var(--v-theme-error));
}

.contact-detail-row a {
    color: rgb(var(--v-theme-primary));
}

/* Services catalogue ----------------------------------------------------- */

.services-filter__chips {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
}

/* The catalogue filter chips - "All Services" plus one per group. They are
   buttons in the same family as every other ghost button, so they take
   `.v-btn-brand`'s resting label; the `is-active` state keeps the filled
   primary it already had, because a selected filter has to be distinguishable
   from an unselected one at a glance and colour alone is the only cue here. */
.v-chip--filter {
    padding: 0.35rem 0.9rem;
    border: 1px solid rgba(var(--v-border-color), var(--v-border-opacity));
    border-radius: 1rem;
    background: transparent;
    color: var(--v-btn-brand-fg);
    font: inherit;
    font-size: 0.875rem;
    cursor: pointer;
    transition:
        background-color 0.2s ease,
        border-color 0.2s ease,
        color 0.2s ease,
        box-shadow 0.2s ease;
}

.v-chip--filter:hover {
    background: rgba(var(--v-theme-primary), 0.08);
    border-color: rgba(var(--v-theme-primary), 0.45);
}

.v-chip--filter:focus-visible {
    outline: 2px solid var(--v-btn-brand-fg);
    outline-offset: 2px;
}

.v-chip--filter.is-active {
    background-color: rgb(var(--v-theme-primary));
    border-color: rgb(var(--v-theme-primary));
    color: rgb(var(--v-theme-on-primary));
}

.service-group__body {
    padding-inline-start: 0.75rem;
    border-inline-start: 2px solid rgba(var(--v-theme-primary), 0.2);
}

.service-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(17rem, 1fr));
    gap: 1rem;
}

.service-card {
    display: block;
    border: 1px solid rgba(var(--v-border-color), var(--v-border-opacity));
    border-radius: 0.5rem;
    text-decoration: none;
    color: inherit;
    transition: transform 0.25s ease, border-color 0.25s ease;
}

.service-card:hover {
    transform: translateY(-2px);
    border-color: rgba(var(--v-theme-primary), 0.5);
}

.service-card__code {
    display: inline-block;
    margin-top: 0.6rem;
    font-size: 0.75rem;
    color: rgba(var(--v-theme-on-surface), 0.6);
}

/* The filter hides whole groups, so the layout has to collapse too. */
.service-group[hidden] {
    display: none;
}

/* Service detail --------------------------------------------------------- */

.service-breadcrumb {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    font-size: 0.875rem;
    color: rgba(var(--v-theme-on-surface), 0.7);
}

.service-breadcrumb a {
    color: rgb(var(--v-theme-primary));
    text-decoration: none;
}

.service-breadcrumb__sep {
    opacity: 0.5;
}

.service-detail__head {
    text-align: center;
}

.service-detail__head .d-flex {
    justify-content: center;
}

.service-detail__text {
    max-width: 52rem;
    margin-inline: auto;
    line-height: 1.75;
}

/* ------------------------------------------------------------------ *
 * Auth pages (login / register).
 *
 * Reuses .contact-form / .contact-input / .contact-label / .contact-error
 * from the contact page so the two forms cannot drift apart; only the
 * page frame and the submit button are new.
 * ------------------------------------------------------------------ */

.page-auth {
    display: flex;
    justify-content: center;
}

.auth-shell {
    width: 100%;
    max-width: 30rem;
}

/* The contact grid splits 1fr / 1fr; a single card needs to fill the shell. */
.auth-shell .contact-form {
    width: 100%;
}

.auth-hint {
    font-size: 0.75rem;
    opacity: 0.7;
    margin-top: 0.35rem;
}

.auth-meta {
    font-size: 0.875rem;
}

.auth-remember {
    cursor: pointer;
    opacity: 0.85;
}

.auth-link {
    color: var(--v-primary, #1a73e8);
    font-weight: 600;
}

.auth-link:hover {
    text-decoration: underline;
}

.auth-submit {
    display: block;
    width: 100%;
    padding: 0.8rem 1rem;
    font-weight: 600;
    color: var(--v-on-primary, #fff);
    background: rgb(var(--v-theme-primary));
    border: none;
    border-radius: 8px;
    cursor: pointer;
}

.auth-submit:hover {
    filter: brightness(1.08);
}

.auth-submit:focus-visible {
    outline: 2px solid rgb(var(--v-theme-primary));
    outline-offset: 2px;
}

/* ---------------------------------------------------------------- verification
   Unverified-account prompt (layouts/app) and the outcome icon on
   auth/verify-email. Both themes, both text directions.
*/
.verify-banner {
    max-width: 68rem;
    margin-inline: auto;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem 1.25rem;
    padding: 0.875rem 1.25rem;
    border: 1px solid var(--v-theme-surface-variant, rgba(0, 0, 0, 0.12));
    border-inline-start: 4px solid rgb(var(--v-theme-warning, 251, 140, 0));
    border-radius: 0.5rem;
    background: rgb(var(--v-theme-surface, 255, 255, 255));
}

.verify-banner__text {
    display: flex;
    flex-direction: column;
    gap: 0.125rem;
    min-width: 0;
}

.verify-banner__text span {
    font-size: 0.8125rem;
    opacity: 0.72;
}

.verify-banner__action {
    flex: 0 0 auto;
    cursor: pointer;
    padding: 0.5rem 1rem;
    border: 0;
    border-radius: 0.375rem;
    font: inherit;
    font-size: 0.875rem;
    font-weight: 600;
    color: rgb(var(--v-theme-on-primary, 255, 255, 255));
    background: rgb(var(--v-theme-primary, 25, 118, 210));
}

.verify-banner__action:hover {
    filter: brightness(1.1);
}

.verify-icon-success {
    color: rgb(var(--v-theme-success, 56, 142, 60));
}

.verify-icon-error {
    color: rgb(var(--v-theme-error, 244, 67, 54));
}

@media (max-width: 600px) {
    .verify-banner {
        flex-direction: column;
        align-items: stretch;
        text-align: center;
    }

    .verify-banner__action {
        width: 100%;
    }
}

/* ---------------------------------------------------------------- requests
   /myrequest, /ourrequest and the inline request form.

   The reference (VR-2026-00042) is the piece the customer reads out on the
   phone, so it is monospaced and higher contrast than the surrounding copy.
   Everything else defers to the Vuetify theme variables the SPA already
   ships, so light/dark and all seven locales come along for free. */

.req-ref {
    font-family: ui-monospace, "SFMono-Regular", "Menlo", "Consolas", monospace;
    font-weight: 700;
    letter-spacing: 0.02em;
    color: rgb(var(--v-theme-primary, 207, 145, 21));
}

.req-ref--lg {
    font-size: 1.5rem;
}

.req-card__top {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    flex-wrap: wrap;
}

.req-badge {
    display: inline-block;
    padding: 0.2rem 0.65rem;
    border-radius: 999px;
    font-size: 0.75rem;
    font-weight: 700;
    line-height: 1.5;
    white-space: nowrap;
    color: #fff;
}

.req-badge--secondary { background: rgb(var(--v-theme-secondary, 84, 82, 82)); }
.req-badge--info { background: rgb(var(--v-theme-info, 33, 150, 243)); }
.req-badge--warning { background: rgb(var(--v-theme-warning, 251, 140, 0)); }
.req-badge--success { background: rgb(var(--v-theme-success, 56, 142, 60)); }

.req-meta {
    display: flex;
    flex-wrap: wrap;
    gap: 1.5rem;
    margin: 0;
}

.req-meta--rows {
    flex-direction: column;
    gap: 0.75rem;
}

.req-meta dt {
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: rgb(var(--v-theme-on-surface-variant, 117, 117, 117));
}

.req-meta dd {
    margin: 0.125rem 0 0;
    font-size: 0.9375rem;
}

/* Visitor free text. `pre-wrap` keeps the line breaks they typed; the long
   unbroken strings that make a textarea look fine but overflow a card. */
.req-message {
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    padding: 0.75rem 1rem;
    border-radius: 6px;
    background: rgb(var(--v-theme-surface-light, 238, 238, 238));
}

.req-timeline {
    list-style: none;
    margin: 0;
    padding: 0;
}

.req-timeline__item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    padding: 0.75rem 0;
    border-bottom: 1px solid rgb(var(--v-theme-surface-variant, 66, 66, 66), 0.15);
}

.req-timeline__item:last-child {
    border-bottom: 0;
}

.req-timeline__meta {
    display: flex;
    gap: 1rem;
    font-size: 0.8125rem;
    color: rgb(var(--v-theme-on-surface-variant, 117, 117, 117));
}

/* Withdraw link. Styled as a quiet text action rather than a filled button:
   it is destructive-adjacent but reversible only by contacting support, so it
   should not read as a primary call to action. */
.req-withdraw-link {
    color: rgb(var(--v-theme-error, 176, 0, 32));
    text-decoration: underline;
    text-underline-offset: 3px;
    font-size: 0.875rem;
    padding: 0.25rem 0.5rem;
}

.req-withdraw-link:hover,
.req-withdraw-link:focus-visible {
    color: rgb(var(--v-theme-error, 176, 0, 32));
    text-decoration-thickness: 2px;
}

/* A destructive action the reader cannot undo, so make the second click cost
   something: confirm() before submitting. Guarded by [data-req-withdraw] so it
   cannot accidentally attach to unrelated forms. */
[data-req-withdraw] button[disabled] {
    opacity: 0.5;
    pointer-events: none;
}

.req-form__grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1rem;
}

.req-filters__row {
    display: flex;
    align-items: flex-end;
    gap: 1rem;
    flex-wrap: wrap;
}

.req-filters__actions {
    display: flex;
    gap: 0.5rem;
}

.req-table-wrap {
    overflow-x: auto;
}

.req-table {
    width: 100%;
    border-collapse: collapse;
    white-space: nowrap;
}

.req-table th,
.req-table td {
    padding: 0.875rem 1rem;
    text-align: left;
    font-size: 0.875rem;
    border-bottom: 1px solid rgb(var(--v-theme-surface-variant, 66, 66, 66), 0.15);
}

.req-table th {
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: rgb(var(--v-theme-on-surface-variant, 117, 117, 117));
}

.req-cell-strong,
.req-cell-sub {
    display: block;
}

.req-cell-sub {
    font-size: 0.8125rem;
    color: rgb(var(--v-theme-on-surface-variant, 117, 117, 117));
}

/* Honeypot: off-screen rather than display:none, because some bots skip
   hidden fields but still submit positioned ones. */
.req-hp {
    position: absolute;
    left: -9999px;
    width: 1px;
    height: 1px;
    overflow: hidden;
}

@media (max-width: 960px) {
    .req-form__grid {
        grid-template-columns: minmax(0, 1fr);
    }
}

@media (max-width: 600px) {
    .req-filters__row > * {
        width: 100%;
    }

    .req-filters__actions .btn {
        flex: 1;
    }
}

/* ---------------------------------------------------------------------------
   Buttons

   Views have been using `btn btn-primary` / `btn btn-secondary` since the
   request-tracking screens landed, but no rule for `.btn` existed anywhere in
   the bundle: vireolin.css is a utility sheet (spacing, flex, radius) and
   theme.css only carries Vuetify's CSS variables. Every one of those buttons
   was falling through to the browser default - grey system face, no padding,
   no brand colour - on /ourrequest, /myrequest, the request form and the
   account pages alike.

   Defined here rather than in theme.css because these are shell components,
   not theme variables. Text colour is hardcoded dark on the gold/amber
   primary: --v-theme-primary is a mid-tone amber in both light and dark
   themes, so white text on it fails contrast in light mode.
   --------------------------------------------------------------------------- */

.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.4rem;
    padding: 0.6rem 1.15rem;
    border: 1px solid transparent;
    border-radius: 0.25rem;
    font: inherit;
    font-weight: 600;
    line-height: 1.4;
    text-align: center;
    text-decoration: none;
    cursor: pointer;
    transition: background-color 0.2s ease, border-color 0.2s ease, color 0.2s ease;
}

.btn-sm {
    padding: 0.35rem 0.75rem;
    font-size: 0.875rem;
}

.btn-primary {
    background-color: rgb(var(--v-theme-primary));
    color: #1a1a1a;
}

.btn-primary:hover {
    background-color: rgba(var(--v-theme-primary), 0.85);
}

.btn-secondary {
    background-color: transparent;
    border-color: rgba(var(--v-border-color), var(--v-border-opacity));
    color: rgb(var(--v-theme-primary));
}

.btn-secondary:hover {
    border-color: rgb(var(--v-theme-primary));
    background-color: rgba(var(--v-theme-primary), 0.08);
}

/* Destructive only: deleting a customer's message. Distinct from btn-secondary
   so the action cannot be taken by habit - every other admin button on these
   screens is the quiet outlined variant. */
.btn-error {
    background-color: transparent;
    border-color: rgb(var(--v-theme-error));
    color: rgb(var(--v-theme-error));
}

.btn-error:hover {
    background-color: rgba(var(--v-theme-error), 0.1);
}

.btn:focus-visible {
    outline: 2px solid rgb(var(--v-theme-primary));
    outline-offset: 2px;
}

.btn[disabled],
.btn[aria-disabled="true"] {
    opacity: 0.55;
    cursor: not-allowed;
}

/* ---------------------------------------------------------------------------
   /ourmessages inbox
   --------------------------------------------------------------------------- */

/* Unread count in the header nav and beside "mark all as read". Inline-block
   rather than a pill so it inherits the button's line-height and stays put
   when the label wraps on narrow screens. */
.msg-badge {
    display: inline-block;
    min-width: 1.35rem;
    padding: 0 0.35rem;
    border-radius: 0.75rem;
    background-color: rgb(var(--v-theme-primary));
    color: #1a1a1a;
    font-size: 0.75rem;
    font-weight: 700;
    line-height: 1.35rem;
    text-align: center;
}

.msg-state {
    display: inline-block;
    padding: 0.15rem 0.55rem;
    border-radius: 0.75rem;
    font-size: 0.8rem;
    font-weight: 600;
}

.msg-state--unread {
    background-color: rgba(var(--v-theme-primary), 0.16);
    color: rgb(var(--v-theme-primary));
}

.msg-state--read {
    background-color: rgba(var(--v-border-color), calc(var(--v-border-opacity) * 0.6));
    color: rgb(var(--v-theme-on-surface));
    opacity: 0.75;
}

/* Row tint for unread mail, so scanning the queue does not mean reading the
   state cell on every line. */
.msg-row--unread td {
    background-color: rgba(var(--v-theme-primary), 0.05);
}

.msg-row--unread .req-cell-strong {
    font-weight: 700;
}

.msg-preview {
    display: block;
    max-width: 42ch;
    /* Clamped to two lines. -webkit-line-clamp needs the display:box, which is
       why this is not just a max-height. */
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    color: rgb(var(--v-theme-on-surface));
    opacity: 0.8;
}

/* Full message on the detail page. pre-wrap keeps the line breaks the sender
   typed; the {{ }} in the view already escaped the markup. */
.msg-body {
    padding: 1rem;
    border: 1px solid rgba(var(--v-border-color), var(--v-border-opacity));
    border-radius: 0.25rem;
    background-color: rgba(var(--v-border-color), 0.04);
    color: rgb(var(--v-theme-on-surface));
    white-space: pre-wrap;
    /* A pasted URL with no spaces is the common case here; without this it
       stretches the panel instead of wrapping. */
    overflow-wrap: break-word;
}

/* ---------------------------------------------------------------------------
   Catalogue administration (/ourservices).
   --------------------------------------------------------------------------- */

/* Delete zone on the edit screen. Separated from the save form so an
   irreversible action does not sit beside the ordinary submit button. */
.admin-danger {
    padding: 1rem 1.25rem;
    border: 1px solid rgba(var(--v-theme-error), 0.4);
    border-radius: 0.25rem;
    background-color: rgba(var(--v-theme-error), 0.06);
}

/* One existing photo plus its "delete on save" checkbox. */
.admin-photo {
    display: flex;
    flex-direction: column;
    gap: 0.375rem;
    padding: 0.5rem;
    border: 1px solid rgba(var(--v-border-color), var(--v-border-opacity));
    border-radius: 0.25rem;
    font-size: 0.75rem;
    cursor: pointer;
}

.admin-photo__img {
    width: 96px;
    height: 96px;
    object-fit: cover;
    border-radius: 0.1875rem;
    background-color: rgba(var(--v-border-color), 0.06);
}

/* The catalogue form stacks one fieldset per locale; keep the rules from
   collapsing into each other when a description runs long. */
.contact-form fieldset {
    border: 0;
    padding: 0;
    margin: 0 0 1.5rem;
    min-width: 0;
}

.contact-form fieldset:last-child {
    margin-bottom: 0;
}

.contact-form legend {
    float: none;
    width: auto;
    font-size: 1rem;
    line-height: 1.5;
    margin-bottom: 0.75rem;
    padding: 0;
}

/* --- Catalogue tree (/ourservices -> Gruppen & Untergruppen) ---------------
   Group and subgroup rows share one table, so the hierarchy has to be carried
   by the row rather than by nesting. Two things matter here:

   1. The indent uses padding-inline-start, not margin-left. Arabic renders
      this page with dir="rtl", and a left margin would indent the subgroup
      against the wrong edge.
   2. .tree-name is a <th scope="row">, so it inherits .req-table th's
      uppercase/letter-spacing treatment unless it is reset - a title is not a
      column heading and looked wrong shouted in a heading case. */

.tree-panel {
    scroll-margin-top: 120px;
}

.tree-table th[scope="row"] {
    text-transform: none;
    letter-spacing: normal;
    font-size: 0.9375rem;
    font-weight: 500;
    color: rgb(var(--v-theme-on-surface));
    white-space: normal;
}

.tree-name {
    display: flex;
    align-items: baseline;
    gap: 0.5rem;
    flex-wrap: wrap;
}

.tree-name--sub {
    padding-inline-start: 2rem;
    font-weight: 400;
}

.tree-icon {
    font-size: 1.125rem;
    flex: none;
}

.tree-row--group > * {
    border-top: 1px solid rgb(var(--v-theme-surface-variant, 66, 66, 66), 0.35);
}

.tree-row--group:first-child > * {
    border-top: 0;
}

.tree-actions {
    white-space: nowrap;
}

.tree-actions .btn + .btn {
    margin-inline-start: 0.25rem;
}

.tree-empty {
    white-space: normal;
}

/* The two mutually exclusive outcomes on the group delete screen. */
.tree-choice {
    display: flex;
    gap: 0.5rem;
    align-items: flex-start;
}

.tree-choice .form-check-input {
    margin-top: 0.3rem;
    flex: none;
}

/* --- Content sections (/ourentries) ----------------------------------------
   The eight editorial tables. Nothing here is new layout vocabulary: the
   tables reuse `.req-table` and `.tree-name`, the buttons reuse `.btn`, and the
   form fields reuse `.contact-input` / `.contact-label`, so these screens look
   like the rest of the panel rather than like a ninth panel.

   What is specific to this one is the translation coverage. The question an
   operator has here is "which languages does this section still need", so the
   list answers it in one column of seven marks and the form answers it in the
   language bar. -- */

.entry-page {
    /* Wider than `.v-container`'s 900px: the section list and the form both
       put a table beside a set of actions, and 900px turns the action column
       into wrapped buttons. */
    max-width: 1100px;
}

.entry-head {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1rem;
}

.entry-head__actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
}

.entry-crumbs {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    font-size: 0.8125rem;
    color: rgba(var(--v-theme-on-surface), 0.6);
}

.entry-crumbs a {
    color: rgba(var(--v-theme-on-surface), 0.6);
    text-decoration: none;
}

.entry-crumbs a:hover,
.entry-crumbs a:focus-visible {
    color: rgb(var(--v-theme-primary));
    text-decoration: underline;
}

/* -- the hub ---------------------------------------------------------------- */

.entry-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
    gap: 1rem;
}

.entry-card {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    padding: 1rem 1.25rem;
    border: 1px solid rgba(var(--v-border-color), var(--v-border-opacity));
    border-radius: 0.25rem;
    text-decoration: none;
    color: inherit;
    background: transparent;
    transition:
        border-color 0.15s ease-in-out,
        background-color 0.15s ease-in-out;
}

.entry-card:hover,
.entry-card:focus-visible {
    border-color: rgba(var(--v-theme-primary), 0.55);
    background-color: rgba(var(--v-theme-primary), 0.05);
}

.entry-card__top {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 0.75rem;
}

.entry-card__name {
    margin: 0;
    font-size: 1.0625rem;
    font-weight: 600;
}

.entry-card__count {
    font-size: 1.5rem;
    font-weight: 700;
    line-height: 1;
    color: rgb(var(--v-theme-primary));
}

.entry-card__note {
    margin: 0;
    font-size: 0.8125rem;
    color: rgba(var(--v-theme-on-surface), 0.68);
}

.entry-card__meta {
    margin: 0;
}

.entry-card__tag {
    display: inline-block;
    font-size: 0.75rem;
    padding: 2px 8px;
    border-radius: 1rem;
}

.entry-card__tag.is-empty {
    background: rgba(var(--v-theme-on-surface), 0.08);
    color: rgba(var(--v-theme-on-surface), 0.7);
}

.entry-card__tag.is-missing {
    /* The theme's warning ramp has no `--v-theme-warning` in this bundle's
       light block, so the fallback in the var() is what actually renders. */
    background: rgba(251, 140, 0, 0.14);
    color: rgb(176, 98, 0);
}

.entry-card__tag.is-ok {
    background: rgba(var(--v-theme-success, 56, 142, 60), 0.12);
    color: rgb(var(--v-theme-success, 56, 142, 60));
}

.entry-footnote {
    font-size: 0.8125rem;
    color: rgba(var(--v-theme-on-surface), 0.6);
    max-width: 60ch;
}

/* -- the list --------------------------------------------------------------- */

.entry-toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
}

.entry-toolbar__count {
    margin: 0;
    font-size: 0.875rem;
    color: rgba(var(--v-theme-on-surface), 0.7);
}

.entry-toolbar__hint {
    display: block;
    font-size: 0.8125rem;
}

.entry-table__num,
.entry-table__actions {
    text-align: end;
    white-space: nowrap;
}

.entry-slug {
    font-size: 0.8125rem;
    overflow-wrap: anywhere;
}

.entry-row__untitled {
    font-style: italic;
    color: rgba(var(--v-theme-on-surface), 0.55);
}

.entry-dots {
    display: inline-flex;
    gap: 3px;
}

.entry-dot {
    width: 0.5rem;
    height: 0.5rem;
    border-radius: 50%;
    border: 1px solid rgba(var(--v-border-color), var(--v-border-opacity));
    background: transparent;
}

.entry-dot.is-on {
    border-color: rgb(var(--v-theme-primary));
    background-color: rgb(var(--v-theme-primary));
}

.entry-empty {
    padding: 2rem 1.25rem;
    border: 1px dashed rgba(var(--v-border-color), var(--v-border-opacity));
    border-radius: 0.25rem;
    text-align: center;
    color: rgba(var(--v-theme-on-surface), 0.68);
}

/* -- the language bar ------------------------------------------------------- */

/* Both the list and the form use it. `has-content` is the same signal the
   coverage dots give on the list, carried across so switching language in the
   form tells you whether you are about to add or overwrite something. */
.entry-locales,
.entry-locale-bar {
    display: flex;
    flex-wrap: wrap;
    gap: 0.375rem;
}

.entry-locale {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    padding: 0.25rem 0.625rem;
    border: 1px solid rgba(var(--v-border-color), var(--v-border-opacity));
    border-radius: 1rem;
    font-size: 0.8125rem;
    text-decoration: none;
    color: rgba(var(--v-theme-on-surface), 0.75);
}

.entry-locale:hover,
.entry-locale:focus-visible {
    border-color: rgba(var(--v-theme-primary), 0.55);
}

.entry-locale.is-current {
    border-color: rgb(var(--v-theme-primary));
    background-color: rgb(var(--v-theme-primary));
    color: rgb(var(--v-theme-on-primary));
}

.entry-locale.has-content:not(.is-current)::after {
    content: '';
    width: 0.4rem;
    height: 0.4rem;
    border-radius: 50%;
    background-color: rgb(var(--v-theme-primary));
}

.entry-locale-hint {
    margin: 0;
    font-size: 0.8125rem;
    color: rgba(var(--v-theme-on-surface), 0.6);
}

/* -- the form --------------------------------------------------------------- */

.entry-form-wrap {
    max-width: 46rem;
}

.entry-legend {
    font-size: 1rem;
    font-weight: 600;
    margin-bottom: 0.75rem;
}

.entry-required {
    color: rgb(var(--v-theme-error));
}

.entry-textarea {
    min-height: 8rem;
    resize: vertical;
}

.entry-icon {
    display: flex;
    align-items: center;
    gap: 0.75rem;
}

.entry-icon .mdi {
    font-size: 1.5rem;
    flex: none;
    color: rgba(var(--v-theme-on-surface), 0.7);
}

.entry-error {
    margin: 0.25rem 0 0;
    font-size: 0.8125rem;
    color: rgb(var(--v-theme-error));
}

.entry-status {
    padding: 0.75rem 1rem;
    border: 1px solid rgba(var(--v-theme-success, 56, 142, 60), 0.4);
    border-radius: 0.25rem;
    background-color: rgba(var(--v-theme-success, 56, 142, 60), 0.08);
}

.entry-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
}

/* ---------------------------------------------------------------------------
   /track - the status legend.

   Five badge/description pairs in a wrapping grid. The descriptions are the
   legacy colour words ("Grau - noch nicht bearbeitet"), so the legend is a
   lookup table rather than prose: each badge has to sit on the same line as the
   text that explains it, and the rows have to keep their rhythm even when one
   translation runs to three lines.
   --------------------------------------------------------------------------- */
.track-legend {
    list-style: none;
    padding: 0;
    margin: 0;
    display: grid;
    gap: 0.5rem 1.5rem;
    grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
}

.track-legend li {
    display: flex;
    align-items: baseline;
    gap: 0.5rem;
    min-width: 0;
}

/* The badge must not be squeezed to nothing by a long translation. */
.track-legend .req-badge {
    flex: 0 0 auto;
}

.track-legend span:last-child {
    min-width: 0;
}

/* ---------------------------------------------------------------------------
   Admin -> Inhalte, the site-string editor.

   A collapsible list of key/value pairs, one per translation key. Two rules
   drive the layout:

    - the key column is fixed-width and does not wrap, because a wrapped key
     makes the row impossible to scan down a column of 750; and
    - an edited row is tinted from its left edge, which is the only cue an
     admin gets that a value is an override rather than the shipped text. It
     has to survive being sorted, searched and collapsed, so it hangs off the
     row rather than off any transient state.
   --------------------------------------------------------------------------- */
.content-summary {
    display: flex;
    flex-wrap: wrap;
    gap: 1rem;
}

.content-summary__stat {
    flex: 1 1 8rem;
    padding: 0.75rem 1rem;
    border-radius: 8px;
    background: rgb(var(--v-theme-surface));
    border: 1px solid rgba(var(--v-border-color), 0.12);
    text-align: center;
}

.content-summary__num {
    display: block;
    font-size: 1.5rem;
    font-weight: 700;
    line-height: 1.2;
    color: rgb(var(--v-theme-primary));
}

/* Overridden rows are the only ones that get a tint, so the count stands out
   against the three static statistics beside it. */
.content-summary__stat.is-edited .content-summary__num {
    color: rgb(var(--v-theme-warning));
}

.content-summary__label {
    display: block;
    font-size: 0.8rem;
    color: rgba(var(--v-theme-on-surface), 0.6);
}

.content-group {
    border: 1px solid rgba(var(--v-border-color), 0.12);
    border-radius: 8px;
    background: rgb(var(--v-theme-surface));
    overflow: hidden;
}

.content-group__head {
    cursor: pointer;
    padding: 0.75rem 1rem;
    font-weight: 600;
    display: flex;
    align-items: center;
    gap: 0.75rem;
    list-style: none;
}

/* The native marker sits on the right in an RTL document, which is correct, but
   the default triangle is invisible against the surface. */
.content-group__head::-webkit-details-marker {
    display: none;
}

.content-group__head::before {
    content: "\25B8";
    color: rgba(var(--v-theme-on-surface), 0.5);
    transition: transform 0.15s ease;
}

.content-group[open] .content-group__head::before {
    transform: rotate(90deg);
}

[dir="rtl"] .content-group__head::before {
    content: "\25C2";
}

[dir="rtl"] .content-group[open] .content-group__head::before {
    transform: rotate(-90deg);
}

.content-group__count {
    font-weight: 400;
    font-size: 0.8rem;
    color: rgba(var(--v-theme-on-surface), 0.6);
}

.content-rows {
    border-top: 1px solid rgba(var(--v-border-color), 0.08);
}

.content-row {
    display: grid;
    grid-template-columns: minmax(0, 22rem) minmax(0, 1fr);
    gap: 1rem;
    padding: 0.6rem 1rem;
    border-bottom: 1px solid rgba(var(--v-border-color), 0.05);
    border-left: 3px solid transparent;
    align-items: start;
}

/* The tint goes on the left edge because it is the only element on the row
   that is always at the same place, and because a tint across the whole row
   would make a page of 750 of them unreadable. */
.content-row.is-overridden,
.content-row.is-dirty {
    border-left-color: rgb(var(--v-theme-warning));
}

.content-row__key {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.4rem;
    min-width: 0;
}

.content-row__code {
    font-size: 0.78rem;
    /* Keys never wrap: a key split across two lines is a key that cannot be
       compared against the coverage flags beside it. */
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 100%;
    direction: ltr;
    unicode-bidi: plaintext;
}

.content-row__coverage {
    display: inline-flex;
    gap: 0.15rem;
}

/* Each flag is a one-click language switch for the row. Flags are emoji
   glyphs, so there is little to style but opacity, a ring and a hover tint -
   which is enough: the point is "the ringed flag is the language I am editing,
   the dimmed ones are languages the key does not ship in, any of them takes me
   there". */
.content-row__flag {
    display: inline-flex;
    align-items: center;
    padding: 0.05rem 0.12rem;
    font-size: 0.85rem;
    line-height: 1;
    border-radius: 3px;
    opacity: 0.55;
    text-decoration: none;
    cursor: pointer;
    transition: opacity 0.12s ease, filter 0.12s ease, background-color 0.12s ease;
}

.content-row__flag:hover,
.content-row__flag:focus-visible {
    opacity: 1;
    background: rgba(var(--v-theme-primary), 0.12);
    outline: none;
}

/* The editing language: ringed so a row reads "I am editing German" at a
   glance, distinct from the coverage meaning of every other flag. Declared
   after .is-missing so an editing language the key does not ship in (the
   "fill in this translation" case) keeps its ring and full opacity. */
.content-row__flag.is-active {
    opacity: 1;
    background: rgba(var(--v-theme-primary), 0.16);
    box-shadow: inset 0 0 0 1px rgba(var(--v-theme-primary), 0.55);
}

/* A language this key does not ship in: dimmed, but still a click away so the
   missing translation can be started from the row itself. */
.content-row__flag.is-missing {
    opacity: 0.28;
    filter: grayscale(0.9);
}

.content-row__flag.is-missing:hover,
.content-row__flag.is-missing:focus-visible {
    opacity: 0.72;
    filter: grayscale(0.35);
}

.content-row__badge {
    font-size: 0.68rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    padding: 0.05rem 0.35rem;
    border-radius: 3px;
    background: rgba(var(--v-theme-warning), 0.18);
    color: rgb(var(--v-theme-on-surface));
}

.content-row__field {
    min-width: 0;
}

.content-save {
    position: sticky;
    bottom: 0;
    padding: 0.75rem 0;
    background: rgb(var(--v-theme-background));
    border-top: 1px solid rgba(var(--v-border-color), 0.1);
}

/* One column on a phone: a 22rem key column plus a field leaves nothing for the
   text an admin is here to edit. */
@media (max-width: 959.98px) {
    .content-row {
        grid-template-columns: minmax(0, 1fr);
    }

    .content-save {
        position: static;
    }
}

/* ---------------------------------------------------------------------------
   Pagination

   Replaces Laravel's Tailwind paginator on /ourrequest, /ourservices,
   /ourmessages and /myrequest. The markup in
   resources/views/vendor/pagination/shell.blade.php is ours; this only has to
   size it.

   Two constraints the Tailwind version got wrong:

    - The pill row wraps rather than overflowing. It overflowed by 18px on
      /ourservices because the pills were inline-flex in a nowrap row with no
      container rule, so the document scrolled sideways on an admin page.
    - The chevrons mirror under RTL. The shell flips `dir` on the document, so
      "previous" has to sit on the right in Arabic; without the flip the arrows
      pointed the wrong way.
--------------------------------------------------------------------------- */
.req-pagination {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem 1rem;
}

.req-pagination__summary {
    font-size: 0.85rem;
    color: rgba(var(--v-theme-on-surface), 0.6);
    margin: 0;
    min-width: 0;
}

.req-pagination__pages {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.25rem;
}

.req-pagination__page {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 2.375rem;
    height: 2.375rem;
    padding: 0 0.5rem;
    border-radius: 6px;
    border: 1px solid rgba(var(--v-border-color), 0.2);
    font-size: 0.9rem;
    line-height: 1;
    color: rgb(var(--v-theme-on-surface));
    text-decoration: none;
    transition: background-color 0.15s ease, border-color 0.15s ease;
}

.req-pagination__page:hover {
    background: rgba(var(--v-theme-on-surface), 0.06);
}

.req-pagination__page.is-current {
    background: rgb(var(--v-theme-primary));
    border-color: rgb(var(--v-theme-primary));
    color: rgb(var(--v-theme-on-primary));
    font-weight: 600;
}

.req-pagination__page.is-disabled {
    opacity: 0.4;
    pointer-events: none;
}

.req-pagination__gap {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1.5rem;
    height: 2.375rem;
    color: rgba(var(--v-theme-on-surface), 0.5);
}

/* ---------------------------------------------------------------------------
   Admin -> Einstellungen

   The settings panel. Its own class prefix rather than a reuse of the
   `.content-*` block from the site-string editor: the two have almost nothing
   in common below the field level - no key column, no coverage flags, no sticky
   per-row state - and folding eleven fixed fields into a grid built for several
   hundred of them would leave most of that grid empty.

   RTL: the locale tags use logical properties throughout, and `.settings-locales`
   inherits `direction` from the document, so the Arabic address inputs mirror
   without a separate rule.
--------------------------------------------------------------------------- */

.settings-group {
    padding: 1.25rem 1.25rem 1rem;
    background: rgb(var(--v-theme-surface));
    border: 1px solid rgba(var(--v-border-color), 0.1);
    border-radius: 8px;
}

.settings-group__name {
    font-size: 1rem;
    font-weight: 600;
    margin-bottom: 0.25rem;
}

.settings-group__note {
    font-size: 0.85rem;
    color: rgba(var(--v-theme-on-surface), 0.6);
    margin-bottom: 0.75rem;
}

.settings-fields {
    display: grid;
    /* Two columns on a desktop: the fields are short (an address, a phone, a
       URL) and a single column would leave a 900px page holding a 400px label. */
    grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr));
    gap: 1rem 1.5rem;
}

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

.settings-field__label {
    display: flex;
    align-items: baseline;
    gap: 0.5rem;
    flex-wrap: wrap;
}

.settings-field__hint {
    font-size: 0.78rem;
    line-height: 1.35;
    color: rgba(var(--v-theme-on-surface), 0.55);
    margin: 0.15rem 0 0.35rem;
}

/* A key nothing reads. Dimmed rather than hidden, and badged, because the whole
   reason it is on this page is so an operator can see that editing it does
   nothing - hiding the field would leave the row in the table invisibly. */
.settings-field.is-unused {
    opacity: 0.75;
}

.settings-field__badge {
    font-size: 0.68rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    padding: 0.05rem 0.35rem;
    border-radius: 3px;
    background: rgba(var(--v-theme-on-surface), 0.12);
    color: rgba(var(--v-theme-on-surface), 0.75);
}

/* The `show*` switch. Sits inline under the URL it governs rather than as a
   field of its own, because "show in the footer" is an action on the profile
   above, not a value in its own right. */
.settings-field__check {
    display: flex;
    align-items: flex-start;
    gap: 0.6rem;
    padding: 0.55rem 0 0.1rem;
}

.settings-field__check input[type='checkbox'] {
    margin-top: 0.15rem;
    width: 1.05rem;
    height: 1.05rem;
    accent-color: rgb(var(--v-theme-primary));
    flex: none;
    cursor: pointer;
}

.settings-field__check label {
    font-size: 0.85rem;
    line-height: 1.3;
    cursor: pointer;
}

.settings-field__check label span {
    display: block;
    color: rgba(var(--v-theme-on-surface), 0.55);
}

.settings-locales {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
    gap: 0.5rem;
}

.settings-locale {
    min-width: 0;
}

.settings-locale__tag {
    display: flex;
    align-items: center;
    gap: 0.3rem;
    font-size: 0.75rem;
    color: rgba(var(--v-theme-on-surface), 0.6);
    margin-bottom: 0.15rem;
}

/* Import leftovers: named, visible, not editable. */
.settings-unmapped {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr));
    gap: 0.5rem 1.5rem;
    margin: 0;
}

.settings-unmapped code {
    font-size: 0.8rem;
    color: rgb(var(--v-theme-primary));
}

.settings-unmapped dd {
    font-size: 0.85rem;
    color: rgba(var(--v-theme-on-surface), 0.75);
    margin: 0;
    overflow-wrap: anywhere;
}

.settings-save {
    position: sticky;
    bottom: 0;
    padding: 0.75rem 0;
    background: rgb(var(--v-theme-background));
    border-top: 1px solid rgba(var(--v-border-color), 0.1);
}

/* ---------------------------------------------------------------------------
   Legal documents (/privacy, /terms)

   A jump list beside the text rather than above it: both documents run to ten
   numbered sections, and a German privacy policy is long enough that a reader
   needs to jump to §8 rather than scroll. Below `md` the jump list collapses
   above the text instead of squeezing it into a quarter of a phone screen.
--------------------------------------------------------------------------- */

.legal-layout {
    display: grid;
    grid-template-columns: minmax(0, 15rem) minmax(0, 1fr);
    gap: 2.5rem;
    align-items: start;
}

.legal-toc {
    position: sticky;
    top: calc(var(--v-app-bar-height, 104px) + 1rem);
    max-height: calc(100vh - var(--v-app-bar-height, 104px) - 2rem);
    overflow-y: auto;
    /* Anchored sections must not land under the fixed bar when a jump link is
       followed, which is the whole point of the anchors. */
    scroll-margin-top: calc(var(--v-app-bar-height, 104px) + 1rem);
}

.legal-toc__title {
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: rgba(var(--v-theme-on-surface), 0.55);
    margin-bottom: 0.5rem;
}

.legal-toc__list {
    list-style: none;
    margin: 0;
    padding: 0;
    /* The headings are numbered in their own text ("8. Ihre Rechte"), so the
       list needs no counter - a second set of numbers would double them. */
    counter-reset: none;
}

.legal-toc__list li {
    margin-bottom: 0.15rem;
}

.legal-toc__list a {
    display: block;
    font-size: 0.85rem;
    line-height: 1.35;
    color: rgba(var(--v-theme-on-surface), 0.7);
    text-decoration: none;
    padding: 0.15rem 0;
    border-inline-start: 2px solid transparent;
    padding-inline-start: 0.6rem;
    transition: color 0.15s ease, border-color 0.15s ease;
}

.legal-toc__list a:hover,
.legal-toc__list a:focus-visible {
    color: rgb(var(--v-theme-primary));
    border-inline-start-color: rgb(var(--v-theme-primary));
}

.legal-body {
    max-width: 46rem;
}

/* /imprint: one free-form body, so it reuses the legal typography without the
   two-column jump-list layout and centres the single column. */
.legal-body--centered {
    margin-inline: auto;
}

.imprint-body p {
    line-height: 1.65;
    color: rgba(var(--v-theme-on-surface), 0.85);
    margin-bottom: 0.75rem;
}

.legal-body__title {
    font-size: clamp(1.5rem, 3vw, 2rem);
    font-weight: 700;
    margin-bottom: 0.5rem;
}

/* The author's own note that the text replaces no legal review. Styled as a
   callout rather than as body copy, and deliberately not removed: it is the
   only thing between a template and a published policy. */
.legal-body__updated {
    font-size: 0.85rem;
    line-height: 1.45;
    color: rgba(var(--v-theme-on-surface), 0.75);
    background: rgba(var(--v-theme-warning), 0.12);
    border-inline-start: 3px solid rgb(var(--v-theme-warning));
    border-radius: 4px;
    padding: 0.6rem 0.9rem;
    margin-bottom: 2rem;
}

.legal-section {
    scroll-margin-top: calc(var(--v-app-bar-height, 104px) + 1rem);
    margin-bottom: 1.75rem;
}

.legal-section__heading {
    font-size: 1.05rem;
    font-weight: 600;
    margin-bottom: 0.4rem;
}

.legal-section p {
    line-height: 1.65;
    color: rgba(var(--v-theme-on-surface), 0.85);
    margin-bottom: 0.75rem;
}

.legal-section ul {
    margin: 0.25rem 0 0.75rem;
    /* The list is a set of statutory rights, so the markers hang rather than
       sit inline - an inline marker would run into the text under RTL. */
    list-style: disc;
    padding-inline-start: 1.4rem;
}

.legal-section li {
    line-height: 1.6;
    color: rgba(var(--v-theme-on-surface), 0.85);
    margin-bottom: 0.2rem;
}

@media (max-width: 959.98px) {
    .legal-layout {
        grid-template-columns: minmax(0, 1fr);
        gap: 1.5rem;
    }

    .legal-toc {
        position: static;
        max-height: none;
        padding: 0.9rem 1rem;
        border: 1px solid rgba(var(--v-border-color), 0.12);
        border-radius: 8px;
    }

    .legal-toc__list {
        columns: 2;
        column-gap: 1.5rem;
    }
}

/* ---------------------------------------------------------------------------
   404

   The code is decorative and the heading carries the message, so the number is
   aria-hidden in the markup. It is sized in `clamp()` rather than a fixed px
   because it is the one element on the page whose size is doing the work: it has
   to read as a 404 from across a room and still fit a phone.
--------------------------------------------------------------------------- */

.page-notfound {
    min-height: 50vh;
    display: flex;
    align-items: center;
}

.notfound__code {
    font-size: clamp(4rem, 18vw, 9rem);
    font-weight: 800;
    line-height: 1;
    letter-spacing: -0.04em;
    color: rgba(var(--v-theme-primary), 0.22);
    margin: 0 0 0.5rem;
}

.notfound__title {
    font-size: clamp(1.35rem, 3.5vw, 2rem);
    font-weight: 700;
    margin-bottom: 0.5rem;
}

.notfound__lead {
    color: rgba(var(--v-theme-on-surface), 0.7);
    max-width: 32rem;
    margin: 0 auto 2rem;
}

.notfound__actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
    justify-content: center;
}

/* The legal links and the website/tracking links used to live in the bottom
   row alongside the address, which the legacy gives its own column. They are
   styled with the Footer block above now. */

/* ---------------------------------------------------------------------------
   The six editorial pages: /faq, /knowledge, /career, /partnerships,
   /industries, /solutions.

   One block for all six because they are the same shape - a page head
   (title + subtitle) over a single column of entries - and three of the six
   carry nothing but a title and a summary. Per-page rules would be six copies
   of the same declarations.

   The `__item` is a <details> on /faq (so a question is its own disclosure) and
   a plain <article> elsewhere; `summary` therefore needs `display: list-item`
   restored explicitly, because a <details> that is not the first summary in its
   parent stops rendering the marker.
   --------------------------------------------------------------------------- */

.page-entries__head {
    max-width: 46rem;
    margin-bottom: 2.5rem;
}

.page-entries__title {
    font-size: clamp(1.5rem, 3vw, 2rem);
    font-weight: 700;
    margin-bottom: 0.5rem;
}

.page-entries__subtitle {
    color: rgba(var(--v-theme-on-surface), 0.7);
}

.page-entries__list {
    max-width: 46rem;
    display: flex;
    flex-direction: column;
    /* Logical, not horizontal: the whole column mirrors under RTL, which is
       what `ar` needs. */
    gap: 1rem;
}

.page-entries__item {
    border: 1px solid rgba(var(--v-theme-on-surface), 0.14);
    border-radius: 0.5rem;
    padding: 1.25rem 1.5rem;
}

.page-entries__question {
    font-size: 1.125rem;
    font-weight: 600;
    cursor: default;
}

details.page-entries__question,
summary.page-entries__question {
    cursor: pointer;
}

.page-entries__summary {
    color: rgba(var(--v-theme-on-surface), 0.7);
    margin-top: 0.5rem;
}

.page-entries__answer {
    margin-top: 1rem;
    color: rgba(var(--v-theme-on-surface), 0.85);
}

.page-entries__meta {
    margin-top: 0.75rem;
    font-size: 0.8125rem;
    color: rgba(var(--v-theme-on-surface), 0.55);
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
}

.page-entries__fact::before {
    content: '·';
    margin-inline-end: 0.75rem;
}

.page-entries__fact:first-child::before {
    content: none;
}

.page-entries__empty {
    color: rgba(var(--v-theme-on-surface), 0.55);
}

/* ---------------------------------------------------------------------------
   Header navigation: the services mega-menu and the "more" overflow menu.

   Both panels follow the same closed/open contract as .v-locale-menu and
   .v-account-menu: hidden by default, shown by the `is-open` class that
   vireolin.js toggles. Reusing that shape rather than inventing `hidden` or
   `display` keeps one transition model across all four menus.

   Positioning is on the anchor wrapper, not the trigger, so the panel can be
   as wide as the catalogue needs without being constrained by the trigger's
   own box - the whole reason a mega-menu is a panel and not a dropdown.
   --------------------------------------------------------------------------- */

.v-mega,
.v-more {
    position: relative;
}

.v-mega__caret,
.v-more__caret {
    font-size: 16px;
    /* Nudged down because the caret's optical centre sits above the baseline
       of the label it sits beside. */
    margin-inline-start: 2px;
    transition: transform 0.15s ease-in-out;
}

.v-mega.is-open .v-mega__caret,
.v-more.is-open .v-more__caret {
    transform: rotate(180deg);
}

/* Two columns, like the legacy's `.dropdown-panel`
   (grid-template-columns: 1fr 1fr, with the trailing `.dd-all` spanning
   both). `auto-fit` rather than a fixed two so the panel collapses to a single
   column on a narrow screen instead of squeezing group titles to two lines -
   the one place where the fixed legacy value was worse than an adaptive one.

   Positioned from the inline start rather than the legacy's
   `left:50%; transform:translateX(-50%)`, which hangs off the trigger's centre
   and mirrors wrongly under RTL. */
.v-mega__panel {
    position: absolute;
    top: calc(100% + 8px);
    inset-inline-start: 0;
    max-width: min(78vw, 1100px);
    padding: 20px;
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
    gap: 2px 1rem;
    border-radius: 12px;
    background-color: rgb(var(--v-theme-surface));
    box-shadow: 0 8px 28px rgba(0, 0, 0, 0.18);
    visibility: hidden;
    opacity: 0;
    transform: translateY(-8px);
    transition: opacity 0.15s ease-in-out, transform 0.15s ease-in-out,
        visibility 0.15s;
}

.v-mega__panel.is-open {
    visibility: visible;
    opacity: 1;
    transform: translateY(0);
}

.v-mega__item {
    display: block;
    padding: 5px 0;
    font-size: 0.9rem;
    color: rgba(var(--v-theme-on-surface), 0.82);
    text-decoration: none;
    transition: color 0.12s ease-in-out;
}

.v-mega__item:hover,
.v-mega__item:focus-visible {
    color: rgb(var(--v-theme-primary));
    text-decoration: underline;
}

/* The trailing "all services" row spans both columns, as `.dd-all` did. */
.v-mega__all {
    grid-column: 1 / -1;
    display: inline-block;
    margin-top: 1.25rem;
    padding-top: 1rem;
    border-top: 1px solid rgba(var(--v-theme-on-surface), 0.12);
    width: 100%;
    font-weight: 700;
    color: rgb(var(--v-theme-primary));
    text-decoration: none;
}

/* -------------------------------------------------------------- more menu */

.v-more__panel {
    position: absolute;
    top: calc(100% + 8px);
    inset-inline-end: 0;
    min-width: 200px;
    padding: 8px 0;
    border-radius: 8px;
    background-color: rgb(var(--v-theme-surface));
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.16);
    visibility: hidden;
    opacity: 0;
    transform: translateY(-8px);
    transition: opacity 0.15s ease-in-out, transform 0.15s ease-in-out,
        visibility 0.15s;
}

.v-more__panel.is-open {
    visibility: visible;
    opacity: 1;
    transform: translateY(0);
}

.v-more__item {
    display: block;
    padding: 9px 16px;
    font-size: 0.9rem;
    color: rgba(var(--v-theme-on-surface), 0.82);
    text-decoration: none;
    white-space: nowrap;
}

.v-more__item:hover,
.v-more__item:focus-visible,
.v-more__item.is-active {
    background-color: rgba(var(--v-theme-primary), 0.08);
    color: rgb(var(--v-theme-primary));
}

/* ---------------------------------------------------------------------------
   /request - the standalone request form.
   --------------------------------------------------------------------------- */

.page-request__head {
    max-width: 46rem;
    margin-bottom: 2rem;
}

.request-eyebrow,
.news-eyebrow {
    font-size: 0.75rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: rgb(var(--v-theme-primary));
    margin-bottom: 0.5rem;
}

.request-done {
    background-color: rgba(var(--v-theme-success), 0.1);
    border: 1px solid rgba(var(--v-theme-success), 0.4);
}

.request-error {
    background-color: rgba(var(--v-theme-error), 0.1);
    border: 1px solid rgba(var(--v-theme-error), 0.4);
}

/* The footer's navigation, services, contact and legal columns are styled with
   the legacy Footer block further up, next to the rest of the footer. The rules
   that used to live here coloured those links with `--v-theme-primary`, which
   is unreadable on the footer's own dark background and was the reason the
   footer had to be a light surface at all. */
