/* ============================================================
   DJ AG - AG Community sign-up

   PALETTE CHANGE 2026-08-03 (v11). The first build derived its colour
   from the cut-out itself: navy jacket, orange embroidery, cobalt
   shirt, on a near-black field. The client kept the layout but asked
   for it lighter and in AG Fest's colours, so the page now runs on
   the AG Fest system instead of the jacket.

   It took three passes to land, and the two rejected ones are worth
   recording because they are the obvious things to try again:

     v10  whole page on AG Fest's light grey #F4F4F4  -> "it's too white"
     v11a purple field, WHITE signup card             -> "don't use white,
                                                         use purple and a
                                                         muted yellow"

   So: purple IS the page, the card is a lighter purple, and the accent
   is a muted yellow. AG Fest has no yellow of its own - its accent is
   the lime #85D000 off the FAQ pills - so #E8C547 is chosen to sit with
   #9B6CFF rather than sampled. Everything else is an AG Fest hex.

   CARD LIGHTENED 2026-08-04 (v12). The client asked for the sign-up box
   type to be black "so it reads better than white". Black on the old
   plum card is 2.7:1, i.e. WORSE than the cream it would replace, so the
   ask was answered by re-grounding the card rather than by recolouring
   the type on it: the card is the light lilac #EFE7FF and the type is
   ink. This is NOT a return to the rejected v11a white card - it is a
   tint of the field's own purple, chosen from a side-by-side render.

     --purple   #9B6CFF  AG Fest primary - the field
     --lilac    #EFE7FF  the card, a light tint of the field
     --plum     #6B3FE0  the card's accent: eyebrow, links, focus ring
     --yellow   #E8C547  muted yellow - the CTA block and the thread
     --cream    #FBF6E9  type on purple. Not white: warm, and it is what
                         keeps the page off the "too white" note above
     --ink      #1C1C1C  AG Fest near-black - borders, footer, card type

   CONTRAST, because purple is now everywhere and it is a trap. On
   #9B6CFF: ink is 4.8:1 (safe at any size), cream is 3.5:1 (DISPLAY
   TYPE ONLY), yellow is 2.1:1 (never text, blocks only). On the card
   #EFE7FF: ink is 14.2:1, plum is 5.1:1 (safe at any size), yellow is
   1.7:1 (NEVER type on this card - solid blocks under ink only, which
   is why the CTA still works). Check any new colour against both
   grounds before using it.

   The AG Fest component idiom comes with the palette: 3px ink borders
   and hard offset shadows (`6px 6px 0`), no blur, no glass. If you are
   adding a component, that is the house style - match it.

   Signature kept: "the thread", a continuous stitch that draws itself
   in once on load. It was the orange embroidery lifted off the jacket;
   here it is the lighter purple and the yellow, and it is the same
   argument - a community is a line that connects people.

   Display face is Mango Grotesque, the AG Fest brand face, because
   the copy promises AG Fest news and the type should already sound
   like it.
   ============================================================ */

/* Mango Grotesque - AG Fest brand face (same client, same brand) */
@font-face {
  font-family: "Mango Grotesque";
  src: url("/assets/fonts/MangoGrotesque-Medium.woff2?v=20260804-12") format("woff2");
  font-weight: 500; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Mango Grotesque";
  src: url("/assets/fonts/MangoGrotesque-Bold.woff2?v=20260804-12") format("woff2");
  font-weight: 700; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Mango Grotesque";
  src: url("/assets/fonts/MangoGrotesque-Black.woff2?v=20260804-12") format("woff2");
  font-weight: 900; font-style: normal; font-display: swap;
}
/* Archivo (OFL) - one variable file covers the whole weight range */
@font-face {
  font-family: "Archivo";
  src: url("/assets/fonts/Archivo-var.woff2?v=20260804-12") format("woff2");
  font-weight: 100 900; font-style: normal; font-display: swap;
}

