/* =====================================================================
   DJ MISHOO — design system
   Pure black, red accent, and short (.15-.3s) transitions rather than
   long showy ones. Display type is a geometric grotesque over a rounded
   geometric body face.
   ===================================================================== */

/* Colour is fully tokenised so the light theme is a token swap rather
   than a second stylesheet. Dark is the default and lives on bare :root,
   so a page that never runs the theme script still renders correctly.
   Anything that was a raw rgba(0,0,0)/rgba(255,255,255) literal is now a
   token, otherwise it would stay dark-shaped when the theme flips. */
:root{
  /* Tells the browser which way round the UI is, so it draws its own
     controls to match: the date picker's calendar glyph, number spinners,
     scrollbars and the picker popup itself. Without this the calendar
     icon is painted dark and vanishes against a dark field. It is a
     browser-drawn glyph in shadow DOM, so this is the supported lever
     rather than trying to restyle it. */
  color-scheme: dark;

  /* colour */
  --bg:        #000000;
  --bg-1:      #07070A;   /* raised surface */
  --bg-2:      #0E1014;   /* card           */
  --bg-3:      #16181E;   /* input / hover  */
  --ink:       #FFFFFF;
  /* Body copy was sitting at .66, which reads grey against pure black.
     Lifted so paragraphs are closer to the headings without going flat
     white, which would remove the hierarchy between the two. */
  --ink-2:     rgba(255,255,255,.84);
  --ink-3:     rgba(255,255,255,.56);
  --red:       #DC2626;   /* primary accent */
  --red-hot:   #FF2E3E;   /* hover / glow   */
  --line:      rgba(255,255,255,.10);
  --line-2:    rgba(255,255,255,.055);
  --line-3:    rgba(255,255,255,.14);  /* dashed empty states */

  /* surfaces that were hardcoded black */
  --header-bg:      rgba(0,0,0,.5);
  --header-bg-solid:rgba(0,0,0,.93);
  --footer-bg:      rgba(0,0,0,.72);
  --scrim:          rgba(0,0,0,.95);   /* lightbox backdrop */
  --vignette:       rgba(0,0,0,.8);    /* body::after over the canvas */
  --shadow:         rgba(0,0,0,.9);
  --shadow-deep:    rgba(0,0,0,.95);
  --media-shade:    rgba(0,0,0,.75);   /* gradient over thumbnails */

  /* text that sits on the red fill stays white in both themes */
  --on-red:  #fff;
  --sheen:   rgba(255,255,255,.28);    /* button hover sweep */
  --ripple:  rgba(255,255,255,.6);     /* button press ripple */
  --canvas-opacity: .9;

  /* Form controls own their surface rather than borrowing --bg-1. The
     form sits on a .card, so the field has to contrast with the CARD,
     not with the page, and those are different colours per theme. */
  --field-bg:     var(--bg-1);
  --field-border: var(--line);
  --field-hover:  var(--bg-3);
  --label-ink:    var(--ink-3);

  /* type
     Space Grotesk for display — geometric with just enough irregularity
     to feel designed rather than default. Kept at 500–700 on purpose:
     its heavier weights go blobby fast, and the wide letterforms already
     carry enough presence without extra thickness. */
  --display: "Space Grotesk", "Helvetica Neue", Arial, sans-serif;
  --sans:    "Outfit", system-ui, -apple-system, Segoe UI, Roboto, sans-serif;

  /* system */
  --radius:   14px;
  --radius-s: 10px;
  --maxw:     1240px;
  --header-h: 76px;
  --ease:     cubic-bezier(.22,.61,.36,1);
  --glow:     0 0 42px -8px rgba(220,38,38,.65);
}

/* =====================================================================
   LIGHT THEME
   Set by the inline script in each <head> (before first paint, so the
   page never flashes black) and toggled by the header button.

   The page sits on a near-white rather than pure white so that cards,
   which stay pure white, still read as raised without needing a heavier
   border. Red is nudged a shade darker here: #DC2626 on white is under
   4.5:1, which the small uppercase eyebrow text would fail.
   ===================================================================== */
:root[data-theme="light"]{
  color-scheme: light;

  /* Warm-neutral greys rather than white. The page is the darkest of the
     three surfaces and the card sits a step above it, so cards still read
     as raised without needing a heavier border. Nothing here is #FFFFFF:
     a pure white page glares, and it left the cards with nowhere lighter
     to go, which is what flattened the contact form earlier. */
  --bg:        #E7E9EF;   /* page            */
  --bg-1:      #F1F3F7;   /* raised surface  */
  --bg-2:      #F3F5F8;   /* card            */
  --bg-3:      #D9DDE5;   /* input / hover   */
  --ink:       #0B0C0F;
  --ink-2:     rgba(11,12,15,.72);
  --ink-3:     rgba(11,12,15,.50);
  --red:       #C01B1B;
  --red-hot:   #D82222;
  --line:      rgba(11,12,15,.18);
  --line-2:    rgba(11,12,15,.11);
  --line-3:    rgba(11,12,15,.22);

  --header-bg:      rgba(238,240,245,.70);
  --header-bg-solid:rgba(233,235,241,.95);
  --footer-bg:      rgba(216,220,229,.85);
  --scrim:          rgba(231,233,239,.96);
  --vignette:       rgba(11,12,15,.07);
  --shadow:         rgba(11,12,15,.22);
  --shadow-deep:    rgba(11,12,15,.32);
  --media-shade:    rgba(0,0,0,.55);

  --sheen:   rgba(255,255,255,.55);
  --ripple:  rgba(255,255,255,.75);
  /* the canvas inverts to a pale wash, so it lifts the page back up;
     pulled down to keep the darker ground from being washed out */
  --canvas-opacity: .24;
  --glow:    0 0 42px -10px rgba(192,27,27,.40);

  /* The form sits on a card, so the field has to contrast with the CARD
     rather than the page. Stepped down from it, with a border and label
     dark enough to give the form an edge. */
  --field-bg:     #DCE0E9;
  --field-border: rgba(11,12,15,.26);
  --field-hover:  #CFD5E0;
  --label-ink:    rgba(11,12,15,.68);
}

*{ box-sizing:border-box; margin:0; padding:0; }
html{ scroll-behavior:smooth; scroll-padding-top:calc(var(--header-h) + 20px); -webkit-text-size-adjust:100%; }
body{
  font-family:var(--sans); font-size:16px; line-height:1.65;
  color:var(--ink); background:var(--bg);
  overflow-x:hidden; -webkit-font-smoothing:antialiased;
}
img{ display:block; max-width:100%; }
a{ color:inherit; text-decoration:none; }
button,input,textarea,select{ font:inherit; color:inherit; }
button{ background:none; border:none; cursor:pointer; }
ul{ list-style:none; }
:focus-visible{ outline:2px solid var(--red-hot); outline-offset:3px; border-radius:4px; }
::selection{ background:var(--red); color:var(--on-red); }

.wrap{ width:100%; max-width:var(--maxw); margin-inline:auto; padding-inline:clamp(18px,4vw,44px); }
.center{ text-align:center; }
.hide{ display:none !important; }

/* ---------- type ---------- */
.eyebrow{
  font-size:.72rem; font-weight:600; letter-spacing:.28em;
  text-transform:uppercase; color:var(--red);
  display:flex; align-items:center; gap:.7rem; margin-bottom:1.1rem;
}
.eyebrow::before{ content:""; width:24px; height:2px; background:var(--red); }
.eyebrow.center{ justify-content:center; }
.eyebrow.center::after{ content:""; width:24px; height:2px; background:var(--red); }

h1{ font-family:var(--display); font-weight:700; text-transform:uppercase;
    font-size:clamp(2.2rem,5.8vw,4.6rem); line-height:1.02; letter-spacing:-.035em; }
h2{ font-family:var(--display); font-weight:600; text-transform:uppercase;
    font-size:clamp(1.65rem,3.6vw,2.7rem); line-height:1.08; letter-spacing:-.028em; }
h3{ font-family:var(--display); font-weight:600; text-transform:uppercase;
    font-size:1.14rem; line-height:1.2; letter-spacing:-.015em; }
.accent{ color:var(--red); }
.lead{ font-size:clamp(1rem,1.6vw,1.14rem); color:var(--ink-2); max-width:62ch; }
p{ color:var(--ink-2); }

section{ padding:clamp(60px,9vw,124px) 0; position:relative; }
.sec-head{ margin-bottom:clamp(2rem,4vw,3.2rem); }
.sec-head p{ margin-top:.8rem; max-width:60ch; }

/* ---------- buttons ---------- */
/* =====================================================================
   BUTTONS — they behave like speaker cones.

   HOVER  a signal sweeps across the face, left to right, and the button
          lifts. The sweep is a background layer rather than a pseudo
          element, so it can never sit on top of the label.
   PRESS  the cone punches: it compresses, springs past its size, then
          settles, while a ripple leaves the exact point pressed and a
          ring of pressure expands outward past the edge.

   The ripple lives on ::before at z-index -1. Painting order puts that
   above the button's own background but below its text, so the label
   stays legible without wrapping it in an extra element. isolate keeps
   the negative layer from escaping behind the section.
   ===================================================================== */
