/* House of Anna Couture — coming soon
   Palette sampled from the studio backdrop and the gold of the logo. See DESIGN.md. */

:root {
  --ink: #1e2a30;
  --ink-deep: #141d22;
  --ink-soft: #27353c;
  --gold: #c9a24a;
  --gold-light: #e3c67e;
  --ivory: #f3efe6;
  --ivory-dim: rgba(var(--fg-rgb), .62);
  --rule: rgba(var(--gold-rgb), .28);
  --error: #e8a0a0;

  /* The three colours the page mixes its translucent layers from. Swapping these three
     lines is what turns the whole page over to the ivory theme below. */
  --fg-rgb: 243, 239, 230;
  --gold-rgb: 201, 162, 74;
  --ink-rgb: 30, 42, 48;
}

/* Ivory theme — the same page on a light ground. Opened with ?theme=ivory.
   Gold has to go darker here: the dark theme's #c9a24a sits at about 2:1 against ivory,
   which is unreadable for text. */
:root[data-theme="ivory"] {
  --ink: #f5f0e6;
  --ink-deep: #ebe3d4;
  --ink-soft: #efe9dc;

  --gold: #75581a;
  --gold-light: #5d4614;
  --ivory: #23313a;
  --ivory-dim: rgba(var(--fg-rgb), .8);
  --rule: rgba(var(--gold-rgb), .34);
  --error: #9c3030;

  --fg-rgb: 35, 49, 58;
  --gold-rgb: 117, 88, 26;
  --ink-rgb: 245, 240, 230;

  --display: "Cormorant Garamond", Georgia, serif;
  --body: "Jost", "Helvetica Neue", Arial, sans-serif;

  --gutter: 24px;
  --measure: 34rem;
  --ease: cubic-bezier(.2, .7, .3, 1);
  /* Slow out, barely any overshoot — couture moves without hurrying. */
  --ease-silk: cubic-bezier(.16, 1, .3, 1);
}

html { scroll-behavior: smooth; }

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--ink);
  color: var(--ivory);
  font-family: var(--body);
  font-weight: 300;
  font-size: 16px;
  line-height: 1.65;
  overflow-x: hidden;
}

img { display: block; max-width: 100%; height: auto; }

a { color: inherit; }

::selection { background: var(--gold); color: var(--ink-deep); }

:focus-visible {
  outline: 2px solid var(--gold-light);
  outline-offset: 3px;
}

.sr-only {
  position: absolute; width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  clip: rect(0 0 0 0); clip-path: inset(50%);
  overflow: hidden; white-space: nowrap;
}

.skip-link {
  position: absolute; left: var(--gutter); top: -4rem; z-index: 10;
  padding: .6rem 1rem;
  background: var(--gold); color: var(--ink-deep);
  font-size: .8rem; letter-spacing: .08em; text-transform: uppercase;
  text-decoration: none;
  transition: top .2s var(--ease);
}
.skip-link:focus { top: var(--gutter); }

/* Page furniture ------------------------------------------------------- */

/* A gold hairline that fills as you read down the page. */
.progress {
  position: fixed;
  inset: 0 0 auto;
  height: 2px;
  z-index: 9;
  pointer-events: none;
}

.progress span {
  display: block;
  height: 100%;
  width: 0;
  background: linear-gradient(to right, rgba(var(--gold-rgb), .25), var(--gold-light));
  transform-origin: left;
}

/* A whisper of film grain. Without it a flat dark page looks like a screen;
   with it, it looks like paper. */
