/* Offline Luxury — two colours, nothing else.
   The design lives in spacing and tracking, not in letterforms. */

*, *::before, *::after { box-sizing: border-box; }

:root {
  --ink:   #12110F;                 /* off-black, warmed */
  --paper: #F4F2EC;                 /* off-white, warmed */

  /* The site sits on off-black. */
  --fg: var(--paper);
  --bg: var(--ink);

  /* Off-white on off-black needs a touch more presence than the reverse —
     light-on-dark hairlines read thinner than they measure. */
  --hair: color-mix(in srgb, var(--fg) 26%, transparent);
  --mute: color-mix(in srgb, var(--fg) 52%, transparent);

  /* Sampled from the gold leaf photo Cameron supplied: the dominant tone in
     the image, 8.6% of its pixels, hue 41.4deg. Contrast 9.26 on the ground. */
  --gold: #F0A808;

  --pad: clamp(20px, 4.5vw, 48px);
  --stack: -apple-system, BlinkMacSystemFont, "Segoe UI", "Helvetica Neue",
           Helvetica, Arial, sans-serif;

  color-scheme: dark;
}

/* The lockout page is the same two colours, inverted. Nothing else changes —
   the site going pale is the whole signal that it has shut. */
[data-invert] {
  --fg: var(--ink);
  --bg: var(--paper);
  --hair: color-mix(in srgb, var(--fg) 22%, transparent);
  --mute: color-mix(in srgb, var(--fg) 48%, transparent);
  /* The bright gold scores 1.82 against the pale ground - illegible. Same
     hue, dropped in value until it clears WCAG AA: 5.00. */
  --gold: #8A6002;
  color-scheme: light;
}

html {
  -webkit-text-size-adjust: 100%;
  /* The ground, so the strip below body when the toolbar retracts is never a
     different colour. */
  background: var(--bg);
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--stack);
  font-weight: 300;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;

  /* svh, not lvh. lvh is the viewport with the mobile toolbar RETRACTED - the
     tallest it ever gets - so sizing to it hides the bottom of the page under
     the toolbar until the reader scrolls. svh is the always-visible band,
     which is what "fits in the viewport" has to mean. On this device that is
     695px against lvh's 735px, and no devtools emulation shows the difference.
     Written as svh directly, never as lvh - svh: WebKit builds exist where the
     two units collapse to one value and the subtraction silently yields zero.
     dvh is wrong too - it resizes mid-scroll. */
  min-height: 100vh;
  min-height: 100svh;

  display: flex;
  flex-direction: column;
}

/* ---------------------------------------------------------------- timer -- */

.timer {
  flex: none;
  padding: var(--pad) var(--pad) 0;
  display: flex;
  justify-content: center;
}

.timer__value {
  font-size: clamp(1.15rem, 2.8vw, 1.6rem);
  font-weight: 300;
  /* Big tracked figures need less air than small ones, or the pairs stop
     reading as a single value. */
  letter-spacing: 0.2em;
  /* Tabular figures, or the countdown jitters horizontally every tick. */
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
  color: color-mix(in srgb, var(--gold) 80%, transparent);
  /* Compensate the trailing letter-space so the value is optically centred. */
  margin-right: -0.2em;
  transition: color .5s ease;
}

/* The last ten seconds: full contrast, and a slow breath so it catches the
   eye without ever becoming an alarm. Killed by the reduced-motion rule. */
.timer__value[data-state="urgent"] {
  color: var(--gold);
  animation: timer-breathe 1s ease-in-out infinite;
}

.timer__value[data-state="done"] {
  font-size: clamp(0.8rem, 1.8vw, 0.95rem);
  letter-spacing: 0.28em;
  margin-right: -0.28em;
  color: color-mix(in srgb, var(--gold) 72%, transparent);
}

@keyframes timer-breathe {
  0%, 100% { opacity: 1; }
  50%      { opacity: .5; }
}

/* ----------------------------------------------------------------- main -- */