.btn{
  position:relative; isolation:isolate; overflow:hidden;
  display:inline-flex; align-items:center; justify-content:center; gap:.55rem;
  font-weight:600; font-size:.92rem; padding:.9rem 1.7rem; border-radius:999px;
  --bx:50%; --by:50%;                       /* press point, set by app.js */
  background-image:linear-gradient(105deg,
    transparent 38%, var(--sheen) 50%, transparent 62%);
  background-size:250% 100%;
  background-position:170% 0;
  background-repeat:no-repeat;
  transition:background-color .18s, color .18s, box-shadow .18s,
             transform .22s var(--ease), background-position .6s var(--ease);
}
.btn:hover{ background-position:-60% 0; }

.btn::before{
  content:""; position:absolute; z-index:-1;
  left:var(--bx); top:var(--by); width:0; height:0;
  transform:translate(-50%,-50%); border-radius:50%;
  background:radial-gradient(circle, var(--ripple), transparent 68%);
  opacity:0;
}
.btn.is-hit::before{ animation:conePush .6s var(--ease) forwards; }
@keyframes conePush{
  0%   { width:0;    height:0;    opacity:.9; }
  100% { width:320%; height:320%; opacity:0;  }
}

/* compress, overshoot, settle. box-shadow is not clipped by overflow,
   so the pressure ring can travel outside the button. */
.btn.is-hit{ animation:coneKick .44s var(--ease), coneRing .62s ease-out; }
@keyframes coneKick{
  0%   { transform:scale(.93); }
  42%  { transform:scale(1.05) translateY(-3px); }
  70%  { transform:scale(.99); }
  100% { transform:none; }
}
@keyframes coneRing{
  0%   { box-shadow:0 0 0 0    rgba(220,38,38,.55); }
  100% { box-shadow:0 0 0 24px rgba(220,38,38,0);   }
}

.btn:active{ transform:scale(.95); transition-duration:.08s; }
.btn[aria-disabled="true"]{ background-image:none; }
.btn[aria-disabled="true"]:hover{ transform:none; }

.btn-primary{ background-color:var(--red); color:var(--on-red); }
.btn-primary:hover{ background-color:var(--red-hot); box-shadow:var(--glow); transform:translateY(-2px); }
.btn-ghost{ color:var(--ink); box-shadow:inset 0 0 0 1.4px var(--line); }
.btn-ghost:hover{ box-shadow:inset 0 0 0 1.4px var(--red); color:var(--red); transform:translateY(-2px); }
.btn-block{ width:100%; }
.ic{ width:19px; height:19px; fill:none; stroke:currentColor; stroke-width:1.7; stroke-linecap:round; stroke-linejoin:round; }

/* =====================================================================
   WEBGL BACKGROUND (js/gl.js) — fixed behind all content
   ===================================================================== */
#gl{ position:fixed; inset:0; width:100%; height:100%; z-index:0; pointer-events:none; display:block; opacity:var(--canvas-opacity); }
/* The shader draws additive glow onto an opaque black frame, so on a light
   page it would sit there as a black slab. Inverting flips the frame to
   white and the glow to its complement; the hue-rotate puts the hue back
   where it started, so the light theme keeps the same red wash instead of
   turning cyan. Cheaper and steadier than recompiling the shader. */
:root[data-theme="light"] #gl{ filter:invert(1) hue-rotate(180deg); }
#page, .site-header, .site-footer, .mobile-nav{ position:relative; z-index:1; }
/* vignette keeps the black rich and the copy readable over the canvas */
body::after{
  content:""; position:fixed; inset:0; z-index:0; pointer-events:none;
  background:radial-gradient(125% 95% at 50% 0%, transparent 38%, var(--vignette));
}

/* =====================================================================
   HEADER
   ===================================================================== */
.site-header{
  position:fixed; inset:0 0 auto 0; z-index:60; height:var(--header-h);
  background:var(--header-bg); backdrop-filter:blur(14px);
  border-bottom:1px solid transparent; transition:background .2s, border-color .2s;
}
.site-header.scrolled{ background:var(--header-bg-solid); border-color:var(--line-2); }
.header-inner{ height:100%; display:flex; align-items:center; justify-content:space-between; gap:1rem; }
.brand{ display:inline-flex; align-items:center; gap:.6rem; }
.brand-mark{
  display:inline-flex; align-items:center; gap:.34em;
  font-family:var(--display); font-weight:700; text-transform:uppercase;
  font-size:1.26rem; letter-spacing:-.03em; line-height:1;
}
.brand-mark em{ font-style:normal; color:var(--red); }

/* music note after the name. Sized in em so it scales with the logo. */
.brand-note{ width:1.05em; height:1.05em; flex:0 0 auto; color:var(--red);
             transform-origin:60% 80%; transition:transform .2s var(--ease); }
.brand-note .head{ fill:currentColor; stroke:none; }
.brand-note .stem{ fill:none; stroke:currentColor; stroke-width:1.9;
                   stroke-linecap:round; stroke-linejoin:round; }
/* it lifts and tilts when the logo is hovered, rather than bobbing
   forever in a fixed header where the motion would nag */
.brand:hover .brand-note{ transform:translateY(-2px) rotate(-10deg); }
.brand-logo{ height:36px; width:auto; }

.nav{ display:flex; gap:1.9rem; }
.nav-link{ font-size:.92rem; font-weight:500; color:var(--ink-2); position:relative; padding:.35rem 0; transition:color .15s; }
.nav-link::after{ content:""; position:absolute; left:0; bottom:-1px; height:2px; width:0; background:var(--red); transition:width .22s var(--ease); }
.nav-link:hover, .nav-link.is-active{ color:var(--ink); }
.nav-link:hover::after, .nav-link.is-active::after{ width:100%; }

.header-actions{ display:flex; align-items:center; gap:.6rem; }
/* Book Me is the only full-size button in a row of small controls, so it
   is stepped down from the default .btn padding to sit level with them.
   nowrap because at phone widths the row got tight enough to break the
   label, dropping "Me" onto a second line under "Book". */
.header-actions .btn{
  padding:.5rem .95rem; font-size:.78rem; line-height:1.1;
  white-space:nowrap;
}
.hamburger{ display:none; width:42px; height:42px; border-radius:10px; }
.hamburger span{ display:block; width:20px; height:2px; margin:4px auto; background:var(--ink); transition:transform .22s var(--ease), opacity .15s; }
.hamburger[aria-expanded="true"] span:nth-child(1){ transform:translateY(6px) rotate(45deg); }
.hamburger[aria-expanded="true"] span:nth-child(2){ opacity:0; }
.hamburger[aria-expanded="true"] span:nth-child(3){ transform:translateY(-6px) rotate(-45deg); }

/* Panel drops from under the header. It is measured against svh so an
   iOS address bar appearing cannot push the last link off screen, and it
   scrolls internally if the list ever outgrows the viewport. */
.mobile-nav{
  position:fixed; inset:var(--header-h) 0 auto 0; z-index:59;
  background:rgba(6,6,8,.96); backdrop-filter:blur(20px) saturate(1.2);
  border-bottom:1px solid var(--line-2);
  box-shadow:0 26px 50px -30px var(--shadow);
  padding:.6rem clamp(18px,4vw,44px) calc(1.4rem + env(safe-area-inset-bottom));
  max-height:calc(100svh - var(--header-h));
  overflow-y:auto; overscroll-behavior:contain;

  /* animate opacity and visibility too, so the panel cannot be tabbed
     into or flash over content while it is closed */
  transform:translateY(-102%);
  opacity:0; visibility:hidden;
  transition:transform .34s var(--ease), opacity .22s var(--ease), visibility 0s .34s;
}
.mobile-nav.open{
  transform:translateY(0); opacity:1; visibility:visible;
  transition:transform .34s var(--ease), opacity .2s var(--ease), visibility 0s;
}

.mobile-nav a{
  display:flex; align-items:center; justify-content:space-between;
  padding:.95rem .25rem; font-family:var(--display); font-weight:600;
  font-size:1.2rem; letter-spacing:-.03em; text-transform:uppercase;
  color:var(--ink-2); border-bottom:1px solid var(--line-2);
  border-radius:8px;
  transition:color .16s, background .16s, padding-left .2s var(--ease);
}
.mobile-nav a:last-child{ border-bottom:none; }
.mobile-nav a:active{ background:rgba(220,38,38,.10); padding-left:.7rem; }
.mobile-nav a.is-active{ color:var(--ink); }
/* red bar marks the current page, matching the desktop underline */
.mobile-nav a.is-active::after{
  content:""; width:20px; height:2px; background:var(--red); border-radius:2px;
}