:root {
  --purple:     #9B6CFF;   /* AG Fest primary - the field */
  --purple-lt:  #AE93FF;   /* AG Fest's own lighter cut - the top-left lift */
  --purple-dk:  #7A45F0;   /* the field's bottom-right fall */
  --plum:       #6B3FE0;   /* card accents: eyebrow, links, the focus ring */
  --plum-dk:    #4E27B8;   /* reserved - no longer paints the input rows */

  /* The signup card ground, lightened 4 Aug 2026 at the client's request so
     the card type could go true black. Still the purple family (a tint of
     --purple), deliberately NOT white: the client rejected a white card in
     v11a. See the card contrast table below. */
  --lilac:      #EFE7FF;   /* the signup card */
  --lilac-fld:  #FDFBF4;   /* input rows inside the card */

  /* Every piece of type inside the card resolves through this one token, so
     the card can be re-grounded without hunting individual rules. It was
     --cream while the card was plum; it is ink now. Type OUTSIDE the card
     (brand column, footer) still uses --cream and must not be swept in. */
  --card-fg:    var(--ink);

  --yellow:     #E8C547;   /* muted yellow - CTA, highlights, the thread */
  --yellow-lt:  #F2D77A;
  --cream:      #FBF6E9;   /* type on purple. Deliberately NOT #FFFFFF */
  --ink:        #1C1C1C;   /* borders, the footer, type on the light purple */

  /* Two grounds, two sets of secondary type colours. Ink on the field
     (4.8:1), ink on the card (14.2:1). Nothing here may go lower.

     The -c pair used to be cream-on-plum. Since the card went light they are
     ink alphas, measured on --lilac: muted 9.7:1, faint 4.5:1. On the cream
     input rows the faint alpha is 4.7:1, so placeholders still clear AA. */
  --muted:      rgba(28, 28, 28, 0.84);    /* on --purple */
  --faint:      rgba(28, 28, 28, 0.64);    /* on --purple */
  --muted-c:    rgba(28, 28, 28, 0.86);    /* on --lilac */
  --faint-c:    rgba(28, 28, 28, 0.62);    /* on --lilac */

  /* Error text sits on the light card now, so it is a true dark red rather
     than the old light coral (which was a dark-ground device and would sit
     at 1.6:1 here). 5.5:1 on #EFE7FF, and still the only warm-red on the
     page so it reads as an error at a glance. */
  --err:        #B3261E;

  --panel-bg:   var(--lilac);
  --field-bg:   var(--lilac-fld);
  --field-brd:  rgba(28, 28, 28, 0.34);
  /* Chrome's autofill box-shadow needs an OPAQUE colour, and it must be the
     FLATTENED equivalent of the field stack, not the field's own rgba, or
     autofilled rows won't match the empty ones beside them. The rows are a
     solid colour here, so it is simply --lilac-fld. */
  --field-flat: #FDFBF4;

  /* Rules inside the card. Ink alpha since the card went light. */
  --hair:       rgba(28, 28, 28, 0.26);

  --font:       "Archivo", "Helvetica Neue", Helvetica, Arial, sans-serif;
  --font-disp:  "Mango Grotesque", "Archivo", Helvetica, Arial, sans-serif;
}

* { box-sizing: border-box; }

/* html carries the base colour; body stays transparent so it never paints
   over the z-index:-1 background layers. */
html {
  background: var(--purple);
  -webkit-text-size-adjust: 100%;
}

/* No sideways scroll on a phone (Adam, 2026-08-03).

   The culprit is the decorative thread: the SVG is viewBox 0 0 1440 900 with
   preserveAspectRatio="slice", so on a tall narrow viewport it scales to
   COVER and its paths run from about -389 to +889 on a 500px-wide screen.
   The <svg> box itself is viewport-sized and desktop browsers clip it, but
   the overflow is real geometry and mobile Safari will hand you a horizontal
   scroll for it.

   Belt and braces, because a page with one column and a fixed background has
   nothing legitimate to scroll sideways: clip at the root AND at the svg, and
   kill the iOS rubber-band with overscroll-behavior-x. No sticky positioning
   anywhere on this page, which is the one thing overflow-x would break. */
html, body {
  max-width: 100%;
  overflow-x: hidden;
  overscroll-behavior-x: none;
}
/* body owns the page-height column so the footer can sit full-bleed outside
   the padded sheet, the way it does on basslayerz. */
