/* Site-wide structural styles supporting includes/header.php and
   includes/footer.php. Page-specific styling (colors, page layouts) is
   intentionally NOT included here — add that per project. */

/* Sticky header: stays visible while scrolling. position: sticky (not
   fixed) keeps it in normal document flow, so unlike the old fixed navbar
   there's no compensating top-padding hack needed on body/main — don't
   reintroduce one. Needs a solid background (page content would otherwise
   show through once it's stuck) and a z-index above ordinary content;
   1020 matches Bootstrap's own .sticky-top utility, keeping it below
   #back-to-top's 1030 in case they ever overlap. The shadow gives a
   subtle "floating above content" separation once stuck, replacing the
   shadow-sm the old Bootstrap navbar had. */
.site-header {
    position: sticky;
    top: 0;
    z-index: 1020;
    background-color: #ffffff;
    box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
}

/* Single combined logo mark (wordmark + arrow flourish in one SVG),
   replacing the old separate icon+wordmark lockup. Height picked to be
   comparable to the old icon's 60px within the header bar. */
.navbar-brand-logo {
    height: 64px;
    width: auto;
}

/* Tagline next to the logo — a single element at every width, always
   inside .site-header's flex row (never dropped to a separate block
   below the header). flex: 1 1 auto + min-width: 0 lets it shrink to
   whatever room the logo leaves and wrap its own text onto 2-3 lines
   within that column, instead of overflowing or forcing the row to wrap.
   Desktop size (1.375rem) was picked by measuring the tagline's actual
   rendered width in Coiny against the space left next to the logo at the
   960px/lg container width (the narrowest realistic "desktop" case) —
   1.5rem (24px) measured wider than the space available there, 1.375rem
   (22px) leaves a comfortable margin. That size is unchanged above the
   575.98px breakpoint; below it, see the media query further down. */
.site-header-tagline {
    font-family: 'Coiny', cursive;
    font-size: 1.375rem;
    flex: 1 1 auto;
    min-width: 0;
}

/* On module pages (modul.php sets $headerTagline to the active module's
   display_name, e.g. "Știri"), the tagline becomes the module's own
   name instead of the generic site tagline, matching the homepage's
   module cards' title treatment exactly — font-family, size, and
   weight all confirmed via computed styles on .card-title (40px/500,
   Rubik Doodle Shadow). Overrides .site-header-tagline's own font-size
   for this element; unchanged above 575.98px, see the media query
   further down for small phones. */
.site-header-tagline-brand {
    font-family: 'Rubik Doodle Shadow', cursive;
    font-size: 40px;
    font-weight: 500;
}

/* At 40px bold cursive right next to the logo with only the container's
   default gap-3, the module name read as fused with the logo itself
   rather than a separate page label (flagged after a real-browser check
   at 1920/1440px — not visible at the narrower widths tested earlier).
   A vertical rule is the standard fix for this exact pattern. Kept at
   every width, including small phones where the tagline wraps to
   multiple lines — the rule's own height (2.75rem) stays centered on
   the row via align-items: center on the flex parent regardless of how
   many lines the text wraps to, and real-device testing down to 320px
   confirmed it doesn't read as cramped. */
.site-header-tagline.site-header-tagline-brand {
    position: relative;
    margin-left: 0.75rem;
    padding-left: 1.75rem;
}

.site-header-tagline.site-header-tagline-brand::before {
    content: '';
    position: absolute;
    left: 0;
    top: 50%;
    transform: translateY(-50%);
    width: 1px;
    height: 2.75rem;
    background: #d8dce1;
}

/* Small phones (below Bootstrap's sm breakpoint): same breakpoint used
   by .site-legal-notice-wrap's mobile override above. Both tagline
   variants shrink here so long text wraps cleanly within its column
   instead of overflowing horizontally - tuned against real canvas
   measurements of "Locuri de muncă" (the longest module name) and the
   full generic homepage sentence (which never fits one line at any
   readable size and is expected to wrap to 2-3 lines) down to 320px.
   The generic tagline's clamp (13-17px) was tuned so its wrapped height
   never exceeds the 64px logo next to it anywhere in this range, while
   still growing to make better use of that height as width increases —
   a flat size left ~25px of unused vertical space next to the logo at
   mid-range widths like 440px. */
@media (max-width: 575.98px) {
    .site-header-tagline-brand {
        font-size: clamp(22px, 7vw, 40px);
    }

    .site-header-tagline:not(.site-header-tagline-brand) {
        font-size: clamp(13px, 4vw, 17px);
    }
}

