/* The homepage stylesheet. Everything the pre-built Tailwind artifact cannot
 *
 * Namespaced under #main-content and .video-header, following the v5 precedent, so
 * the shared header and footer components are untouched by anything here.
 *
 * Plain CSS on purpose. css/styles.min.css is a committed Tailwind artifact from
 * March and tailwind.config.js does not glob .njk, so any utility class invented in
 * a template silently does nothing. Everything novel lives here.
 *
 * THE BRIEF. The hero was "boring text wise". Its largest element was the DJ's name
 * rather than a proposition, and its display font was never loading. The video stays -
 * it is the best thing in the hero and the reason not to add competing imagery.
 */

#main-content,
.video-header {
    --v8-red: #E60000;
    --v8-red-deep: #CC0000;
    --v8-amber: #FF6B35;
    --v8-line: rgba(255, 255, 255, 0.10);
    --v8-mist: rgba(255, 255, 255, 0.62);
    --v8-ease: cubic-bezier(0.16, 1, 0.3, 1);

    /* ----------------------------------------------------------------
       SPACING SCALE

       The hero's gaps were 20 / 14 / 18 / 38 / 40px: three near-identical
       small values then two near-identical large ones. Nothing grouped and
       nothing separated, because a gap only means something relative to its
       neighbours. Five elements at roughly equal separation read as five
       unrelated things, which is what "feels off".

       A 4px-based scale, fluid so one set of decisions holds from 375 to
       1920 without a second set of breakpoint overrides.
       ---------------------------------------------------------------- */
    --v8-density: 1;
    --v8-s1: calc(clamp(0.5rem,  0.9vw, 0.75rem) * var(--v8-density));  /*  8 - 12  hairline */
    --v8-s2: calc(clamp(0.75rem, 1.2vw, 1rem)    * var(--v8-density));  /* 12 - 16  bound together */
    --v8-s3: calc(clamp(1.25rem, 2.2vw, 1.75rem) * var(--v8-density));  /* 20 - 28  supporting */
    --v8-s4: calc(clamp(2rem,    3.4vw, 3rem)    * var(--v8-density));  /* 32 - 48  separate */
    --v8-s5: calc(clamp(2.5rem,  4.4vw, 4rem)    * var(--v8-density));  /* 40 - 64  distinct group */
    --v8-s6: calc(clamp(3rem,    5.5vw, 5rem)    * var(--v8-density));  /* 48 - 80  the big break */
}

/* One knob, not a second set of spacing decisions. The rhythm - the RATIOS
   between the intervals - is what does the grouping, so a phone should
   compress it uniformly rather than re-litigate each gap. */
@media (max-width: 640px) {
    #main-content,
    .video-header { --v8-density: 0.74; }
}

/* ====================================================================
   HERO RHYTHM

   The cadence, top to bottom, and why each interval is what it is:

     logo      -> eyebrow    s4   two separate identities, so: air
     eyebrow   -> headline   s2   the eyebrow LABELS the headline; they are
                                  one unit and must read as one
     headline  -> lede       s3   the lede supports the headline; closer than
                                  a new group, looser than a label
     lede      -> buttons    s5   a new group: this is the ask
     buttons   -> stats      s6   a different kind of thing entirely: proof

   Generous, tight, medium, generous, widest. Contrast between the intervals
   is what does the grouping - not the absolute values.
   ==================================================================== */

/* ====================================================================
   HERO
   ==================================================================== */

/* NAV CLEARANCE - the reason the logo was cut in half.
 *
 * .video-content centres its stack inside min-height:100vh, but the top of that
 * 100vh sits UNDERNEATH the fixed header, which base.njk deliberately excludes
 * from its usual first-child offset. The old hero never noticed because its
 * stack was short enough to stay clear. This one is taller, so centring pushed
 * the logo up behind the nav, where overflow:hidden cut it off.
 *
 * Padding equal to the nav height makes the stack centre in the VISIBLE band
 * instead of the whole viewport. The fallback below is the measured height of
 * the real header (py-4 + an h-16 logo + a 1px border); the script at the foot
 * of the page then measures the live nav and corrects it exactly, so a future
 * header change cannot silently swallow the logo again. */
