/*
 * delvia.health — one stylesheet for every page and every locale.
 *
 * Tokens are the app's canonical design-system values, so the site and the
 * product read as one thing. Externalized (rather than inlined per page) so
 * the Caddy vhost can serve the static handle under a strict CSP without
 * 'unsafe-inline'.
 */

/* IBM Plex Sans — self-hosted, not the Google Fonts CDN: a health app that
   advertises privacy shouldn't hand visitor IPs to a font CDN. unicode-range
   means a Russian reader never downloads the Arabic face. */
@font-face {
  font-family: 'IBM Plex Sans';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/assets/fonts/ibm-plex-sans-latin-400-normal.24828974.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: 'IBM Plex Sans';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('/assets/fonts/ibm-plex-sans-latin-600-normal.90d9c226.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: 'IBM Plex Sans';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/assets/fonts/ibm-plex-sans-latin-ext-400-normal.c23e9877.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, 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: 'IBM Plex Sans';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('/assets/fonts/ibm-plex-sans-latin-ext-600-normal.2e84f56d.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, 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: 'IBM Plex Sans';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/assets/fonts/ibm-plex-sans-cyrillic-400-normal.e24ab12d.woff2') format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'IBM Plex Sans';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('/assets/fonts/ibm-plex-sans-cyrillic-600-normal.76fa1c68.woff2') format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'IBM Plex Sans Arabic';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/assets/fonts/ibm-plex-sans-arabic-arabic-400-normal.a9cefdca.woff2') format('woff2');
  unicode-range: U+0600-06FF, U+0750-077F, U+0870-088E, U+0890-0891, U+0898-08E1, U+08E3-08FF, U+200C-200E, U+2010-2011, U+204F, U+2E41, U+FB50-FDFF, U+FE70-FE74, U+FE76-FEFC;
}
@font-face {
  font-family: 'IBM Plex Sans Arabic';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('/assets/fonts/ibm-plex-sans-arabic-arabic-600-normal.9e5c019d.woff2') format('woff2');
  unicode-range: U+0600-06FF, U+0750-077F, U+0870-088E, U+0890-0891, U+0898-08E1, U+08E3-08FF, U+200C-200E, U+2010-2011, U+204F, U+2E41, U+FB50-FDFF, U+FE70-FE74, U+FE76-FEFC;
}

/* Canonical design-system tokens — light, then dark. Components only ever
   reference these, never a raw hex.
 *
 * The site is LIGHT for everyone by default: there is deliberately no
 * prefers-color-scheme branch here. The app's own captures are light-theme, so
 * a dark page would be selling a product it does not show, and the previous
 * behaviour — silently following the operating system with no control anywhere
 * — read to a dark-OS reader as "this site has no light mode". Dark is now a
 * choice, made with the header button and stored by assets/ui.js. */
:root {
  color-scheme: light;
  --canvas: #fafbfc;
  --surface: #ffffff;
  --surface-alt: #f1f5f9;
  --border: #e2e8f0;
  --t1: #0f172a;
  --t2: #475569;
  --t3: #94a3b8;
  --primary: #0f766e;
  --primary-pressed: #115e59;
  --primary-tint: #f0fdfa;
  --success: #16a34a;
  --warning: #d97706;
  --danger: #dc2626;
  --danger-tint: #fef2f2;
  --on-primary: #ffffff;
  --shadow-lift: 0 24px 48px -24px rgb(15 23 42 / 25%);
  --shadow-crop: 0 18px 34px rgb(15 23 42 / 16%);

  /* The landing page's one inverted ground — the section carrying the three
     problem statistics. One change of ground on a page is a decision; five is
     a template, which is what the alternating bands here used to be. */
  --ink: #0f172a;
  --on-ink: #f1f5f9;
  --on-ink-dim: rgb(241 245 249 / 72%);
  --ink-rule: rgb(241 245 249 / 14%);

  /* Chrome and the landing page run wide; long prose stays at .prose-page. */
  --page: 68rem;
  /* The landing page runs wider still: its panels carry a phone beside a
     column of prose, which --page cannot hold without squeezing one of them. */
  --page-lp: 76rem;
  --measure: 44rem;
  /* The landing page's prose column: shorter than .prose-page's, because it
     sits beside images rather than running the width of the page. */
  --measure-lp: 34rem;
  --radius: 12px;
  /* Each landing section is a panel on the page's ground rather than a band
     across it — the app's own screens are rounded cards, and the page that
     sells them should not read as a document. */
  --panel-radius: 28px;
  --shadow-panel: 0 1px 2px rgb(15 23 42 / 4%), 0 14px 36px -18px rgb(15 23 42 / 14%);
  --font: 'IBM Plex Sans', -apple-system, 'Segoe UI', Roboto, sans-serif;
}