body {
  margin: 0;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  background: transparent;
  color: var(--ink);
  font-family: var(--font);
  font-size: 16px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

img { max-width: 100%; }
a { color: inherit; }

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

:focus-visible {
  outline: 3px solid var(--yellow);
  outline-offset: 3px;
  border-radius: 2px;
}
/* The keyboard ring is yellow because the page is purple. Inside the card,
   which is light since v12, yellow falls to 1.7:1 and stops being a ring at
   all - plum is 5.1:1 on that ground. Same ring, correct ground. */
.panel :focus-visible { outline-color: var(--plum); }

/* ============================================================
   Background: the AG Fest purple, plus the thread
   ============================================================ */

.bg {
  position: fixed;
  inset: 0;
  z-index: -2;
  /* A flat #9B6CFF across a whole viewport goes plasticky, so the field
     gets a lighter lift top-left, a deeper fall bottom-right and one weak
     yellow wash - the same three-layer recipe as the navy build,
     re-pointed at the AG Fest hues. */
  background:
    radial-gradient(120% 78% at 22% 8%, rgba(174, 147, 255, 0.65) 0%, transparent 62%),
    radial-gradient(96% 70% at 84% 96%, rgba(232, 197, 71, 0.22) 0%, transparent 58%),
    linear-gradient(168deg, var(--purple) 0%, var(--purple) 44%, var(--purple-dk) 100%);
}

/* The thread: the signature. Draws itself in once, then stops. */
.thread {
  position: fixed;
  inset: 0;
  z-index: -1;
  width: 100%;
  height: 100%;
  pointer-events: none;
  opacity: 0.6;
  /* Explicit, not relying on the UA's svg:root default - see the note on
     html/body above. This is the element whose paths overflow. */
  overflow: hidden;
}
.thread path {
  fill: none;
  stroke: var(--cream);
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-dasharray: 3000;
  stroke-dashoffset: 3000;
  animation: stitch 5.4s cubic-bezier(.35, .1, .2, 1) forwards;
  vector-effect: non-scaling-stroke;
}
/* The middle stitch is the yellow one. One line, not all three - the
   accent works because it is rationed. */
.thread path:nth-child(2) { animation-delay: .5s;  opacity: .9;  stroke: var(--yellow); stroke-width: 2.1; }
.thread path:nth-child(3) { animation-delay: 1.0s; opacity: .55; }

@keyframes stitch { to { stroke-dashoffset: 0; } }

@media (prefers-reduced-motion: reduce) {
  .thread path { animation: none; stroke-dashoffset: 0; }
}

/* ============================================================
   Sheet / stage
   ============================================================ */

.sheet {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  padding: clamp(14px, 2.6vw, 30px);
}

.stage {
  flex: 1 1 auto;
  display: flex;
  min-height: 0;
}
.stage__inner {
  width: 100%;
  max-width: 1240px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: clamp(20px, 3.4vw, 34px);
  min-height: 0;
}

/* ============================================================
   Brand column - sits on the purple field, so it is ink type
   ============================================================ */

.brand {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  min-width: 0;
}

/* The mark is served in TWO colourways: ag-mark.png is white (it was drawn
   for the old near-black field) and ag-mark-dark.png is the same file
   tinted #1C1C1C, which is what the purple field needs. Swapping the
   palette back means swapping the src in index.html back - CSS cannot
   recolour the opaque pixels of a PNG. */
.brand__mark {
  width: clamp(52px, 9vw, 76px);
  height: auto;
  margin-bottom: clamp(12px, 2vw, 18px);
}

.brand__title {
  margin: 0;
  font-family: var(--font-disp);
  font-weight: 900;
  font-size: clamp(2.8rem, 12.5vw, 4.6rem);
  line-height: 0.86;
  letter-spacing: 0.005em;
  text-transform: uppercase;
  text-wrap: balance;
  color: var(--ink);
}
/* Cream, not yellow: yellow on #9B6CFF is 2.1:1 and illegible even at
   4.6rem. Cream is 3.5:1, which display type at this weight can carry. */
.brand__title em {
  display: block;
  font-style: normal;
  color: var(--cream);
}

.brand__line {
  margin: clamp(14px, 2.4vw, 20px) 0 0;
  max-width: 46ch;
  font-size: clamp(0.95rem, 3.5vw, 1.05rem);
  line-height: 1.6;
  color: var(--muted);
}

/* Second paragraph (client copy, 2026-08-03). Same measure as the line
   above it so the two read as one block; the AG Fest mention is the only
   thing lifted out, because that is what the paragraph is for. */
.brand__note {
  margin: 0.7rem 0 0;
  max-width: 46ch;
  font-size: clamp(0.9rem, 3.3vw, 0.98rem);
  line-height: 1.6;
  color: var(--muted);
}
/* Underline rather than a colour change: there is no colour that both
   reads as a highlight on the purple AND clears 4.5:1 at 0.98rem. */
.brand__note strong {
  font-weight: 800;
  color: var(--ink);
  text-decoration: underline;
  text-decoration-color: var(--yellow);
  text-decoration-thickness: 3px;
  text-underline-offset: 3px;
}

/* The three things you get. A set, not a sequence, so no 01/02/03 -
   just the words, separated by a stitch-coloured tick. */
.brand__gets {
  list-style: none;
  margin: clamp(14px, 2.4vw, 20px) 0 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.4rem 0.9rem;
  font-family: var(--font-disp);
  font-weight: 700;
  font-size: clamp(0.9rem, 3.4vw, 1.05rem);
  letter-spacing: 0.10em;
  text-transform: uppercase;
  color: var(--ink);
}
.brand__gets li {
  display: flex;
  align-items: center;
  gap: 0.9rem;
}
/* The dots are a block, not type, so the yellow is safe here - and this is
   the one place the accent appears in the brand column. */
.brand__gets li + li::before {
  content: "";
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--yellow);
  border: 1px solid var(--ink);
  flex: none;
}