.grain {
  position: fixed;
  inset: 0;
  z-index: 8;
  pointer-events: none;
  opacity: .035;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* Ivory adjustments ---------------------------------------------------- */

/* Grain reads as dirt on a pale ground, so it is barely there. */
:root[data-theme="ivory"] .grain { opacity: .02; }

/* Faint greys survive on a dark ground and disappear on a pale one — the footer line was
   sitting at 1.75:1 against ivory, which is not readable at all. Every one of these is
   lifted to clear 4.5:1. */
:root[data-theme="ivory"] .notify__note,
:root[data-theme="ivory"] .notify__interest-label,
:root[data-theme="ivory"] .hero__scroll { color: rgba(var(--fg-rgb), .74); }

:root[data-theme="ivory"] .foot__legal { color: rgba(var(--fg-rgb), .74); }
:root[data-theme="ivory"] .notify__input::placeholder { color: rgba(var(--fg-rgb), .58); }
:root[data-theme="ivory"] .notify__input { background: rgba(255, 255, 255, .5); }
:root[data-theme="ivory"] .notify__interest label span { border-color: rgba(var(--fg-rgb), .22); }

/* Pale gowns on pale paper need an edge, or they dissolve into the page. The hero is the
   exception: a line there would draw the rectangle we are trying to hide. */
:root[data-theme="ivory"] .looks__group img {
  box-shadow: 0 0 0 1px rgba(var(--gold-rgb), .18);
}

/* The gown was shot on a cool grey; the page is warm ivory. Fading all three visible
   edges into the page is what stops that difference reading as a pasted-on box. */
:root[data-theme="ivory"] .hero__media::after {
  background:
    linear-gradient(to right, var(--ink) 0%, rgba(var(--ink-rgb), .55) 12%, transparent 38%),
    linear-gradient(to bottom, var(--ink) 0%, transparent 14%),
    linear-gradient(to top, var(--ink) 0%, transparent 14%);
}

/* The wash over the photograph is lighter here: there is no dark ground for it to
   recover contrast from, and too much of it turns the gown grey. */
:root[data-theme="ivory"] .hero__media img { opacity: .42; }

/* Shared -------------------------------------------------------------- */

.eyebrow {
  margin: 0;
  font-size: .72rem;
  letter-spacing: .26em;
  text-transform: uppercase;
  color: var(--gold);
}

.section-title {
  position: relative;
  margin: 0 0 2.6rem;
  padding-bottom: 1.2rem;
  font-family: var(--display);
  font-weight: 300;
  font-size: clamp(1.9rem, 4vw, 2.7rem);
  letter-spacing: .01em;
}

/* The rule draws itself out from the left as the heading arrives. */
.section-title::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  width: 4rem;
  height: 1px;
  background: var(--gold);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 1.1s var(--ease-silk) .25s;
}

.section-title.is-revealed::after { transform: scaleX(1); }

/* Only hide what the script can bring back. Without JS the page reads as written. */
.js [data-reveal] {
  opacity: 0;
  transform: translateY(18px);
}
[data-reveal].is-revealed {
  opacity: 1;
  transform: none;
  transition: opacity 1.1s var(--ease-silk), transform 1.1s var(--ease-silk);
}

/* Line reveal: each line rises out from behind its own edge, the way a
   garment drops when it is unpinned. */
.js [data-lines] .line {
  display: block;
  overflow: hidden;
  /* Room for descenders and the italic's tail, which the clip would otherwise cut. */
  padding-bottom: .14em;
  margin-bottom: -.14em;
}

.js [data-lines] .line > span {
  display: block;
  /* Past 100% because the line box also carries the descender padding above —
     anything less leaves a sliver of the glyph tops showing. */
  transform: translateY(125%);
  transition: transform 1.25s var(--ease-silk);
}

.js [data-lines].is-revealed .line > span { transform: none; }
.js [data-lines].is-revealed .line:nth-child(2) > span { transition-delay: .12s; }

/* Hero ---------------------------------------------------------------- */

.hero {
  position: relative;
  min-height: 100svh;
  display: grid;
  /* The content row takes whatever is left, so the cue rides at the bottom when the
     hero is taller than its content and simply follows it when it is not. Pinning the
     cue absolutely looked right until the form grew and it landed on the fine print. */
  grid-template-rows: 1fr auto;
  align-items: center;
  padding: clamp(2rem, 5vh, 3.5rem) var(--gutter) 3rem;
  isolation: isolate;
  overflow: hidden;
}