/* font-family is re-declared, not just the token. var() substitutes at the
   element that DECLARES the property — and font-family is declared on body.
   A descendant that only redefines --font inherits body's already-resolved
   latin stack, which is why the Arabic endonym in the language switcher used
   to render in a system fallback face on every non-Arabic page. */
:root:lang(ar),
:lang(ar),
[dir='rtl'] {
  --font: 'IBM Plex Sans Arabic', 'IBM Plex Sans', -apple-system, 'Segoe UI', sans-serif;
  font-family: var(--font);
}

/* Attribute, not a media query: ui.js sets it from the reader's stored choice
   before the first paint. Nothing here fires on an operating-system setting. */
:root[data-theme='dark'] {
  color-scheme: dark;
  --canvas: #0b1220;
  --surface: #111a2c;
  --surface-alt: #1a2436;
  --border: #253248;
  --t1: #f1f5f9;
  --t2: #94a3b8;
  --t3: #64748b;
  --primary: #2dd4bf;
  --primary-pressed: #14b8a6;
  --primary-tint: #0f2e2b;
  --success: #4ade80;
  --warning: #fbbf24;
  --danger: #f87171;
  --danger-tint: #2d1416;
  --on-primary: #0b1220;
  --shadow-lift: 0 24px 48px -24px rgb(0 0 0 / 55%);
  --shadow-crop: 0 18px 34px rgb(0 0 0 / 45%);
  --shadow-panel: 0 1px 2px rgb(0 0 0 / 20%), 0 14px 36px -18px rgb(0 0 0 / 45%);
  /* Deeper than the canvas, so the inverted panel still reads as a change of
     ground on a page that is already dark. */
  --ink: #060b15;
  --on-ink: #f1f5f9;
  --on-ink-dim: rgb(241 245 249 / 70%);
  --ink-rule: rgb(241 245 249 / 12%);
}

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

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

body {
  background: var(--canvas);
  color: var(--t1);
  font-family: var(--font);
  font-size: 16px;
  line-height: 1.65;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
}

a {
  color: var(--primary);
}

:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
  border-radius: 4px;
}

.skip {
  position: absolute;
  inset-inline-start: -9999px;
}
.skip:focus {
  inset-inline-start: 1rem;
  top: 1rem;
  z-index: 10;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 0.5rem 0.9rem;
}

/* ---------------------------------------------------------------- chrome */

.wrap {
  width: 100%;
  max-width: var(--page);
  margin-inline: auto;
  padding-inline: 1.5rem;
}

/* Long prose reads at a measure, not at the full page width. Declared after
   .wrap so the narrower max-width wins on `.wrap.prose-page`. */
.prose-page {
  max-width: var(--measure);
  padding-block: 2.5rem 4rem;
}

/* Sticky, because the language menu and the theme button are the only
   navigation the site has and both should stay reachable. Translucent over
   the canvas so a panel scrolling under it is visible but not legible. */
.site-head {
  position: sticky;
  top: 0;
  z-index: 20;
  border-bottom: 1px solid var(--border);
  padding-block: 0.7rem;
  background: var(--canvas);
  background: color-mix(in srgb, var(--canvas) 80%, transparent);
  backdrop-filter: blur(14px);
}

.site-head .wrap {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.brand {
  display: inline-flex;
  align-items: center;
  text-decoration: none;
  color: var(--t1);
  margin-inline-end: auto;
}

.brand-lockup {
  display: block;
  width: auto;
  height: 32px;
  overflow: visible;
}

.brand-lockup__mark {
  color: var(--primary);
}

/* ------ the way into the web app
 *
 * Outlined, in the shape of the language control beside it, rather than
 * filled: the hero's "Open Delvia" is the page's one filled button, and two
 * of them one above the other would be shouting. Same 34px height as the
 * theme button so the three controls sit on one line. */

.head-cta {
  flex: none;
  display: inline-flex;
  align-items: center;
  height: 34px;
  padding-inline: 0.85rem;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--surface);
  color: var(--primary);
  font-size: 0.85rem;
  font-weight: 600;
  line-height: 1;
  text-decoration: none;
  white-space: nowrap;
}