/* Links fade in one after another as the panel drops. Delays only apply
   while opening, so closing stays a single clean movement. */
.mobile-nav a{ opacity:0; transform:translateY(-6px); }
.mobile-nav.open a{ opacity:1; transform:none; transition:opacity .26s var(--ease), transform .26s var(--ease), color .16s, background .16s, padding-left .2s var(--ease); }
.mobile-nav.open a:nth-child(1){ transition-delay:.05s }
.mobile-nav.open a:nth-child(2){ transition-delay:.09s }
.mobile-nav.open a:nth-child(3){ transition-delay:.13s }
.mobile-nav.open a:nth-child(4){ transition-delay:.17s }
.mobile-nav.open a:nth-child(5){ transition-delay:.21s }
.mobile-nav.open a:nth-child(6){ transition-delay:.25s }

/* stop the page behind the open panel from scrolling */
body.nav-open{ overflow:hidden; }

/* =====================================================================
   HERO
   ===================================================================== */
.hero{ min-height:100svh; display:flex; align-items:center; padding-top:calc(var(--header-h) + 40px); padding-bottom:70px; overflow:hidden; }
.hero-inner{ max-width:920px; }
.hero h1{ margin:.3rem 0 1.2rem; }
.hero h1 span{ display:block; }
.hero-sub{ font-size:clamp(1rem,1.8vw,1.22rem); color:var(--ink-2); max-width:52ch; }
.hero-cta{ display:flex; flex-wrap:wrap; gap:.8rem; margin-top:2.1rem; }
.hero-scroll{
  position:absolute; left:50%; bottom:24px; transform:translateX(-50%);
  font-size:.68rem; letter-spacing:.24em; text-transform:uppercase; color:var(--ink-3);
  display:flex; flex-direction:column; align-items:center; gap:.5rem;
}
.hero-scroll::after{
  content:""; width:1px; height:42px;
  background:linear-gradient(to bottom, var(--red), transparent);
  animation:scrollPulse 2.4s ease-in-out infinite;
}
@keyframes scrollPulse{ 0%,100%{ opacity:.35; transform:scaleY(.7); transform-origin:top } 50%{ opacity:1; transform:scaleY(1) } }

/* page banner (inner pages) */
.page-head{ padding-top:calc(var(--header-h) + clamp(52px,9vw,110px)); padding-bottom:clamp(30px,5vw,60px); }
.crumbs{ font-size:.8rem; color:var(--ink-3); margin-top:1rem; }
.crumbs a:hover{ color:var(--red); }

/* stats */
.stats{ display:flex; flex-wrap:wrap; gap:clamp(1.4rem,5vw,4rem); margin-top:3rem; }
.stat b{ font-family:var(--display); font-weight:600; font-size:2.2rem; line-height:1; display:block; letter-spacing:-.04em; }
.stat span{ font-size:.72rem; letter-spacing:.2em; text-transform:uppercase; color:var(--ink-3); }

/* =====================================================================
   MARQUEE
   ===================================================================== */
.marquee{ border-block:1px solid var(--line-2); background:rgba(220,38,38,.06); overflow:hidden; padding:.85rem 0; }
.marquee-track{ display:flex; gap:2.6rem; width:max-content; animation:marquee 36s linear infinite; }
.marquee-track span{ font-family:var(--display); font-weight:500; text-transform:uppercase; font-size:.96rem; letter-spacing:.02em; color:var(--ink-2); display:inline-flex; align-items:center; gap:2.6rem; }
.marquee-track span::after{ content:"◆"; color:var(--red); font-size:.66rem; }
@keyframes marquee{ from{ transform:translateX(0) } to{ transform:translateX(-50%) } }

/* =====================================================================
   CARDS
   ===================================================================== */
.grid{ display:grid; gap:1.2rem; }
/* min() guards the track floor: without it a 320px minimum is wider than
   the content area on a 320px phone and the grid overflows sideways */
.grid-2{ grid-template-columns:repeat(auto-fit,minmax(min(320px,100%),1fr)); }
.grid-3{ grid-template-columns:repeat(auto-fit,minmax(min(270px,100%),1fr)); }

.card{
  background:var(--bg-2); border:1px solid var(--line-2); border-radius:var(--radius);
  padding:1.6rem; transition:border-color .18s, transform .2s var(--ease), box-shadow .2s;
}
.card:hover{ border-color:rgba(220,38,38,.5); transform:translateY(-4px); box-shadow:0 24px 50px -30px rgba(220,38,38,.6); }
.card h3{ margin-bottom:.5rem; }
.card p{ font-size:.94rem; }
.card .ic{ color:var(--red); width:26px; height:26px; margin-bottom:1rem; }

/* =====================================================================
   MIXES
   ===================================================================== */
.mix{
  display:grid; grid-template-columns:auto 1fr auto; align-items:center; gap:1.2rem;
  padding:1.05rem 1.3rem; border:1px solid var(--line-2); border-radius:var(--radius);
  background:var(--bg-2); transition:border-color .18s, background .18s, transform .2s var(--ease);
}
.mix + .mix{ margin-top:.7rem; }
.mix:hover{ border-color:rgba(220,38,38,.55); background:var(--bg-3); transform:translateX(4px); }
.mix-num{ font-family:var(--display); font-weight:600; font-size:1.3rem; color:var(--red); min-width:2.4rem; letter-spacing:-.03em; }
.mix-name{ display:block; font-family:var(--display); font-weight:600; text-transform:uppercase; font-size:1.05rem; line-height:1.2; letter-spacing:-.02em; }
.mix-meta{ display:block; font-size:.78rem; color:var(--ink-3); letter-spacing:.06em; text-transform:uppercase; }
.mix-play{
  width:46px; height:46px; border-radius:50%; display:grid; place-items:center;
  background:rgba(220,38,38,.14); color:var(--red);
  box-shadow:inset 0 0 0 1.4px rgba(220,38,38,.45);
  transition:background .18s, color .18s, box-shadow .18s;
}
.mix:hover .mix-play{ background:var(--red); color:var(--on-red); box-shadow:var(--glow); }
.embed{ margin-top:1.4rem; border-radius:var(--radius); overflow:hidden; border:1px solid var(--line-2); background:var(--bg-2); }
.embed iframe{ display:block; width:100%; border:0; }
.embed-empty{ padding:2.4rem 1.4rem; text-align:center; color:var(--ink-3); font-size:.9rem; }

/* =====================================================================
   TOUR DATES
   ===================================================================== */
.date-row{
  display:grid; grid-template-columns:auto 1fr auto; align-items:center; gap:1.4rem;
  padding:1.2rem .4rem; border-bottom:1px solid var(--line-2);
  transition:background .18s, padding-inline .2s var(--ease);
}
.date-row:hover{ background:rgba(220,38,38,.06); padding-inline:1rem .4rem; }
.date-when{ font-family:var(--display); font-weight:600; font-size:1.2rem; min-width:6.2rem; line-height:1; letter-spacing:-.03em; }
.date-when small{ display:block; font-family:var(--sans); font-size:.68rem; letter-spacing:.2em; color:var(--ink-3); }
.date-venue{ font-weight:600; color:var(--ink); }
.date-city{ color:var(--ink-3); font-size:.88rem; }
.date-row .btn{ padding:.58rem 1.2rem; font-size:.82rem; }
.tag-soldout{ font-size:.7rem; letter-spacing:.16em; text-transform:uppercase; color:var(--ink-3); border:1px solid var(--line); padding:.5rem 1rem; border-radius:999px; }

/* =====================================================================
   PACKAGES
   ===================================================================== */
.pkg{
  background:var(--bg-2); border:1px solid var(--line-2); border-radius:var(--radius);
  padding:2rem 1.7rem; display:flex; flex-direction:column; gap:.9rem; position:relative;
  transition:border-color .18s, transform .2s var(--ease), box-shadow .2s;
}
.pkg:hover{ transform:translateY(-5px); border-color:rgba(220,38,38,.45); box-shadow:0 26px 60px -34px rgba(220,38,38,.7); }
.pkg.featured{ border-color:var(--red); box-shadow:0 0 0 1px var(--red), 0 24px 60px -34px rgba(220,38,38,.8); }
.pkg-badge{
  position:absolute; top:-11px; left:1.7rem; background:var(--red); color:var(--on-red);
  font-size:.64rem; font-weight:700; letter-spacing:.18em; text-transform:uppercase;
  padding:.3rem .8rem; border-radius:999px;
}
.pkg-price{ font-family:var(--display); font-weight:600; font-size:2.4rem; line-height:1; letter-spacing:-.045em; }
.pkg-price small{ font-family:var(--sans); font-size:.78rem; color:var(--ink-3); letter-spacing:.08em; }
.pkg ul{ display:flex; flex-direction:column; gap:.55rem; margin:.3rem 0 1rem; }
.pkg li{ display:flex; gap:.6rem; align-items:flex-start; font-size:.92rem; color:var(--ink-2); }
.pkg li::before{ content:"✓"; color:var(--red); font-size:.85rem; line-height:1.7; }
.pkg li.no{ color:var(--ink-3); }
.pkg li.no::before{ content:"✕"; color:var(--ink-3); }
.pkg .btn{ margin-top:auto; }

