/* ==========================================================================
   norlux-ui.css — Norlux Paints design system layer
   --------------------------------------------------------------------------
   Loaded AFTER bootstrap.min.css and style.css, so it is the last word.

   WHY THIS FILE EXISTS
   The compiled css/bootstrap.min.css (Bootstrap 5.0.0) has hardcoded colour
   utilities — .bg-light is baked in as #cb0707, a RED, where the scss source
   says #F2F3F5. Because .bg-light sits on the navbar of every page and on the
   feature/contact sections, the whole site renders drenched in red. The colour
   utilities are compiled literals with !important, so overriding --bs-* custom
   properties does nothing; the utilities have to be redefined outright. That is
   what the "Bootstrap utility repairs" block below does.

   PALETTE — read off img/logo.png (red #F00000, navy #104080, white) and then
   disciplined: navy carries the design, red is reserved for calls to action and
   accents. Before this file, red was ~40% of the page; after, it is ~5%.

   Nothing here needs a build step: plain CSS custom properties.
   ========================================================================== */

/* ==========================================================================
   1 · TOKENS
   ========================================================================== */
:root {
    /* Brand */
    --nx-navy:        #0B2A5B;
    --nx-navy-600:    #123A75;
    --nx-navy-800:    #08203F;
    --nx-navy-900:    #061831;
    --nx-red:         #E01B1B;
    --nx-red-600:     #C41616;
    --nx-red-700:     #A81212;

    /* Surfaces + ink */
    --nx-white:       #FFFFFF;
    --nx-mist:        #F5F7FA;
    --nx-mist-200:    #EDF1F7;
    --nx-line:        #E3E8EF;
    --nx-ink:         #1A1D21;
    --nx-body:        #4B5563;
    --nx-muted:       #6B7280;

    /* Tint of navy, for scrims and shadows that must stay in-family */
    --nx-navy-a08:    rgba(11, 42, 91, 0.08);
    --nx-navy-a12:    rgba(11, 42, 91, 0.12);
    --nx-navy-a18:    rgba(11, 42, 91, 0.18);

    /* Shape */
    --nx-radius:      14px;
    --nx-radius-sm:   10px;
    --nx-radius-lg:   20px;
    --nx-radius-pill: 999px;

    /* Depth — tinted navy, never neutral black, so cards sit in the palette */
    --nx-shadow-1: 0 1px 2px var(--nx-navy-a08), 0 2px 8px var(--nx-navy-a08);
    --nx-shadow-2: 0 8px 24px var(--nx-navy-a12);
    --nx-shadow-3: 0 20px 56px var(--nx-navy-a18);

    /* Motion — one ease for the whole site, so everything feels related */
    --nx-ease:      cubic-bezier(0.22, 0.61, 0.36, 1);
    --nx-ease-out:  cubic-bezier(0.16, 1, 0.3, 1);
    --nx-fast:      0.18s;
    --nx-base:      0.32s;
    --nx-slow:      0.6s;

    /* Vertical rhythm — one value drives every section, which is most of what
       "looks more professional" actually means. */
    --nx-section-y: clamp(3.25rem, 6.5vw, 6rem);
    --nx-gutter:    clamp(1rem, 2.5vw, 2rem);
}

/* ==========================================================================
   2 · BASE REPAIRS
   The old index.html inline block had a global `img { width: 100%; height: auto }`
   which stretched every image on the page — including the logo — to its
   container. Images are made fluid per component instead.
   ========================================================================== */
body {
    font-family: 'Roboto', system-ui, -apple-system, "Segoe UI", sans-serif;
    color: var(--nx-body);
    background: var(--nx-white);
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
    overflow-x: hidden;           /* stops the 1px horizontal scroll on mobile */
}

img,
svg,
video {
    max-width: 100%;
    height: auto;
}

/* The logo is a fixed-height brand mark, not fluid content. */
.navbar-brand img {
    height: clamp(56px, 7vw, 78px) !important;
    width: auto !important;
    max-width: none;
    transition: height var(--nx-base) var(--nx-ease);
}

a { text-decoration: none; }

::selection {
    background: var(--nx-navy);
    color: #fff;
}

:focus-visible {
    outline: 3px solid var(--nx-red);
    outline-offset: 2px;
}

/* ==========================================================================
   3 · TYPE SCALE
   Fluid, so headings stop overflowing on small screens without a stack of
   per-breakpoint font-size overrides.
   ========================================================================== */
h1, h2, h3, h4, h5, h6,
.h1, .h2, .h3, .h4, .h5, .h6 {
    font-family: "Playfair Display", Georgia, serif;
    color: var(--nx-ink);
    font-weight: 700;
    line-height: 1.15;
    letter-spacing: -0.01em;
}

h1, .h1           { font-size: clamp(2rem,   4.4vw, 3.5rem); }
h2, .h2           { font-size: clamp(1.65rem, 3.4vw, 2.6rem); }
h3, .h3           { font-size: clamp(1.35rem, 2.4vw, 1.9rem); }
h4, .h4           { font-size: clamp(1.15rem, 1.8vw, 1.4rem); }
h5, .h5           { font-size: 1.1rem; }

.display-1, .display-2, .display-3,
.display-4, .display-5, .display-6 {
    font-family: "Playfair Display", Georgia, serif;
    line-height: 1.1;
    letter-spacing: -0.015em;
}
.display-4 { font-size: clamp(1.9rem, 4vw, 3.1rem); }
.display-5 { font-size: clamp(1.7rem, 3.4vw, 2.6rem); }
.display-6 { font-size: clamp(1.45rem, 2.6vw, 2.05rem); }

p { line-height: 1.7; }

.lead,
p.fs-5 { font-size: clamp(1rem, 1.25vw, 1.125rem); }

/* The Lobster brand wordmark — was #e63946, an off-brand red. */
.stylish-font {
    font-family: 'Lobster', cursive;
    font-size: clamp(1.35rem, 2.6vw, 2rem);
    color: var(--nx-navy);
    line-height: 1.2;
}

/* Eyebrow labels above section headings. The markup already writes these as
   `text-uppercase text-secondary`, so red stays as a deliberate accent here. */
.text-uppercase.text-secondary {
    letter-spacing: 0.16em;
    font-weight: 700;
    font-size: 0.82rem !important;
}

/* ==========================================================================
   4 · BOOTSTRAP UTILITY REPAIRS
   These have to carry !important because the compiled utilities do.
   ========================================================================== */
.bg-light        { background-color: var(--nx-mist) !important; }
.bg-secondary    { background-color: var(--nx-red) !important; }
.bg-primary      { background-color: var(--nx-navy) !important; }
.bg-dark         { background-color: var(--nx-navy-900) !important; }
.bg-white        { background-color: var(--nx-white) !important; }