.head-cta:hover {
  border-color: var(--primary);
}

.head-cta:focus-visible {
  border-radius: 999px;
}

/* The short label exists for phones only; see the narrow-header rule below. */
.head-cta__short {
  display: none;
}

/* ------ theme button */

/* flex: none, like the app link: squeezed, a 34px circle became a 20px oval
   before anything else on the row gave way. */
.theme-toggle {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  padding: 0;
  border: 1px solid transparent;
  border-radius: 999px;
  background: none;
  color: var(--t2);
  cursor: pointer;
}

.theme-toggle:hover {
  background: var(--surface-alt);
  color: var(--t1);
}

.theme-toggle svg {
  width: 18px;
  height: 18px;
}

/* One icon per theme: the moon is what the button will do, not what is on. */
.theme-toggle__sun {
  display: none;
}

[data-theme='dark'] .theme-toggle__sun {
  display: block;
}

[data-theme='dark'] .theme-toggle__moon {
  display: none;
}

/* ------ language menu
 *
 * Seven endonyms laid out inline took more width than the logo and wrapped
 * onto two rows on a phone, so the first thing a reader met was a language
 * list. One disclosure instead — native <details>, so it still opens with
 * JavaScript off; ui.js only closes it on Escape or an outside click. */

.langs {
  position: relative;
}

.langmenu > summary {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.35rem 0.7rem;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--surface);
  color: var(--t2);
  font-size: 0.85rem;
  cursor: pointer;
  list-style: none;
  user-select: none;
  white-space: nowrap;
}

.langmenu > summary::-webkit-details-marker {
  display: none;
}

.langmenu > summary:hover,
.langmenu[open] > summary {
  color: var(--t1);
}

.langmenu__panel {
  position: absolute;
  inset-inline-end: 0;
  top: calc(100% + 0.5rem);
  z-index: 30;
  display: flex;
  flex-direction: column;
  min-width: 12rem;
  padding: 0.3rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 14px;
  box-shadow: var(--shadow-lift);
}

.langmenu__panel a {
  padding: 0.45rem 0.7rem;
  border-radius: 9px;
  color: var(--t2);
  text-decoration: none;
  font-size: 0.92rem;
}

.langmenu__panel a:hover {
  background: var(--surface-alt);
  color: var(--t1);
}

.langmenu__panel a[aria-current='page'] {
  color: var(--primary);
  font-weight: 600;
}

/* No page padding here — the landing page's bands run edge to edge and set
   their own; prose pages get theirs from .prose-page. */
main {
  flex: 1;
}

.site-foot {
  border-top: 1px solid var(--border);
  margin-block-start: clamp(2rem, 5vw, 4rem);
  padding-block: clamp(2rem, 4vw, 3rem) 2.5rem;
  color: var(--t3);
  font-size: 0.9rem;
}

.site-foot .wrap {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
}

/* align-items, not the default stretch: an <svg> with width:auto stretched to
   the column's full width centres its own artwork inside it, which read as a
   logo mysteriously centred over left-aligned text. */
.site-foot__brand {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.5rem;
}

.site-foot .brand-lockup {
  height: 26px;
  color: var(--t1);
}

.site-foot nav {
  display: flex;
  gap: 0.6rem 1.5rem;
  flex-wrap: wrap;
}

.site-foot a {
  color: var(--t2);
}

.site-foot__legal {
  padding-block-start: 1rem;
  border-block-start: 1px solid var(--border);
}

.site-foot__disclosure {
  margin-block-end: 0.4rem;
  max-width: 65ch;
  line-height: 1.45;
  font-size: 0.85rem;
}

.disclaimer {
  color: var(--t3);
  max-width: 42ch;
}

/* ------------------------------------------------------------ long prose */

.prose h1 {
  font-size: 1.7rem;
  line-height: 1.25;
  margin-bottom: 0.4rem;
  text-wrap: balance;
}

.prose .meta {
  color: var(--t3);
  font-size: 0.9rem;
  margin-bottom: 2rem;
}

.prose h2 {
  font-size: 1.15rem;
  margin: 2.2rem 0 0.6rem;
}

.prose p,
.prose ul,
.prose ol {
  color: var(--t2);
  margin-bottom: 0.9rem;
}