/* =====================================================================
   REVIEWS
   ===================================================================== */
.review{
  background:var(--bg-2); border:1px solid var(--line-2); border-radius:var(--radius);
  padding:1.7rem; display:flex; flex-direction:column; gap:1rem;
  transition:border-color .18s, transform .2s var(--ease), box-shadow .2s;
}
.review:hover{ border-color:rgba(220,38,38,.45); transform:translateY(-4px); box-shadow:0 24px 50px -30px rgba(220,38,38,.6); }
.review blockquote{ color:var(--ink-2); font-size:.98rem; }
.review blockquote::before{ content:"\201C"; }
.review blockquote::after{ content:"\201D"; }
.review figcaption strong{ display:block; font-family:var(--display); text-transform:uppercase; font-size:1rem; font-weight:600; letter-spacing:-.02em; }
.review figcaption span{ font-size:.74rem; letter-spacing:.16em; text-transform:uppercase; color:var(--ink-3); }
/* Empty state for the review grid. The generic .embed-empty grey sits at
   40% white and vanished against black, so this gets its own dark panel
   and full-strength copy. Spans the whole grid row. */
.reviews-empty{
  grid-column:1 / -1;
  background:linear-gradient(180deg, rgba(220,38,38,.10), var(--bg-2) 70%);
  border:1px dashed rgba(220,38,38,.55);
  border-radius:var(--radius);
  padding:2.6rem 1.6rem; text-align:center;
}
.reviews-empty b{
  display:block; font-family:var(--display); font-weight:600;
  text-transform:uppercase; font-size:1.2rem; letter-spacing:-.02em;
  color:var(--ink); margin-bottom:.4rem;
}
.reviews-empty span{ color:var(--red-hot); font-size:.95rem; font-weight:500; }

.stars{ color:var(--red); letter-spacing:.18em; font-size:1rem; line-height:1; }
.stars i{ color:var(--line); font-style:normal; }

/* Star picker in the review form. The stars sit in DOM order 5→1 and are
   flipped with row-reverse, so "~ label" reaches every star below the one
   hovered or checked. Selectors are prefixed with .field so they outrank
   the generic .field label / .field input rules further down this file. */
.field .rating{ display:flex; flex-direction:row-reverse; justify-content:flex-end; gap:.3rem; }
.field .rating input{ position:absolute; opacity:0; width:0; height:0; padding:0; border:0; }
.field .rating label{
  font-size:1.8rem; line-height:1; color:var(--line); cursor:pointer;
  letter-spacing:0; text-transform:none; transition:color .15s, transform .15s var(--ease);
}
.field .rating label:hover, .field .rating label:hover ~ label,
.field .rating input:checked ~ label{ color:var(--red); }
.field .rating label:hover{ transform:scale(1.12); }
.field .rating input:focus-visible + label{ outline:2px solid var(--red-hot); outline-offset:3px; border-radius:4px; }

/* =====================================================================
   DEPOSIT PICKER
   ===================================================================== */
.deposit-row{
  display:flex; flex-wrap:wrap; align-items:flex-end; gap:1.2rem;
  margin:1.6rem 0 1.2rem;
}
.deposit-row .field{ flex:1 1 240px; }
.deposit-amount{ flex:0 0 auto; }
.deposit-amount span{
  display:block; font-size:.66rem; letter-spacing:.18em;
  text-transform:uppercase; color:var(--ink-3); margin-bottom:.45rem;
}
.deposit-amount b{
  display:block; font-family:var(--display); font-weight:600; font-size:2.1rem;
  line-height:1; color:var(--red); letter-spacing:-.04em;
}
.deposit-row .btn{ flex:0 0 auto; }
/* The header row (logo, language pill, theme switch, Book Me) runs out of
   width well before the 400px breakpoint on a real phone, so it steps
   down here first rather than waiting and breaking. */
@media (max-width:560px){
  .header-actions{ gap:.5rem; }
  .header-actions .btn{ padding:.46rem .8rem; font-size:.75rem; }
}

@media (max-width:560px){
  .deposit-row{ align-items:stretch; }
  .deposit-row .btn{ width:100%; }
}

/* =====================================================================
   GALLERY
   ===================================================================== */
.gallery{ display:grid; grid-template-columns:repeat(auto-fill,minmax(min(230px,100%),1fr)); gap:.8rem; }
.shot{
  position:relative; aspect-ratio:1/1; border-radius:var(--radius-s); overflow:hidden;
  background:var(--bg-2); border:1px solid var(--line-2); cursor:pointer;
}
.shot img{ width:100%; height:100%; object-fit:cover; transition:transform .5s var(--ease), filter .3s; }
.shot::after{ content:""; position:absolute; inset:0; background:linear-gradient(to top, var(--media-shade), transparent 55%); opacity:.5; transition:opacity .25s; }
.shot:hover img{ transform:scale(1.09); filter:saturate(1.15); }
.shot:hover::after{ opacity:.85; }
.shot-cap{
  position:absolute; left:.9rem; bottom:.8rem; z-index:2;
  font-size:.76rem; letter-spacing:.12em; text-transform:uppercase;
  opacity:0; transform:translateY(6px); transition:opacity .25s, transform .25s var(--ease);
}
.shot:hover .shot-cap{ opacity:1; transform:translateY(0); }
/* a slot with no photo uploaded yet */
.shot.empty{
  display:grid; place-items:center; cursor:default;
  background:var(--bg-2); border:1px dashed var(--line-3);
  color:var(--ink-3); font-size:.74rem; letter-spacing:.1em;
  text-align:center; padding:1rem;
}
.shot.empty::after{ display:none; }
.shot.empty:hover{ border-color:var(--line-3); }

/* jump links between the Photos and Videos sections */
.section-jump{ display:flex; gap:.6rem; flex-wrap:wrap; margin-top:1.6rem; }
.section-jump a{
  font-size:.84rem; font-weight:600; padding:.55rem 1.2rem; border-radius:999px;
  color:var(--ink-2); box-shadow:inset 0 0 0 1.4px var(--line);
  transition:color .16s, box-shadow .16s, background .16s;
}
.section-jump a:hover{
  color:var(--red); box-shadow:inset 0 0 0 1.4px var(--red);
  background:rgba(220,38,38,.08);
}

/* =====================================================================
   VIDEOS
   ===================================================================== */
.video-grid{ display:grid; grid-template-columns:repeat(auto-fit,minmax(min(300px,100%),1fr)); gap:.9rem; }
.video-card{
  position:relative; border-radius:var(--radius); overflow:hidden; cursor:pointer;
  border:1px solid var(--line-2); background:var(--bg-2); aspect-ratio:4/5;
  transition:border-color .2s, transform .28s var(--ease), box-shadow .28s;
}
.video-card img{
  width:100%; height:100%; object-fit:cover; display:block;
  transition:transform .6s var(--ease), filter .3s;
}
/* darken toward the bottom so the caption and play badge stay readable */
.video-card::after{
  content:""; position:absolute; inset:0; pointer-events:none;
  background:linear-gradient(to top, var(--media-shade), transparent 55%);
  opacity:.65; transition:opacity .25s;
}
.video-card:hover{
  border-color:rgba(220,38,38,.55); transform:translateY(-5px);
  box-shadow:0 28px 55px -28px rgba(220,38,38,.7);
}
.video-card:hover img{ transform:scale(1.07); filter:saturate(1.12); }
.video-card:hover::after{ opacity:.85; }

/* play badge, pulsing like the speaker rings in the background */
.video-play{
  position:absolute; inset:0; margin:auto; z-index:2;
  width:60px; height:60px; border-radius:50%;
  display:grid; place-items:center;
  background:var(--red); color:var(--on-red);
  box-shadow:0 0 0 0 rgba(220,38,38,.55);
  transition:transform .28s var(--ease), background .2s;
}
.video-play svg{ width:24px; height:24px; fill:currentColor; margin-left:3px; }
.video-card:hover .video-play{ transform:scale(1.12); background:var(--red-hot); animation:playPulse 1.4s ease-out infinite; }
@keyframes playPulse{
  0%   { box-shadow:0 0 0 0    rgba(220,38,38,.55); }
  100% { box-shadow:0 0 0 26px rgba(220,38,38,0);   }
}

.video-card figcaption{
  position:absolute; left:1rem; right:1rem; bottom:.9rem; z-index:2;
  font-size:.74rem; letter-spacing:.12em; text-transform:uppercase; color:var(--ink);
  opacity:0; transform:translateY(6px);
  transition:opacity .25s, transform .25s var(--ease);
}
.video-card:hover figcaption{ opacity:1; transform:none; }