.text-primary    { color: var(--nx-navy) !important; }
.text-secondary  { color: var(--nx-red) !important; }
.text-dark       { color: var(--nx-ink) !important; }
.text-light      { color: var(--nx-mist) !important; }
.text-muted      { color: var(--nx-muted) !important; }
.text-body       { color: var(--nx-body) !important; }

.border-primary   { border-color: var(--nx-navy) !important; }
.border-secondary { border-color: var(--nx-red) !important; }

/* On a light surface, "light" text would be invisible. The old red --bs-light
   accidentally hid this; now it has to be handled honestly. */
.bg-light .text-light,
.bg-white .text-light { color: var(--nx-body) !important; }

/* Rounded corners: the scss set $border-radius to 0, which is what makes the
   current build look dated. */
.rounded    { border-radius: var(--nx-radius) !important; }
.rounded-sm { border-radius: var(--nx-radius-sm) !important; }
.rounded-lg { border-radius: var(--nx-radius-lg) !important; }

/* ==========================================================================
   5 · BUTTONS
   ========================================================================== */
.btn {
    --nx-btn-bg: var(--nx-navy);
    --nx-btn-fg: #fff;
    font-family: 'Roboto', sans-serif;
    font-weight: 600;
    letter-spacing: 0.01em;
    border-radius: var(--nx-radius-pill);
    padding: 0.75rem 1.6rem;
    position: relative;
    overflow: hidden;
    isolation: isolate;
    transition: transform var(--nx-base) var(--nx-ease),
                box-shadow var(--nx-base) var(--nx-ease),
                color var(--nx-fast) linear,
                background-color var(--nx-base) var(--nx-ease);
}

/* Wipe fill on hover, instead of a flat colour swap. */
.btn::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    background: var(--nx-btn-hover, var(--nx-navy-800));
    transform: translateY(101%);
    transition: transform var(--nx-base) var(--nx-ease-out);
}
.btn:hover::after { transform: translateY(0); }

.btn:hover {
    transform: translateY(-2px);
    box-shadow: var(--nx-shadow-2);
}
.btn:active { transform: translateY(0); }

.btn-primary,
.btn.btn-primary {
    background-color: var(--nx-navy);
    border-color: var(--nx-navy);
    color: #fff;
    --nx-btn-hover: var(--nx-navy-800);
}
.btn-primary:hover,
.btn.btn-primary:hover {
    background-color: var(--nx-navy);
    border-color: var(--nx-navy-800);
    color: #fff;
}

/* Red is the single call-to-action colour. */
.btn-secondary,
.btn.btn-secondary {
    background-color: var(--nx-red);
    border-color: var(--nx-red);
    color: #fff;
    --nx-btn-hover: var(--nx-red-700);
}
.btn-secondary:hover,
.btn.btn-secondary:hover {
    background-color: var(--nx-red);
    border-color: var(--nx-red-700);
    color: #fff;
}