/* Hero cut-out.

   History worth keeping, because it constrains this rule: the FIRST artwork had
   the DJ AG lockup baked in, running to 97.5% of the image height, so the fade
   that softens the crop edge was eating the client's own logotype (Adam,
   2026-08-03). Adam then supplied a logo-free cut-out, which removes the
   constraint entirely - the brand mark now lives once, above the headline, and
   the photograph is free to dissolve.

   So: if this image is ever swapped back for one with a lockup burned in, this
   mask has to go with it.

   The cut-out is a real alpha cut-out, so it composites onto whatever is
   behind it - checked against the purple before this palette was committed.
   The jacket is navy and the field is purple, which is the one weak point of
   this colourway: the separation comes from the orange embroidery and the
   mask, not from the value difference. Do not darken the field further. */
.brand__hero {
  display: block;
  width: auto;
  max-width: 100%;
  height: auto;
  max-height: 34svh;
  margin: clamp(10px, 2vw, 18px) auto 0;
  object-fit: contain;
  object-position: bottom center;
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 62%, rgba(0,0,0,.55) 84%, transparent 100%);
          mask-image: linear-gradient(to bottom, #000 0%, #000 62%, rgba(0,0,0,.55) 84%, transparent 100%);
  /* A soft drop shadow does the separating that value cannot: it lifts the
     cut-out off a field that is close to the jacket in tone. */
  filter: drop-shadow(0 18px 26px rgba(35, 12, 82, 0.34));
}

/* ============================================================
   Signup panel

   AG Fest idiom: a flat colour block, a 3px ink border and a hard
   offset shadow. No blur, no translucency - the old build's glass
   panel was a dark-field device and reads as dirt on purple.
   ============================================================ */

.signup {
  display: flex;
  flex-direction: column;
  align-items: center;
  min-width: 0;
}

.panel {
  width: 100%;
  max-width: 430px;
  margin: 0 auto;
  /* isolate so no decorative layer can stack above the country dropdown */
  isolation: isolate;
  background: var(--panel-bg);
  border: 3px solid var(--ink);
  border-radius: 14px;
  box-shadow: 8px 8px 0 var(--ink);
  color: var(--card-fg);
}
.panel__inner {
  position: relative;
  z-index: 1;
  padding: clamp(20px, 4.6vw, 30px);
}

/* one state visible at a time */
.panel__state { display: none; }
.panel[data-form-state="idle"]    .panel__idle    { display: block; }
.panel[data-form-state="success"] .panel__success { display: block; }

/* The card accent is PLUM, not yellow. Yellow was the accent while the card
   was plum (3.7:1, headings only); on the light card it collapses to 1.7:1
   and is unusable as type. Plum on --lilac is 5.1:1, safe at any size, and
   it keeps the accent in the same family as the field. Yellow survives on
   this card only as a solid block behind ink: the CTA and the fest pill. */
.panel__eyebrow {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  margin: 0 0 0.7rem;
  font-family: var(--font-disp);
  font-weight: 700;
  font-size: 0.86rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--plum);
}
.panel__eyebrow-hair {
  flex: 1 1 auto;
  height: 2px;
  background: rgba(107, 63, 224, 0.34);
}
.panel__eyebrow span:not(.panel__eyebrow-hair) { flex: none; }

.panel__title {
  margin: 0;
  font-family: var(--font-disp);
  font-weight: 900;
  font-size: clamp(1.9rem, 7.4vw, 2.5rem);
  line-height: 0.92;
  letter-spacing: 0.005em;
  text-transform: uppercase;
  text-wrap: balance;
  color: var(--card-fg);
}
.panel__title em { font-style: normal; color: var(--plum); }