/* "Precizări legale" collapsible notice, right after the header (outside
   <header>, so it scrolls away normally instead of staying sticky).
   Uses native <details>/<summary> — no JS dependency, works even if
   bootstrap.bundle.min.js hasn't loaded yet, accessible by default.
   The default browser disclosure triangle is removed in favor of the
   local Bootstrap Icons chevron, which flips via a pure-CSS transform
   keyed off the [open] attribute — still no JS involved. */
.site-legal-notice-summary {
    list-style: none;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
}

.site-legal-notice-summary::-webkit-details-marker {
    display: none;
}

.site-legal-notice-label,
.site-legal-notice-text {
    font-family: 'Kalam', cursive;
}

.site-legal-notice-chevron {
    transition: transform 0.2s ease;
}

.site-legal-notice[open] .site-legal-notice-chevron {
    transform: rotate(180deg);
}

.site-legal-notice-text {
    margin-top: 0.75rem;
}

/* Modifier for the three filter-form labels that reuse
   .site-legal-notice-label's font-family/weight/color (Stiri's "Arată
   știrile din"/"Caută în titluri", Vremea's "Arată vremea din") but need
   a larger size — matching .module-card .card-text's 1.125rem from
   home.css (the homepage card description text), not the smaller size
   "Precizări legale" itself uses. Scoped to this modifier rather than
   changed on .site-legal-notice-label directly, since that class is
   still used as-is by "Precizări legale" in header.php and must keep
   its current (smaller) size there. */
.site-legal-notice-label--lg {
    font-size: 1.125rem;
}

/* Mobile only: the wrapper's own py-2 (0.5rem/8px) padding-top is on top
   of the mobile tagline block's spacing above it, reading as too much gap.
   Desktop must stay at the unmodified py-2 value (0.5rem/8px) — this only
   applies below the sm breakpoint. padding-bottom and everything else on
   this wrapper is untouched. */
@media (max-width: 575.98px) {
    .site-legal-notice-wrap {
        padding-top: 0.25rem !important;
    }
}

/* Dark footer background — flat color rather than a photo, since no
   per-project background image ships with this template. */
.site-footer {
    background-color: #0f141a;
}

/* "Built by NRFBIZ" footer credit. */
.nrfbiz-credit-logo {
    height: 2em;
    width: auto;
    aspect-ratio: 1 / 1;
    flex: 0 0 auto;
    min-width: 0;
}

/* Both links lost their color when text-white-50/text-light was removed
   directly from the <a> elements in footer.php (that Bootstrap utility,
   applied right on the link, was the only thing setting their color —
   links don't pick up a parent's color by simple inheritance, since the
   browser's own default link-color rule outranks that). !important is
   needed for the same reason those removed utilities needed it: beating
   that browser default. */
.contact-email-link,
.footer-credit-link {
    color: #ffffff !important;
}

.footer-credit-link:hover,
.footer-credit-link:focus {
    color: #ffffff !important;
}

/* Floating "back to top" button — shown after scrolling down (main.js adds
   .is-visible). Small circular button, fixed bottom-right, site-wide. */
#back-to-top {
    position: fixed;
    right: 1.25rem;
    bottom: 1.25rem;
    z-index: 1030;
    width: 2.75rem;
    height: 2.75rem;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    font-size: 1.25rem;
    line-height: 1;
    box-shadow: 0 0.25rem 0.75rem rgba(0, 0, 0, 0.25);
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.2s ease, visibility 0.2s ease;
}

#back-to-top.is-visible {
    opacity: 1;
    visibility: visible;
}

/* Floating Home/Back widget — fixed to the right edge, anchored at
   roughly 75% of viewport height (a natural mobile thumb-reach zone,
   lower than dead center), on every page except the homepage (guarded
   in header.php via $isHomepage). Always visible (no scroll-triggered
   show/hide, unlike #back-to-top). z-index sits above the sticky header
   (1020) but below #back-to-top (1030) in case a page is both scrolled
   and short enough for the two to ever sit near each other.

   Deliberately NO viewport-relative unit here at all (no %, vh, or
   svh) — main.js always sets an inline pixel top instead, computed
   once and left static. Earlier attempts used vh, then svh, to
   position this; both still visibly wobbled during a mobile browser's
   address-bar show/hide animation on a real Samsung S25 (not
   reproducible in devtools, which doesn't simulate that animation), and
   svh additionally showed a brief paint/hit-test desync during that same
   animation. Root cause: ANY viewport-relative unit on a position: fixed
   element gets re-evaluated by the browser's layout/compositor on every
   frame of that animation, regardless of which specific unit is used —
   svh only changes what value it resolves to, not whether it keeps
   getting re-evaluated. A plain static pixel value needs no such
   re-evaluation at all; the element just stays exactly where it was
   painted. This top value is a static fallback only, for the rare case
   JS doesn't run — see main.js, which overwrites it unconditionally on
   load and is what actually positions this in every normal case. */