.prose ul,
.prose ol {
  padding-inline-start: 1.3rem;
}

.prose li {
  margin-bottom: 0.35rem;
}

.prose strong {
  color: var(--t1);
}

/* Tables can be wider than the measure — scroll them, never the page. */
.table-scroll {
  overflow-x: auto;
  margin-bottom: 1rem;
}

.prose table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.92rem;
  min-width: 34rem;
}

.prose th,
.prose td {
  text-align: start;
  padding: 0.5rem 0.6rem;
  border-bottom: 1px solid var(--border);
  vertical-align: top;
  color: var(--t2);
}

.prose th {
  color: var(--t1);
}

.card {
  background: var(--primary-tint);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 1rem 1.1rem;
  margin: 1rem 0;
}

.card p:last-child {
  margin-bottom: 0;
}

.translation-note {
  color: var(--t3);
  font-size: 0.85rem;
  border-inline-start: 3px solid var(--border);
  padding-inline-start: 0.9rem;
  margin-bottom: 1.5rem;
}

/* ---------------------------------------------------------------- forms */

.form-row {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  margin-bottom: 1rem;
}

label {
  font-size: 0.9rem;
  font-weight: 600;
}

input[type='email'],
input[type='password'] {
  font: inherit;
  font-size: 1rem;
  color: var(--t1);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 0.7rem 0.85rem;
  width: 100%;
}

.consent {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  font-weight: 400;
  color: var(--t2);
  line-height: 1.5;
}

.consent input {
  margin-top: 0.3rem;
  accent-color: var(--primary);
}

.btn {
  font: inherit;
  font-weight: 600;
  cursor: pointer;
  border: 1px solid transparent;
  border-radius: 10px;
  padding: 0.7rem 1.2rem;
  background: var(--primary);
  color: var(--on-primary);
}

.btn:hover {
  background: var(--primary-pressed);
}

.btn[disabled] {
  opacity: 0.55;
  cursor: default;
}

/* Not a hard-coded white: --danger is a light red in dark mode, and white on
   it lands around 2.5:1. This is the account-deletion button — the one
   destructive control on the site — so it takes the token that is defined to
   contrast with a bright fill in both themes. */
.btn-danger {
  background: var(--danger);
  color: var(--on-primary);
}

.btn-danger:hover {
  filter: brightness(0.92);
}

.notice {
  border-radius: var(--radius);
  padding: 0.9rem 1rem;
  margin: 1rem 0;
  border: 1px solid var(--border);
}

.notice-error {
  background: var(--danger-tint);
  border-color: var(--danger);
  color: var(--danger);
}

.notice-success {
  background: var(--primary-tint);
  border-color: var(--success);
  color: var(--success);
}

[hidden] {
  display: none !important;
}

/* --------------------------------------------------------------- landing
 *
 * A column of soft panels on the page's own ground, in the shape of the app's
 * own screens. The version before this was one flat canvas with hairlines
 * between sections, which read as ten thousand pixels of grey document; the
 * panels give each section an edge and give the screenshots somewhere to sit.
 *
 * The imagery is nothing but real captures of the shipped app. An earlier
 * version drew a phone in CSS with an invented transcript and an SVG trend
 * chart with an invented polyline. Both are gone: assets/shots/ holds the real
 * thing in all seven languages, and a drawn imitation of your own product is
 * the one asset you never have to fake.
 *
 * Everything sits on logical properties (inline-start/end, border-block) so
 * the Arabic build mirrors without a second set of rules.
 */

.lp {
  width: 100%;
  max-width: var(--page-lp);
  margin-inline: auto;
  padding-inline: clamp(1rem, 3vw, 2rem);
  display: flex;
  flex-direction: column;
  gap: clamp(1rem, 1.5vw, 1.5rem);
}

.lp-panel {
  display: flex;
  flex-direction: column;
  gap: clamp(2rem, 4vw, 3rem);
  padding: clamp(1.75rem, 4vw, 3.5rem);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--panel-radius);
  box-shadow: var(--shadow-panel);
  /* No overflow: hidden here. A stage clips its own screenshot and never
     reaches the panel's edge anyway, and an overflow on an ancestor makes it
     the scroll container for any position: sticky inside — which would stop
     the FAQ heading sticking to the viewport. */
  /* The header is sticky: an anchored panel would otherwise land under it. */
  scroll-margin-block-start: 5rem;
}