.hero__media {
  position: absolute;
  inset: 0;
  z-index: -1;
  overflow: hidden;
}

/* The photograph settles in rather than appearing: a slow release of scale. */
.js .hero__media {
  opacity: 0;
  transform: scale(1.05);
  transition: opacity 1.6s var(--ease-silk), transform 2.4s var(--ease-silk);
}

.js .hero__media.is-revealed { opacity: 1; transform: none; }

/* <picture> is only a wrapper for the two sources; it must not become a box of its own
   or the sizing below would resolve against it instead of the frame. */
.hero__media picture { display: contents; }

.hero__media img {
  position: relative;
  top: -6%;
  width: 100%;
  height: 112%;
  object-fit: cover;
  /* On a phone the picture is a wash behind the words, so frame it on the brides rather
     than on the rafters above them. */
  object-position: 50% 34%;
  opacity: .3;
  /* --py is written by the scroll handler; the transition makes it trail
     the scroll by a beat instead of sticking to it. */
  transform: translate3d(0, var(--py, 0px), 0);
  transition: transform .5s cubic-bezier(.22, 1, .36, 1);
  will-change: transform;
}

/* A vignette so the text never fights the photograph. */
.hero__media::after {
  content: "";
  position: absolute;
  inset: 0;
  background:
    linear-gradient(to bottom, rgba(var(--ink-rgb), .55) 0%, rgba(var(--ink-rgb), .8) 55%, var(--ink) 100%),
    radial-gradient(120% 90% at 50% 40%, transparent 20%, rgba(20,29,34,.75) 100%);
}

.hero__inner {
  width: 100%;
  max-width: var(--measure);
  margin: 0 auto;
}

.hero__brand { margin-bottom: 1.1rem; }

.hero__logo {
  width: clamp(120px, 26vw, 152px);
  height: auto;
  /* The logo is gold artwork on transparency — a soft lift keeps it off the dark ground. */
  filter: drop-shadow(0 2px 14px rgba(0, 0, 0, .45));
}

.hero__title {
  margin: .8rem 0 1rem;
  font-family: var(--display);
  font-weight: 300;
  font-size: clamp(2.7rem, 10vw, 4.1rem);
  line-height: 1.02;
  letter-spacing: -.01em;
}

.hero__title em {
  font-style: italic;
  color: var(--gold-light);
}

.hero__lede {
  margin: 0 0 1.8rem;
  max-width: 30rem;
  color: var(--ivory-dim);
}

/* In flow by default. Three form fields make the hero taller than most phones,
   and a cue pinned to the bottom of the section lands on top of the form text. */
.hero__scroll {
  grid-column: 1 / -1;
  justify-self: center;
  margin-top: 1.8rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: .7rem;
  font-size: .62rem;
  letter-spacing: .3em;
  text-transform: uppercase;
  text-decoration: none;
  color: rgba(var(--fg-rgb), .35);
  transition: color .4s var(--ease);
}

.hero__scroll:hover { color: var(--gold); }

/* A thread that keeps being drawn downward. */
.hero__scroll i {
  display: block;
  width: 1px;
  height: 2.6rem;
  background: linear-gradient(to bottom, var(--gold), transparent);
  transform-origin: top;
  animation: thread 2.8s var(--ease-silk) infinite;
}

@keyframes thread {
  0%        { transform: scaleY(0); opacity: 0; }
  28%       { opacity: 1; }
  60%, 100% { transform: scaleY(1); opacity: 0; }
}

/* Form ---------------------------------------------------------------- */

.notify { margin: 0; }

.notify__hp { position: absolute; left: -9999px; }

.notify__grid {
  display: grid;
  gap: .6rem;
  max-width: 32rem;
}

.notify__field { margin: 0; }