.btn-outline-primary {
    border: 2px solid var(--nx-navy);
    color: var(--nx-navy);
    background: transparent;
    --nx-btn-hover: var(--nx-navy);
}
.btn-outline-primary:hover { color: #fff; border-color: var(--nx-navy); background: transparent; }

.btn-outline-light {
    border: 2px solid rgba(255, 255, 255, 0.75);
    color: #fff;
    background: transparent;
    --nx-btn-hover: #fff;
}
.btn-outline-light:hover { color: var(--nx-navy); background: transparent; }

/* Square icon buttons must stay circular and must not grow a wipe. */
.btn-square, .btn-sm-square, .btn-md-square, .btn-lg-square, .btn-xl-square {
    border-radius: 50%;
    padding: 0;
    overflow: visible;
}
.btn-square::after, .btn-sm-square::after, .btn-md-square::after,
.btn-lg-square::after, .btn-xl-square::after { display: none; }

/* Arrow nudge on any button whose label ends in an icon. */
.btn i { transition: transform var(--nx-base) var(--nx-ease); }
.btn:hover i.fa-arrow-right,
.btn:hover i.fa-angle-right,
.btn:hover i.bi-arrow-right { transform: translateX(4px); }

/* The old "Join Us" counter button: was #fa0808 red with a GREY hover. */
.counter-btn {
    background-color: var(--nx-red);
    color: #fff;
    border: none;
    padding: 0.85rem 2rem;
    font-family: 'Roboto', sans-serif;
    font-weight: 700;
    font-size: 1rem;
    border-radius: var(--nx-radius-pill);
    cursor: pointer;
    box-shadow: var(--nx-shadow-1);
    transition: transform var(--nx-base) var(--nx-ease),
                box-shadow var(--nx-base) var(--nx-ease),
                background-color var(--nx-base) var(--nx-ease);
}
.counter-btn:hover {
    background-color: var(--nx-red-700);
    transform: translateY(-3px);
    box-shadow: var(--nx-shadow-2);
}

/* ==========================================================================
   6 · TOPBAR + NAVBAR
   The navbar carried `navbar-dark bg-light`, i.e. white text on the accidental
   red. It becomes a white bar with navy links and a red underline on hover.
   ========================================================================== */
.topbar {
    background: var(--nx-navy) !important;
    padding: 0.5rem 1rem;
    font-size: 0.9rem;
}
.topbar,
.topbar a,
.topbar i,
.topbar small,
.topbar span { color: rgba(255, 255, 255, 0.92) !important; }
.topbar a:hover { color: #fff !important; }

.navbar.bg-light,
.navbar.navbar-dark.bg-light {
    background-color: rgba(255, 255, 255, 0.96) !important;
    backdrop-filter: saturate(180%) blur(10px);
    border-bottom: 1px solid var(--nx-line);
    box-shadow: 0 1px 0 rgba(11, 42, 91, 0.04);
    padding-top: 0.65rem !important;
    padding-bottom: 0.65rem !important;
    transition: padding var(--nx-base) var(--nx-ease),
                box-shadow var(--nx-base) var(--nx-ease);
}

/* Compact once the page is scrolled (js adds .nx-stuck). */
.navbar.nx-stuck {
    padding-top: 0.3rem !important;
    padding-bottom: 0.3rem !important;
    box-shadow: var(--nx-shadow-2);
}
.navbar.nx-stuck .navbar-brand img { height: clamp(46px, 5vw, 58px) !important; }

.navbar .navbar-nav .nav-link,
.navbar .navbar-nav .nav-item.nav-link {
    color: var(--nx-ink) !important;
    font-family: 'Roboto', sans-serif;
    font-weight: 500;
    font-size: 1rem;
    padding: 0.5rem 0.15rem !important;
    margin: 0 0.6rem;
    position: relative;
}

/* Kill the old ::before/::after box effect from style.css and use a rule. */
.navbar .navbar-nav .nav-item::before,
.navbar .navbar-nav .nav-item::after { display: none !important; }

.navbar .navbar-nav .nav-link::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: -2px;
    height: 2px;
    background: var(--nx-red);
    transform: scaleX(0);
    transform-origin: left;
    transition: transform var(--nx-base) var(--nx-ease-out);
}
.navbar .navbar-nav .nav-link:hover::after,
.navbar .navbar-nav .nav-link.active::after { transform: scaleX(1); }

.navbar .navbar-nav .nav-link:hover,
.navbar .navbar-nav .nav-link.active {
    color: var(--nx-navy) !important;
}

.navbar-toggler {
    border: 1px solid var(--nx-line);
    border-radius: var(--nx-radius-sm);
    padding: 0.45rem 0.6rem;
}
.navbar-toggler:focus { box-shadow: 0 0 0 3px var(--nx-navy-a12); }
/* navbar-dark ships a white burger icon, invisible on the new white bar. */
.navbar-dark .navbar-toggler-icon {
    background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='%230B2A5B' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e");
}

/* ==========================================================================
   7 · SECTION RHYTHM + HEADINGS
   ========================================================================== */
.container-fluid.py-5,
section.py-5,
div.py-5 {
    padding-top: var(--nx-section-y) !important;
    padding-bottom: var(--nx-section-y) !important;
}
.container.py-5 {
    padding-top: 0 !important;
    padding-bottom: 0 !important;
}

/* Accent rule under centred section headings. */
.text-center.mx-auto.pb-5 { padding-bottom: clamp(2rem, 4vw, 3.25rem) !important; }

.text-center.mx-auto > .text-uppercase.text-secondary { margin-bottom: 0.5rem !important; }

.text-center.mx-auto > h2::after,
.text-center.mx-auto > .display-4::after,
.text-center.mx-auto > .display-5::after {
    content: "";
    display: block;
    width: 68px;
    height: 3px;
    margin: 1.1rem auto 0;
    border-radius: 2px;
    background: linear-gradient(90deg, var(--nx-red), var(--nx-navy));
    transform: scaleX(0);
    transform-origin: center;
    transition: transform var(--nx-slow) var(--nx-ease-out) 0.15s;
}
.text-center.mx-auto.nx-in > h2::after,
.text-center.mx-auto.nx-in > .display-4::after,
.text-center.mx-auto.nx-in > .display-5::after { transform: scaleX(1); }

/* ==========================================================================
   8 · CARD COMPONENTS
   One treatment shared by every *-item block, which is what makes the pages
   read as one system: service (20), project (34), feature (6), team (4),
   counter (12), mancap (4).
   ========================================================================== */
.service-item,
.project-item,
.feature-item,
.team-item,
.blog-item,
.counter-item,
.mancap-img-card,
.depot-item {
    background: var(--nx-white);
    border: 1px solid var(--nx-line);
    border-radius: var(--nx-radius);
    overflow: hidden;
    height: 100%;
    box-shadow: var(--nx-shadow-1);
    transition: transform var(--nx-base) var(--nx-ease),
                box-shadow var(--nx-base) var(--nx-ease),
                border-color var(--nx-base) var(--nx-ease);
}

.service-item:hover,
.project-item:hover,
.feature-item:hover,
.team-item:hover,
.blog-item:hover,
.mancap-img-card:hover,
.depot-item:hover {
    transform: translateY(-6px);
    box-shadow: var(--nx-shadow-3);
    border-color: transparent;
}

/* Image wrappers: crop, then zoom the image inside on hover. */
.service-img,
.project-img,
.feature-img,
.team-img,
.blog-img {
    position: relative;
    overflow: hidden;
    background: var(--nx-mist);
}

.service-img img,
.project-img img,
.feature-img img,
.team-img img,
.blog-img img {
    width: 100%;
    display: block;
    transition: transform var(--nx-slow) var(--nx-ease);
    will-change: transform;
}

.service-item:hover .service-img img,
.project-item:hover .project-img img,
.feature-item:hover .feature-img img,
.team-item:hover .team-img img,
.blog-item:hover .blog-img img { transform: scale(1.07); }

/* A red hairline that draws across the top of a card on hover. */
.service-item,
.project-item,
.feature-item { position: relative; }

.service-item::before,
.project-item::before,
.feature-item::before {
    content: "";
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 3px;
    background: var(--nx-red);
    transform: scaleX(0);
    transform-origin: left;
    transition: transform var(--nx-base) var(--nx-ease-out);
    z-index: 2;
}
.service-item:hover::before,
.project-item:hover::before,
.feature-item:hover::before { transform: scaleX(1); }

.service-content,
.project-content,
.about-item-content { padding: clamp(1.1rem, 2vw, 1.6rem); }

.service-content h3,
.service-content h4,
.project-content h3,
.project-content h4 { transition: color var(--nx-base) var(--nx-ease); }

.service-item:hover .service-content h3,
.service-item:hover .service-content h4,
.project-item:hover .project-content h3,
.project-item:hover .project-content h4 { color: var(--nx-navy); }

/* Counters */
.counter-item { text-align: center; padding: clamp(1.25rem, 2.5vw, 2rem); }
.counter-item-inner { border-radius: var(--nx-radius-sm); }
.counter-item .h1,
.counter-item h1,
.counter-item [data-toggle="counter-up"] {
    color: var(--nx-navy);
    font-family: "Playfair Display", serif;
    font-weight: 700;
}
.counter-item:hover { transform: translateY(-4px); }

/* Team icon strip */
.team-icon a,
.team-icon .btn { transition: transform var(--nx-base) var(--nx-ease), background-color var(--nx-base) var(--nx-ease); }
.team-icon a:hover { transform: translateY(-3px); }

/* ==========================================================================
   9 · VIDEO + GALLERY
   61 mp4s carry this site, so the play affordance matters.
   ========================================================================== */
.video-thumbnail {
    position: relative;
    overflow: hidden;
    border-radius: var(--nx-radius);
    background: var(--nx-navy-900);
    box-shadow: var(--nx-shadow-1);
    transition: transform var(--nx-base) var(--nx-ease), box-shadow var(--nx-base) var(--nx-ease);
}
.video-thumbnail:hover {
    transform: translateY(-5px);
    box-shadow: var(--nx-shadow-3);
}
.video-thumbnail video {
    display: block;
    width: 100%;
    border-radius: inherit;
    object-fit: cover;
}

.play-button {
    cursor: pointer;
    width: 66px;
    height: 66px;
    display: grid;
    place-items: center;
    border-radius: 50%;
    background: rgba(224, 27, 27, 0.94);
    box-shadow: 0 10px 30px rgba(224, 27, 27, 0.35);
    transition: transform var(--nx-base) var(--nx-ease-out), background-color var(--nx-base) var(--nx-ease);
}
.play-button i { color: #fff; font-size: 1.35rem; margin-left: 3px; }
.video-thumbnail:hover .play-button { transform: translate(-50%, -50%) scale(1.12); }
.play-button:hover { background: var(--nx-red-700); }

/* Soft pulse ring, so an unplayed video reads as interactive. */
.play-button::before {
    content: "";
    position: absolute;
    inset: -10px;
    border-radius: 50%;
    border: 2px solid rgba(224, 27, 27, 0.5);
    animation: nx-pulse 2.4s var(--nx-ease) infinite;
}
@keyframes nx-pulse {
    0%   { transform: scale(0.9); opacity: 0.8; }
    70%  { transform: scale(1.25); opacity: 0; }
    100% { transform: scale(1.25); opacity: 0; }
}

/* MANCAP award cards */
.mancap-img-card { border: none; }
.mancap-img-card:hover { transform: translateY(-8px) scale(1.02); }

/* ==========================================================================
   10 · FORMS
   The old inline CSS styled bare `form`, `label`, `input`, `select` and
   `input[type=submit]` globally — so the join-us modal's rules leaked onto the
   contact form site-wide (including `form { display: flex }`). Everything is
   scoped to its component here.
   ========================================================================== */
.nx-form,
#myModal form {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
}

.form-control,
.form-select,
#myModal input,
#myModal select,
.nx-form input,
.nx-form select,
.nx-form textarea {
    border: 1.5px solid var(--nx-line);
    border-radius: var(--nx-radius-sm);
    padding: 0.8rem 1rem;
    font-size: 1rem;
    font-family: 'Roboto', sans-serif;
    color: var(--nx-ink);
    background: var(--nx-white);
    transition: border-color var(--nx-fast) var(--nx-ease), box-shadow var(--nx-fast) var(--nx-ease);
}

.form-control:focus,
.form-select:focus,
#myModal input:focus,
#myModal select:focus,
.nx-form input:focus,
.nx-form textarea:focus {
    border-color: var(--nx-navy);
    box-shadow: 0 0 0 4px var(--nx-navy-a12);
    outline: none;
}

.form-label,
#myModal label,
.nx-form label {
    font-weight: 600;
    font-size: 0.9rem;
    color: var(--nx-ink);
    margin-bottom: 0.35rem;
}

/* Submit was #4CAF50 green — off-brand. */
#myModal input[type="submit"],
.nx-form input[type="submit"],
.nx-form button[type="submit"] {
    background-color: var(--nx-red);
    color: #fff;
    border: none;
    border-radius: var(--nx-radius-pill);
    padding: 0.85rem 1.5rem;
    font-weight: 700;
    cursor: pointer;
    margin-top: 0.75rem;
    transition: background-color var(--nx-base) var(--nx-ease), transform var(--nx-base) var(--nx-ease), box-shadow var(--nx-base) var(--nx-ease);
}
#myModal input[type="submit"]:hover,
.nx-form input[type="submit"]:hover,
.nx-form button[type="submit"]:hover {
    background-color: var(--nx-red-700);
    transform: translateY(-2px);
    box-shadow: var(--nx-shadow-2);
}

.input-icon { position: relative; }
.input-icon i {
    position: absolute;
    left: 0.95rem;
    top: 50%;
    transform: translateY(-50%);
    color: var(--nx-muted);
    pointer-events: none;
    transition: color var(--nx-fast) var(--nx-ease);
    z-index: 2;
}
.input-icon input,
.input-icon select { padding-left: 2.6rem !important; width: 100%; }
.input-icon:focus-within i { color: var(--nx-navy); }

/* ==========================================================================
   11 · MODAL (join-us)
   ========================================================================== */
#myModal.modal {
    display: none;
    position: fixed;
    inset: 0;
    z-index: 9999;
    overflow: auto;
    background: rgba(6, 24, 49, 0.55);
    backdrop-filter: blur(4px);
    animation: nx-fade var(--nx-base) var(--nx-ease);
}
#myModal .modal-content {
    background: var(--nx-white);
    border-radius: var(--nx-radius-lg);
    box-shadow: var(--nx-shadow-3);
    padding: clamp(1.5rem, 3vw, 2.25rem);
    max-width: 520px;
    width: calc(100% - 2rem);
    margin: clamp(2rem, 8vh, 6rem) auto;
    animation: nx-slide-in var(--nx-slow) var(--nx-ease-out);
}
#myModal .close {
    color: var(--nx-muted);
    float: right;
    font-size: 1.9rem;
    font-weight: 700;
    line-height: 1;
    cursor: pointer;
    transition: color var(--nx-fast) var(--nx-ease), transform var(--nx-fast) var(--nx-ease);
}
#myModal .close:hover { color: var(--nx-red); transform: rotate(90deg); }