.video-header .video-content {
    padding-top: var(--v8-nav, 97px);
}

/* THE HERO MUST NOT BE ABLE TO CLIP. At any size. Ever.
 *
 * The incumbent hero is `height: 100vh` with `overflow: hidden` - a box of fixed
 * height that hides whatever does not fit. That is survivable only while the
 * content is short enough, at every viewport, forever. It is not: the stack's
 * height depends on how many lines the headline and the eyebrow wrap to, which
 * depends on the width, so every width-by-height combination is its own case.
 * Chasing them with breakpoints is a losing game - there is always one more
 * screen, and the failure is silent, because clipped content leaves no scrollbar
 * and no sign that anything is missing.
 *
 * So the box grows instead of hiding:
 *
 *   height: auto + min-height  the hero is AT LEAST a screen and as tall as it
 *                              needs to be. overflow:hidden then has nothing to
 *                              clip, whatever the content does.
 *   100svh                     the SMALL viewport height: the space actually on
 *                              screen with the mobile browser's chrome showing.
 *                              100vh measures as if that chrome were not there,
 *                              so it promises more room than exists.
 *   safe center                centring overflows in BOTH directions, and the
 *                              top overflow is the one behind the nav. `safe`
 *                              falls back to flex-start the moment content is
 *                              too tall, so the top can never be pushed out of
 *                              reach. Ignored by browsers that lack it, which
 *                              simply get the old behaviour.
 *
 * The result degrades in one direction only: on a small or short screen the hero
 * becomes slightly taller than the viewport and the page scrolls, which a
 * visitor can see and act on. It never removes anything. */
.video-header {
    height: auto;
    min-height: 100svh;
}
.video-header .video-content {
    min-height: 100svh;
    justify-content: safe center;
    padding-bottom: clamp(1.5rem, 3vh, 3rem);
}

/* Short and wide - a laptop in landscape, a half-height window, a projector.
   The stack is compressed rather than allowed to grow the page. */
@media (max-height: 800px) and (min-width: 641px) {
    #main-content,
    .video-header { --v8-density: 0.7; }
    /* Short viewports lift too, for the same reason: a 1366x768 laptop was
       getting 51px. Still smaller than the full-height scale, because height
       is the constraint here rather than width. */
    .video-content .v8-headline { font-size: clamp(1.9rem, 4.6vw, 3.5rem); }
}
@media (max-height: 620px) {
    #main-content,
    .video-header { --v8-density: 0.55; }
}

/* A long eyebrow cannot fit one line on a phone at any readable size: 56
   characters of tracked caps needs about 440px and a 375px screen offers 327.
   So it wraps there, and the wrap is made to look deliberate.
   
   The max-width is MOBILE ONLY. Applying it at every width was a bug: 26rem is
   far narrower than a desktop hero, so the line broke mid-phrase at
   "KZN MIDLANDS / & DURBAN" on a 1440px screen. */
.video-content .v8-eyebrow {
    line-height: 1.7;
    text-wrap: balance;
}
@media (max-width: 640px) {
    .video-content .v8-eyebrow { max-width: 22rem; margin-inline: auto; }
}

/* A pool of shadow under the copy only, rather than dimming the whole frame.
   The page-level .video-overlay already carries a top-to-bottom scrim; this adds
   depth exactly where the words are, so a bright frame of the video cannot wash
   the headline out while the footage keeps its brightness everywhere else. */
.video-header .video-content::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    pointer-events: none;
    background: radial-gradient(58% 46% at 50% 48%,
        rgba(0, 0, 0, 0.78) 0%,
        rgba(0, 0, 0, 0.45) 46%,
        transparent 78%);
}

.video-content .v8-eyebrow {
    /* Quieter than it was. At 0.24em tracking this line ran almost the full
       width of the headline and read as a second headline rather than as a
       label on the first. */
    font-size: 0.7rem;
    font-weight: 600;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--v8-mist);
    /* Bound to the headline it labels. */
    margin: 0 0 var(--v8-s2);
    text-shadow: 0 2px 10px rgba(0, 0, 0, 0.9);
}
@media (min-width: 768px) {
    .video-content .v8-eyebrow { font-size: 0.78rem; letter-spacing: 0.19em; }
}