.notify__input {
  width: 100%;
  min-width: 0;
  padding: .95rem 1.1rem;
  background: rgba(var(--fg-rgb), .05);
  border: 1px solid var(--rule);
  border-radius: 0;
  color: var(--ivory);
  font-family: var(--body);
  font-size: 1rem;
  transition: border-color .25s var(--ease), background .25s var(--ease);
}

.notify__input::placeholder { color: rgba(var(--fg-rgb), .38); }

.notify__input:hover { border-color: rgba(var(--gold-rgb), .5); }

.notify__input:focus {
  border-color: var(--gold);
  background: rgba(var(--fg-rgb), .08);
  outline: none;
}

.notify__button {
  position: relative;
  overflow: hidden;
  padding: 1rem 1.9rem;
  background: var(--gold);
  border: 1px solid var(--gold);
  border-radius: 0;
  color: var(--ink-deep);
  font-family: var(--body);
  font-size: .78rem;
  font-weight: 500;
  letter-spacing: .16em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background .4s var(--ease), border-color .4s var(--ease);
}

/* A light passes across the gold on hover, the way it would across satin. */
.notify__button::after {
  content: "";
  position: absolute;
  inset: 0 auto 0 -60%;
  width: 45%;
  background: linear-gradient(100deg, transparent, rgba(255, 255, 255, .55), transparent);
  transform: skewX(-18deg);
  transition: left .7s var(--ease-silk);
}

.notify__button:hover { background: var(--gold-light); border-color: var(--gold-light); }
.notify__button:hover::after { left: 115%; }

.notify__button-label { position: relative; z-index: 1; }

.notify__button[disabled] { opacity: .6; cursor: default; }
.notify__button[disabled]::after { display: none; }

.notify__interest {
  margin: 1.4rem 0 0;
  padding: 0;
  border: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .5rem;
}

.notify__interest-label {
  flex: 1 0 100%;
  margin-bottom: -.1rem;
  font-size: .72rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: rgba(var(--fg-rgb), .45);
}

.notify__interest label { cursor: pointer; }

.notify__interest input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

.notify__interest label span {
  display: inline-block;
  padding: .38rem .85rem;
  border: 1px solid rgba(var(--fg-rgb), .16);
  font-size: .78rem;
  color: var(--ivory-dim);
  transition: border-color .2s var(--ease), color .2s var(--ease), background .2s var(--ease);
}

.notify__interest label:hover span { border-color: rgba(var(--gold-rgb), .55); color: var(--ivory); }

.notify__interest input:checked + span {
  border-color: var(--gold);
  background: rgba(var(--gold-rgb), .14);
  color: var(--gold-light);
}

.notify__interest input:focus-visible + span {
  outline: 2px solid var(--gold-light);
  outline-offset: 3px;
}

.notify__note {
  margin: 1.2rem 0 0;
  font-size: .78rem;
  color: rgba(var(--fg-rgb), .4);
}

.notify__error {
  margin: .9rem 0 0;
  font-size: .82rem;
  color: var(--error);
}

/* Thank-you state ----------------------------------------------------- */

.thanks { max-width: 28rem; }

.thanks__mark {
  margin: 0 0 .6rem;
  font-size: 1.6rem;
  color: var(--gold);
}

.thanks__title {
  margin: 0 0 .8rem;
  font-family: var(--display);
  font-weight: 300;
  font-size: clamp(2rem, 6vw, 2.6rem);
}

.thanks__body { margin: 0; color: var(--ivory-dim); }
.thanks__body a { color: var(--gold-light); text-underline-offset: 3px; }

.thanks__fallback {
  margin: 1.1rem 0 0;
  padding-top: 1.1rem;
  border-top: 1px solid var(--rule);
  font-size: .84rem;
  color: rgba(var(--fg-rgb), .5);
}

.thanks__fallback a { color: var(--gold-light); text-underline-offset: 3px; }

/* What is being made --------------------------------------------------- */

.coming {
  max-width: 72rem;
  margin: 0 auto;
  padding: clamp(4rem, 10vh, 7rem) var(--gutter);
}