@keyframes nx-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes nx-slide-in {
    from { transform: translateY(-24px); opacity: 0; }
    to   { transform: translateY(0);     opacity: 1; }
}

/* ==========================================================================
   12 · FLOATING ACTIONS
   ========================================================================== */
.whatsapp-button {
    position: fixed;
    bottom: 22px;
    right: 22px;
    width: 58px;
    height: 58px;
    display: grid;
    place-items: center;
    background-color: #25D366;   /* WhatsApp's own brand green, left alone */
    border: none;
    border-radius: 50%;
    box-shadow: 0 8px 24px rgba(37, 211, 102, 0.4);
    z-index: 1000;
    cursor: pointer;
    transition: transform var(--nx-base) var(--nx-ease-out), box-shadow var(--nx-base) var(--nx-ease);
}
.whatsapp-button:hover {
    transform: translateY(-4px) scale(1.06);
    box-shadow: 0 14px 34px rgba(37, 211, 102, 0.5);
    background-color: #1DA851;
}
.whatsapp-button img { width: 30px; height: 30px; }

.back-to-top {
    right: 22px;
    bottom: 92px;              /* clears the WhatsApp button */
    width: 46px;
    height: 46px;
    display: grid !important;
    place-items: center;
    border-radius: 50%;
    background: var(--nx-navy);
    color: #fff;
    box-shadow: var(--nx-shadow-2);
    transition: transform var(--nx-base) var(--nx-ease), background-color var(--nx-base) var(--nx-ease);
}
.back-to-top:hover { background: var(--nx-navy-800); transform: translateY(-3px); }