/* ------ type */

/* hyphens, because German headline nouns are compounds: "Gesundheitsgeschichte"
   is 21 characters and at the hero size it is wider than a 390px phone, with
   no space in it to break at. The <html lang> picks the dictionary;
   overflow-wrap is the backstop for a language that has none. */
.lp h1 {
  font-size: clamp(2.6rem, 5.6vw, 4.25rem);
  line-height: 1.03;
  letter-spacing: -0.035em;
  font-weight: 600;
  text-wrap: balance;
  hyphens: auto;
  overflow-wrap: break-word;
}

.lp h2 {
  font-size: clamp(1.75rem, 3vw, 2.5rem);
  line-height: 1.14;
  letter-spacing: -0.022em;
  font-weight: 600;
  text-wrap: balance;
  hyphens: auto;
  overflow-wrap: break-word;
}

.lp-lede {
  font-size: clamp(1.125rem, 1.5vw, 1.3rem);
  line-height: 1.55;
  color: var(--t2);
  text-wrap: pretty;
}

.lp-body {
  font-size: 1.0625rem;
  line-height: 1.7;
  color: var(--t2);
  text-wrap: pretty;
}

.lp-label {
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--t3);
}

/* Prose stops at a measure even when its column is wider. Applied to the
   children so the column itself still fills its grid track. */
.lp-copy {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.lp-copy > * {
  max-width: var(--measure-lp);
}

/* ------ two columns */

.lp-split {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 0.8fr);
  gap: clamp(2rem, 4.5vw, 4rem);
  align-items: start;
}

.lp-split-center {
  align-items: center;
}

/* Image first, copy second — alternated down the page so it does not read as
   a stack of identical rows. `order` rather than source order, so the reading
   order stays copy-then-image for a screen reader and for a narrow screen.
   The tracks swap with it, or the image lands in the track sized for prose. */
.lp-split-flip {
  grid-template-columns: minmax(0, 0.8fr) minmax(0, 1fr);
}

.lp-split-flip > :first-child {
  order: 2;
}

.lp-split-flip > :last-child {
  order: 1;
}

/* Fifteen questions under a heading leaves half the panel empty; beside it,
   the heading holds the column the answers do not need — and it travels with
   them, because fifteen rows are taller than one heading and the column would
   otherwise empty out under it. */
.lp-split-faq {
  grid-template-columns: minmax(0, 0.55fr) minmax(0, 1fr);
}

.lp-split-faq > .lp-copy {
  position: sticky;
  top: 5.5rem;
  align-self: start;
}

/* ------ the real screenshots
 *
 * One treatment everywhere: the capture inset in a thin bezel of the page's
 * own surface. No drawn notch and no invented status bar — the Play assets
 * carry those because a bare capture reads as a card at thumbnail size, but at
 * this scale they would just be more fiction on a page that is removing it.
 *
 * The captures are light-theme (capture.mjs pins the preference), which is
 * what a lit phone looks like on any ground, so nothing is recoloured. */
.lp-shot {
  width: min(20rem, 100%);
  padding: 6px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 30px;
  box-shadow: var(--shadow-lift);
}

.lp-shot img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 24px;
}

/* A phone is taller than any column of copy beside it. Rather than shrink it
   until the app is unreadable, it stands on a tinted stage and runs off the
   bottom of it: a deliberate crop with an edge, instead of a mask fading into
   nothing — and true to the app, where these screens keep going below the
   fold too. */
.lp-stage {
  display: flex;
  justify-content: center;
  align-items: flex-start;
  height: clamp(21rem, 44vw, 28rem);
  padding: clamp(1.25rem, 3vw, 2rem) 0.75rem 0;
  background: var(--surface-alt);
  border-radius: 22px;
  overflow: hidden;
}

.lp-stage .lp-shot {
  width: min(19rem, 100%);
  box-shadow: none;
}

.lp-stage-sm {
  height: clamp(18rem, 36vw, 23rem);
}

/* A single element lifted out of a capture at reading size — the one thing a
   screenshot of a whole screen cannot do at web scale. It sits under the
   paragraph it illustrates, not over the phone: a crop laid on the device's
   face reads as a sticker, and lands somewhere different at every width. Its
   corners are transparent in the file itself, so the shadow follows the
   card's own shape rather than a box around it. */