.panel__lede {
  margin: 0.8rem 0 0;
  font-size: 0.94rem;
  line-height: 1.58;
  color: var(--muted-c);
}
.panel__lede strong { color: var(--card-fg); font-weight: 700; }

/* ============================================================
   Form
   ============================================================ */

.form { margin-top: clamp(16px, 3vw, 22px); }
.form__row { margin-bottom: 0.85rem; }

/* Labels stay for screen readers; placeholders carry the meaning visually. */
.form__label {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}

.form__input {
  width: 100%;
  padding: 0.8rem 0.9rem;
  background: var(--field-bg);
  border: 2px solid var(--field-brd);
  border-radius: 8px;
  color: var(--card-fg);
  font-family: var(--font);
  font-size: 1rem;   /* 16px floor, or iOS zooms the page on focus */
  line-height: 1.3;
  transition: border-color .16s ease, box-shadow .16s ease;
}
.form__input::placeholder { color: var(--faint-c); }
.form__input:hover { border-color: var(--card-fg); }
.form__input:focus {
  outline: none;
  border-color: var(--plum);
  box-shadow: 3px 3px 0 var(--plum);
}

/* Chrome paints autofilled fields pale lavender and ignores `background`.
   The only override that holds is a huge inset shadow, and its colour must
   be the FLATTENED opaque equivalent of the field (--field-flat), or
   autofilled rows won't match the empty ones beside them.

   NOTE the trade-off: this inset shadow occupies the same property as the
   focus offset block above, so an autofilled field does not draw it. The
   border still turns yellow on focus, and losing the block is better than
   losing the fill. */
.form__input:-webkit-autofill,
.form__input:-webkit-autofill:hover,
.form__input:-webkit-autofill:focus,
.form__input:-webkit-autofill:active {
  -webkit-box-shadow: 0 0 0 1000px var(--field-flat) inset !important;
          box-shadow: 0 0 0 1000px var(--field-flat) inset !important;
  -webkit-text-fill-color: var(--card-fg) !important;
  caret-color: var(--card-fg);
  transition: background-color 9999s ease-in-out 0s;
}

/* Optional field gets a visible hint, since a blank row with no label
   otherwise reads as something the user has failed to fill in. */
.form__hint {
  margin: 0.35rem 0 0;
  font-size: 0.74rem;
  line-height: 1.4;
  color: var(--faint-c);
}

/* Honeypot: display:none, never off-screen. Chrome/Edge autofill fills
   off-screen fields and silently kills real signups. */
.hp-row { display: none !important; }

.form__row--check { margin-top: 1.05rem; }

.form__check {
  display: flex;
  align-items: flex-start;
  gap: 0.65rem;
  cursor: pointer;
  font-size: 0.8rem;
  line-height: 1.5;
  color: var(--muted-c);
}
.form__check input {
  flex: none;
  width: 17px; height: 17px;
  margin: 0.14rem 0 0;
  accent-color: var(--plum);
  cursor: pointer;
}
.form__check a { color: var(--plum); font-weight: 600; text-underline-offset: 2px; }
.form__check a:hover { color: var(--plum-dk); }

.form__error {
  margin: 0.4rem 0 0;
  font-size: 0.78rem;
  font-weight: 700;
  line-height: 1.4;
  color: var(--err);
}
.form__error--global { margin-top: 0.7rem; text-align: center; }

/* ============================================================
   Buttons
   ============================================================ */

.btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  width: 100%;
  margin-top: 1.15rem;
  padding: 0.92rem 1rem;
  border: 3px solid var(--ink);
  border-radius: 10px;
  font-family: var(--font-disp);
  font-weight: 900;
  font-size: clamp(0.95rem, 3.6vw, 1.1rem);
  letter-spacing: clamp(.06em, .5vw, .14em);
  text-transform: uppercase;
  text-decoration: none;
  text-align: center;
  white-space: nowrap;      /* shrink the type before it is ever allowed to wrap */
  cursor: pointer;
  transition: transform .12s ease, box-shadow .12s ease, filter .16s ease;
}
.btn[disabled] { opacity: .6; cursor: default; }

/* The AG Fest ticket button, borrowed wholesale, in the muted yellow:
   a solid block, an ink border, and a hard shadow that deepens on hover
   and collapses on press. Ink on yellow is 10:1, the strongest pairing
   anywhere on the page, which is what the one CTA should be. */