/* The headline. Scaled for a 34-character line: the reference this borrows from
   ran to 7.4rem, but it was carrying three or four words. At that size this copy
   would break to four lines on a laptop and swamp the CTAs.

   line-height below 1 and negative tracking are doing as much work as the size -
   they are what makes a big heading read as designed rather than merely large. */
.video-content .v8-headline {
    /* 6vw, not 5.2vw, and a 5.5rem ceiling rather than 4.2rem.
     *
     * At 5.2vw/4.2rem the headline hit its ceiling at about 1290px wide and then
     * never grew again - a 1440px laptop and a 2560px desktop got the identical
     * 67px, which on a high-resolution laptop is a small headline in a lot of
     * space. Raising only the ceiling would have changed nothing there, because
     * the vw term was the binding constraint, not the cap. Both had to move.
     *
     * 4.5rem: a little above the 4.2rem it started at, well below the 5.5rem
     * that read as shouting. 72px from a MacBook upward.
     *
     * The size was tuned three times in isolation before the real problem showed
     * itself, which was never the headline's absolute size. The hero's type scale
     * ran 12 / 14 / 18 / 30 and then jumped 2.6x straight to 77px. Nothing sat
     * between the stats and the headline, so the hero read as one enormous thing
     * and a scattering of small ones - and every increase made that worse. The
     * lede was raised at the same time as this came down, which closes the gap
     * from both ends.
     *
     * The vw term stays at 6. That part was right and is independent of the size:
     * at 5.2vw the headline hit its ceiling near 1290px, so a 1440 laptop and a
     * 2560 desktop got an identical size.
     *
     * The upper bound on all this is wrapping: the two white lines are 12.4em and
     * 14.9em, and if either exceeds the viewport the authored three-line shape
     * breaks. Checked from iPad portrait upward - none wrap, and the hero still
     * fits one screen everywhere. */
    font-size: clamp(2.1rem, 6vw, 4.5rem);
    font-weight: 800;
    letter-spacing: -0.03em;
    line-height: 0.98;
    text-transform: uppercase;
    /* balance would re-break lines that are now authored. */
    text-wrap: normal;
    color: #fff;
    /* Three lines, not two.
     *
     * Measured in em rather than ch on purpose. ch is the width of a "0", and
     * this line is bold uppercase, whose caps run roughly a fifth wider - so a
     * ch value means something different at every size and had to be guessed
     * twice already. An em measure is relative to the headline's OWN font-size,
     * so the characters-per-line stays constant from 375px to 2560px and the
     * line breaks in the same place everywhere.
     *
     * The three lines are now AUTHORED rather than wrapped:
     *
     *     A PACKED DANCE FLOOR
     *     ALL NIGHT            <- own line, in the accent red
     *     DOESN'T HAPPEN BY CHANCE
     *
     * "all night" is the whole claim - anyone fills a floor for one song - so it
     * gets its own line and the only colour in the headline. That also removes the
     * break the wrapper kept producing, "ALL NIGHT DOESN'T", which split a verb
     * phrase across lines because three balanced lines out of this sentence had to
     * break somewhere awkward.
     *
     * The measure now only has to stop the two white lines wrapping on their own.
     * "DOESN'T HAPPEN BY CHANCE" is 24 characters, about 14.9em at this weight, so
     * 15.2em is the floor. Below it that line breaks and the authored shape is
     * lost. text-wrap: balance is off for the same reason: the breaks are chosen
     * here, not computed.
     *
     * It was 11.5em while this read "dancefloor" as one word. Splitting it adds
     * a character AND a new break opportunity, and at 11.5em the first line had
     * almost nothing to spare - a hair wider and it would have broken to
     * "A FULL DANCE / FLOOR DOESN'T HAPPEN", splitting the noun in half. The
     * whole line is still 43 characters, so three lines remains the minimum and
     * the break does not collapse back to two.
     *
     * On a phone the viewport is narrower than 11.5em at that font-size, so the
     * screen constrains it instead and nothing changes there. */
    max-width: 15.2em;
    margin: 0 auto var(--v8-s3);
    text-shadow: 0 6px 30px rgba(0, 0, 0, 0.75), 0 2px 8px rgba(0, 0, 0, 0.6);
}