/* a clip that has not been uploaded yet */
.video-card.empty{
  display:grid; place-items:center; aspect-ratio:4/5; cursor:default;
  border-style:dashed; border-color:var(--line-3);
  color:var(--ink-3); font-size:.74rem; letter-spacing:.1em;
}
.video-card.empty::after{ display:none; }
.video-card.empty:hover{ transform:none; box-shadow:none; border-color:var(--line-3); }

/* =====================================================================
   TILE ENTRANCE
   Photos and clips rise and settle in sequence as they scroll in. The
   --i on each tile staggers them; it wraps every 6 so a long grid never
   ends up waiting seconds for the last item.
   ===================================================================== */
.tile-in{ opacity:1; transform:none; }
html.js .tile-in{
  opacity:0; transform:translateY(20px) scale(.96);
  transition:opacity .55s var(--ease), transform .55s var(--ease);
  transition-delay:calc(var(--i, 0) * 60ms);
}
html.js .tile-in.in{ opacity:1; transform:none; }

.lightbox{
  position:fixed; inset:0; z-index:90; display:grid; place-items:center; padding:4vw;
  background:var(--scrim); backdrop-filter:blur(6px);
  opacity:0; visibility:hidden; transition:opacity .25s, visibility 0s .25s;
}
.lightbox.open{ opacity:1; visibility:visible; transition:opacity .25s; }
.lightbox img,
.lightbox video{
  max-width:100%; max-height:86svh; border-radius:var(--radius-s);
  display:block; background:#000;
  box-shadow:0 40px 90px -40px var(--shadow-deep), 0 0 0 1px var(--line-2);
}
.lightbox [hidden]{ display:none; }
.lightbox-close{ position:absolute; top:18px; right:22px; width:44px; height:44px; border-radius:50%; background:var(--bg-2); display:grid; place-items:center; transition:background .18s; }
.lightbox-close:hover{ background:var(--red); }

/* portrait photo on the About page */
.portrait{
  position:relative; aspect-ratio:4/5; overflow:hidden;
  border-radius:var(--radius); border:1px solid var(--line-2);
  background:var(--bg-2);
}
.portrait img{ width:100%; height:100%; object-fit:cover; object-position:center 30%; }
/* a red wash along the bottom ties the photo to the rest of the palette */
.portrait::after{
  content:""; position:absolute; inset:0; pointer-events:none;
  background:linear-gradient(to top, rgba(220,38,38,.20), transparent 55%);
}

.video-frame{ position:relative; border-radius:var(--radius); overflow:hidden; border:1px solid var(--line-2); background:var(--bg-2); aspect-ratio:16/9; }
.video-frame iframe, .video-frame video{ width:100%; height:100%; display:block; border:0; object-fit:cover; }
.video-frame .embed-empty{ height:100%; display:grid; place-items:center; }

/* =====================================================================
   FORMS
   ===================================================================== */
.form{ display:flex; flex-direction:column; gap:1rem; }
.field{ display:flex; flex-direction:column; gap:.4rem; }
.field label{ font-size:.74rem; letter-spacing:.16em; text-transform:uppercase; color:var(--label-ink); }
/* an aside inside a label, for "(optional)" style hints */
.field label .doc-opt{ text-transform:none; letter-spacing:0; opacity:.7; }
/* background-COLOR, not the background shorthand — the shorthand would
   wipe the custom chevron image on .field select below */
.field input, .field textarea, .field select{
  background-color:var(--field-bg); border:1px solid var(--field-border); border-radius:var(--radius-s);
  padding:.85rem 1rem; transition:border-color .15s, background-color .15s, box-shadow .15s;
}
.field input:focus, .field textarea:focus, .field select:focus{
  outline:none; border-color:var(--red); background-color:var(--field-hover); box-shadow:0 0 0 3px rgba(220,38,38,.18);
}

/* The native select arrow sits hard against the border and ignores
   padding, so draw our own and inset it to match the text. */
.field select{
  appearance:none; -webkit-appearance:none;
  padding-right:2.9rem;
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23ffffff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' opacity='.5'><path d='M6 9l6 6 6-6'/></svg>");
  background-repeat:no-repeat;
  background-position:right 1rem center;
  background-size:15px 15px;
}
/* The chevron is a data URI, which cannot read a CSS variable, so the
   stroke colour is baked in. The default one is white; on a light field
   that is invisible, hence the dark twin below. */
:root[data-theme="light"] .field select{
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%230B0C0F' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' opacity='.55'><path d='M6 9l6 6 6-6'/></svg>");
}

.field textarea{ resize:vertical; min-height:120px; }

/* Grid and flex children default to min-width:auto, so an input with a
   wide intrinsic size (date, time and number are the worst offenders)
   refuses to shrink and pushes straight out of the card. Forcing the
   track and the control to be shrinkable is what keeps them inside. */
.field{ min-width:0; }
.field input, .field select, .field textarea{ width:100%; min-width:0; max-width:100%; }
.field-row{ display:grid; grid-template-columns:1fr 1fr; gap:1rem; min-width:0; }
.field-row > *{ min-width:0; }

/* long forms read better in labelled groups than as one tall column */
.form-group{ display:flex; flex-direction:column; gap:1rem; min-width:0; }
.form-group + .form-group{
  margin-top:.5rem; padding-top:1.5rem; border-top:1px solid var(--line-2);
}
.form-legend{
  font-size:.68rem; font-weight:600; letter-spacing:.2em;
  text-transform:uppercase; color:var(--red); margin-bottom:-.2rem;
}

/* tick lists for services, effects and consents. The label wraps the box
   so the whole line is a hit target, which matters most on a phone. */
.check-list{
  display:grid; gap:.7rem 1.2rem;
  grid-template-columns:repeat(auto-fit,minmax(min(220px,100%),1fr));
}
.check{
  display:flex; gap:.6rem; align-items:flex-start;
  font-size:.88rem; color:var(--ink-2); cursor:pointer;
}
.check input{
  width:auto; min-width:0; flex:0 0 auto;
  margin-top:.15rem; accent-color:var(--red);
  /* without this the native unchecked box is drawn white, which on a black
     card reads as eight bright squares before anything is even ticked */
  color-scheme:dark;
}