.btn--primary {
  background: var(--yellow);
  color: var(--ink);
  box-shadow: 5px 5px 0 var(--ink);
}
.btn--primary:hover:not([disabled]) {
  transform: translate(-2px, -2px);
  box-shadow: 7px 7px 0 var(--ink);
  background: var(--yellow-lt);
}
.btn--primary:active:not([disabled]) {
  transform: translate(2px, 2px);
  box-shadow: 2px 2px 0 var(--ink);
}

/* ============================================================
   Success state
   ============================================================ */

.panel__success-note {
  margin: 0.8rem 0 0;
  font-size: 0.94rem;
  line-height: 1.58;
  color: var(--card-fg);
  font-weight: 600;
}

/* State-scoped p rules must exclude the eyebrow, or they out-specify it
   and it renders at the wrong size. */
.panel__success p:not(.panel__eyebrow) { text-wrap: pretty; }

.panel__follow {
  margin: 1.3rem 0 0;
  padding-top: 1.1rem;
  border-top: 2px solid var(--hair);
}
.panel__follow-title {
  margin: 0 0 0.75rem;
  font-family: var(--font-disp);
  font-weight: 700;
  font-size: 0.78rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--plum);
}

/* The success pills sit on the light card, not on the ink footer, so they
   get their own colourway. */
.panel__follow .social__link {
  border-color: var(--hair);
  color: var(--card-fg);
}
.panel__follow .social__link:hover {
  background: var(--yellow);
  border-color: var(--yellow);
  color: var(--ink);
}
.panel__follow .social__link--fest {
  background: var(--yellow);
  border-color: var(--yellow);
  color: var(--ink);
}
.panel__follow .social__link--fest:hover {
  background: var(--yellow-lt);
  border-color: var(--yellow-lt);
}

/* ============================================================
   Footer

   Fleet-standard footer bar (basslayerz shape): full-bleed, tinted,
   hairline top rule. Left group = copyright + the built-by pill, right
   = privacy, with the social row between them. Three groups instead of
   two, so it wraps to centred on narrow viewports rather than stranding
   the middle one.

   It is the ink bar, like AG Fest's own footer. On a page that is purple
   from edge to edge this is the only thing giving the layout a floor,
   and it is where the white Furiosa credit mark stays legible.
   ============================================================ */

.foot {
  flex: 0 0 auto;
  width: 100%;
  margin: 0;
  padding: 16px clamp(16px, 4vw, 40px) 22px;
  background: var(--ink);
  border-top: 3px solid var(--ink);
  color: var(--cream);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 14px 20px;
}
.foot__left {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px 18px;
}

.social {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.55rem;
  list-style: none;
  margin: 0;
  padding: 0;
}
.social__link {
  display: inline-flex;
  align-items: center;
  gap: 0.42rem;
  padding: 0.42rem 0.68rem;
  border: 2px solid rgba(251, 246, 233, 0.30);
  border-radius: 999px;
  color: var(--cream);
  text-decoration: none;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  white-space: nowrap;
  transition: color .16s ease, border-color .16s ease, background-color .16s ease;
}
.social__link:hover {
  background: var(--purple);
  border-color: var(--purple);
  color: var(--ink);
}
.social__link svg { width: 15px; height: 15px; flex: none; }

/* AG Fest is a different destination from DJ AG's own channels, so it is
   labelled rather than left as a second unlabelled Instagram glyph nobody
   can tell apart from the first. It also carries the AG Fest purple, which
   is the fastest way to say "this one is the festival". */
.social__link--fest {
  background: var(--purple);
  border-color: var(--purple);
  color: var(--ink);
}
.social__link--fest:hover {
  background: var(--yellow);
  border-color: var(--yellow);
}

.foot__legal {
  margin: 0;
  font-size: 12px;
  letter-spacing: .02em;
  color: rgba(251, 246, 233, 0.72);
}
.foot__legal a { color: rgba(251, 246, 233, 0.72); text-decoration: none; }
.foot__legal a:hover { color: var(--yellow); }

/* The built-by credit is a pill, matching the fleet footer. The Furiosa
   mark is a white-on-transparent PNG and the footer is ink, so it needs
   no inversion here - it would on any light footer. */