/* ==========================================================================
   13 · FOOTER
   ========================================================================== */
.footer,
.container-fluid.footer {
    background: var(--nx-navy-900) !important;
    color: rgba(255, 255, 255, 0.72);
}
.footer h1, .footer h2, .footer h3, .footer h4, .footer h5,
.footer .h4, .footer .h5 { color: #fff; }
.footer a { color: rgba(255, 255, 255, 0.72); transition: color var(--nx-fast) var(--nx-ease), padding-left var(--nx-fast) var(--nx-ease); }
.footer a:hover { color: #fff; }
.footer-item a:hover { padding-left: 5px; }
.footer .btn-square,
.footer .btn-sm-square,
.footer .btn-md-square {
    background: rgba(255, 255, 255, 0.1);
    color: #fff;
    border: 1px solid rgba(255, 255, 255, 0.18);
}
.footer .btn-square:hover,
.footer .btn-sm-square:hover,
.footer .btn-md-square:hover { background: var(--nx-red); border-color: var(--nx-red); }
.copyright { background: var(--nx-navy-900); border-top: 1px solid rgba(255, 255, 255, 0.1); }
.copyright, .copyright a { color: rgba(255, 255, 255, 0.6); }

/* ==========================================================================
   14 · HERO
   The old markup used a homegrown slider whose wrapper class was `.carousel` —
   the same name Bootstrap uses for its own component — with slides hard-cut by
   inline `display:none/block` from JS, a fixed 20px caption and a translucent
   grey box behind the text. It is now `.nx-hero`/`.nx-slide`: crossfaded, with
   a slow Ken Burns push on the active slide, a navy scrim for legibility and
   fluid type.
   ========================================================================== */
.nx-hero {
    position: relative;
    overflow: hidden;
    background: var(--nx-navy-900);
    min-height: clamp(460px, 74vh, 820px);
    isolation: isolate;
}

.nx-slide {
    position: absolute;
    inset: 0;
    opacity: 0;
    visibility: hidden;
    transition: opacity 1.1s var(--nx-ease), visibility 0s linear 1.1s;
}
.nx-slide.is-active {
    opacity: 1;
    visibility: visible;
    z-index: 1;
    transition: opacity 1.1s var(--nx-ease), visibility 0s linear 0s;
}

.nx-slide img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center;
    display: block;
}

/* Slow push on whichever slide is showing. */
.nx-slide.is-active img { animation: nx-kenburns 12s var(--nx-ease) both; }
@keyframes nx-kenburns {
    from { transform: scale(1.02); }
    to   { transform: scale(1.12); }
}

/* Navy scrim — a gradient, so the photo stays visible at the top while the
   copy sits on solid contrast at the bottom.

   It has to live on .nx-slide, NOT on .nx-hero: the active slide is
   positioned with a z-index, which makes it its own stacking context, so a
   scrim on the hero would paint above the entire slide — including the copy
   nested inside it — and wash the headline out. Inside the slide, the three
   layers order correctly: image 0, scrim 1, copy 2. */
.nx-slide::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 1;
    pointer-events: none;
    background:
        linear-gradient(to bottom, rgba(6, 24, 49, 0.34) 0%, rgba(6, 24, 49, 0.12) 38%, rgba(6, 24, 49, 0.78) 100%),
        linear-gradient(to right, rgba(6, 24, 49, 0.45), rgba(6, 24, 49, 0) 62%);
}

.nx-slide img { position: relative; z-index: 0; }

.nx-hero-copy {
    position: absolute;
    z-index: 2;
    left: 0;
    right: 0;
    bottom: 0;
    padding: clamp(1.5rem, 5vw, 4.5rem) var(--nx-gutter);
    max-width: 1180px;
    margin: 0 auto;
    text-align: left;
}

.nx-hero-copy h1 {
    color: #fff !important;
    font-size: clamp(1.75rem, 4.6vw, 3.6rem);
    margin: 0 0 0.75rem;
    max-width: 21ch;
    text-shadow: 0 2px 24px rgba(6, 24, 49, 0.5);
}

.nx-hero-copy p {
    color: rgba(255, 255, 255, 0.92);
    font-size: clamp(0.95rem, 1.5vw, 1.1rem);
    max-width: 62ch;
    margin: 0 0 0.65rem;
    text-shadow: 0 1px 12px rgba(6, 24, 49, 0.55);
}
.nx-hero-copy p:last-of-type { margin-bottom: 1.4rem; }

/* Staggered entrance for the copy of the active slide. */
.nx-slide.is-active .nx-hero-copy > * {
    animation: nx-rise 0.9s var(--nx-ease-out) both;
}
.nx-slide.is-active .nx-hero-copy > *:nth-child(1) { animation-delay: 0.15s; }
.nx-slide.is-active .nx-hero-copy > *:nth-child(2) { animation-delay: 0.28s; }
.nx-slide.is-active .nx-hero-copy > *:nth-child(3) { animation-delay: 0.4s; }
.nx-slide.is-active .nx-hero-copy > *:nth-child(4) { animation-delay: 0.52s; }
@keyframes nx-rise {
    from { opacity: 0; transform: translateY(22px); }
    to   { opacity: 1; transform: none; }
}

/* Hero CTA — the markup's `<button class="button">`, which was a raw red box. */
.nx-hero-copy .button,
.nx-hero-copy .nx-cta {
    display: inline-flex;
    align-items: center;
    gap: 0.55rem;
    margin: 0;
    padding: 0.85rem 1.9rem;
    background: var(--nx-red);
    color: #fff;
    border: none;
    border-radius: var(--nx-radius-pill);
    font-family: 'Roboto', sans-serif;
    font-weight: 700;
    font-size: 1rem;
    cursor: pointer;
    box-shadow: 0 10px 30px rgba(224, 27, 27, 0.35);
    transition: transform var(--nx-base) var(--nx-ease),
                background-color var(--nx-base) var(--nx-ease),
                box-shadow var(--nx-base) var(--nx-ease);
}
.nx-hero-copy .button:hover,
.nx-hero-copy .nx-cta:hover {
    background: var(--nx-red-700);
    transform: translateY(-3px);
    box-shadow: 0 16px 40px rgba(224, 27, 27, 0.45);
}