/* invoice line items: wide description, narrow amount */
.line-row{ display:grid; grid-template-columns:1fr 132px; gap:.9rem; min-width:0; }
.line-row > *{ min-width:0; }
@media (max-width:560px){ .line-row{ grid-template-columns:1fr; } }
.form-status{ font-size:.88rem; min-height:1.4em; }
.form-status.ok{ color:#37D67A; }
.form-status.err{ color:var(--red-hot); }
.form-note{ font-size:.78rem; color:var(--ink-3); }

/* =====================================================================
   CONTACT / SOCIAL
   ===================================================================== */
.contact-list{ display:flex; flex-direction:column; gap:1.3rem; margin:2rem 0; }
.contact-list li{ display:flex; gap:1rem; align-items:flex-start; }
.contact-list .ic{ color:var(--red); flex:0 0 auto; margin-top:.2rem; }
.contact-list span{ display:block; font-size:.7rem; letter-spacing:.18em; text-transform:uppercase; color:var(--ink-3); }
.contact-list a:hover{ color:var(--red); }
.socials{ display:flex; gap:.7rem; flex-wrap:wrap; }
.social{
  width:46px; height:46px; border-radius:50%; display:grid; place-items:center;
  border:1px solid var(--line); color:var(--ink-2);
  transition:background .18s, border-color .18s, color .18s, transform .18s, box-shadow .18s;
}
/* tint and lift rather than flood with red — matches .mix-play and the
   cards, and keeps the icon legible instead of white-on-solid-red */
.social:hover{
  background:rgba(220,38,38,.12);
  border-color:rgba(220,38,38,.55);
  color:var(--red-hot);
  transform:translateY(-3px);
  box-shadow:0 12px 28px -16px rgba(220,38,38,.85);
}

/* =====================================================================
   FOOTER
   ===================================================================== */
.site-footer{ border-top:1px solid var(--line-2); background:var(--footer-bg); padding:clamp(40px,6vw,70px) 0 26px; }
.footer-grid{ display:grid; grid-template-columns:1.5fr 1fr 1fr; gap:2.4rem; }
.footer-grid h4{ font-size:.72rem; letter-spacing:.2em; text-transform:uppercase; color:var(--ink-3); margin-bottom:1rem; }
/* Scoped to the Explore column on purpose. A blanket ".footer-grid a"
   also catches the social buttons and the CTA, overriding their display
   and colour — which knocks the icon out of its circle and turns it red
   on a red background. Keep this selector narrow. */
.footer-nav a{ display:block; padding:.3rem 0; color:var(--ink-2); font-size:.92rem; transition:color .15s; }
.footer-nav a:hover{ color:var(--red); }

/* "Get in touch" column: labelled rows, then one real button */
.footer-contact{ display:flex; flex-direction:column; gap:1rem; margin-bottom:1.6rem; }
.footer-contact span{
  display:block; font-size:.66rem; letter-spacing:.18em;
  text-transform:uppercase; color:var(--ink-3);
}
.footer-contact a{
  display:inline-block; padding:.15rem 0; color:var(--ink); font-weight:500;
  overflow-wrap:anywhere;                    /* long emails must not overflow */
  transition:color .15s;
}
.footer-contact a:hover{ color:var(--red); }
.footer-bottom{
  margin-top:2.4rem; padding-top:1.3rem; border-top:1px solid var(--line-2);
  display:flex; justify-content:space-between; align-items:center;
  gap:.8rem 1.6rem; flex-wrap:wrap;
  font-size:.83rem; color:var(--ink-3);
}
.footer-legal{ display:flex; gap:1.4rem; flex-wrap:wrap; }
.footer-legal a{ color:var(--ink-3); transition:color .15s; }
.footer-legal a:hover{ color:var(--red); }

/* =====================================================================
   LEGAL PAGES — long-form prose, so lists get their bullets back and
   the measure is capped for readability
   ===================================================================== */
.legal{ max-width:78ch; }
.legal h2{ font-size:clamp(1.25rem,2.3vw,1.6rem); margin:2.8rem 0 .9rem; }
.legal h2:first-of-type{ margin-top:0; }
.legal h3{ font-size:.98rem; margin:1.7rem 0 .5rem; color:var(--ink); }
.legal p{ margin-bottom:1rem; }
.legal ul{ list-style:disc; padding-left:1.35rem; margin:0 0 1.3rem; }
.legal li{ color:var(--ink-2); margin-bottom:.55rem; }
.legal li::marker{ color:var(--red); }
.legal strong{ color:var(--ink); font-weight:600; }
.legal a{ color:var(--red); }
.legal a:hover{ color:var(--red-hot); text-decoration:underline; }
.legal-updated{
  font-size:.72rem; letter-spacing:.2em; text-transform:uppercase;
  color:var(--ink-3); margin-bottom:2.4rem;
  padding-bottom:1.2rem; border-bottom:1px solid var(--line-2);
}

/* =====================================================================
   DOCUMENTS — generated contract, invoice and receipt
   On screen these sit on a light card so they read as paper rather than
   as part of the site. The print rules further down strip everything
   else away so the PDF is just the document.
   ===================================================================== */
.doc{
  background:#fff; color:#14161a;
  border-radius:var(--radius); padding:clamp(1.6rem,4vw,3rem);
  max-width:900px; margin-inline:auto;
  box-shadow:0 40px 80px -50px rgba(0,0,0,.9);
  font-size:.95rem; line-height:1.6;
}
.doc h2{ color:#14161a; font-size:1.9rem; letter-spacing:-.03em; }
.doc h3{
  color:#14161a; font-size:.82rem; letter-spacing:.16em; text-transform:uppercase;
  margin:1.8rem 0 .6rem; padding-bottom:.4rem; border-bottom:1px solid #e3e6ea;
}
.doc p{ color:#3c414a; }
/* the page-level section rule pads by 124px, which is right for the site
   and absurd inside a document, so the document keeps its own rhythm */
.doc section{ padding:0; }
.doc-head{ display:flex; flex-wrap:wrap; gap:1.4rem; justify-content:space-between; align-items:flex-start; }
.doc-head + .doc-recital{ margin-top:1.5rem; }
.doc-head h2{ margin-bottom:.3rem; }
.doc-meta{ font-size:.82rem; color:#6a7079; }
.doc-brand{ text-align:right; font-size:.84rem; color:#3c414a; display:flex; flex-direction:column; gap:.1rem; }
.doc-brand strong{ font-family:var(--display); font-size:1.05rem; letter-spacing:-.02em; text-transform:uppercase; color:#14161a; }

.doc-parties{ display:grid; grid-template-columns:repeat(auto-fit,minmax(min(240px,100%),1fr)); gap:1.4rem; margin-top:1.4rem; }

.doc-table{ width:100%; border-collapse:collapse; margin-bottom:.6rem; }
.doc-table th, .doc-table td{
  text-align:left; padding:.5rem .2rem; border-bottom:1px solid #e9ecef;
  vertical-align:top; font-size:.9rem;
}
.doc-table th{ color:#6a7079; font-weight:500; width:38%; }
.doc-table td{ color:#14161a; }
.doc-num{ text-align:right; width:auto; }
.doc-items th{ width:auto; }
.doc-items tfoot th{ text-align:right; color:#3c414a; }
.doc-due th, .doc-due td{ border-top:2px solid #14161a; border-bottom:none; padding-top:.7rem; font-size:1rem; }

.doc-blank{ display:inline-block; min-width:150px; border-bottom:1px solid #b9bfc7; }
.doc-terms{ list-style:decimal; padding-left:1.3rem; }
.doc-terms li{ color:#3c414a; margin-bottom:.5rem; font-size:.89rem; }

/* Article and clause numbering.
   Two counters do the work a legal document expects: `art` ticks once per
   <h3 class="doc-art">, `cl` restarts inside each clause list, and the
   marker prints them together as 4.2 rather than a bare 2. Because both
   counters live on .doc, the clause list can still read the article
   number set by the heading above it. */
.doc{ counter-reset:art; }
.doc-art{ counter-increment:art; }
.doc-art::before{ content:counter(art) ". "; }

.doc-clauses{ list-style:none; padding-left:0; counter-reset:cl; margin-bottom:.4rem; }
.doc-clauses > li{
  counter-increment:cl; position:relative; padding-left:3.1rem;
  color:#3c414a; font-size:.89rem; margin-bottom:.55rem;
}
.doc-clauses > li::before{
  content:counter(art) "." counter(cl);
  position:absolute; left:0; top:0;
  color:#6a7079; font-variant-numeric:tabular-nums;
}
.doc-clauses strong{ color:#14161a; }

.doc-lead{ color:#3c414a; font-size:.92rem; }
.doc-quiet{ color:#6a7079; font-size:.8rem; }
.doc-recital{ font-size:.89rem; color:#3c414a; margin-bottom:.5rem; }

/* the initials strip that closes each appendix and the terms */
.doc-initials{
  display:flex; gap:.6rem; align-items:flex-end; justify-content:flex-end;
  margin-top:1.2rem; font-size:.78rem; color:#6a7079;
}
.doc-initials .doc-blank{ min-width:90px; }

.doc-stamp{
  display:inline-block; margin-top:1rem; padding:.4rem 1rem; border-radius:6px;
  border:2px solid #157f3d; color:#157f3d !important;
  font-weight:700; letter-spacing:.14em; text-transform:uppercase; font-size:.78rem;
}

.doc-sign{ display:grid; grid-template-columns:repeat(auto-fit,minmax(min(240px,100%),1fr)); gap:2rem; margin-top:1.6rem; }
.doc-sig-line{
  display:block; min-height:2.1rem; border-bottom:1px solid #14161a;
  font-family:var(--display); font-size:1.2rem; color:#14161a;
}
.doc-sig-label{ display:block; font-size:.74rem; color:#6a7079; margin-top:.35rem; }

.doc-actions{ max-width:900px; margin:2rem auto 0; display:flex; flex-direction:column; gap:1rem; }
.doc-agree{
  display:flex; gap:.7rem; align-items:flex-start;
  font-size:.9rem; color:var(--ink-2); max-width:60ch;
}
.doc-agree input{ width:auto; margin-top:.3rem; }

/* =====================================================================
   PRINT — only the document survives
   ===================================================================== */
@media print{
  @page{ margin:16mm; }
  html, body{ background:#fff !important; color:#000 !important; }
  body::after{ display:none !important; }
  #gl, .site-header, .site-footer, .mobile-nav,
  .page-head, .doc-form, .doc-actions, .no-print{ display:none !important; }
  #page{ padding:0 !important; }
  section{ padding:0 !important; }
  .wrap{ max-width:none !important; padding:0 !important; }
  .doc{
    box-shadow:none !important; border-radius:0 !important;
    padding:0 !important; max-width:none !important;
  }
  .doc h3{ break-after:avoid; }
  .doc-terms li, .doc-clauses > li, .doc-table tr{ break-inside:avoid; }
  .doc-sign, .doc-initials, .doc-parties{ break-inside:avoid; }
  .reveal{ opacity:1 !important; transform:none !important; }
}

/* =====================================================================
   SCROLL REVEAL — short and understated, matching the reference
   ===================================================================== */
/* The hidden starting state is applied ONLY when .js is on <html>.

   Previously .reveal was opacity:0 in the base stylesheet, so the copy
   was invisible until motion.js loaded AND its observer fired. Any delay
   or failure in that chain left readable text stranded at zero opacity,
   which is what "I have to refresh to see the words" was. CSS arrives
   before the scripts do, so the safe default has to be visible. */
.reveal{ opacity:1; transform:none; }
html.js .reveal{ opacity:0; transform:translateY(18px); transition:opacity .5s var(--ease), transform .5s var(--ease); }
html.js .reveal.in{ opacity:1; transform:none; }
.reveal.d1{ transition-delay:.06s } .reveal.d2{ transition-delay:.12s }
.reveal.d3{ transition-delay:.18s } .reveal.d4{ transition-delay:.24s }

/* =====================================================================
   RESPONSIVE
   ===================================================================== */
@media (max-width:900px){
  .nav{ display:none; }
  .hamburger{ display:block; }
  .footer-grid{ grid-template-columns:1fr 1fr; }
  .date-row{ grid-template-columns:auto 1fr; row-gap:.7rem; }
  .date-row .btn, .date-row .tag-soldout{ grid-column:2; justify-self:start; }
}
@media (max-width:560px){
  .field-row{ grid-template-columns:1fr; }
  .footer-grid{ grid-template-columns:1fr; }
  .mix{ grid-template-columns:auto 1fr; }
  .mix-play{ grid-column:2; }
  .stats{ gap:1.6rem 2.2rem; }
  .stat b{ font-size:2rem; }
  /* two clean columns beats four cramped ones */
  .stat{ flex:1 1 40%; }
  .lightbox-close{ top:12px; right:14px; }
}

/* Small phones: the logo, the Book Me button and the hamburger stop
   fitting on one line around here, so the button loses its padding. */
@media (max-width:400px){
  .header-actions .btn{ padding:.44rem .72rem; font-size:.72rem; }
  .brand-mark{ font-size:1.12rem; }
  .header-actions{ gap:.45rem; }
  .pkg{ padding:1.6rem 1.25rem; }
  .card{ padding:1.3rem; }
  .deposit-amount b{ font-size:1.8rem; }
}

@media (prefers-reduced-motion:reduce){
  *{ animation-duration:.001ms !important; animation-iteration-count:1 !important;
     transition-duration:.001ms !important; transition-delay:0s !important;
     animation-delay:0s !important; scroll-behavior:auto !important; }
  /* the menu's staggered links must land instantly, not just quickly */
  .mobile-nav a{ opacity:1; transform:none; }
  .reveal{ opacity:1; transform:none; }
  #gl{ display:none; }
}


/* =====================================================================
   THEME SWITCH — sliding toggle in the header

   A track with a knob that slides between the sun and the moon, rather
   than a single swapping icon. Both icons stay visible so the two states
   are readable at a glance; the knob says which one you are in.

   The knob moves with translateX, which is a compositor-only property,
   so the slide stays smooth without triggering layout.
   ===================================================================== */
.theme-switch{
  position:relative; flex:none;
  width:48px; height:26px; border-radius:999px;
  display:flex; align-items:center; justify-content:space-between;
  padding:0 5px;
  background:var(--bg-3);
  box-shadow:inset 0 0 0 1.4px var(--line);
  transition:box-shadow .18s, background-color .22s var(--ease);
}
.theme-switch:hover{ box-shadow:inset 0 0 0 1.4px var(--red); }
.theme-switch:active .ts-knob{ width:19px; }   /* squashes toward the travel */

.theme-switch .ts-ic{
  width:11px; height:11px; flex:none; position:relative; z-index:1;
  fill:none; stroke:currentColor; stroke-width:2;
  stroke-linecap:round; stroke-linejoin:round;
  transition:color .22s var(--ease), opacity .22s var(--ease);
}
/* the icon the knob is NOT covering is the one that stays bright */
.theme-switch .ts-sun { color:var(--ink-3); opacity:.55; }
.theme-switch .ts-moon{ color:var(--ink); opacity:1; }
:root[data-theme="light"] .theme-switch .ts-sun { color:var(--red); opacity:1; }
:root[data-theme="light"] .theme-switch .ts-moon{ color:var(--ink-3); opacity:.55; }

.ts-knob{
  position:absolute; top:50%; left:2.5px;
  width:21px; height:21px; border-radius:50%;
  background:var(--ink); transform:translateY(-50%);
  transition:transform .26s var(--ease), background-color .22s var(--ease), width .12s;
}
/* light = knob travels to the sun end */
:root[data-theme="light"] .ts-knob{
  transform:translateY(-50%) translateX(22px);
  background:var(--red);
}
/* In RTL the whole header mirrors, so the knob must travel the other way
   or it would slide away from the icon it is meant to land on. */
:root[data-lang="ar"] .ts-knob{ left:auto; right:2.5px; }
:root[data-lang="ar"][data-theme="light"] .ts-knob{ transform:translateY(-50%) translateX(-22px); }

/* =====================================================================
   LANGUAGE TOGGLE — En / Ar

   Both codes are shown at once with the active one lit, so the control
   states which language you are in AND which one you would get. A single
   swapping label cannot do both, and readers disagree about whether it
   means the current language or the destination.
   ===================================================================== */
.lang-toggle{
  flex:none; height:26px; padding:0 .5rem;
  display:inline-flex; align-items:center; gap:.22rem;
  border-radius:999px;
  font-family:var(--display); font-weight:600; font-size:.7rem;
  line-height:1; letter-spacing:.02em;
  box-shadow:inset 0 0 0 1.4px var(--line);
  transition:box-shadow .18s, transform .2s var(--ease);
}
.lang-toggle:hover{ box-shadow:inset 0 0 0 1.4px var(--red); transform:translateY(-2px); }
.lang-toggle:active{ transform:scale(.94); transition-duration:.08s; }
.lang-toggle i{ font-style:normal; color:var(--ink-3); opacity:.6; }
.lang-toggle span{ transition:color .2s var(--ease), opacity .2s var(--ease); }
/* dim whichever code is not active */
.lang-toggle span[data-lg]{ color:var(--ink-3); opacity:.6; }
:root[data-lang="en"] .lang-toggle span[data-lg="en"],
:root[data-lang="ar"] .lang-toggle span[data-lg="ar"]{ color:var(--red); opacity:1; }
/* the codes are Latin either way, so keep them LTR inside an RTL header */
.lang-toggle{ direction:ltr; }

/* Small phones: the switch and the language pill are two extra items in a
   header row that was already tight.

   This block has to sit AFTER the control definitions above. Same-
   specificity rules are decided by source order, so declaring these
   earlier in the file, next to the other 400px overrides, meant the base
   sizes further down silently won and the shrink never happened. */
@media (max-width:400px){
  .theme-switch{ width:44px; height:24px; padding:0 4px; }
  .theme-switch .ts-ic{ width:10px; height:10px; }
  .ts-knob{ width:19px; height:19px; }
  :root[data-theme="light"] .ts-knob{ transform:translateY(-50%) translateX(20px); }
  :root[data-lang="ar"][data-theme="light"] .ts-knob{ transform:translateY(-50%) translateX(-20px); }
  .lang-toggle{ height:24px; padding:0 .42rem; font-size:.64rem; }
}

/* =====================================================================
   ARABIC / RTL

   Most of the layout is flex, grid and logical properties, so it mirrors
   on its own once dir="rtl" is set. What follows is only the handful of
   places that used physical left/right and would otherwise stay pinned
   to the wrong edge.
   ===================================================================== */
:root[data-lang="ar"] body{
  font-family:"Noto Kufi Arabic","Geeza Pro","Segoe UI",Tahoma,sans-serif;
}
/* Arabic letters join, so the negative tracking tuned for the Latin
   display face pulls the joins apart and words look broken. */
:root[data-lang="ar"] h1,
:root[data-lang="ar"] h2,
:root[data-lang="ar"] h3,
:root[data-lang="ar"] h4{
  font-family:"Noto Kufi Arabic","Geeza Pro",sans-serif;
  letter-spacing:normal; text-transform:none; line-height:1.35;
}
/* Uppercasing and wide tracking are Latin typographic devices and do
   nothing for Arabic except damage legibility. */
:root[data-lang="ar"] .eyebrow,
:root[data-lang="ar"] .field label,
:root[data-lang="ar"] .marquee-track span,
:root[data-lang="ar"] .ar-translit{
  letter-spacing:normal; text-transform:none;
}
:root[data-lang="ar"] .eyebrow{ font-size:.8rem; }

/* underline grows from the correct edge */
:root[data-lang="ar"] .nav-link::after{ left:auto; right:0; }

/* mobile drawer indents inward, not outward */
:root[data-lang="ar"] .mobile-nav a{ transition:color .16s, background .16s, padding-right .2s var(--ease); }
:root[data-lang="ar"] .mobile-nav a:active{ padding-left:0; padding-right:.7rem; }

/* badges, captions and the lightbox close button flip edges */
:root[data-lang="ar"] .pkg-tag{ left:auto; right:1.7rem; }
:root[data-lang="ar"] .shot-cap{ left:auto; right:.9rem; }
:root[data-lang="ar"] .lightbox-close{ right:auto; left:22px; }
:root[data-lang="ar"] .legal ul{ padding-left:0; padding-right:1.35rem; }
:root[data-lang="ar"] .field select{ padding-right:1rem; padding-left:2.9rem; background-position:left 1rem center; }
:root[data-lang="ar"] .video-play svg{ margin-left:0; margin-right:3px; transform:scaleX(-1); }

/* The marquee is translated by a fixed -50%, which is direction
   agnostic, but the row itself should read right to left. */
:root[data-lang="ar"] .marquee-track{ direction:rtl; }

@media (max-width:400px){
}

/* Documents stay left-to-right: they are legal paperwork kept in English */
.doc{ direction:ltr; text-align:left; }

/* =====================================================================
   LATIN DATA INSIDE RTL TEXT

   A phone number is digits plus neutral characters ("+", spaces), and
   the bidi algorithm resolves neutrals against the surrounding
   paragraph. Inside an Arabic (RTL) block that pushes the leading "+"
   to the far side and can reorder the digit groups, so +1 403 437 6153
   renders as something like 6153 437 403 1+.

   The stored value is never wrong, only its visual order. Isolating each
   value in its own left-to-right run pins the display, which is why
   numbers keep their English formatting in Arabic. Applied in both
   languages: it is a no-op in LTR and cannot then be forgotten.

   Kept to inline value carriers on purpose. Setting direction on a block
   would also flip its text alignment and pull it to the wrong edge.
   ===================================================================== */
a[href^="tel:"],
a[href^="mailto:"],
[data-phone],
[data-email],
[data-price],
.deposit-amount b,
.footer-contact a{
  direction:ltr;
  unicode-bidi:isolate;
}

/* =====================================================================
   PAGE TRANSITIONS

   Navigating between pages was an instant cut. This fades the content
   out, navigates, then eases the next page in, so moving from Book Me to
   the booking page reads as one continuous move rather than a jump.

   Only #page is animated, never <body>. A transform on an ancestor
   becomes the containing block for position:fixed descendants, which
   would strand the sticky header and the lightbox mid-screen. The
   lightbox lives outside #page, and the header and footer are siblings
   of it, so all three stay put while the content moves.

   Gated on html.js: with scripts off there is nothing to fade back in,
   so the content must simply be visible.
   ===================================================================== */
html.js #page{
  /* backwards, not both: after it finishes the element returns to its
     own style rather than holding the animation's last frame, so a
     stalled or skipped animation can never strand it. */
  animation:pageIn .38s var(--ease) backwards;
}
html.js.is-leaving #page{
  animation:pageOut .22s var(--ease) both;
}
@keyframes pageIn{
  from{ opacity:0; transform:translateY(10px); }
  to  { opacity:1; transform:none; }
}
@keyframes pageOut{
  from{ opacity:1; transform:none; }
  to  { opacity:0; transform:translateY(-8px); }
}

/* The header and footer come with it, softly, so the whole frame settles
   rather than the middle sliding under fixed furniture. Opacity only:
   it makes a stacking context but not a containing block, so the sticky
   header keeps sticking. */
html.js .site-header,
html.js .site-footer{ animation:chromeIn .5s var(--ease) backwards; }
html.js.is-leaving .site-header,
html.js.is-leaving .site-footer{ animation:chromeOut .22s var(--ease) both; }
@keyframes chromeIn { from{ opacity:0 } to{ opacity:1 } }
@keyframes chromeOut{ from{ opacity:1 } to{ opacity:0 } }

@media (prefers-reduced-motion:reduce){
  html.js #page, html.js.is-leaving #page,
  html.js .site-header, html.js .site-footer,
  html.js.is-leaving .site-header, html.js.is-leaving .site-footer{
    animation:none !important; opacity:1 !important; transform:none !important;
  }
}

/* Last line of defence. If the entry animation has not left the content
   visible shortly after load, motion.js sets this and the animations are
   dropped entirely. Text being readable beats text being animated. */
html.js.anim-failsafe #page,
html.js.anim-failsafe .site-header,
html.js.anim-failsafe .site-footer{
  animation:none !important; opacity:1 !important; transform:none !important;
}

/* =====================================================================
   BACK TO TOP
   Sits below the header (60) and the mobile drawer (59) so it can never
   cover navigation, and well below the lightbox (90).

   inset-inline-end rather than right: it mirrors to the left side on its
   own when the page is in Arabic, with no RTL override needed.
   ===================================================================== */
.to-top{
  position:fixed; z-index:55;
  inset-block-end:20px; inset-inline-end:20px;
  width:46px; height:46px; border-radius:50%;
  display:grid; place-items:center;
  background:var(--red); color:var(--on-red);
  box-shadow:0 14px 30px -14px var(--shadow), var(--glow);
  opacity:0; visibility:hidden; transform:translateY(14px) scale(.92);
  transition:opacity .24s var(--ease), transform .24s var(--ease),
             background-color .18s, visibility 0s .24s;
}
/* visibility is delayed on the way out and immediate on the way in, so
   the hidden button is never a click target sitting over the footer */
.to-top.show{
  opacity:1; visibility:visible; transform:none;
  transition:opacity .24s var(--ease), transform .24s var(--ease),
             background-color .18s;
}
.to-top:hover{ background:var(--red-hot); transform:translateY(-3px); }
.to-top:active{ transform:scale(.93); transition-duration:.08s; }
.to-top svg{
  width:20px; height:20px; fill:none; stroke:currentColor;
  stroke-width:2.2; stroke-linecap:round; stroke-linejoin:round;
}
/* the drawer covers the page, so the button has no business floating over it */
body.nav-open .to-top{ opacity:0; visibility:hidden; transform:translateY(14px) scale(.92); }

@media (max-width:560px){
  .to-top{ width:42px; height:42px; inset-block-end:16px; inset-inline-end:16px; }
  .to-top svg{ width:18px; height:18px; }
}
@media (prefers-reduced-motion:reduce){
  .to-top{ transition:opacity .01s, visibility 0s; transform:none; }
  .to-top.show{ transform:none; }
  .to-top:hover{ transform:none; }
}
@media print{ .to-top{ display:none !important; } }

/* The contract and invoice documents are always light paper, in both
   themes, so their controls must be drawn light regardless. */
.doc, .doc *{ color-scheme: light; }

/* Belt and braces for engines that ignore color-scheme on the indicator:
   lift the glyph on dark fields so it can be seen and clicked. */
:root:not([data-theme="light"]) input[type="date"]::-webkit-calendar-picker-indicator,
:root:not([data-theme="light"]) input[type="time"]::-webkit-calendar-picker-indicator{
  filter:invert(1) brightness(1.8);
  opacity:.9;
  cursor:pointer;
}
:root:not([data-theme="light"]) .doc input[type="date"]::-webkit-calendar-picker-indicator,
:root:not([data-theme="light"]) .doc input[type="time"]::-webkit-calendar-picker-indicator{
  filter:none; opacity:1;
}

/* =====================================================================
   LARGE SCREENS

   Everything was tuned for a laptop and then simply stopped: the
   container caps at 1240px, the display type stops growing at 4.6rem,
   and .hero-inner is capped at 920px with no auto margin, so it hugs the
   left edge of that column. Maximised on a big monitor the result is a
   narrow strip of small text sitting off-centre in a lot of empty space.

   These steps let the container, the type and the hero block keep
   scaling with the screen instead of freezing at laptop size.
   ===================================================================== */
@media (min-width:1500px){
  :root{ --maxw:1400px; }

  h1{ font-size:clamp(4.6rem, 5vw, 6rem); }
  h2{ font-size:clamp(2.7rem, 3vw, 3.4rem); }
  h3{ font-size:1.26rem; }
  .lead{ font-size:1.2rem; max-width:64ch; }
  .card p{ font-size:1.02rem; }
  .eyebrow{ font-size:.78rem; }

  /* The hero block grows with the container and is centred within it, so
     it reads as sitting in the middle of the screen rather than pinned
     to one side. The copy inside stays left aligned: centred ragged text
     at this size is hard to read across long lines. */
  .hero-inner{ max-width:1150px; margin-inline:auto; }
  .hero-sub{ font-size:1.34rem; max-width:58ch; }

  .stat b{ font-size:3.1rem; }
}

@media (min-width:1900px){
  :root{ --maxw:1560px; }

  h1{ font-size:clamp(6rem, 5.2vw, 7.2rem); }
  h2{ font-size:3.6rem; }
  .lead{ font-size:1.28rem; }
  .hero-inner{ max-width:1300px; }
  .hero-sub{ font-size:1.46rem; }
  .stat b{ font-size:3.6rem; }
}

/* Ultrawide: stop widening the text column. Past roughly 1700px a line
   of body copy becomes tiring to read because the eye loses the start of
   the next line, so the container holds and only the type keeps growing. */
@media (min-width:2400px){
  :root{ --maxw:1700px; }
  h1{ font-size:7.6rem; }
  .hero-inner{ max-width:1440px; }
}