.site-built { margin: 0; }
.site-built a {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 5px 11px;
  border: 2px solid rgba(251, 246, 233, 0.24);
  border-radius: 999px;
  font-size: 11px;
  letter-spacing: .04em;
  color: rgba(251, 246, 233, 0.72);
  text-decoration: none;
  transition: color .16s ease, border-color .16s ease;
}
.site-built a:hover { border-color: var(--yellow); color: var(--cream); }
.site-built img { display: block; opacity: .9; }

/* Narrow viewports: everything centres rather than leaving the middle group
   marooned against one edge. */
@media (max-width: 700px) {
  .foot { justify-content: center; text-align: center; }
  .foot__left { justify-content: center; }
  .foot .social { justify-content: center; }
}

/* ============================================================
   intl-tel-input
   ============================================================ */

/* The vendor stylesheet owns the hidden state; until it loads, the whole
   country list paints open on the first frame. */
.iti__dropdown-content.iti__hide { display: none !important; }

.iti { width: 100%; display: block; }
.iti__country-container { z-index: 3; }
.iti__country-list,
.iti__dropdown-content {
  /* The dropdown renders INSIDE the card (no dropdownContainer is set), so
     it follows the card's ground, not the old dark one. */
  background: var(--lilac-fld);
  border: 2px solid var(--ink);
  border-radius: 8px;
  color: var(--card-fg);
  text-align: left;
}
.iti__country { padding: 8px 10px; }
.iti__country.iti__highlight,
.iti__country:hover { background: rgba(107, 63, 224, 0.16); }
.iti__dial-code { color: var(--faint-c); }
.iti__search-input {
  width: 100%;
  /* The horizontal padding is NOT free to choose: the vendor absolutely
     positions .iti__search-icon at left:8px and .iti__search-clear at right:4px
     and reserves 30px/28px of padding to clear them. A shorthand `padding: 9px
     10px` wipes that out and the magnifying glass sits on top of the word
     "Search" (Adam, 2026-08-03). Set the vertical padding only, and keep the
     reserved horizontal room. */
  padding: 9px 30px 9px 32px;
  background: #F5F0FF;
  border: 0;
  border-bottom: 2px solid rgba(28, 28, 28, 0.26);
  color: var(--card-fg);
  font-family: var(--font);
  font-size: 0.95rem;
}
.iti__search-input::placeholder { color: var(--faint-c); }
.iti__selected-country { border-radius: 6px 0 0 6px; }
.iti__selected-country:hover,
.iti__selected-country-primary:hover { background: rgba(28, 28, 28, 0.07); }

/* ============================================================
   Wide layout: two columns.

   Gated on aspect ratio, not width alone - width-only breakpoints leave
   squarish desktop windows (~570-900px) in a gap where neither the phone
   nor the desktop treatment applies.
   ============================================================ */

@media (min-width: 768px) and (min-aspect-ratio: 7/10) {
  .sheet { padding: clamp(20px, 2.4vw, 34px); }

  .stage__inner {
    flex-direction: row;
    align-items: stretch;
    gap: clamp(28px, 4.4vw, 64px);
  }

  .brand {
    flex: 1 1 54%;
    align-items: flex-start;
    text-align: left;
    /* flex-START, not flex-end: the artwork is the first item in this column, so
       any slack must fall to the BOTTOM and let the photo ride up to the top of
       the stage. With flex-end the slack sat above the photo and pushed it down
       (Adam: "move it up on desktop", 2026-08-03). It is also the safer failure
       mode - overflow now scrolls instead of clipping the top of his head. */
    justify-content: flex-start;
    min-height: 0;
  }
  /* Everything below is a vertical-budget decision. The brand column is already
     the full height of the stage, so the ONLY way to make the photo bigger
     without introducing a scrollbar is to spend less height on the type.

     I briefly dropped the gets row here to buy that height; Adam asked for it
     back (2026-08-03), so the height comes out of the photo cap instead - see
     the calc() on .brand__hero below, which is derived from what these blocks
     actually measure rather than from a guessed svh fraction. */
  .brand__gets { justify-content: flex-start; }
  .brand__line { margin-top: clamp(14px, 1.5vw, 18px); }
  .brand__mark { width: 52px; margin-bottom: 10px; }
  /* Sized so three lines of h1 plus both paragraphs and the photo all clear
     the fold at 1440x900. Raising this re-opens the overflow described below. */
  .brand__title { font-size: clamp(2.8rem, 5vw, 4.4rem); }

  /* The photo sits above the headline on wide screens, but it must NOT grow
     into all the leftover height: with `flex: 1 1 auto` and no cap it pushed
     the h1 clean below the fold at 1440x900 (caught on the live 2026-08-03
     deploy). Height-cap it and let the type own the rest of the column. */
  .brand__hero {
    order: -1;
    flex: 0 1 auto;
    min-height: 0;
    width: auto;
    max-width: 100%;
    /* This is an UPPER bound, not the operating size. `flex: 0 1 auto` with
       `min-height: 0` lets the photo shrink to whatever the column has left,
       and the column height is set by the signup panel opposite (both columns
       are `align-items: stretch`), not by the artwork.

       Consequence: raising this cap is safe - it only lets big screens use the
       room they actually have. What is NOT safe is removing the shrink
       (`flex: 1 1 auto` with no cap), which pushed the h1 below the fold on the
       first live deploy. */
    /* Derived, not guessed, and RE-derived for v11: the column was ~386px of
       type (mark 62 + h1 182 + lede 99 + gets 43) against `100svh - 540px`.
       The client's second paragraph adds ~68px (two lines plus its margin), so
       the subtrahend goes to 610px. Leave the 200px floor and the 380px ceiling
       alone - 211px read as too small to Adam and 472px as too big, and the
       ceiling is what stops 1080p overshooting. */
    max-height: clamp(200px, calc(100svh - 610px), 380px);
    margin: 0 0 clamp(12px, 1.6vw, 20px);
    object-position: bottom left;
  }

  .signup {
    flex: 0 1 430px;
    justify-content: center;
  }
  /* margin stays `0 auto`, never a bare `0` - a bare 0 left-shifts the panel */
  .panel { margin: 0 auto; }
}