.video-content .v8-lede {
    margin: 0 auto;
    /* 52ch, not 44ch: the line grew from 118 characters to 137 and at the old
       measure it broke into four short centred lines. Three sits better under a
       two-line headline. */
    max-width: 52ch;
    /* Raised from a 1.14rem ceiling. This is the step the hero did not have:
       the scale ran 12 / 14 / 18 / 30 and then leapt to the headline. At 20px
       the lede has enough presence to be the middle of the composition rather
       than another small thing, which matters more now it carries his name. */
    font-size: clamp(1.02rem, 1.6vw, 1.25rem);
    font-weight: 400;
    line-height: 1.55;
    color: rgba(255, 255, 255, 0.88);
    text-wrap: pretty;
    text-shadow: 0 2px 12px rgba(0, 0, 0, 0.85);
}


/* "all night" on its own line, and the only colour in the headline. White,
   red, white: the eye lands on the claim that actually separates him, and the
   line break is chosen rather than wherever the text happened to run out.
   Brighter than the brand #E60000, which goes muddy at this size over a dark
   moving video. */
.video-content .v8-hl-accent {
    display: block;
    color: #FF5A3C;
}

/* ====================================================================
   THE CALL TO ACTION
   The buttons were fine on the old hero. Against an uppercase, weight-800
   headline they read as a different design: sentence case, quiet, and sat
   straight under the lede with nothing separating them.

   Three fixes, all specificity-raised with .video-content so they beat the
   page's own .hero-btn rules regardless of stylesheet order.
   ==================================================================== */

/* A new group: this is the ask. */
.video-content .v8-cta { margin-top: var(--v8-s5); }


.video-content .hero-btn {
    min-height: 60px;
    padding: 0 2.4rem;
    /* Uppercase with tracking, to answer the headline. Sentence-case buttons
       under an uppercase headline look like two designers had a go. */
    font-size: 0.86rem;
    font-weight: 800;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    gap: 0.65em;
    transition: background-color 0.25s var(--v8-ease),
                border-color 0.25s var(--v8-ease),
                box-shadow 0.25s var(--v8-ease),
                transform 0.25s var(--v8-ease);
}
@media (min-width: 768px) { .video-content .hero-btn { min-height: 64px; padding: 0 2.8rem; } }

/* The arrow is the affordance: it says "this goes somewhere" before you read
   the label, and it moves on hover so the button feels answerable. */
.video-content .v8-arw {
    display: inline-block;
    transition: transform 0.3s var(--v8-ease);
}
.video-content .hero-btn:hover .v8-arw { transform: translateX(5px); }

/* Primary: a stronger pool of red under it, and a real lift. The old shadow was
   there but too tight to register against a dark, busy video frame. */
.video-content .hero-btn-primary {
    background-color: var(--v8-red);
    box-shadow: 0 14px 40px -12px rgba(230, 0, 0, 0.85),
                0 1px 0 rgba(255, 255, 255, 0.18) inset;
}
.video-content .hero-btn-primary:hover {
    background-color: #F41010;
    transform: translateY(-2px);
    box-shadow: 0 20px 52px -12px rgba(230, 0, 0, 0.95),
                0 1px 0 rgba(255, 255, 255, 0.22) inset;
}
.video-content .hero-btn-primary:active { transform: translateY(0); }

/* Ghost: the old border at 0.38 alpha nearly vanished over bright video. Brighter
   edge, and a faint dark fill so it holds its shape whatever is playing behind. */
.video-content .hero-btn-ghost {
    border: 1.5px solid rgba(255, 255, 255, 0.55);
    background-color: rgba(0, 0, 0, 0.28);
    backdrop-filter: blur(2px);
}
.video-content .hero-btn-ghost:hover {
    border-color: #fff;
    background-color: rgba(255, 255, 255, 0.14);
    transform: translateY(-2px);
}

@media (prefers-reduced-motion: reduce) {
    .video-content .hero-btn,
    .video-content .hero-btn:hover,
    .video-content .v8-arw { transform: none; transition: none; }
}

/* The hero now carries more copy than it did. Tighten the stats so the whole
   thing still lands on one screen, which is the thing most likely to break. */
/* The scale is fluid, so the phone needs no spacing overrides at all - only the
   two things that are about size rather than rhythm. */