/* Slide dots */
.nx-hero-dots {
    position: absolute;
    z-index: 4;
    bottom: 1.1rem;
    left: 50%;
    transform: translateX(-50%);
    display: flex;
    gap: 0.5rem;
}
.nx-hero-dots button {
    width: 9px;
    height: 9px;
    padding: 0;
    border: none;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.45);
    cursor: pointer;
    transition: width var(--nx-base) var(--nx-ease), background-color var(--nx-base) var(--nx-ease);
}
.nx-hero-dots button.is-active {
    width: 26px;
    border-radius: var(--nx-radius-pill);
    background: var(--nx-red);
}

/* Desktop / mobile art direction, kept from the original markup. */
@media (max-width: 768px) {
    .nx-slide img.desktop, img.desktop { display: none; }
    .nx-slide img.mobile,  img.mobile  { display: block; }
}
@media (min-width: 769px) {
    .nx-slide img.desktop, img.desktop { display: block; }
    .nx-slide img.mobile,  img.mobile  { display: none; }
}

/* ==========================================================================
   15 · ANIMATION LAYER
   Two systems, deliberately:
   (a) The 119 existing `.wow` elements keep working — animate.css is only
       retuned below, because its stock fadeInUp travels 100% of the element
       height, which reads as cheap. 28px is enough.
   (b) `data-nx-reveal` is the new IntersectionObserver layer, used for
       anything WOW does not already cover. It degrades to visible if JS fails.
   ========================================================================== */

/* (a) Retune animate.css */
.animated {
    animation-duration: 0.9s !important;
    animation-timing-function: var(--nx-ease-out) !important;
    animation-fill-mode: both;
}
@keyframes fadeInUp {
    from { opacity: 0; transform: translate3d(0, 28px, 0); }
    to   { opacity: 1; transform: none; }
}
@keyframes fadeInDown {
    from { opacity: 0; transform: translate3d(0, -24px, 0); }
    to   { opacity: 1; transform: none; }
}
@keyframes fadeInLeft {
    from { opacity: 0; transform: translate3d(-30px, 0, 0); }
    to   { opacity: 1; transform: none; }
}
@keyframes fadeInRight {
    from { opacity: 0; transform: translate3d(30px, 0, 0); }
    to   { opacity: 1; transform: none; }
}

/* (b) Reveal layer */
[data-nx-reveal] {
    opacity: 0;
    transform: translateY(24px);
    transition: opacity 0.75s var(--nx-ease-out), transform 0.75s var(--nx-ease-out);
    transition-delay: calc(var(--nx-d, 0) * 90ms);
}
[data-nx-reveal="left"]  { transform: translateX(-28px); }
[data-nx-reveal="right"] { transform: translateX(28px); }
[data-nx-reveal="scale"] { transform: scale(0.94); }
[data-nx-reveal="fade"]  { transform: none; }

[data-nx-reveal].nx-in {
    opacity: 1;
    transform: none;
}

/* If JS never runs, nothing stays hidden. */
.no-js [data-nx-reveal] { opacity: 1; transform: none; }

/* Count-up figures shouldn't jump layout as digits change. */
[data-toggle="counter-up"] { font-variant-numeric: tabular-nums; }

/* ==========================================================================
   16 · PAGE HEADER / BREADCRUMB
   ========================================================================== */
