:root {
  --color-bg: #ede3df;
  --color-text: #0d1b2a;
  /* Muted hyperlink blue; 5.2:1 on --color-bg, so it clears AA for body text. */
  --color-link: #3f5f8f;
  --color-border: #b8ae9a;
  --color-button: #0d1b2a;
  --color-button-hover: #1b2c42;
  --font-serif: "Playfair Display", Georgia, serif;
  --font-times: "Times New Roman", Times, serif;
  --font-sans: "Helvetica Neue", Helvetica, Arial, sans-serif;
  --icon-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M3 8.5l3.5 3.5L13 5' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  --font-mono: "Space Mono", "Courier New", monospace;
}

* {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

html, body {
  min-height: 100%;
}

body {
  margin: 0;
  background: var(--color-bg);
  color: var(--color-text);
  font-family: var(--font-mono);
  -webkit-font-smoothing: antialiased;
}

.page {
  /* Optical centring. The TV artwork carries ~12.2% empty margin on each side
     of its frame; that space counts in the layout box but shows as nothing, so
     centring the row by its boxes leaves the visible composition sitting right
     of centre (measured +34 to +45px). Shifting both columns left by half that
     margin lines the visible content up with the page centre. Expressed
     against the same min(52rem, 72vh) that caps the hero, so it tracks the
     video at every size, and applied as a transform rather than padding so it
     cannot change where the flex line wraps. */
  --optical-shift: min(3.17rem, 4.39vh);
  position: relative;
  min-height: 100vh;
  min-height: 100svh;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: clamp(2.5rem, 3.5vw, 3.5rem) clamp(2.5rem, 8vw, 7rem);
  padding: 3rem 2rem 2.75rem;
}

/* Hero TV image */

.hero-image {
  /* Both columns grow into the row and stop at their max-widths, so any
     leftover width stays as equal margin either side of the pair. Height-capped
     as well, since the artwork is close to square. */
  flex: 1 1 520px;
  max-width: min(52rem, 72vh);
  display: flex;
  flex-direction: column;
  /* Dropped a little, together with the text column. Visual offset only, so
     the stockists line keeps the position it already has. */
  position: relative;
  top: 2rem;
  transform: translateX(calc(-1 * var(--optical-shift)));
}

/* Shadow and reflection are baked into the footage, so no CSS reflection is
   needed. Its backdrop is a soft studio gradient (#e8dfdb-#f1e9e6) rather than
   a flat --color-bg, so the outer 10% is feathered to stop the frame reading as
   a rectangle. The cabinet keeps a 15%+ clear margin, so nothing is clipped. */
.tv-photo {
  width: 100%;
  height: auto;
  display: block;
  /* A video box paints black before the poster decodes; match the page instead. */
  background: var(--color-bg);
  -webkit-mask-image:
    linear-gradient(to bottom, transparent 0, #000 10%, #000 90%, transparent 100%),
    linear-gradient(to right, transparent 0, #000 10%, #000 90%, transparent 100%);
  mask-image:
    linear-gradient(to bottom, transparent 0, #000 10%, #000 90%, transparent 100%),
    linear-gradient(to right, transparent 0, #000 10%, #000 90%, transparent 100%);
  -webkit-mask-composite: source-in;
  mask-composite: intersect;
}

/* Content column */

.content {
  flex: 1 1 420px;
  max-width: 560px;
  transform: translateX(calc(-1 * var(--optical-shift)));
  display: flex;
  flex-direction: column;
  /* Stretch to the row's height and centre the contents inside, rather than
     shrink-wrapping and being centred by the row. Looks identical, but the
     column's bottom edge now sits at the row's bottom edge, so the space
     between the sales line and the closing lines is the row gap — a constant —
     instead of half the leftover height, which swung from -32px on a short
     screen to +271px on a tall one. */
  align-self: stretch;
  justify-content: center;
  align-items: center;
  text-align: center;
}

.wordmark-picture {
  display: contents;
}

.wordmark {
  /* Artwork carries ~12.2% transparent padding top and bottom, so the negative
     margins pull the visible mark back into flow. The factor is that padding
     expressed against the width (12.17% of height, at 1.562:1), so it must be
     re-derived whenever the logo file changes. */
  --wordmark-width: clamp(16rem, 48vw, 23rem);
  width: var(--wordmark-width);
  max-width: 100%;
  height: auto;
  display: block;
  margin: calc(var(--wordmark-width) * -0.0779) 0;
}

.tagline,
.season,
.stockists {
  font-family: var(--font-times);
  font-style: normal;
  font-weight: 400;
  color: var(--color-text);
}

.tagline {
  font-size: clamp(1.45rem, 2.6vw, 1.9rem);
  /* The 2rem taken off the bottom here is given back on .sign-off below, so
     the column's overall height — and therefore the wordmark and tagline,
     which are centred with it — stay exactly where they are while the signup
     block, sales line and signature all shift up together. */
  margin: 5rem 0 2.5rem;
  /* Hand-drawn underline. .content centres its children rather than stretching
     them, so this element is already the width of its text and the stroke
     tracks it at any size. The side padding lets the stroke overshoot the text
     slightly, the way a drawn line would; the bottom padding is the room it
     sits in. Canvas is 10.82:1 with 18.5% transparent padding above the
     stroke and 32.3% below. */
  /* The stroke is anchored to the bottom edge and its height follows its
     width, so the bottom padding has to clear it or the line cuts through the
     text. Re-tuned for the 80% background-size below. */
  padding: 0 0.5em 0.77em;
  background-image: url("assets/Blue-underline-2.png");
  background-repeat: no-repeat;
  background-position: center bottom;
  background-size: 80% auto;
}

.season,
.stockists {
  font-size: clamp(0.95rem, 1.5vw, 1.1rem);
}

/* Forced break in the stores line, after "Goldring,". Hidden by default so
   the desktop layout keeps it on one line; the space before it lives in the
   text, so when the break is suppressed the sentence still reads
   "Goldring, and Andrew". */
.stores-break {
  display: none;
}

/* Closing group: season line directly above the stockists */

.closing {
  /* Full-width flex line, so it centres on the page rather than on a column. */
  flex: 0 0 100%;
  text-align: center;
  /* Sits at the top of its own flex line. The page wraps, so its line also
     stretches to fill leftover height; centring within that line was the last
     thing making this gap depend on viewport height. With this, the distance
     from the sales line above is simply the row gap — the same on every
     screen. The small lift then centres it in the space between the sales line
     above and the footer below — without it the group sat only ~11px clear of
     the copyright while leaving ~87px above, which read as far too low. */
  align-self: flex-start;
  position: relative;
  top: -2.75rem;
}

.season {
  margin: 0 0 0.5rem;
}

.stockists {
  margin: 0;
}

/* Signup form */

.signup-form {
  width: 100%;
}

.signup-label {
  font-family: var(--font-serif);
  font-style: italic;
  font-size: 1.05rem;
  /* Flush with the input's left edge, overriding .content's centring. */
  text-align: left;
  margin: 0 0 0.85rem;
}

.input-row {
  display: flex;
  width: 100%;
  gap: 1rem;
}

.input-row input[type="email"] {
  flex: 1;
  min-width: 0;
  padding: 0.6rem 1rem;
  border: 1px solid var(--color-border);
  border-radius: 0;
  -webkit-appearance: none;
  appearance: none;
  background: transparent;
  font-family: var(--font-times);
  font-size: 0.8rem;
  color: var(--color-text);
}

.input-row input[type="email"]:focus {
  outline: none;
  border-color: var(--color-text);
}

.input-row input[type="email"]::placeholder {
  color: #8a8374;
}

.input-row button {
  flex: 0 0 auto;
  border: none;
  border-radius: 0;
  -webkit-appearance: none;
  appearance: none;
  background: var(--color-button);
  color: var(--color-bg);
  padding: 0.6rem 1.5rem;
  font-family: var(--font-sans);
  font-weight: 700;
  font-size: 0.8rem;
  letter-spacing: 0.03em;
  cursor: pointer;
  white-space: nowrap;
  transition: background 0.15s ease;
}

.input-row button:hover,
.input-row button:focus-visible {
  background: var(--color-button-hover);
}

/* Marketing consent notice. Submitting the form is the consent, so this has
   to stay readable, but it should sit back from the form. 65% ink is ~5:1 on
   --color-bg, which still clears AA for body text. */
.fine-print {
  margin: 0.75rem 0 0;
  font-family: var(--font-times);
  font-size: 0.72rem;
  line-height: 1.45;
  color: var(--color-text);
  opacity: 0.65;
  text-align: center;
}

/* Same ink as the sentence, marked by the underline alone. The link blue
   faded to 65% would drop under 3:1. */
.fine-print a {
  color: inherit;
  text-underline-offset: 0.2em;
}

.form-message {
  min-height: 1.2rem;
  margin: 0.75rem 0 0;
  font-size: 0.75rem;
  color: var(--color-text);
  opacity: 1;
  transition: opacity 0.6s ease;
}

.form-message[data-fading] {
  opacity: 0;
}

.form-message[data-state="error"] {
  color: #a3402f;
}

.form-message[data-state="success"] {
  /* Deliberately the page's own ink rather than a green: the confirmation is
     meant to read as part of the type, not as a system alert. */
  color: var(--color-text);
}

/* Tick drawn as a masked SVG rather than a "\2713" glyph: Space Mono has no
   check character, so a glyph would silently fall back to whatever system font
   does, at a different weight. Masking paints it in currentColor, so it keeps
   the ink colour and fades out with the text. */
.form-message[data-state="success"]::before {
  content: "";
  display: inline-block;
  width: 0.85em;
  height: 0.85em;
  margin-right: 0.4em;
  vertical-align: -0.12em;
  background-color: currentColor;
  -webkit-mask: var(--icon-check) center / contain no-repeat;
  mask: var(--icon-check) center / contain no-repeat;
}

/* Sales contact */

/* The sales line stays centred in the column like everything above it, so the
   signature is taken out of flow rather than sharing a row — in flow it would
   push the text off-centre. It cannot sit level with the text either: the line
   is ~351px wide and the column is at most 560px, leaving ~104px beside it for
   a 144px signature. So it hangs just below, right-aligned, where it clears
   the text at every width. Absolute, so it adds no height. */
.sign-off {
  position: relative;
  width: 100%;
  /* Bottom margin replaces the height removed from .tagline — see there. */
  margin: 1.25rem 0 2rem;
}

.sales-contact {
  font-family: var(--font-serif);
  font-size: 0.95rem;
  margin: 0;
}

.signature {
  position: absolute;
  right: 0;
  top: calc(100% + 0.25rem);
  width: 9rem;
  height: auto;
  display: block;
  transform: rotate(7deg);
  transform-origin: center;
  pointer-events: none;
}

/* Only one copy is ever shown. Must come after .signature, which sets
   display: block at the same specificity. */
.signature--stacked {
  display: none;
}

.sales-contact a {
  color: var(--color-link);
  text-decoration: underline;
}

/* Copyright */

.copyright {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 1.25rem;
  margin: 0;
  text-align: center;
  font-size: 0.65rem;
  color: var(--color-text);
}

/* ---------------------------------------------------------------------------
   Stacked layout.

   The two-column row breaks naturally at ~1091px of client width (520px + 420px
   bases plus the column gap). Media queries match on window width, which is up
   to 15px wider than the client area when a scrollbar is present, so this
   breakpoint sits above 1091 + 15 to be sure the stacked styles are in force
   before flex-wrap ever acts on its own. Order follows the DOM: TV, then wordmark and
   text, then stockists, then the footer.
   --------------------------------------------------------------------------- */

@media (max-width: 1120px) {
  /* The stacked running order interleaves elements that live in three
     different parents on desktop: the wordmark and tagline sit in .content,
     the season line in .closing. `order` only sorts siblings, so those two
     wrappers are flattened with display: contents and every piece becomes a
     direct child of .page, which can then be ordered freely. Flattening drops
     the wrappers' own boxes, so the width, centring and text alignment they
     were providing are reapplied here. */
  .page {
    --page-pad-x: 2rem;
    flex-direction: column;
    flex-wrap: nowrap;
    align-items: center;
    /* Content is normally taller than the viewport here; centring would push
       the top out of reach, since you cannot scroll above the origin. */
    justify-content: flex-start;
    /* No row gap: with the pieces flattened, each one sets its own spacing so
       the rhythm can be tuned step by step. */
    gap: 0;
    text-align: center;
    /* Symmetric: the vertical space now comes from centring, so uneven
       padding would just bias the result. Slightly less on top because the
       wordmark's box extends ~10px above its visible ink (its negative margin
       cancels the artwork's transparent padding), which would otherwise make
       the block sit optically low. */
    padding: 1.4rem var(--page-pad-x) 3.4rem;
  }

  .content,
  .closing {
    display: contents;
  }

  /* Inline lockup: 6.42:1 with 23.5% transparent padding top and bottom,
     where the stacked mark had 18%. That works out to 0.0366 of the width
     rather than 0.127, so the pull-in has to change with the artwork. */
  .wordmark {
    --wordmark-width: min(20rem, 76%);
    margin: calc(var(--wordmark-width) * -0.0366) 0;
  }

  /* Desktop offsets are relative to the two-column composition. */
  .hero-image {
    position: static;
    flex: 0 0 auto;
    top: auto;
    transform: none;
  }

  /* Pinned to the foot of the screen rather than riding at the end of the
     stack, so the centred content above it is unaffected by its height. Out of
     flow, so .page reserves room for it with padding-bottom below. */
  .copyright {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 1.25rem;
    transform: none;
    margin: 0;
  }

  /* Running order: wordmark, TV, tagline, season, form, then the sign-off,
     stockists, signature and footer. */
  /* The video carries transform: scale(1.1), and a transform creates a
     stacking context that paints above ordinary in-flow content. Without
     these, the TV — pulled up to overlap — covers the wordmark, and would
     cover the tagline too. Lift both back above it. */
  .wordmark,
  .tagline {
    position: relative;
    z-index: 1;
  }

  .wordmark           { order: 1; }
  .hero-image         { order: 2; }
  .tagline            { order: 3; }
  .season             { order: 4; }
  .signup-form        { order: 5; }
  .sign-off           { order: 6; }
  .stockists          { order: 7; }
  .signature--stacked { order: 8; }
  .copyright          { order: 9; }

  .hero-image {
    /* Runs edge to edge. The artwork already carries ~12% empty margin of its
       own, so the page gutter on top of that was making the TV read small.
       Width reaches back across both gutters; no negative margins, so the flex
       centring still holds when the max-width caps it on a tablet.
       The vh term only binds on short viewports, e.g. a phone in landscape.
       svh overrides vh where supported; vh remains the fallback. */
    width: calc(100% + 2 * var(--page-pad-x));
    /* Sized from viewport height, not width, so the whole page fits one
       screen. svh is the height with the browser UI showing. */
    /* Takes whatever height the rest of the page leaves. 27rem is the
       measured height of everything else stacked up; 1.11 converts the
       leftover height back into a width, since the frame is cropped to 90%.
       The max() floor keeps the result positive in landscape, where a
       negative max-width would be invalid and drop the cap entirely. */
    max-width: min(40rem, 72vw, max(8rem, calc((100vh - 32rem) * 1.11)));
    max-width: min(40rem, 72vw, max(8rem, calc((100svh - 32rem) * 1.11)));
    overflow: hidden;
    /* Safe to crop now: the mask below fades the reflection to fully
       transparent by ~90% of the frame, so this removes only dead space.
       Cropping before that mask existed is what left a visible edge. */
    aspect-ratio: 100 / 90;
    /* Negative: the frame's top ~16% is empty, so the TV can ride up into the
       wordmark's space without the cabinet ever touching the lettering. */
    margin: -1rem 0 0;
  }

  .tv-photo {
    /* Crops into the artwork's own empty margin, which measures 12.2% at the
       sides and 16% at the top, so more of the frame is actually cabinet.
       1.1 trims 5% a side — comfortably inside that. */
    transform: scale(1.1);
    /* Bring the reflection to a full stop before the tagline instead of
       letting its long tail tint the band behind the text. A gradient ends it
       without the hard edge a crop leaves. The cabinet's feet sit at 70% here,
       so the fade starts just below them. Stops are in the element's own
       coordinates, which scale(1.1) expands about the centre, so 86% lands at
       roughly 90% of the rendered frame. */
    -webkit-mask-image:
      linear-gradient(to bottom, transparent 0, #000 10%, #000 72%, transparent 86%),
      linear-gradient(to right, transparent 0, #000 10%, #000 90%, transparent 100%);
    mask-image:
      linear-gradient(to bottom, transparent 0, #000 10%, #000 72%, transparent 86%),
      linear-gradient(to right, transparent 0, #000 10%, #000 90%, transparent 100%);
  }

  /* Tucked up against the TV, overlapping it. Safe because the mask fades the
     reflection to nothing by ~90% of the frame and the frame is then cropped
     to 90%, so this sits over empty pixels rather than artwork. */
  .tagline {
    margin: -1.25rem 0 0;
  }

  .season {
    margin: 0.25rem 0 0;
  }

  .signup-form,
  .sign-off {
    width: 100%;
    max-width: 35rem;
  }

  .signup-form {
    max-width: 22rem;
  }

  .signup-form {
    margin-top: 2.25rem;
  }

  /* The message slot reserves blank height to stop the form jumping when it
     fills. That reserve competes directly with fitting one screen, so here it
     collapses until there is actually a message to show; script.js sets
     data-state on submit. A small shift then is the better trade on a phone. */
  .form-message {
    min-height: 0;
    margin-top: 0;
    font-size: 0.7rem;
  }

  .form-message[data-state] {
    margin-top: 0.4rem;
  }

  .sign-off {
    margin: 2.6rem 0 0;
  }

  .stockists {
    max-width: 35rem;
    margin-top: 2.5rem;
  }

  .stores-break {
    display: inline;
  }

  /* On desktop this is flush with the input's left edge inside a 560px
     column, which reads as deliberate. Stacked, the form spans the full page
     width, so it ended up hard against the left gutter while everything
     else on the page is centred. Centre it here so the column reads as one. */
  .signup-label {
    text-align: center;
  }

  .signature--inline {
    display: none;
  }

  .signature--stacked {
    display: block;
    position: static;
    width: 3.25rem;
    margin: 0.5rem 0 0;
  }

  .copyright {
    margin: 0.6rem 0 0;
  }
}

/* Centre the stack vertically, but only where it is known to fit. Plain
   `justify-content: center` on a column that overflows pushes the top out of
   reach — you cannot scroll above the origin — so this is gated on a viewport
   tall enough to hold the content. Short and landscape viewports keep
   flex-start and stay scrollable from the top. */
@media (max-width: 1120px) and (min-height: 560px) {
  .page {
    justify-content: center;
  }
}

@media (max-width: 640px) {
  .page {
    --page-pad-x: 1.25rem;
    padding: 1.1rem var(--page-pad-x) 3.1rem;
  }

  /* Narrower signup block than the text around it. */
  .signup-form {
    max-width: 18rem;
  }

  /* Type and control sizes step down so the whole page clears one screen,
     with the signup block kept largest as the focal point. */
  .tagline {
    font-size: 1.3rem;
  }

  .season,
  .stockists {
    font-size: 0.8rem;
  }

  .signup-label {
    font-size: 0.95rem;
    margin-bottom: 0.6rem;
  }

  .sales-contact {
    font-size: 0.85rem;
  }

  .fine-print {
    margin-top: 0.6rem;
    font-size: 0.68rem;
  }

  .input-row {
    gap: 0.6rem;
  }

  .input-row input[type="email"],
  .input-row button {
    padding-top: 0.55rem;
    padding-bottom: 0.55rem;
  }

  .input-row {
    flex-direction: column;
  }

  .input-row input[type="email"] {
    /* iOS Safari zooms the page when a focused field is under 16px. */
    font-size: 1rem;
  }

  .input-row button {
    width: 100%;
  }
}

/* Short phones (older 4.7" and 5" hardware, and small Android). The stack
   itself cannot shrink much further, so the TV gives up the difference. Split
   from the rule above so tall phones keep the larger frame. */
@media (max-width: 640px) and (max-height: 700px) {
  .hero-image {
    max-width: min(40rem, 72vw, max(5rem, calc((100vh - 35rem) * 1.11)));
    max-width: min(40rem, 72vw, max(5rem, calc((100svh - 35rem) * 1.11)));
  }
}