@media (max-width: 640px) {
    .video-content .v8-lede { font-size: 0.95rem; line-height: 1.5; }
    .video-content .hero-btn { min-height: 54px; font-size: 0.8rem; }
}

/* ====================================================================
   VENUE MARQUEE
   Sits between the video and the intro, so it reads as the join between them:
   a thin bordered strip rather than another padded section.
   ==================================================================== */
#main-content .v8-marq {
    border-top: 1px solid var(--v8-line);
    border-bottom: 1px solid var(--v8-line);
    background: #0F0F0F;
    padding: 1rem 0;
    overflow: hidden;

    /* Fade both ends instead of clipping names mid-letter. */
    --v8-mask: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
    -webkit-mask-image: var(--v8-mask);
    mask-image: var(--v8-mask);
}

/* width: max-content is load-bearing. The track holds the full list TWICE, so at
   translateX(-50%) the second copy sits exactly where the first began and the loop
   has no seam. Any width that wraps the flex line breaks that alignment. */
#main-content .v8-marq-track {
    display: flex;
    align-items: center;
    width: max-content;
    /* 18 venues, not 62, so the loop is retuned: the old 90s was pitched for a
       list three times this long and would crawl. */
    animation: v8Slide 42s linear infinite;
}
#main-content .v8-marq-track > span { display: flex; align-items: center; }
/* No pause on hover. It was there so a name could be read and clicked; with
   nothing to click, stopping under the cursor is just the strip reacting to
   something the visitor did not mean. */

@keyframes v8Slide { to { transform: translateX(-50%); } }

/* Nothing here is interactive, so nothing behaves as though it is: no hover,
   no focus ring, no pointer. A hover state on plain text is a promise the strip
   cannot keep. */
#main-content .v8-venue {
    font-family: 'Schibsted Grotesk', 'Figtree', sans-serif;
    font-size: 0.88rem;
    font-weight: 700;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    white-space: nowrap;
    color: #8C8C8C;
}
@media (min-width: 768px) { #main-content .v8-venue { font-size: 1.02rem; } }

#main-content .v8-venue-sep {
    color: var(--v8-red);
    font-size: 0.6rem;
    padding-inline: 1.25rem;
    flex: none;
}
@media (min-width: 768px) { #main-content .v8-venue-sep { padding-inline: 1.6rem; } }

/* Decoration over a list that reads perfectly well standing still. */
@media (prefers-reduced-motion: reduce) {
    #main-content .v8-marq-track { animation: none; }
    #main-content .v8-marq {
        overflow-x: auto;
        -webkit-mask-image: none;
        mask-image: none;
    }
}


/* ====================================================================
   THE PAGE BELOW THE HERO

   Three things, all the same lesson the hero taught: a value repeated
   everywhere creates no hierarchy, and a value chosen ad hoc creates no
   system.
   ==================================================================== */

/* ---- 1. Solid headings ---------------------------------------------
   Eight headings were filled with a warm gradient. Emphasis reads stronger
   from weight and size than from a gradient fill, and next to a hero that is
   now solid and confident the gradient ones looked like a different, older
   page. The accent word keeps its colour - it is just a colour now, not a
   fade - so the emphasis survives and the mechanism gets simpler.

   Specificity raised past the page's own .gradient-warm-text, which sets
   -webkit-text-fill-color and would otherwise keep the text transparent. */
#main-content .gradient-warm-text {
    background: none;
    -webkit-background-clip: border-box;
    background-clip: border-box;
    -webkit-text-fill-color: currentColor;
    color: #FF5A3C;
}

/* ---- 2. One container ----------------------------------------------
   The page used seven different max-widths: 1800, 1200, 1024, 1000, 768, 767
   and 640px. So the left edge of the content moved as you scrolled, with
   nothing to explain why. One measure for everything that is prose or a
   heading; the wide grids keep their own room because they genuinely need it. */
#main-content .v8-wrap {
    max-width: var(--v8-measure, 1200px);
}
/* The two grids that genuinely need the room keep it: five venue cards and a
   three-across review grid both collapse into something cramped at 1200. */
#main-content #venues .v8-wrap,
#main-content #testimonials .v8-wrap {
    --v8-measure: 1500px;
}

