@charset "utf-8";

/* ═══════════════════════════════════════════════════════════════
   Which Gay App Is For You?
   Every colour, radius and size below is taken from the Figma file
   1yJv45fXjHx4g5kSkLhpvQ. Layout is mobile-first; the desktop
   composition lives in the (min-width: 901px) block at the bottom.
   ═══════════════════════════════════════════════════════════════ */

:root {
  /* Backgrounds */
  --bg-top: #bfdaf2;
  --bg-bot: #60b5ff;

  /* Ink */
  --ink: #071f5d;
  --ink-shadow: 1px 1px 1px rgba(255, 255, 255, .8);
  --on-btn: #fff7f2;

  /* Glossy button */
  --btn-frame: #264576;
  --btn-edge: #cce9fe;
  --btn-top: #779af2;
  --btn-bot: #2d55c0;
  --btn-gloss: inset 0 0 9px rgba(255, 255, 255, .75);

  /* Glossy button, sage variant (TRY AGAIN) */
  --ghost-top: #c9d6c0;
  --ghost-bot: #89a47f;

  /* Sunken track, shared by sliders and the unit toggle */
  --track: #9fb4e0;
  --track-border: #6384ca;
  --track-shadow: inset 0 2px 2px #5266a0;
  --track-lip: 0 2px 1px #e0e8f9;

  /* Calculator panel */
  --panel: rgba(203, 218, 250, .7);
  --panel-radius: 24px;
  --rule: #84a1df;
  --rule-lip: #d2e1f9;

  /* Slider thumb */
  --knob-top: #c9d6c0;
  --knob-bot: #89a47f;
  --knob-edge: #3c4438;

  /* Figure springs — overridden under prefers-reduced-motion.
     X overshoots 9.8%, Y only 1.25%: see FIGURE_SCALE in js/data.js for why the
     vertical axis has almost no room to overshoot into. */
  --spring-x: .34s cubic-bezier(.34, 1.56, .64, 1);
  --spring-y: .34s cubic-bezier(.25, 1.2, .5, 1);
}

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

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

body {
  margin: 0;
  min-height: 100vh;
  min-height: 100dvh;
  background: linear-gradient(180deg, var(--bg-top) 0%, var(--bg-bot) 100%);
  background-attachment: fixed;
  font: 700 16px/1.2 'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;
  color: var(--ink);
  overflow-x: hidden;

  /* The plumbob cursor. Its sharp tip is the top-left corner of the bitmap, so
     the hotspot sits there. Declared once here — everything interactive says
     `cursor: inherit` rather than redeclaring it. The second declaration is a
     progressive upgrade: browsers without image-set() keep the first one. */
  cursor: url('../images/cursor-32.png') 1 0, auto;
  cursor: image-set(
      url('../images/cursor-32.png') 1x,
      url('../images/cursor-64.png') 2x
    ) 1 0, auto;
}

img { display: block; max-width: 100%; height: auto; }

/* ── Screens ──────────────────────────────────────────────────── */

.screen { display: none; }
.screen:focus { outline: none; }

body[data-screen="main"]   .screen--main,
body[data-screen="calc"]   .screen--calc,
body[data-screen="result"] .screen--result { display: flex; }

/* Symmetrical padding keeps the content optically centred exactly where the
   mockups put it on both the 393×852 and 1440×800 frames. */
.screen--main,
.screen--result {
  position: relative;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 32px;
  min-height: 100vh;
  min-height: 100dvh;
  padding: 40px 16px;
  text-align: center;
}