.breadcrumb-item,
.breadcrumb-item a { color: rgba(255, 255, 255, 0.8); }
.breadcrumb-item a:hover { color: #fff; }
.breadcrumb-item.active { color: #fff; }
.breadcrumb-item + .breadcrumb-item::before { color: rgba(255, 255, 255, 0.5); }

/* ==========================================================================
   17 · MISC PAGE PIECES
   ========================================================================== */
/* about.html image blocks — the old rule set these to 50%/50% then 25%/25% on
   mobile, which made them tiny. */
.about-item-image-content { width: 100%; height: auto; }
.about-item-image-content img {
    width: 100%;
    height: auto;
    object-fit: cover;
    border-radius: var(--nx-radius);
}

/* Depot cards sat on the accidental red via bg-light p-4 rounded. */
.bg-light.p-4.rounded {
    background: var(--nx-white) !important;
    border: 1px solid var(--nx-line);
    border-radius: var(--nx-radius) !important;
    box-shadow: var(--nx-shadow-1);
    transition: transform var(--nx-base) var(--nx-ease), box-shadow var(--nx-base) var(--nx-ease);
}
.bg-light.p-4.rounded:hover {
    transform: translateY(-4px);
    box-shadow: var(--nx-shadow-2);
}

/* Owl carousel controls, in brand. */
.owl-carousel .owl-nav button.owl-prev,
.owl-carousel .owl-nav button.owl-next {
    width: 44px;
    height: 44px;
    border-radius: 50%;
    background: var(--nx-white) !important;
    color: var(--nx-navy) !important;
    border: 1px solid var(--nx-line) !important;
    box-shadow: var(--nx-shadow-1);
    transition: background-color var(--nx-base) var(--nx-ease), color var(--nx-base) var(--nx-ease), transform var(--nx-base) var(--nx-ease);
}
.owl-carousel .owl-nav button:hover {
    background: var(--nx-red) !important;
    color: #fff !important;
    transform: translateY(-2px);
}
.owl-dots .owl-dot span { background: var(--nx-line) !important; transition: background-color var(--nx-base) var(--nx-ease), width var(--nx-base) var(--nx-ease); }
.owl-dots .owl-dot.active span { background: var(--nx-red) !important; }

/* Spinner */
#spinner { background: var(--nx-white); }
#spinner .spinner-border { color: var(--nx-navy) !important; }

/* ==========================================================================
   18 · RESPONSIVE
   The original had six media queries in total for the whole site.
   ========================================================================== */

/* Tablet and below */
@media (max-width: 991.98px) {
    .navbar.bg-light,
    .navbar.navbar-dark.bg-light {
        padding: 0.5rem 1rem !important;
    }

    /* Mobile menu panel: a real surface, not links floating on the page. */
    .navbar-collapse {
        background: var(--nx-white);
        border: 1px solid var(--nx-line);
        border-radius: var(--nx-radius);
        box-shadow: var(--nx-shadow-2);
        margin-top: 0.75rem;
        padding: 0.5rem;
        max-height: 78vh;
        overflow-y: auto;
    }

    .navbar .navbar-nav .nav-link,
    .navbar .navbar-nav .nav-item.nav-link {
        padding: 0.85rem 0.9rem !important;   /* ≥44px tap target */
        margin: 0;
        border-radius: var(--nx-radius-sm);
        border-bottom: 1px solid var(--nx-line);
    }
    .navbar .navbar-nav .nav-item:last-child .nav-link { border-bottom: none; }
    .navbar .navbar-nav .nav-link:hover { background: var(--nx-mist); }
    /* An underline that slides is meaningless in a stacked menu. */
    .navbar .navbar-nav .nav-link::after { display: none; }
    .navbar .navbar-nav .nav-link.active {
        background: var(--nx-mist);
        color: var(--nx-navy) !important;
        border-left: 3px solid var(--nx-red);
    }

    .nx-hero { min-height: clamp(420px, 62vh, 560px); }
    .nx-hero-copy { text-align: center; padding-bottom: 3.25rem; }
    .nx-hero-copy h1 { max-width: none; }
    .nx-hero-copy p { max-width: none; margin-left: auto; margin-right: auto; }

    .text-center.mx-auto.pb-5 { padding-bottom: 2rem !important; }
}

/* Phones */
@media (max-width: 575.98px) {
    :root { --nx-section-y: 2.75rem; }

    .nx-hero { min-height: 66vh; }
    .nx-hero-copy p:not(:first-of-type) { display: none; }  /* one line of copy is enough on a phone */

    /* Anything the pages set as a big display size needs a floor on mobile. */
    .display-1, .display-2, .display-3 { font-size: clamp(1.8rem, 8vw, 2.4rem) !important; }

    .btn, .counter-btn { padding: 0.75rem 1.35rem; min-height: 44px; }

    .service-content, .project-content { padding: 1.1rem; }

    /* Vertical 9:16 gallery clips: one per row reads far better than four. */
    .video-thumbnail video { border-radius: var(--nx-radius); }

    .whatsapp-button { width: 52px; height: 52px; bottom: 16px; right: 16px; }
    .whatsapp-button img { width: 26px; height: 26px; }
    .back-to-top { right: 16px; bottom: 80px; width: 42px; height: 42px; }

    /* Long words / URLs in cards must not push the layout sideways. */
    .service-content, .project-content, .footer, .about-item-content { overflow-wrap: anywhere; }
}

/* Wide screens: stop the content from stretching thin. */
@media (min-width: 1400px) {
    .container { max-width: 1240px; }
}

/* ==========================================================================
   19 · MOTION + PRINT PREFERENCES
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.001ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.001ms !important;
        scroll-behavior: auto !important;
    }
    [data-nx-reveal] { opacity: 1 !important; transform: none !important; }
    .nx-slide.is-active img { animation: none; }
    .play-button::before { animation: none; }
}

html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

@media print {
    .navbar, .topbar, .whatsapp-button, .back-to-top, #spinner, .nx-hero-dots { display: none !important; }
    .nx-hero { min-height: auto; }
    [data-nx-reveal] { opacity: 1 !important; transform: none !important; }
}

/* ==========================================================================
   20 · GALLERY  (ported out of gallery.html's inline <style>)
   The original used a flex wrap with `max-width: 400px` per item and a global
   `video { width:100%; height:100% }`. Rebuilt as a real grid so the 9:16
   clips and 16:9 clips can each sit in a sane column, and so one clip per row
   on a phone instead of four cramped ones.
   ========================================================================== */
.gallery-section { margin-bottom: clamp(2.5rem, 5vw, 4rem); }

.gallery-section h2 {
    text-align: center;
    margin-bottom: clamp(1.25rem, 3vw, 2rem);
    color: var(--nx-ink);          /* was #b30909 — yet another red */
}

.gallery-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
    gap: clamp(0.85rem, 1.8vw, 1.4rem);
    justify-content: center;
    align-items: start;
}

.gallery-grid video,
.gallery-grid img {
    width: 100%;
    height: auto;
    max-width: none;
    display: block;
    border-radius: var(--nx-radius);
    background: var(--nx-navy-900);
    box-shadow: var(--nx-shadow-1);
    transition: transform var(--nx-base) var(--nx-ease),
                box-shadow var(--nx-base) var(--nx-ease);
}
.gallery-grid video:hover,
.gallery-grid img:hover {
    transform: translateY(-4px);
    box-shadow: var(--nx-shadow-3);
}

/* Portrait clips (the vt and hori sets) get a narrower cell so they are not
   letterboxed into a wide box. */
.gallery-grid.is-portrait { grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); }

@media (max-width: 575.98px) {
    .gallery-grid { grid-template-columns: 1fr; }
    .gallery-grid.is-portrait { grid-template-columns: repeat(2, 1fr); }
}

/* ==========================================================================
   21 · SMALL HELPERS used by the page markup
   ========================================================================== */
.nx-tagline {
    font-size: 1.05rem;
    color: var(--nx-navy);
    font-weight: 500;
    letter-spacing: 0.01em;
}

/* Eyebrow + emphasis on the dark awards band. The three award cards each had
   a different accent (gold, green, red) with small bold text on near-black
   navy — under 4.5:1 in every case. Unified to a light tint that passes. */
.nx-eyebrow-light {
    font-family: 'Roboto', sans-serif;
    font-size: 0.85rem;
    text-transform: uppercase;
    letter-spacing: 0.16em;
    font-weight: 700;
    color: rgba(255, 255, 255, 0.82);
}

/* The toggler markup is <span class="fa fa-bars">, not Bootstrap's
   .navbar-toggler-icon, so it inherits colour from .navbar-dark — which is
   near-white and would vanish on the new white bar. */
.navbar .navbar-toggler,
.navbar-dark .navbar-toggler,
.navbar .navbar-toggler .fa-bars {
    color: var(--nx-navy) !important;
    font-size: 1.35rem;
    line-height: 1;
}

/* Brand lockup has to share the bar with the toggler on a narrow phone. */
@media (max-width: 575.98px) {
    .navbar-brand img { height: 48px !important; }
    .navbar-brand .ms-3 { margin-left: 0.6rem !important; }
    .stylish-font { font-size: 1.2rem; }
    .nx-tagline { font-size: 0.82rem; }
}

/* ==========================================================================
   22 · --bs-* VARIABLE OVERRIDES
   css/style.css refers to var(--bs-primary) / var(--bs-secondary) /
   var(--bs-light) / var(--bs-dark) in dozens of rules (the topbar background,
   the toggler, nav hovers, footer accents). Those DO follow the custom
   properties, so retargeting them here fixes every one of those rules at
   once. Bootstrap's own compiled bg- and text- utilities do not read these —
   they are baked literals, handled in section 4.
   ========================================================================== */
:root {
    --bs-primary:   #0B2A5B;
    --bs-secondary: #E01B1B;
    --bs-light:     #F5F7FA;
    --bs-dark:      #1A1D21;
    --bs-white:     #FFFFFF;
    --bs-body-color: #4B5563;
}

