/* PhotoWash landing page styles.
 *
 * Shared by index.html and grindr/index.html. It used to be an inline <style>
 * block in the one page, and moved out here the moment there were two: a
 * duplicated copy would have drifted the first time either page was touched.
 * Still no build step, just one more file to serve.
 *
 * Paths here are root absolute, because this file is loaded from /site.css by a
 * page at / and by a page at /grindr/, and a relative url would resolve against
 * this file's own directory in one case and read wrong in the other.
 */
/* Poppins, three weights, two subsets each. The unicode ranges are Google's own
   latin and latin-ext splits and must stay with the files make-assets.sh cuts to
   match them: change one without the other and a character silently disappears.
   latin carries the current copy; latin-ext is here so a European name in future
   copy does not fall back mid-sentence. */
@font-face {
  font-family: 'Poppins'; font-style: normal; font-weight: 400; font-display: swap;
  src: url(/assets/fonts/poppins-400-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Poppins'; font-style: normal; font-weight: 400; font-display: swap;
  src: url(/assets/fonts/poppins-400-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Poppins'; font-style: normal; font-weight: 600; font-display: swap;
  src: url(/assets/fonts/poppins-600-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Poppins'; font-style: normal; font-weight: 600; font-display: swap;
  src: url(/assets/fonts/poppins-600-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Poppins'; font-style: normal; font-weight: 700; font-display: swap;
  src: url(/assets/fonts/poppins-700-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Poppins'; font-style: normal; font-weight: 700; font-display: swap;
  src: url(/assets/fonts/poppins-700-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* The palette is the app's own. --accent is brand blue, which in the app is two
   colours rather than one: the deep blue stays put as a surface, and lifts in
   dark mode when it is a foreground on an adaptive background. Same split here,
   for the same reason: #0304D5 on near-black is close to unreadable.
   See Color+Brand.swift. */
:root {
  --bg: #f4f4f7; --card: #ffffff; --text: #312a3b; --muted: #6e6e79;
  --line: #d9d9e1; --accent: #0304d5; --accent-soft: #ebecfb;
  --warm: #e8763f; --radius: 18px;
  --shadow: 0 1px 3px rgba(0,0,0,0.05), 0 10px 30px rgba(0,0,0,0.07);
  /* One stack, used everywhere. The fallbacks only show while the font loads. */
  --font: 'Poppins', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}
@media (prefers-color-scheme: dark) {
  :root {
    --bg: #0b0b0f; --card: #17171c; --text: #f2f0f6; --muted: #9a9aa5;
    --line: #33333c; --accent: #6b73ff; --accent-soft: #1b1c39;
    --warm: #f08a56;
    --shadow: 0 1px 3px rgba(0,0,0,0.5), 0 10px 30px rgba(0,0,0,0.5);
  }
}
* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
/* A figure carries 40px of side margin by default, which quietly takes 80px out
   of whichever grid track a screenshot sits in and shrinks every phone here. */
figure { margin: 0; }
body {
  margin: 0; background: var(--bg); color: var(--text);
  font: 17px/1.6 var(--font);
  -webkit-font-smoothing: antialiased;
}
/* Poppins is geometric and sets wide, so headings take a touch more negative
   tracking than a system font would want. */
h1, h2, h3 { font-family: var(--font); }
.wrap { max-width: 1120px; margin: 0 auto; padding: 0 24px; }
a { color: var(--accent); }

/* Hero. On a wide screen the words take the left half and the devices the right,
   so the first thing above the fold is the app rather than a column of centred
   text with the screenshots a scroll away. */
.hero { padding: clamp(24px, 3.6vw, 44px) 0 clamp(20px, 2.6vw, 32px); }
.hero .wrap {
  display: grid; grid-template-columns: 1fr 1fr;
  gap: clamp(24px, 4vw, 52px); align-items: center;
}
.hero img.icon {
  width: 76px; height: 76px; border-radius: 18px;
  box-shadow: var(--shadow); margin-bottom: 16px;
}
.hero h1 {
  font-size: clamp(31px, 4.2vw, 48px); line-height: 1.08;
  letter-spacing: -0.02em; font-weight: 700; margin: 0 0 14px;
}
.hero p.lede {
  font-size: clamp(17px, 1.9vw, 21px); color: var(--muted);
  max-width: 36ch; margin: 0 0 20px;
}
.platforms { display: flex; gap: 8px; flex-wrap: wrap; }
.pill {
  border: 1px solid var(--line); border-radius: 999px;
  padding: 7px 14px; font-size: 15px; color: var(--muted); background: var(--card);
}
.pill strong { color: var(--text); font-weight: 600; }

/* The Ukrainian grant. Its own pill because it is a real offer rather than a
   spec line, marked with the flag's two colours as a small dot: the house style
   carries no emoji in copy, and a 10px emoji renders differently on every
   platform anyway.
   Hidden by default and shown only on the Ukrainian page: the offer is for
   Ukrainian readers, so it is noise on the other three. The explicit rule is
   needed because the display below would otherwise beat the hidden attribute. */
.pill.ua[hidden] { display: none; }
.pill.ua {
  border-color: #0057b7; color: var(--text);
  display: inline-flex; align-items: center; gap: 8px;
}
.pill.ua::before {
  content: ""; width: 11px; height: 11px; border-radius: 50%;
  background: linear-gradient(180deg, #0057b7 50%, #ffd700 50%);
  flex: none;
}

/* Apple's official badge, unmodified and at its native 129x43. Apple's marketing
   guidelines forbid recolouring or redrawing it, ask for a minimum height of
   40px, and ask for clear space of at least a quarter of the badge height, which
   the 18px top margin satisfies.
   Deliberately not scaled up past its native size: it is only supplied here as a
   1x PNG, and stretching it would both soften it and break the "unmodified"
   rule. A vector copy from Apple's marketing toolbox would be an improvement. */
.stores { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; margin-top: 18px; }
.stores a { display: inline-flex; line-height: 0; }
.stores img { height: 43px; width: auto; display: block; }

/* Device frames. The screenshots are raw simulator captures, so the bezel is
   drawn here rather than baked into the images: one set of files then serves
   this page, the store listing and the schema.org markup, and reshooting a
   screen does not mean re-framing it. The radii are percentages so a phone reads
   the same in the hero and at a third of the size further down. */
.device .screen {
  background: #0b0b0d; padding: 2.4%; border-radius: 14% / 6.4%;
  box-shadow: 0 2px 6px rgba(0,0,0,0.18), 0 18px 40px rgba(0,0,0,0.22);
}
.device .screen img {
  display: block; width: 100%; height: auto; border-radius: 11.5% / 5.2%;
}

/* The hero cluster: two phones behind, one in front, sized as percentages of a
   box with a fixed ratio so the arrangement holds at every width rather than
   coming apart between breakpoints. */
.cluster {
  position: relative; width: 100%; max-width: 520px;
  margin: 0 auto; aspect-ratio: 1.02;
}
.cluster > * { position: absolute; }
/* The widths add up to more than the box, which is the point: they overlap. Keep
   the sum near 110% though. At 119% the middle phone covered the best half of
   both of the others and the arrangement read as one phone with debris behind
   it. */
.cluster .d1 { left: 0; top: 1%; width: 36%; transform: rotate(-5deg); z-index: 1; }
.cluster .d2 { right: 0; top: 1%; width: 36%; transform: rotate(5deg); z-index: 1; }
/* The home screen sits in front and lower down, so it covers the ends of the
   other two rather than their best half. */
.cluster .d3 { left: 50%; bottom: 0; width: 38%; transform: translateX(-50%); z-index: 3; }

/* The App Store posters. Finished store artwork with the phone, the headline and
   the badge painted in, so they get a plain rounded corner and no .device bezel:
   framing one would draw a phone inside a phone. They stand in for the raw
   captures everywhere except the hero cluster, which is still three real screens
   with the frame drawn around them. */
.poster img {
  display: block; width: 100%; height: auto; border-radius: 14px;
  box-shadow: 0 2px 6px rgba(0,0,0,0.18), 0 18px 40px rgba(0,0,0,0.22);
}

/* Background Cleanup's own band. The gradient is sampled from the poster it sits
   beside, so the artwork reads as part of the block rather than pasted onto it.
   Deliberately the same in both colour schemes: it is dark enough for white type
   either way, and a band that is bright in one and muted in the other stops
   being the loud thing on the page. */
.shout-block { padding: clamp(26px, 3.2vw, 42px) 0; }
.shout {
  display: grid; grid-template-columns: 1fr minmax(150px, 200px);
  gap: clamp(20px, 3vw, 40px); align-items: center;
  padding: clamp(22px, 2.8vw, 38px);
  border-radius: 24px; color: #fff;
  background: linear-gradient(115deg, #0d0d78 0%, #2a1fa0 52%, #8a2585 100%);
  box-shadow: 0 10px 30px rgba(13,13,120,0.28);
}
.shout h2 {
  font-size: clamp(24px, 3vw, 34px); line-height: 1.15;
  letter-spacing: -0.02em; font-weight: 700; margin: 0 0 12px; color: #fff;
}
.shout p { margin: 0 0 10px; color: rgba(255,255,255,0.84); font-size: 16px; }
.shout p:last-child { margin-bottom: 0; }
/* The tag is the one on the feature cards, inverted. Its own rule rather than a
   modifier class, since there is only ever one of these on the page. */
.shout .tag { background: rgba(255,255,255,0.17); color: #fff; }

/* Sections */
.block { padding: clamp(32px, 4vw, 48px) 0; border-top: 1px solid var(--line); }
.block h2 {
  font-size: clamp(23px, 3vw, 32px); letter-spacing: -0.015em;
  font-weight: 700; margin: 0 0 8px;
}
.block p.sub { color: var(--muted); margin: 0 0 22px; max-width: 640px; }
.grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 18px;
}
.card {
  background: var(--card); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 22px; box-shadow: var(--shadow);
}
.card h3 { margin: 0 0 8px; font-size: 18px; letter-spacing: -0.01em; font-weight: 600; }
.card p { margin: 0; color: var(--muted); font-size: 16px; }

/* Features: two to a row on a wide screen, each one a screenshot beside the
   thing it shows. Stacked full width rows leave a phone sized hole of empty
   space next to three lines of copy. */
.features { display: grid; grid-template-columns: repeat(2, 1fr); gap: 20px; }
.feature {
  display: grid; grid-template-columns: minmax(130px, 180px) 1fr;
  gap: 22px; align-items: center;
  background: var(--card); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 22px; box-shadow: var(--shadow);
}
.feature .copy h3 {
  font-size: clamp(19px, 1.9vw, 23px); letter-spacing: -0.015em;
  line-height: 1.25; font-weight: 700; margin: 0 0 10px;
}
.feature .copy p { margin: 0 0 10px; color: var(--muted); font-size: 16px; }
.feature .copy p:last-child { margin-bottom: 0; }
.tag {
  display: inline-block; background: var(--accent-soft); color: var(--accent);
  border-radius: 999px; padding: 4px 12px; font-size: 14px; font-weight: 600;
  margin-bottom: 10px;
}
.tag.warm { background: color-mix(in srgb, var(--warm) 14%, transparent); color: var(--warm); }

/* Language bar. Sits above the hero, right aligned, small: it is for the
   minority whose browser language we guessed wrong, not a headline feature. */
.langbar { display: flex; gap: 6px; justify-content: flex-end; padding: 14px 0 0; }
.langbar button {
  font: 14px/1 var(--font); font-weight: 600;
  border: 1px solid var(--line); border-radius: 999px;
  background: var(--card); color: var(--muted);
  padding: 7px 13px; cursor: pointer;
}
.langbar button:hover { color: var(--text); }
.langbar button.active { background: var(--accent); border-color: var(--accent); color: #fff; }

footer {
  border-top: 1px solid var(--line); padding: 32px 0 56px;
  color: var(--muted); font-size: 15px;
}
footer h2 {
  font-size: 20px; font-weight: 700; letter-spacing: -0.01em;
  color: var(--text); margin: 0 0 14px;
}
footer .links { display: flex; gap: 18px; flex-wrap: wrap; margin-bottom: 14px; }

/* Below 900px the hero stacks, with the devices under the words. The features
   stay two to a row down to 700px on a smaller screenshot: one wide card per row
   leaves a phone's worth of empty space beside three lines of copy. */
@media (max-width: 900px) {
  .hero .wrap { grid-template-columns: 1fr; text-align: center; }
  .hero p.lede { margin-left: auto; margin-right: auto; }
  .platforms, .stores { justify-content: center; }
  .cluster { max-width: 440px; }
  .features { gap: 16px; }
  .feature {
    grid-template-columns: minmax(105px, 140px) 1fr;
    gap: 16px; padding: 16px;
  }
  .feature .copy p { font-size: 15px; }
}
@media (max-width: 700px) {
  /* The band stacks, and the poster stops being a column, so it needs a width
     of its own or it runs the full measure of the copy above it. */
  .shout { grid-template-columns: 1fr; justify-items: center; text-align: center; }
  .shout .poster { max-width: 240px; }
  .features { grid-template-columns: 1fr; }
  .feature { grid-template-columns: minmax(130px, 175px) 1fr; gap: 20px; padding: 20px; }
}
@media (max-width: 520px) {
  .feature { grid-template-columns: 1fr; gap: 18px; justify-items: center; text-align: center; }
  /* Both kinds of image, since a feature row draws a poster and the hero cluster
     a framed capture, and an uncapped figure here fills the whole card. */
  .feature .device, .feature .poster { max-width: 200px; }
}

/* The chat mockup in the /grindr hero. Drawn rather than photographed: the
   conversation is invented, so there is nothing to capture, and CSS keeps it
   sharp on a retina screen and translatable with the rest of the copy, neither
   of which a PNG would manage.
   The type is deliberately oversized. This phone renders about 180px wide in the
   cluster, so a life sized 17px bubble would come out around 6px and read as
   grey mush. Everything is sized in cqw against the screen's own width, so the
   same rules hold whatever size the frame is drawn at. */
.chat {
  container-type: inline-size;
  aspect-ratio: 736 / 1600;
  background: #000; border-radius: 11.5% / 5.2%;
  overflow: hidden;
}
/* The thread is a separate element from the container on purpose. Padding and
   gap in cqw on .chat itself would be circular, since cqw is a percentage of the
   very content box that padding decides, and Chrome resolves that cycle silently
   by roughly halving the unit: every bubble came out at half the intended size
   with nothing in the console to say why. A descendant has no such problem. */
.chat .thread {
  height: 100%;
  display: flex; flex-direction: column; justify-content: center;
  gap: 5cqw; padding: 10cqw 6cqw;
}
.chat .msg {
  max-width: 84%;
  font-size: 19cqw; line-height: 1.15; font-weight: 600;
  padding: 4cqw 7cqw; border-radius: 8cqw;
}
/* His messages one colour, yours the other, the way any chat app splits them.
   The tail corner is squared off on the side the bubble is anchored to. */
.chat .them {
  background: #1877f2; color: #fff;
  align-self: flex-start; border-bottom-left-radius: 2cqw;
}
.chat .you {
  background: #f5c518; color: #101014;
  align-self: flex-end; border-bottom-right-radius: 2cqw;
}