.lp-crop {
  width: min(24rem, 100%);
  margin: 0.5rem 0 0;
}

.lp-crop img {
  display: block;
  width: 100%;
  height: auto;
  filter: drop-shadow(var(--shadow-crop));
}

/* ------ hero */

/* Centred, on open canvas rather than in a panel, so the page opens with air
   and the product gets one moment instead of half a column. Centred also
   mirrors for Arabic with nothing to flip. */
.lp-hero {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 1.25rem;
  padding-block: clamp(2.5rem, 6vw, 4.5rem) 0;
}

.lp-hero h1 {
  max-width: min(18ch, 100%);
}

.lp-hero .lp-lede {
  max-width: 46ch;
}

/* The wash and the phone share one grid cell, so the glow is centred on the
   device in both directions without a physical-property transform. */
.lp-hero-shot {
  display: grid;
  justify-items: center;
  width: 100%;
  margin-block-start: clamp(2rem, 5vw, 3.5rem);
}

.lp-hero-shot > * {
  grid-area: 1 / 1;
}

.lp-hero-shot::before {
  content: '';
  grid-area: 1 / 1;
  align-self: stretch;
  width: min(52rem, 94vw);
  background: radial-gradient(
    closest-side,
    color-mix(in srgb, var(--primary) 12%, transparent),
    transparent
  );
}

/* An outlined chip, not a filled button: it states a fact (the web app is
   live), and the button that acts on it is .lp-cta below the lede. Two
   button-shaped things saying the same thing would be one too many. */
.lp-pill {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.35rem 0.85rem;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--surface);
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--primary);
}

.lp-pill::before {
  content: '';
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--primary);
  flex: none;
}

.lp-textlink {
  font-size: 0.95rem;
  color: var(--t2);
  text-decoration-color: var(--border);
  text-underline-offset: 4px;
}

.lp-textlink:hover {
  color: var(--primary);
}

/* The button and the line about the phone apps belong together, so they sit
   closer to each other than the hero's own gap puts its children. They open
   the hero, above the headline, where its chip used to be. */
.lp-hero-actions {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.6rem;
  margin-block-end: 0.35rem;
}

/* The hero's way into the web app: the old chip's shape grown into a real
   button. A lifted white pill with ink text rather than a teal block (user
   decision 2026-09-29): the bloom says whose app it is, the arrow says it
   goes somewhere, and the one teal thing is that arrow. Hover lifts it and
   slides the arrow on, both themes from the tokens. */
.lp-open {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  min-height: 46px;
  padding-block: 0.55rem;
  padding-inline: 0.8rem 1.05rem;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--surface);
  color: var(--t1);
  font-size: 1rem;
  font-weight: 600;
  line-height: 1.2;
  text-decoration: none;
  box-shadow:
    0 1px 2px rgb(15 23 42 / 5%),
    0 8px 22px -12px color-mix(in srgb, var(--primary) 45%, transparent);
  transition: border-color 150ms ease, box-shadow 150ms ease, transform 150ms ease;
}

.lp-open:hover {
  border-color: color-mix(in srgb, var(--primary) 45%, var(--border));
  box-shadow:
    0 1px 2px rgb(15 23 42 / 5%),
    0 14px 30px -14px color-mix(in srgb, var(--primary) 60%, transparent);
  transform: translateY(-1px);
}

.lp-open:active {
  transform: translateY(0);
}

/* The global focus ring rounds itself to 4px; keep the pill's shape. */
.lp-open:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 3px;
  border-radius: 999px;
}

.lp-open__mark {
  flex: none;
  width: 26px;
  height: 26px;
  padding: 3px;
  border-radius: 50%;
  background: var(--primary-tint);
  color: var(--primary);
}

.lp-open__arrow {
  flex: none;
  width: 18px;
  height: 18px;
  color: var(--primary);
  transition: transform 150ms ease;
}

.lp-open:hover .lp-open__arrow {
  transform: translateX(3px);
}

/* The arrow points the way the line reads. */
[dir='rtl'] .lp-open__arrow {
  transform: scaleX(-1);
}

[dir='rtl'] .lp-open:hover .lp-open__arrow {
  transform: scaleX(-1) translateX(3px);
}

@media (prefers-reduced-motion: reduce) {
  .lp-open,
  .lp-open__arrow {
    transition: none;
  }
}