/* ---- 3. A section rhythm -------------------------------------------
   Padding was py-20 five times over, plus a py-16, a py-28 and a
   pt-20 pb-28. One value repeated means no section is more important than any
   other, and the odd ones read as mistakes rather than emphasis.

   Now: a standard interval, a tighter one where a section is a companion to
   the one above it, and a wider one where the page should breathe before it
   asks for something. */
/* :not(.v8-marq) is load-bearing. The marquee is a section too, and it is the
   FIRST one, so without this the strip inherits a 6rem section interval and
   stops being a thin join between the video and the page. An id selector beats
   its own .v8-marq padding, so excluding it is the only way. */
#main-content > section:not(.v8-marq) {
    padding-top: var(--v8-sec, clamp(3.5rem, 7vw, 6rem));
    padding-bottom: var(--v8-sec, clamp(3.5rem, 7vw, 6rem));
}

/* The icon grid is a companion to the bio above it, not a new argument, so it
   sits closer and loses the full interval.

   Named, not counted. This was nth-of-type(2), which landed on #about instead,
   because the marquee is itself a section and shifted every index by one. A
   class says which section is meant; a number says which position, and
   positions move. */
#main-content > section.v8-companion { --v8-sec: clamp(2.25rem, 4.5vw, 3.5rem); }

/* The closing ask gets air before it, because it is the one moment on the page
   that changes what the visitor is being asked to do. */
#main-content > section:last-of-type { --v8-sec: clamp(4.5rem, 9vw, 8rem); }


/* ====================================================================
   THE CLOSING CTA
   Same treatment as the header button, because it is the same action.
   ==================================================================== */

/* It was bg-gray-900 sitting on a bg-gray-800 section: a dark button on a dark
   ground, which is barely a button at all. As the only thing left on the
   closing ask - the Call Now button beside it has gone - it has to carry, so it
   matches the header: white at rest, red wiping in from the left on hover.

   hover:scale-105 went with the old classes. Growing on hover and filling on
   hover are two answers to the same gesture, and the fill is the better one. */
#main-content .v8-wipe {
    position: relative;
    isolation: isolate;
    overflow: hidden;
    display: inline-block;
    background: #fff;
    color: #111827;
    text-decoration: none;
    box-shadow: 0 12px 30px -14px rgba(0, 0, 0, 0.7);
    transition: color 0.32s var(--v8-ease), box-shadow 0.32s var(--v8-ease);
}
#main-content .v8-wipe::before {
    content: "";
    position: absolute;
    inset: 0;
    background: var(--v8-red);
    transform: scaleX(0);
    transform-origin: left center;
    transition: transform 0.32s var(--v8-ease);
    z-index: -1;
}
#main-content .v8-wipe:hover::before,
#main-content .v8-wipe:focus-visible::before { transform: scaleX(1); }
#main-content .v8-wipe:hover,
#main-content .v8-wipe:focus-visible {
    color: #fff;
    box-shadow: 0 16px 38px -14px rgba(230, 0, 0, 0.8);
}
#main-content .v8-wipe:focus-visible {
    outline: 3px solid rgba(255, 107, 53, 0.75);
    outline-offset: 3px;
}
/* The wipe IS the feedback, so with motion reduced it becomes an instant fill
   rather than no response at all. */
@media (prefers-reduced-motion: reduce) {
    #main-content .v8-wipe::before { transition: none; }
}


/* ====================================================================
   MOBILE: SECTION HEADINGS CENTRE
   Most of the page's h2s are already centred by a wrapping .text-center.
   The one in #about is not, because on desktop it sits beside a float-right
   portrait and left alignment is correct there. On a phone that float
   collapses, the heading is left-aligned against nothing, and it reads as
   the odd one out among five centred siblings.

   Scoped to #main-content so the footer's own headings, which are correctly
   left-aligned in their columns, are untouched. h2 only: the card and
   feature h3s sit inside centred or left-aligned blocks that are already
   deliberate.
   ==================================================================== */
@media (max-width: 767px) {
    #main-content h2 { text-align: center; }
    /* The paragraph directly under a centred heading follows it, or the
       heading looks detached from its own copy. */
    #main-content h2 + p { text-align: center; }
}