.coming__list {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 2.4rem;
}

.coming__list li {
  padding-top: 1.4rem;
  border-top: 1px solid var(--rule);
}

.coming__num {
  display: block;
  margin-bottom: .7rem;
  font-size: .7rem;
  letter-spacing: .22em;
  color: var(--gold);
}

.coming__list h3 {
  margin: 0 0 .5rem;
  font-family: var(--display);
  font-weight: 400;
  font-size: 1.45rem;
}

.coming__list p {
  margin: 0;
  font-size: .94rem;
  color: var(--ivory-dim);
}

/* Photo marquee -------------------------------------------------------- */

.looks {
  padding: 1rem 0 clamp(3rem, 8vh, 5rem);
  overflow: hidden;
  -webkit-mask-image: linear-gradient(to right, transparent, #000 8%, #000 92%, transparent);
          mask-image: linear-gradient(to right, transparent, #000 8%, #000 92%, transparent);
}

.looks__track {
  display: flex;
  width: max-content;
  animation: drift 64s linear infinite;
}

.looks__group {
  display: flex;
  gap: 1rem;
  padding-right: 1rem;
}

.looks__group figure {
  margin: 0;
  flex: 0 0 auto;
  width: clamp(170px, 24vw, 270px);
}

.looks__group img {
  width: 100%;
  aspect-ratio: 2 / 3;
  object-fit: cover;
  filter: saturate(.92);
}

/* The track holds the group twice, so half a turn lands exactly where it started. */
@keyframes drift {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}

/* Meanwhile ------------------------------------------------------------ */

.meanwhile {
  border-top: 1px solid var(--rule);
  background: var(--ink-soft);
}

.meanwhile__inner {
  max-width: 54rem;
  margin: 0 auto;
  padding: clamp(4rem, 10vh, 6.5rem) var(--gutter);
}

.meanwhile__title {
  margin: 1rem 0 1.1rem;
  font-family: var(--display);
  font-weight: 300;
  font-size: clamp(1.9rem, 5.2vw, 3rem);
  line-height: 1.12;
}

.meanwhile__body {
  margin: 0 0 2rem;
  max-width: 36rem;
  color: var(--ivory-dim);
}

.meanwhile__cta { margin: 0 0 2.8rem; }

/* Same gold as the sign-up button, outlined rather than filled: the form is still the
   page's one solid call to action. */
.button {
  display: inline-block;
  padding: .95rem 2.1rem;
  border: 1px solid var(--gold);
  color: var(--gold-light);
  font-size: .78rem;
  font-weight: 500;
  letter-spacing: .16em;
  text-transform: uppercase;
  text-decoration: none;
  transition: background .35s var(--ease), color .35s var(--ease);
}

.button:hover {
  background: var(--gold);
  color: var(--ink-deep);
}

.meanwhile__contacts {
  display: grid;
  gap: 1.6rem;
}

.contact {
  display: block;
  margin: 0;
  padding-top: 1.1rem;
  border-top: 1px solid var(--rule);
  text-decoration: none;
}

.contact span {
  display: block;
  margin-bottom: .3rem;
  font-size: .68rem;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--gold);
}

.contact strong {
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(1.1rem, 2.6vw, 1.4rem);
  letter-spacing: .01em;
  transition: color .25s var(--ease);
}

a.contact:hover strong { color: var(--gold-light); }

.contact--static strong { color: var(--ivory-dim); }

/* Footer --------------------------------------------------------------- */

.foot {
  padding: 3rem var(--gutter);
  background: var(--ink-deep);
  text-align: center;
}

.foot__tag {
  margin: 0 0 1.4rem;
  font-family: var(--display);
  font-style: italic;
  font-size: 1.25rem;
  color: var(--gold-light);
}

.foot__social {
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  gap: 1.6rem;
  margin-bottom: 1.6rem;
}

.foot__social a {
  font-size: .75rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--ivory-dim);
  transition: color .25s var(--ease);
}