main {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  /* The address form is tall enough to overflow a laptop window. Plain
     `center` would then clip the top of it PAST the scroll origin, putting the
     first field permanently out of reach. `safe` falls back to flex-start the
     moment the content stops fitting. */
  justify-content: safe center;
  gap: clamp(36px, 7vh, 72px);
  padding: clamp(28px, 6vh, 64px) var(--pad);
  text-align: center;
}

.wordmark {
  margin: 0;
  font-size: clamp(1.9rem, 8.5vw, 4.75rem);
  font-weight: 200;
  line-height: 1;
  letter-spacing: 0.17em;
  text-transform: uppercase;
  margin-right: -0.17em;
}

.lede {
  margin: 0;
  max-width: 30ch;
  font-size: clamp(0.95rem, 2.4vw, 1.15rem);
  font-weight: 300;
  line-height: 1.65;
  letter-spacing: 0.02em;
  text-wrap: balance;
}

.eyebrow {
  margin: 0;
  font-size: 0.7rem;
  font-weight: 400;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--mute);
  margin-right: -0.3em;
}

/* -------------------------------------------------------------- actions -- */

.actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: clamp(12px, 2.4vw, 18px);
}

.btn {
  appearance: none;
  display: inline-block;
  border: 1px solid var(--hair);
  background: transparent;
  color: var(--fg);
  font: inherit;
  font-size: 0.76rem;
  font-weight: 400;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  text-decoration: none;
  padding: 1.15em 2.6em;
  margin-right: -0.24em;          /* optical centring of the tracked label */
  cursor: pointer;
  transition: background-color .35s ease, color .35s ease, border-color .35s ease;
}

.btn:hover,
.btn:focus-visible {
  background: var(--fg);
  color: var(--bg);
  border-color: var(--fg);
}

.btn[disabled] { opacity: .38; pointer-events: none; }

/* ----------------------------------------------------------------- form -- */

.form {
  width: min(100%, 30rem);
  /* A grid, not a column, so short fields can share a row. Six tracks divide
     evenly into both halves and thirds. */
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  /* Row gap answers to viewport height, column gap to width. */
  gap: clamp(11px, 2.5vh, 26px) clamp(12px, 3vw, 20px);
  text-align: left;
}

/* Full width unless a breakpoint below says otherwise. */
.form > * { grid-column: span 6; }

.field { display: flex; flex-direction: column; gap: 0.7em; }

.field__label {
  font-size: 0.68rem;
  font-weight: 400;
  letter-spacing: 0.26em;
  text-transform: uppercase;
  color: var(--mute);
}

.field__input {
  appearance: none;
  -webkit-appearance: none;
  width: 100%;
  border: 0;
  border-bottom: 1px solid var(--hair);
  border-radius: 0;
  background: transparent;
  color: var(--fg);
  font: inherit;
  font-size: 1rem;
  font-weight: 300;
  letter-spacing: 0.01em;
  line-height: 1.6;
  padding: 0.35em 0 0.6em;
  transition: border-color .3s ease;
}

textarea.field__input { resize: none; min-height: 5.4em; }

.field__input::placeholder { color: color-mix(in srgb, var(--fg) 30%, transparent); }
.field__input:focus { outline: none; border-bottom-color: var(--fg); }

/* Native date chrome is the one thing that will not obey a two-colour rule. */
.field__input::-webkit-calendar-picker-indicator {
  filter: grayscale(1);
  opacity: .45;
  cursor: pointer;
}
.field__input::-webkit-calendar-picker-indicator:hover { opacity: 1; }

/* `appearance: none` strips the native arrow along with the native chrome, so
   the chevron has to come back as a background image. Hard-coded to the paper
   colour rather than a token: a data URI cannot read a custom property, and
   this control only ever appears on the off-black ground. */
select.field__input {
  cursor: pointer;
  padding-right: 1.6em;
  background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 12 8"><path d="M1 1.5l5 5 5-5" fill="none" stroke="%23F4F2EC" stroke-width="1.3"/></svg>');
  background-repeat: no-repeat;
  background-position: right 1px center;
  background-size: 11px auto;
}