/* The app's primary button: 48px, radius 12, teal with its on-primary text.
   Both themes come from the tokens (dark mode is bright teal with dark text,
   exactly as in the app), so there is no second rule for dark. */
.lp-cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  min-width: 12rem;
  padding: 0.75rem 1.6rem;
  border: 1px solid transparent;
  border-radius: var(--radius);
  background: var(--primary);
  color: var(--on-primary);
  font-size: 1rem;
  font-weight: 600;
  line-height: 1.2;
  text-align: center;
  text-decoration: none;
  box-shadow: 0 10px 24px -14px color-mix(in srgb, var(--primary) 70%, transparent);
  transition: background-color 120ms ease, transform 120ms ease;
}

.lp-cta:hover {
  background: var(--primary-pressed);
}

.lp-cta:active {
  background: var(--primary-pressed);
  transform: translateY(1px);
}

/* The global focus ring rounds itself to 4px, which would square the
   button's corners the moment it takes focus. */
.lp-cta:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 3px;
  border-radius: var(--radius);
}

/* The same button without the fill, for a page where it is the way out rather
   than the thing to do (the checkout page's "Back to Delvia"). */
.lp-cta--quiet {
  background: var(--surface);
  border-color: var(--border);
  color: var(--t1);
  box-shadow: none;
}

.lp-cta--quiet:hover,
.lp-cta--quiet:active {
  background: var(--surface-alt);
}

/* Quiet, but --t2 rather than --t3: at this size --t3 on the canvas is well
   under a readable contrast, and this line is information, not decoration. */
.lp-soon {
  font-size: 0.9rem;
  color: var(--t2);
}

/* ------ the three numbers, on the page's one inverted ground */

.lp-ink {
  background: var(--ink);
  border-color: transparent;
  color: var(--on-ink);
}

.lp-ink h2 {
  color: var(--on-ink);
}

.lp-ink .lp-lede {
  color: var(--on-ink-dim);
}

/* Three explicit columns rather than auto-fit: with three items, an auto-fit
   grid at tablet width strands the third on a row of its own. */
.lp-figures {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(1.5rem, 3vw, 2.5rem);
  margin: 0;
}

.lp-figures > div {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  padding-block-start: clamp(1rem, 2vw, 1.5rem);
  border-block-start: 1px solid var(--ink-rule);
}

.lp-figures dt {
  font-size: clamp(1.9rem, 3.2vw, 2.8rem);
  line-height: 1.05;
  font-weight: 600;
  letter-spacing: -0.03em;
  text-wrap: balance;
}

.lp-figures dd {
  margin: 0;
  font-size: 1rem;
  line-height: 1.6;
  color: var(--on-ink-dim);
  text-wrap: pretty;
}

/* ------ what it remembers about you */

.lp-cats-wrap {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

/* A list, not an icon grid: six icons in six boxes is the feature grid this
   page is deliberately not. Six divides evenly by three, two and one, so
   auto-fit never strands a row here. */
.lp-cats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(15rem, 100%), 1fr));
  column-gap: clamp(1.5rem, 4vw, 3rem);
  margin: 0;
}

/* Name over detail, always — inline would put the short ones on one line and
   the long ones on two, and six rows at two different heights read as an
   accident. */
.lp-cats > div {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  padding-block: 1rem;
  border-block-start: 1px solid var(--border);
}

.lp-cats dt {
  font-weight: 600;
}

.lp-cats dd {
  margin: 0;
  color: var(--t2);
  font-size: 0.95rem;
}

/* ------ languages */

.lp-langs {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-block-start: 0.5rem;
  max-width: none;
}

.lp-langs span {
  padding: 0.3rem 0.8rem;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--surface-alt);
  font-size: 0.9rem;
  color: var(--t2);
}

/* ------ your data */

/* Two columns, because there are four of them: a three-across grid leaves the
   fourth stranded on a row of its own. */
.lp-points {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  column-gap: clamp(2rem, 5vw, 3.5rem);
  margin: 0;
}

.lp-points > div {
  padding-block: 1.4rem;
  border-block-start: 1px solid var(--border);
}

.lp-points dt {
  font-weight: 600;
  margin-block-end: 0.3rem;
}

.lp-points dd {
  margin: 0;
  color: var(--t2);
  line-height: 1.65;
}

/* The one inset strip on the page, because it is the one thing that should
   read as a notice rather than as prose. */