.foot__social a:hover { color: var(--gold); }

.foot__legal {
  margin: 0;
  font-size: .72rem;
  color: rgba(var(--fg-rgb), .3);
}

/* Wider screens -------------------------------------------------------- */

@media (min-width: 760px) {
  :root { --gutter: 48px; }

  /* name | email on one line, phone | button on the next */
  .notify__grid { grid-template-columns: 1fr 1fr; }

  .coming__list { grid-template-columns: repeat(2, 1fr); gap: 2.8rem 3rem; }

  .meanwhile__contacts { grid-template-columns: repeat(3, 1fr); gap: 2rem; }
}

@media (min-width: 1040px) {
  .hero {
    grid-template-columns: minmax(0, 1fr) minmax(0, .85fr);
    grid-template-rows: 1fr auto;
    gap: 2.5rem;
    align-items: center;
    /* Past this the screen only adds empty ground between the words and the picture,
       so the pair is held together and centred instead. */
    max-width: 1480px;
    margin-inline: auto;
    padding-inline: clamp(48px, 7vw, 110px);
  }

  .hero__inner {
    max-width: var(--measure);
    margin: 0;
    grid-row: 1;
    grid-column: 1;
  }

  /* On desktop the photograph stops being wallpaper and becomes the other half of the page —
     bled past the padding on three sides so it reads as a panel, not a floating card. The
     hero above is kept inside one screen so the figure is never cut by the fold. */
  .hero__media {
    z-index: 0;
    /* The frame keeps her 2:3 proportion, so a cover crop can only ever trim the
       backdrop at the sides — never her feet or the top of her head. Out of flow, so
       the picture's height never pushes the hero past one screen. */
    /* No grid-column here: for an absolutely positioned child, naming a grid area would
       make that area the containing block, and the max-width below needs to measure
       against the whole hero. */
    position: absolute;
    right: 0;
    /* `left` has to be released explicitly: the phone rule pins the picture with
       `inset: 0`, and left plus right plus a width is over-constrained, so left wins
       and she would sit on top of the words. */
    left: auto;
    /* Held inside the first screen rather than centred in the hero: where the copy runs
       taller than the viewport, centring would drop her feet below the fold. Not
       translateY either — the entrance animation owns `transform`. */
    top: 0;
    bottom: auto;
    aspect-ratio: 2 / 3;
    /* The full height of the screen: with only 1.7% of empty frame above her head and
       none below her feet, her 2:3 proportion cannot be cropped, so height is the only
       way to make her larger — and one screen is as tall as she can be and still be
       seen whole. */
    height: 100svh;
    width: auto;
    /* …unless that would crowd the words. Then she narrows and loses backdrop, not feet. */
    max-width: calc(100% - var(--measure) - 2rem);
  }

  /* No parallax here: the photograph has almost no margin around her, so any headroom
     for it to travel through would have to come out of the figure. */
  .hero__media img {
    position: absolute;
    inset: 0;
    top: 0;
    width: 100%;
    height: 100%;
    opacity: 1;
    object-position: 50% 50%;
    transform: none;
  }

  /* Only the first slice is washed. The runway photograph carries its subject near the
     centre of the frame, and the old half-width fade swallowed her whole. The words sit
     in their own column out here, so this edge is a seam to soften, not a backdrop to
     darken for legibility. */
  .hero__media::after {
    background: linear-gradient(to right, var(--ink) 0%, rgba(var(--ink-rgb), .3) 9%, transparent 26%);
  }

  .looks__group figure { width: 270px; }
}


@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  .js [data-reveal],
  .js [data-lines] .line > span,
  .js .hero__media { opacity: 1; transform: none; transition: none; }

  .section-title::after { transform: scaleX(1); transition: none; }
  .hero__media img { transition: none; transform: none; }
  .looks__track,
  .hero__scroll i { animation: none; }
  .notify__button::after { display: none; }
  .grain { display: none; }
}