/* Result screens get an app-coloured background instead of the blue sky. */
body[data-app="goose"]      { --result-bg: #7b8e46; }
body[data-app="grindr"]     { --result-bg: linear-gradient(180deg, #ffcc36 0%, #ffc51a 100%); }
body[data-app="growlr"]     { --result-bg: #805733; }
body[data-app="biggercity"] { --result-bg: #4a7bda; }

/* Growlr's brown is the one background dark enough to fail against the ink
   (3.3:1) — it gets light chrome. On BiggerCity's blue, black is the better
   of the two (5.1:1 vs 4.1:1 for white), so it keeps the default. */
body[data-app="growlr"] {
  --chrome-ink: #fff7f2;
  --chrome-shadow: 0 1px 2px rgba(0, 0, 0, .45);
}

body[data-screen="result"] {
  background: var(--result-bg, var(--bg-bot));
  --ink: #000;
}

/* ── Logo ────────────────────────────────────────────────────────
   The frame is the layout box; the artwork fills it whole. Figma zooms the
   image to 119% inside these frames, but the exported PNG has almost no
   transparent margin (art is 916px of a 960px canvas), so that zoom would
   crop the wordmark. Fitting it instead keeps the logo intact. */

.logo-frame {
  display: block;
  flex: none;
}

.logo-frame img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.logo-frame--hero   { width: 320px; height: 320px; }
.logo-frame--corner { width: 96px;  height: 96px; }

/* ── About link & corner logo ─────────────────────────────────── */

.about-link {
  position: fixed;
  top: 20px;
  right: 20px;
  z-index: 3;
  padding: 4px 2px;
  border: 0;
  background: none;
  font: inherit;
  font-size: 16px;
  line-height: 15px;
  color: var(--chrome-ink, var(--ink));
  text-shadow: var(--chrome-shadow, var(--ink-shadow));
  cursor: inherit;
}

.about-link:hover { text-decoration: underline; }

/* ── Music toggle ─────────────────────────────────────────────────
   Sits left of About, optically centred on it. Sage while off, blue while
   playing, using the same tokens as the big buttons. */
.music-btn {
  position: fixed;
  top: 14px;
  right: 84px;
  z-index: 3;
  width: 36px;
  height: 36px;
  padding: 0;
  border: 0;
  border-radius: 11px;
  background: var(--btn-frame);
  font: 900 18px/1 'Inter', system-ui, sans-serif;
  color: var(--on-btn);
  cursor: inherit;
  -webkit-tap-highlight-color: transparent;
}

.music-btn::before {
  content: '';
  position: absolute;
  inset: 2px;
  border-radius: 9px;
  background: linear-gradient(180deg, var(--ghost-top) 0%, var(--ghost-bot) 100%);
  box-shadow: inset 1px 2px 1px #fff;
  transition: opacity .15s ease;
}

.music-btn[aria-pressed="true"]::before {
  border: 2px solid var(--btn-edge);
  background: linear-gradient(180deg, var(--btn-top) 0%, var(--btn-bot) 100%);
  box-shadow: var(--btn-gloss);
}

.music-btn > span {
  position: relative;
  display: block;
  padding-bottom: 2px;
}

.music-btn:hover::before { filter: brightness(1.07); }
.music-btn:active > span { transform: translateY(1px); }

.music-btn:focus-visible {
  outline: 3px solid #fff;
  outline-offset: 3px;
}

/* Pinned to the viewport so it lands at 20/20 regardless of where it sits in
   the DOM; the desktop calculator puts it back into flow (see media query). */
.corner-logo {
  position: fixed;
  top: 20px;
  left: 20px;
  z-index: 3;
  padding: 0;
  border: 0;
  background: none;
  cursor: inherit;
  line-height: 0;
}

.corner-logo:focus-visible {
  outline: 3px solid #fff;
  outline-offset: 2px;
  border-radius: 8px;
}

/* ── Type ─────────────────────────────────────────────────────── */

.tagline {
  margin: 0;
  font-size: 20px;
  line-height: 24px;
  text-shadow: var(--ink-shadow);
}

/* ── Glossy Sims button ──────────────────────────────────────────
   Outer element = dark 15px frame, ::before = the gradient face
   inset 2px with a 13px radius, exactly as the design nests them. */

.sims-btn {
  position: relative;
  display: grid;
  place-items: center;
  width: 100%;
  max-width: 320px;
  height: 76px;
  padding: 0;
  border: 0;
  border-radius: 15px;
  background: var(--btn-frame);
  font: 900 30px/1 'Inter', system-ui, sans-serif;
  color: var(--on-btn);
  text-decoration: none;
  cursor: inherit;
  -webkit-tap-highlight-color: transparent;
}

.sims-btn::before {
  content: '';
  position: absolute;
  inset: 2px;
  border: 2px solid var(--btn-edge);
  border-radius: 13px;
  background: linear-gradient(180deg, var(--btn-top) 0%, var(--btn-bot) 100%);
  box-shadow: var(--btn-gloss);
  transition: filter .12s ease;
}

.sims-btn > span {
  position: relative;
  padding-bottom: 3px; /* optical centring: Inter Black caps sit high */
}

.sims-btn:hover::before { filter: brightness(1.06); }
.sims-btn:active::before { filter: brightness(.94); }
.sims-btn:active > span { transform: translateY(2px); }

.sims-btn:focus-visible {
  outline: 3px solid #fff;
  outline-offset: 3px;
}

/* Sage variant: no light edge, a hard white inner highlight instead. */
.sims-btn--ghost::before {
  border: 0;
  background: linear-gradient(180deg, var(--ghost-top) 0%, var(--ghost-bot) 100%);
  box-shadow: inset 2px 3px 1px #fff, 1px 2px 4px rgba(0, 0, 0, .25);
}

.sims-btn--small {
  height: 56px;
  max-width: 200px;
  font-size: 22px;
}

/* A placeholder link keeps the designed look but loses its hover response. */
.sims-btn[aria-disabled="true"]:hover::before { filter: none; }

/* ── Calculator ───────────────────────────────────────────────── */

.screen--calc {
  align-items: center;
  justify-content: center;
  min-height: 100vh;
  min-height: 100dvh;
  padding: 20px 16px 40px;
}

.calc {
  --fig-w: min(320px, 84vw);
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 100%;
}

.calc__figure {
  width: var(--fig-w);
  flex: none;
}

/* Stretched live by the sliders — JS writes --body-sx / --body-sy onto
   .calc__figure and the two children inherit them. Split across two elements so
   each axis can carry its own spring, and both anchored at the bottom so the
   feet stay on the ground.

   Width gets the full back-out bounce: it peaks 9.8% past the target, and even
   at the widest setting (1.40) that peak keeps the artwork inside its box.
   Height gets a gentler one — the art has only 11px of headroom, so its 4.1%
   peak against a 0.97 ceiling lands at 1.010, just under the 1.020 limit. */
.calc__stretch {
  transform-origin: 50% 100%;
  transform: scaleY(var(--body-sy, 1));
  transition: transform var(--spring-y);
}

.calc__figure img {
  transform-origin: 50% 100%;
  transform: scaleX(var(--body-sx, 1));
  transition: transform var(--spring-x);
  will-change: transform;
}

/* The panel rides up over the lower two thirds of the figure, as on the
   mobile mockup. 268/320 keeps that overlap proportional when the figure
   is scaled down on narrow phones. */
.calc__column {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: 320px;
  margin-top: calc(var(--fig-w) * -0.8375);
  display: flex;
  flex-direction: column;
  align-items: center;
}

.panel {
  width: 100%;
  padding: 24px;
  border-radius: var(--panel-radius);
  background: var(--panel);
}

/* ── Field (label + big number + slider) ─────────────────────── */

.field { margin-top: 40px; }

.field__label {
  display: block;
  margin-bottom: 10px;
  font-size: 16px;
  line-height: 15px;
  text-shadow: var(--ink-shadow);
}

.field__value {
  display: block;
  margin-bottom: 16px;
  font-size: 40px;
  line-height: 30px;
  letter-spacing: -.08em;
  text-shadow: var(--ink-shadow);
  font-variant-numeric: tabular-nums;
}

.field__sep {
  margin: 18px 0 0;
  border: 0;
  border-top: 1px solid var(--rule);
  box-shadow: 0 1px 0 var(--rule-lip);
}

.field__sep + .field { margin-top: 20px; }

.sims-btn--reveal { margin-top: 48px; }

/* ── Slider ───────────────────────────────────────────────────── */

.slider {
  position: relative;
  height: 32px;
  --pct-num: 0;
}

.slider__track {
  position: absolute;
  top: 8px;
  left: 0;
  right: 0;
  height: 15px;
  border: 1px solid var(--track-border);
  border-radius: 78px;
  background: var(--track);
  box-shadow: var(--track-shadow), var(--track-lip);
}

/* Ends under the centre of the thumb, which only travels 16px…100%-16px. */
.slider__fill {
  display: block;
  width: calc(16px + var(--pct-num) * (100% - 32px));
  height: 100%;
  min-width: 13px;
  margin: -1px 0 0 -1px;
  border: 1px solid #143d7a;
  border-radius: 13px;
  background: linear-gradient(180deg, var(--btn-top) 0%, var(--btn-bot) 100%);
  box-shadow: inset 0 1px 2px #fff;
}

.slider__input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 32px;
  margin: 0;
  background: none;
  -webkit-appearance: none;
  appearance: none;
  cursor: inherit;
}

.slider__input::-webkit-slider-runnable-track { height: 32px; background: none; }
.slider__input::-moz-range-track { height: 32px; background: none; }

.slider__input::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 32px;
  height: 32px;
  border: 2px solid var(--knob-edge);
  border-radius: 50%;
  background: linear-gradient(180deg, var(--knob-top) 0%, var(--knob-bot) 100%);
  box-shadow: inset 2px 3px 1px rgba(255, 255, 255, .55), 1px 2px 4px rgba(0, 0, 0, .25);
}

.slider__input::-moz-range-thumb {
  width: 28px;
  height: 28px;
  border: 2px solid var(--knob-edge);
  border-radius: 50%;
  background: linear-gradient(180deg, var(--knob-top) 0%, var(--knob-bot) 100%);
  box-shadow: inset 2px 3px 1px rgba(255, 255, 255, .55), 1px 2px 4px rgba(0, 0, 0, .25);
}

.slider__input:focus-visible { outline: none; }
.slider__input:focus-visible::-webkit-slider-thumb { box-shadow: 0 0 0 3px #fff, 1px 2px 4px rgba(0, 0, 0, .25); }
.slider__input:focus-visible::-moz-range-thumb { box-shadow: 0 0 0 3px #fff, 1px 2px 4px rgba(0, 0, 0, .25); }

/* ── Metric / Imperial toggle ─────────────────────────────────── */

.sims-toggle {
  position: relative;
  display: flex;
  height: 43px;
  border: 1px solid var(--track-border);
  border-radius: 78px;
  background: var(--track);
  box-shadow: var(--track-shadow), var(--track-lip);
}

.sims-toggle__pill {
  position: absolute;
  top: 1px;
  left: 1px;
  width: calc(50% - 1px);
  height: 41px;
  border-radius: 200px;
  background: linear-gradient(180deg, var(--btn-top) 0%, var(--btn-bot) 100%);
  box-shadow: inset 0 1px 2px #fff;
  transition: transform .18s ease;
}

.sims-toggle[data-units="imperial"] .sims-toggle__pill { transform: translateX(100%); }

.sims-toggle__opt {
  position: relative;
  z-index: 1;
  flex: 1;
  display: grid;
  place-items: center;
  font-size: 16px;
  line-height: 16px;
  cursor: inherit;
}

.sims-toggle__opt input {
  position: absolute;
  opacity: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  cursor: inherit;
}

.sims-toggle__opt input:checked + span {
  font-weight: 900;
  color: var(--on-btn);
}

.sims-toggle__opt input:focus-visible + span {
  outline: 2px solid #fff;
  outline-offset: 4px;
  border-radius: 4px;
}

/* ── Result ───────────────────────────────────────────────────── */

.result {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 24px;
  width: 100%;
  max-width: 320px;
}

/* The wordmark deliberately bleeds past the 320px column, as in the design. */
.result__logo {
  width: min(800px, 100vw);
  max-width: none;
  aspect-ratio: 2 / 1;
  flex: none;
}

.result__text {
  margin: 0;
  font-size: 20px;
  line-height: 24px;
  text-shadow: var(--ink-shadow);
}

.result__lede,
.result__roast { display: block; }

.result .sims-btn { max-width: 316px; }

/* ── Loading screen ───────────────────────────────────────────────
   Full-screen, above everything, in the same sky as the rest of the site. */

.loader {
  position: fixed;
  inset: 0;
  z-index: 10;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 28px;
  padding: 40px 16px;
  background: linear-gradient(180deg, var(--bg-top) 0%, var(--bg-bot) 100%);
}

.loader[hidden] { display: none; }

/* The icon hops, with squash on take-off and landing plus a ground shadow that
   shrinks as it rises — without those two the jump reads as a plain slide. */
.hopper {
  position: relative;
  width: 128px;
  height: 128px;
  margin-bottom: 16px;
}

.hopper__icon {
  width: 128px;
  height: 128px;
  transform-origin: 50% 100%;
  animation: hop .9s ease-in-out infinite;
}

.hopper__shadow {
  position: absolute;
  left: 50%;
  bottom: -14px;
  width: 90px;
  height: 14px;
  margin-left: -45px;
  border-radius: 50%;
  background: rgba(7, 31, 93, .28);
  filter: blur(3px);
  animation: hop-shadow .9s ease-in-out infinite;
}

@keyframes hop {
  0%   { transform: translateY(0)     scale(1, 1); }
  12%  { transform: translateY(0)     scale(1.12, .88); }
  32%  { transform: translateY(-45px) scale(.94, 1.06); }
  50%  { transform: translateY(-50px) scale(1, 1); }
  68%  { transform: translateY(-45px) scale(.96, 1.04); }
  88%  { transform: translateY(0)     scale(1.12, .88); }
  100% { transform: translateY(0)     scale(1, 1); }
}

@keyframes hop-shadow {
  0%, 100% { transform: scale(1);   opacity: .28; }
  50%      { transform: scale(.62); opacity: .12; }
}

.loader__track {
  width: min(272px, 100%);
  height: 15px;
  overflow: hidden;
  border: 1px solid var(--track-border);
  border-radius: 78px;
  background: var(--track);
  box-shadow: var(--track-shadow), var(--track-lip);
}

.loader__fill {
  width: 0;
  height: 100%;
  border-radius: 13px;
  background: linear-gradient(180deg, var(--btn-top) 0%, var(--btn-bot) 100%);
  box-shadow: inset 0 1px 2px #fff;
}

.loader__msg {
  margin: 0;
  min-height: 24px;
  font-size: 20px;
  line-height: 24px;
  text-align: center;
  text-shadow: var(--ink-shadow);
}

/* ── About modal ──────────────────────────────────────────────── */

.modal {
  width: min(420px, calc(100vw - 32px));
  padding: 28px 24px 24px;
  border: 2px solid #cce9fe;
  border-radius: var(--panel-radius);
  background: linear-gradient(180deg, #dfeeff 0%, #bcd8f4 100%);
  color: #071f5d;
  font-size: 16px;
  line-height: 1.45;
  text-align: center;
  box-shadow: 0 18px 40px rgba(7, 31, 93, .35);
}

.modal::backdrop { background: rgba(7, 31, 93, .55); }

.modal__title {
  margin: 0 0 12px;
  font-weight: 900;
  font-size: 28px;
}

.modal p { margin: 0 0 12px; }

.modal__fineprint {
  font-size: 13px;
  line-height: 1.4;
  opacity: .75;
}

.modal .sims-btn { margin: 8px auto 0; }

/* ═══════════════════════ Desktop ═══════════════════════════════ */

@media (min-width: 901px) {

  .screen--main,
  .screen--result { gap: 24px; }

  .logo-frame--hero   { width: 480px; height: 480px; }
  .logo-frame--corner { width: 128px; height: 128px; }

  /* Figure and panel sit side by side, overlapping 45px, bottoms aligned. */
  .calc {
    --fig-w: 320px;
    flex-direction: row;
    align-items: flex-end;
    justify-content: center;
    width: auto;
  }

  .calc__figure { margin-right: -45px; }

  .calc__column {
    width: 320px;
    max-width: none;
    margin-top: 0;
  }

  /* On desktop the small logo is centred over the top of the panel. */
  .screen--calc .corner-logo {
    position: relative;
    top: auto;
    left: auto;
    margin: 0 auto -64px;
  }

  .panel { padding: 84px 24px 24px; }

  /* The mockup sits the calculator slightly above centre: 56px above the
     logo, 120px below the panel on the 800px-tall frame. */
  .screen--calc { padding: 56px 16px 120px; }
}

/* ═══════════════════════ Motion ════════════════════════════════ */

/* Targeted rather than a blanket `transition: none` on everything — that would
   also reset the springs' timing functions and the loader bar, which are either
   informational or need to stay smooth. */
@media (prefers-reduced-motion: reduce) {
  /* Purely decorative easing goes away. */
  .sims-btn::before,
  .sims-toggle__pill { transition: none; }

  /* The figure keeps following the sliders, but without the springy overshoot. */
  :root {
    --spring-x: .15s ease-out;
    --spring-y: .15s ease-out;
  }

  /* The icon keeps hopping — it is the loader's only "still working" signal.
     Just at half speed. */
  .hopper__icon,
  .hopper__shadow { animation-duration: 1.8s; }
}