@media (min-width: 1100px) and (min-aspect-ratio: 7/10) {
  .brand__hero { max-width: 640px; }
}

/* ============================================================
   Landscape phone. A rotated handset (844x390, 932x430, 667x375)
   satisfies the width + aspect conditions above but has almost no
   height, so the wide layout renders cramped. Placed AFTER the
   desktop blocks so it wins at equal specificity.
   ============================================================ */

@media (min-width: 640px) and (min-aspect-ratio: 7/10) and (max-height: 520px) {
  .sheet { padding: 12px 16px; }

  .stage__inner {
    flex-direction: row;
    align-items: start;
    gap: 20px;
    min-height: 0;
  }

  .brand {
    flex: 1 1 auto;
    justify-content: flex-start;
    min-height: 0;
  }
  .brand__mark { width: 40px; margin-bottom: 8px; }
  .brand__title { font-size: clamp(1.9rem, 5vw, 2.6rem); }
  .brand__line {
    margin-top: 8px;
    font-size: 0.82rem;
    line-height: 1.45;
    max-width: 42ch;
  }
  /* The AG Fest paragraph is the first thing to go on a 390px-high handset -
     the panel opposite it is the point of the page, and the same promise is
     still made in the panel lede. */
  .brand__note { display: none; }
  .brand__gets {
    margin-top: 9px;
    font-size: 0.72rem;
    letter-spacing: 0.06em;
    gap: 0.3rem 0.7rem;
  }

  /* The cut-out becomes a small height-capped anchor rather than a
     column-filling element with no column height to fill. */
  .brand__hero {
    order: 0;
    flex: 0 1 auto;
    width: auto;
    max-width: 42%;
    max-height: calc(100svh - 200px);
    margin: 10px 0 0;
    object-position: bottom left;
  }

  .signup { flex: 0 1 360px; }
  .panel { box-shadow: 5px 5px 0 var(--ink); }
  .panel__inner { padding: 16px 18px; }
  .panel__title { font-size: 1.5rem; }
  .panel__lede { display: none; }   /* the brand column already carries the pitch */
  .form { margin-top: 12px; }
  .form__row { margin-bottom: 0.6rem; }
  .form__input { padding: 0.58rem 0.8rem; }
  .form__hint { display: none; }
  .btn { margin-top: 0.85rem; padding: 0.72rem 1rem; }
  .foot { padding: 9px 16px 11px; gap: 8px 14px; }
  .foot .social__link { padding: 0.3rem 0.5rem; font-size: 0.66rem; }
}

/* Very short landscape (375-high handsets): drop the photo rather than ship
   a 60px sliver of someone's chin. */
@media (min-width: 640px) and (min-aspect-ratio: 7/10) and (max-height: 400px) {
  .brand__hero { display: none; }
  .brand__gets { display: none; }
}