.lp-note {
  display: flex;
  gap: 0.9rem;
  align-items: flex-start;
  background: var(--surface-alt);
  border-radius: 18px;
  padding: 1.25rem 1.4rem;
}

.lp-note svg {
  width: 22px;
  height: 22px;
  flex: none;
  color: var(--t3);
  margin-block-start: 0.15rem;
}

.lp-note p {
  color: var(--t2);
  font-size: 0.95rem;
  line-height: 1.65;
}

/* ------ FAQ */

.lp-faq-list {
  display: flex;
  flex-direction: column;
}

.lp-faq-list details {
  border-block-start: 1px solid var(--border);
  padding-block: 1.05rem;
}

.lp-faq-list details:last-child {
  border-block-end: 1px solid var(--border);
}

.lp-faq-list summary {
  cursor: pointer;
  font-size: 1.0625rem;
  font-weight: 600;
  list-style: none;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 0.75rem;
}

.lp-faq-list summary::-webkit-details-marker {
  display: none;
}

.lp-faq-list summary::after {
  content: '+';
  color: var(--t3);
  font-weight: 400;
  font-size: 1.2rem;
  line-height: 1;
}

.lp-faq-list details[open] summary::after {
  content: '\2212';
}

.lp-faq-list details p {
  margin-block-start: 0.75rem;
  color: var(--t2);
  line-height: 1.65;
  max-width: 62ch;
}

/* -------------------------------------------------------------- checkout
 *
 * What sits behind Paddle's overlay. One card, one status line at a time
 * (checkout.js reveals it), and a way back. No panel stack and no marketing:
 * someone who is paying should meet nothing but the payment. */

.checkout-page {
  display: flex;
  justify-content: center;
  padding-block: clamp(2.5rem, 9vw, 5.5rem) 1rem;
}

.checkout {
  width: min(28rem, 100%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1rem;
  padding: clamp(1.75rem, 5vw, 2.5rem);
  text-align: center;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--panel-radius);
  box-shadow: var(--shadow-panel);
}

.checkout__mark {
  width: 48px;
  height: 48px;
  padding: 13px;
  border-radius: 50%;
  background: var(--primary-tint);
  color: var(--primary);
}

.checkout h1 {
  font-size: 1.5rem;
  line-height: 1.25;
  font-weight: 600;
  letter-spacing: -0.01em;
  text-wrap: balance;
}

/* Holds one line's height while no line shows, so the button below does not
   jump each time the state changes. */
.checkout__status {
  min-height: 1.65em;
  margin-block-end: 0.5rem;
  color: var(--t2);
}

.checkout__line {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  text-wrap: balance;
}

.checkout__line--done {
  color: var(--t1);
  font-weight: 600;
}

.checkout__spinner {
  flex: none;
  width: 16px;
  height: 16px;
  border: 2px solid var(--border);
  border-block-start-color: var(--primary);
  border-radius: 50%;
  animation: checkout-spin 0.8s linear infinite;
}

@keyframes checkout-spin {
  to {
    transform: rotate(360deg);
  }
}

/* ------ narrow screens */

/* A phone. Brand, app link, theme and language have to share one row in every
   locale, and measured at 320-512px they do not: "Bahasa Melayu" alone is a
   157px pill, and Russian's "Открыть приложение" is 172px. So below 32rem
   (the widest locale's long label needs ~490px) the app link takes its short
   label, the language control shows its globe and chevron only, and the
   gutter drops to 16px. The language name stays in the control for screen
   readers — visually hidden, never removed — and the menu it opens is
   unchanged. */
@media (max-width: 32rem) {
  .site-head .wrap {
    padding-inline: 1rem;
    gap: 0.4rem;
  }

  .head-cta {
    padding-inline: 0.7rem;
  }

  .head-cta__long {
    display: none;
  }

  .head-cta__short {
    display: inline;
  }

  .langmenu > summary > span {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
}

@media (max-width: 56rem) {
  .lp-split,
  .lp-split-flip,
  .lp-split-faq {
    grid-template-columns: 1fr;
    gap: 2.25rem;
  }

  /* Source order again: the copy introduces the screenshot it sits above. */
  .lp-split-flip > :first-child,
  .lp-split-flip > :last-child {
    order: 0;
  }

  .lp-figures,
  .lp-points {
    grid-template-columns: 1fr;
  }

  .lp-stage {
    height: clamp(19rem, 62vw, 24rem);
  }
}

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