.site-float-nav {
    position: fixed;
    top: 480px;
    right: 16px;
    z-index: 1025;
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.site-float-nav-btn {
    width: 36px;
    height: 36px;
    border-radius: 50%;
    background: #ffffff;
    border: 2.5px solid #171717;
    box-shadow: 0 0.25rem 0.75rem rgba(0, 0, 0, 0.25);
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

.site-float-nav-btn svg {
    width: 19px;
    height: 19px;
    display: block;
}

/* The share button is a <button>, unlike home/back (<a>) — resets the
   default browser button chrome (padding, font inheritance) the shared
   .site-float-nav-btn rule above never had to account for, without
   touching that rule itself (tag-qualified, so home/back are untouched). */
button.site-float-nav-btn {
    padding: 0;
    cursor: pointer;
    font: inherit;
}

/* A long unbroken token (e.g. an email address) shouldn't force the page
   wider than the viewport on narrow screens. */
.contact-email-link {
    overflow-wrap: anywhere;
    word-break: break-word;
}

/* Same reasoning as .contact-email-link above, applied to headline/title
   text pulled from content we don't fully control (RSS feed titles) or
   that visitors type/paste themselves (listing titles) — a long run with
   no normal breakable space (e.g. words joined by a stray non-breaking
   space from a pasted-from-Word source, or any other unbreakable token)
   would otherwise force the whole page wider than the viewport on narrow
   screens, same failure shape as the email case. Deliberately character-
   agnostic (overflow-wrap: anywhere breaks at ANY point if nothing better
   is available, not just at known problem characters) rather than
   depending on knowing in advance what's going to cause the next one of
   these. .news-item-title: template-news-feed.php's article headlines
   (Stiri/Comunicate oficiale, both the sponsored and organic list).
   .listing-item-title: the parallel listing-card headline shared by
   template-job-board.php (Locuri de muncă/Imobiliare) and
   template-general-board.php (Anunțuri generale). */
.news-item-title,
.listing-item-title,
.editorial-item-title,
.editorial-title,
.editorial-body {
    overflow-wrap: anywhere;
    word-break: break-word;
}

/* Site-wide loading overlay — see main.js for what triggers .is-visible
   and the ~200ms delay before it's added (so a fast load never flashes
   it). display:none by default rather than opacity/visibility, since
   there's nothing to transition: the page is about to be replaced by
   navigation anyway, so there's no benefit to an exit animation, and
   this keeps the markup fully inert (no click-through, no a11y tree
   presence) until JS actually decides to show it. z-index above
   everything else on the page (header 1020, float-nav 1025, back-to-top
   1030) since it's meant to cover the whole page while a navigation is
   in flight. */
.site-loading-overlay {
    display: none;
    position: fixed;
    inset: 0;
    z-index: 2000;
    background: rgba(255, 255, 255, 0.75);
    align-items: center;
    justify-content: center;
}

.site-loading-overlay.is-visible {
    display: flex;
}

.site-loading-overlay-content {
    text-align: center;
    color: #212529;
}

/* Vremea's per-day "Vezi pe ore" hourly detail (template-live-api.php).
   Collapsed by default via native <details> — no JS. The hour list
   itself scrolls horizontally rather than wrapping, since 24 chips in a
   narrow card column would otherwise make the card absurdly tall. */
.weather-hourly-summary {
    cursor: pointer;
}

.weather-hourly-scroll {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
}

.weather-hour-chip {
    flex: 0 0 auto;
}

.weather-hour-chip-icon {
    font-size: 1.25rem;
    line-height: 1;
}

/* City-selector's "Alege" submit button (partials/city-selector.php) is
   redundant once JS is confirmed working — the dropdown already
   auto-submits via requestSubmit() on change — so it's hidden under the
   .js flag main.js sets on <html>. Stays in the DOM either way; with JS
   disabled, html never gets .js, so this rule simply never matches and
   the button is the form's only way to submit, same as it always was. */
.js .city-selector-submit {
    display: none;
}

/* "Arată pentru locația mea" geolocation button (partials/city-selector.php,
   Vremea only) is the mirror image of .city-selector-submit just above —
   hidden by default, shown only once .js (main.js) confirms JS actually
   ran. Unlike the "Alege" button (which still works as a genuine no-JS
   fallback), this one is a plain type="button" with no click handler at
   all without the script that defines one (template-live-api.php) — so
   it must never be visible to a no-JS visitor, who could click it and
   get nothing. template-live-api.php's own script additionally hides it
   again at runtime (inline style, overriding this rule) specifically
   when navigator.geolocation itself isn't supported even though JS did
   run. */
.geo-weather-btn {
    display: none;
}

.js .geo-weather-btn {
    display: inline-block;
}

/* Sponsored/pinned articles (news_sponsored, template-news-feed.php) —
   rendered in their own .list-group above the normal news_items list.
   A warm accent border (both the thin default border, overridden, and a
   thicker left edge) is the "clearly distinguishing" visual cue, plus
   the flame icon next to the title — deliberately no text label like
   "Promovat", per the feature's own spec. */
.news-item-sponsored {
    border-color: #f0ad4e;
}

.news-item-sponsored-icon {
    font-size: 0.9rem;
}

/* Stiri/Comunicate Oficiale (template-news-feed.php) only — halves the
   top padding between "Precizări legale" and the filter row, from the
   1rem every other module-content wrapper still uses (pt-3, shared by
   card-grid.php, template-live-api.php and template-coming-soon.php —
   deliberately NOT changed there, only this one template's wrapper
   swaps pt-3 for this instead). */
.news-feed-container {
    padding-top: 0.5rem;
}

/* ad-rotator.js's crossfade mechanism (every rotating ad slot — mobile
   spot2, desktop box2+box3, position2; NOT the static premium spots,
   which are a plain <img>, no JS, no layers at all). Each
   .ad-rotator-slot container gets two stacked .ad-rotator-slot-layer
   <img>s (position: relative on the container, set inline by the PHP
   partial alongside its width/height — this file only owns the layer
   stacking/fade). ad-rotator.js preloads the next image into the
   currently-hidden layer, then toggles .is-visible on both layers at
   once so the opacity transition below does the actual crossfade — a
   plain instant src swap would never get this look however JS timed
   it, hence the two-layer approach rather than a single <img>.
   prefers-reduced-motion: reduce drops the transition to 0s instead of
   skipping it in JS — the swap is still a class toggle either way, just
   instant, so there's exactly one code path for both cases. */
.ad-rotator-slot {
    position: relative;
    overflow: hidden;
}

.ad-rotator-slot-layer {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
    opacity: 0;
    transition: opacity 1.2s ease;
}

.ad-rotator-slot-layer.is-visible {
    opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
    .ad-rotator-slot-layer {
        transition-duration: 0s;
    }
}

/* "Adaugă anunț" + "Șterge anunț" pair, atop each listing-board page
   (template-job-board.php, template-general-board.php). flex-wrap
   (not nowrap) lets the second button drop to its own row, at its own
   natural size, whenever there isn't room for both on one line — a
   plain nowrap flex row instead lets each button shrink below its own
   text's natural width (flex items' default min-width: auto doesn't
   stop that), wrapping the label internally onto 2-3 lines instead,
   which is what originally inflated the row's height. white-space:
   nowrap on each button's own label is what makes that shrinking
   impossible in the first place, forcing the "doesn't fit" case to go
   through flex-wrap (drop to a new line) rather than internal wrap.
   Deliberately no fixed breakpoint — the exact width where this
   switches depends on the two labels' real combined text width, which
   is exactly the point: it keeps working correctly if either label's
   text changes length later. */
.listing-board-actions {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
}

.listing-board-actions .btn {
    white-space: nowrap;
}

/* adauga-anunt.php's shared submission form (#listing-form, used
   identically by all three listing-board categories) — bolds its
   field labels (Tip anunț/Subcategorie, Titlu, Descriere, Nume
   (opțional), Telefon, Email). Scoped to #listing-form specifically so
   this doesn't affect .form-label usage on any other form site-wide
   (e.g. admin pages). The GDPR consent checkbox's label uses a
   different class (form-check-label) and the honeypot field's label
   has no class at all, so neither is affected either. */
#listing-form .form-label {
    font-weight: 700;
}