/* The menu button: style.css gives it var(--bs-secondary) as a background and
   var(--bs-dark) as its colour — dark ink on red, which is unreadable. Made a
   deliberate red brand button with white bars, matching the Join Us CTA. */
.navbar .navbar-toggler,
.navbar-dark .navbar-toggler {
    background: var(--nx-red) !important;
    border: none !important;
    border-radius: var(--nx-radius-sm);
    padding: 0.55rem 0.85rem !important;
    box-shadow: 0 6px 18px rgba(224, 27, 27, 0.3);
}
.navbar .navbar-toggler,
.navbar-dark .navbar-toggler,
.navbar .navbar-toggler .fa-bars,
.navbar .navbar-toggler span {
    color: #fff !important;
}
.navbar .navbar-toggler:focus { box-shadow: 0 0 0 4px rgba(224, 27, 27, 0.3); }

/* Phone hero: the art in these slides is busy through the middle, where the
   bottom-weighted scrim is at its lightest, so the headline lands on low
   contrast. Deepen it when the copy is centred over the image. */
@media (max-width: 767.98px) {
    .nx-slide::after {
        background: linear-gradient(to bottom,
            rgba(6, 24, 49, 0.5) 0%,
            rgba(6, 24, 49, 0.42) 28%,
            rgba(6, 24, 49, 0.88) 100%);
    }
}

/* Phone hero, part two: art direction, not just contrast.
   The mobile slide images (3p.jpeg and friends) already contain the Norlux
   wordmark and a paint-splash through the middle, so overlaying our headline
   on top stacks type on type and reads as clutter however dark the scrim is.
   Below 768px the copy drops onto its own navy panel at the foot of the hero:
   the photograph stays clean above it, and legibility no longer depends on
   what happens to be in the picture. */
@media (max-width: 767.98px) {
    .nx-slide::after {
        background: linear-gradient(to bottom,
            rgba(6, 24, 49, 0.28) 0%,
            rgba(6, 24, 49, 0.10) 30%,
            rgba(6, 24, 49, 0.55) 100%);
    }

    .nx-hero-copy {
        top: auto;
        bottom: 0;
        padding: 3.5rem 1.15rem 3rem;
        background: linear-gradient(to top,
            rgba(6, 24, 49, 0.97) 0%,
            rgba(6, 24, 49, 0.93) 55%,
            rgba(6, 24, 49, 0.55) 82%,
            rgba(6, 24, 49, 0) 100%);
    }

    .nx-hero-copy h1 {
        font-size: clamp(1.5rem, 6.2vw, 2rem);
        margin-bottom: 0.6rem;
        text-shadow: none;          /* the panel does the work now */
    }
    .nx-hero-copy p {
        font-size: 0.95rem;
        line-height: 1.6;
        text-shadow: none;
        margin-bottom: 1rem;
    }
    .nx-hero-copy .button,
    .nx-hero-copy .nx-cta { padding: 0.8rem 1.6rem; }

    .nx-hero-dots { bottom: 0.55rem; }
}

/* ==========================================================================
   23 · CARD INTERNALS
   The service/project cards hold copy of differing length, so their buttons
   landed at different heights across a row and the grid read as ragged. Make
   each card a column and push the action to the foot.
   ========================================================================== */
.service-item,
.project-item,
.feature-item,
.team-item,
.blog-item {
    display: flex;
    flex-direction: column;
}
.service-content,
.project-content {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
}
/* Whichever element ends the card body becomes the anchored action. */
.service-content > .btn:last-child,
.service-content > a.btn,
.project-content > .btn:last-child,
.service-content > p:last-child + .btn { margin-top: auto; }

/* Give the buttons a consistent width so a row of cards lines up. */
.service-content .btn,
.project-content .btn { align-self: center; }

/* A flex child will not shrink below its content's intrinsic width, which is
   what pushed a column 8px past the viewport on two pages. min-width:0 is the
   standard release valve. */
.row > [class*="col-"] { min-width: 0; max-width: 100%; }

/* ==========================================================================
   24 · FIXES FOUND IN TESTING
   ========================================================================== */

/* REGRESSION: section 5 gives .btn `position: relative` so the hover wipe has
   something to anchor to. .back-to-top is also a .btn, and this file loads
   after style.css — where its `position: fixed` lives — so equal specificity
   plus later source order silently demoted it to relative and the floating
   button dropped into the footer flow. Restated here, after .btn. */
.back-to-top {
    position: fixed !important;
    z-index: 99;
}

/* Horizontal reveal offsets are fine on a desktop grid but on a narrow screen
   a ±28px translate on a full-width column pushes the document 28px wider than
   the viewport (measured at 504px). Sideways entrances are the wrong gesture
   on a phone anyway — everything rises instead. */
@media (max-width: 767.98px) {
    [data-nx-reveal="left"],
    [data-nx-reveal="right"] { transform: translateY(22px); }
}

/* ==========================================================================
   25 · CONTACT MAPS
   The two Google Maps iframes carry inline `height: 1000px; aspect-ratio: 9/16`
   — a portrait map two-thirds of a laptop screen tall, twice over. Behind each
   one, style.css paints two 70%x70% offset slabs (::before navy, ::after red)
   as a picture-frame effect, which at that size becomes a wall of flat colour
   rather than a frame. Beating an inline style needs !important.
   ========================================================================== */
.contact .contact-map {
    padding: 0;
    border-radius: var(--nx-radius);
    overflow: hidden;
    border: 1px solid var(--nx-line);
    box-shadow: var(--nx-shadow-2);
    transition: box-shadow var(--nx-base) var(--nx-ease), transform var(--nx-base) var(--nx-ease);
}
.contact .contact-map:hover {
    transform: translateY(-4px);
    box-shadow: var(--nx-shadow-3);
}
.contact .contact-map::before,
.contact .contact-map::after { display: none; }

.contact .contact-map iframe {
    height: clamp(260px, 32vw, 420px) !important;
    aspect-ratio: auto !important;
    width: 100% !important;
    display: block;
    border: 0;
}

/* The three address cards use `border border-secondary`, i.e. a full red
   outline each. Kept as a red top rule instead — the accent survives, the page
   stops looking boxed-in. */
.contact .border.border-secondary {
    border-color: var(--nx-line) !important;
    border-top: 3px solid var(--nx-red) !important;
    border-radius: var(--nx-radius);
    box-shadow: var(--nx-shadow-1);
    transition: transform var(--nx-base) var(--nx-ease), box-shadow var(--nx-base) var(--nx-ease);
}
.contact .border.border-secondary:hover {
    transform: translateY(-4px);
    box-shadow: var(--nx-shadow-2);
}