/* The open dropdown is drawn by the OS on Windows and Linux and inherits
   nothing useful — without this the options are off-white on off-white. */
select.field__input option {
  background: var(--ink);
  color: var(--paper);
}

/* Month and day share a row under a single Birthday label. Two selects rather
   than a date input, because no year is collected and type="date" cannot
   express a month-day. */
.field__pair {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(12px, 3vw, 20px);
}

.form__note {
  margin: 0;
  font-size: 0.72rem;
  line-height: 1.7;
  letter-spacing: 0.04em;
  color: var(--mute);
}


.form__actions { display: flex; justify-content: flex-start; }

/* --------------------------------------------------------------- footer -- */

.foot {
  flex: none;
  padding: 0 var(--pad) var(--pad);
  display: flex;
  justify-content: center;
}

.foot a {
  color: var(--mute);
  text-decoration: none;
  font-size: 0.68rem;
  font-weight: 400;
  letter-spacing: 0.26em;
  text-transform: uppercase;
  margin-right: -0.26em;
  transition: color .3s ease;
}

.foot a:hover, .foot a:focus-visible { color: var(--fg); }

/* ------------------------------------------------- fitting the viewport -- */

/* Every page must fit its viewport at every breakpoint, with no scrolling.
   Three pages are small enough that this is free; /receive has seven fields
   and is the whole problem.

   The space is bought with LAYOUT and RHYTHM, never with type size. Inputs
   must stay at 16px: below that, iOS Safari zooms the page in on focus,
   leaving the reader zoomed and scrolled sideways with the clock running. */

/* Pair the short fields as soon as there is width for them: seven rows
   become five. */
@media (min-width: 19rem) {
  .field--city    { grid-column: span 3; }
  .field--region  { grid-column: span 3; }
  .field--postal  { grid-column: span 2; }
  .field--country { grid-column: span 4; }
}

/* Tier 1 — a short window (landscape phone, small laptop). Squeeze the
   vertical rhythm only. */
@media (max-height: 760px) {
  main {
    gap: clamp(14px, 2.6vh, 30px);
    padding-block: clamp(10px, 2vh, 26px);
  }
  .timer { padding-top: clamp(10px, 2vh, 24px); }
  .foot  { padding-bottom: clamp(10px, 2vh, 24px); }
  .field { gap: 0.45em; }
  .field__input { padding: 0.2em 0 0.42em; }
  .btn { padding: 0.9em 2.2em; }
  .timer__value { font-size: clamp(1rem, 2.2vw, 1.25rem); }
}

/* Tier 2 — genuinely short. Everything tightens to its floor; the input font
   size deliberately does not move. */
@media (max-height: 600px) {
  main { gap: clamp(10px, 2vh, 20px); padding-block: clamp(8px, 1.6vh, 16px); }
  .timer { padding-top: clamp(8px, 1.6vh, 16px); }
  .foot  { padding-bottom: clamp(8px, 1.6vh, 16px); }
  .field { gap: 0.28em; }
  .field__input { padding: 0.1em 0 0.3em; }
  .btn { padding: 0.72em 1.9em; font-size: 0.7rem; }
  .field__label { font-size: 0.62rem; letter-spacing: 0.2em; }
  .eyebrow { font-size: 0.62rem; }
  .foot a { font-size: 0.6rem; }
}

/* Wide and short — a landscape phone has the width for three columns, which
   takes /receive down to three rows. */
@media (max-height: 620px) and (min-width: 40rem) {
  .form { width: min(100%, 44rem); }
  .field--line1    { grid-column: span 3; }
  .field--line2    { grid-column: span 3; }
  .field--city     { grid-column: span 2; }
  .field--region   { grid-column: span 2; }
  .field--postal   { grid-column: span 2; }
  .field--country  { grid-column: span 3; }
  .field--birthday { grid-column: span 3; }
}

/* -------------------------------------------------------------- utility -- */

[hidden] { display: none !important; }

.visually-hidden {
  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;
}

::selection { background: var(--fg); color: var(--bg); }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    transition-duration: .01ms !important;
  }
}
