/* plippo.app — the house page. One stylesheet, no framework, no external requests.
   Written in LOGICAL properties throughout, so the whole layout mirrors for Arabic. */

:root {
    --paper: #F7F4EE;
    --ink: #23201C;
    --soft: #6B655C;
    --line: #E2DCD1;
    --teal: #0F6257;          /* the house mark's green — the page's only accent */
    --card: #FFFFFF;
    --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue",
        "Noto Sans", "Noto Sans Arabic", "Noto Sans Devanagari", "Noto Sans JP",
        "Noto Sans KR", "Noto Sans SC", sans-serif;
}

* { box-sizing: border-box }

body {
    margin: 0;
    font-family: var(--font);
    color: var(--ink);
    background: var(--paper);
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
}

.wrap { max-width: 860px; margin-inline: auto; padding-inline: 24px }

.sr-only {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}

/* ---- header ---- */
.bar {
    display: flex; align-items: center; justify-content: space-between;
    padding-block: 26px; border-block-end: 1px solid var(--line);
}
.logo {
    display: flex; align-items: center; gap: 10px;
    font-weight: 800; font-size: 18px; letter-spacing: -.01em;
    color: inherit; text-decoration: none;
}
img.mark { width: 32px; height: 32px; border-radius: 9px; object-fit: cover; display: block }
.bar nav a { color: var(--soft); text-decoration: none; font-size: 14px; margin-inline-start: 18px }
.bar nav a:hover { color: var(--ink) }

/* ---- hero ---- */
.hero { padding-block: 70px 34px }
.heroText { max-width: 660px }
h1 { font-size: 46px; line-height: 1.12; margin: 0 0 20px; letter-spacing: -.025em; font-weight: 800 }
.lede { font-size: 19px; line-height: 1.65; color: var(--soft); margin: 0 }

/* ---- the principles ---- */
.rules { margin-block: 44px; border-block-start: 1px solid var(--line) }
.rule {
    display: flex; gap: 20px; align-items: baseline;
    padding-block: 18px; border-block-end: 1px solid var(--line);
}
.rule .n {
    font-variant-numeric: tabular-nums; color: var(--teal);
    font-weight: 800; font-size: 14px; min-width: 26px;
}
.rule b { font-size: 16px; min-width: 190px }
.rule > span:last-child { color: var(--soft); font-size: 15px; line-height: 1.5 }

/* ---- the two apps ---- */
.cards { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-block: 44px }
.card {
    border: 1px solid var(--line); border-radius: 18px; padding: 26px;
    text-decoration: none; color: inherit; display: block; background: var(--card);
    transition: border-color .18s ease, transform .18s ease;
}
.card:hover { border-color: rgba(15, 98, 87, .35); transform: translateY(-2px) }
img.ic { width: 62px; height: 62px; border-radius: 15px; object-fit: cover; display: block; margin-block-end: 12px }
.card h3 { margin: 0 0 4px; font-size: 21px }
.card .age { font-size: 13px; color: var(--soft); font-weight: 600 }
.card p { color: var(--soft); line-height: 1.55; font-size: 15px; margin-block: 12px 14px }
.card .go { font-weight: 700; font-size: 14px; color: var(--teal) }

/* ---- privacy (the anchor the shipped apps and the App Store link to) ---- */
.sec { margin-block: 46px; padding-block-start: 26px; border-block-start: 1px solid var(--line) }
.sec h2 { font-size: 19px; margin: 0 0 10px }
.sec p { color: var(--soft); line-height: 1.65; font-size: 15px; margin: 0 0 12px }
.sec a { color: var(--teal) }
.sec .links { display: flex; gap: 8px; flex-wrap: wrap }

footer {
    padding-block: 26px 50px; border-block-start: 1px solid var(--line);
    color: var(--soft); font-size: 13px; display: flex; gap: 18px; flex-wrap: wrap;
}
footer a { color: var(--soft) }

@media (max-width: 760px) {
    .cards { grid-template-columns: 1fr }
    h1 { font-size: 34px }
    .hero { padding-block: 48px 24px }
    .rule { flex-wrap: wrap; gap: 6px 20px }
    .rule b { min-width: 0; flex: 1 }
    .rule > span:last-child { flex-basis: 100%; padding-inline-start: 46px }
}

/* Legal pages (Impressum / Datenschutz) — long-form prose on the shared sheet. Inline <style> is
   not an option: the site CSP is `style-src 'self'`, which blocks inline style blocks outright. */
.legal { border-block-start: none; padding-block-start: 0 }
.legal h1 { font-size: 26px; margin: 0 0 18px }
.legal h2 { font-size: 17px; margin: 26px 0 8px }
.legal p, .legal li { color: var(--soft); line-height: 1.65; font-size: 15px }
.legal p { margin: 0 0 12px }
.legal ul { margin: 0 0 12px; padding-inline-start: 20px }
.legal li { margin-block-end: 6px }
.legal address { font-style: normal; color: var(--soft); line-height: 1.65; font-size: 15px; margin: 0 0 12px }
.legal a { color: var(--teal) }

/* ── The business model: one picture, then the steps behind it ───────────────
   Rebuilt 2026-09-21. It used to be two stacked lists AND a separate line chart
   making the same argument twice. Now the two roads ARE the chart lines, and the
   shaded wedge between them is the thing the section is about: not two prices,
   but the distance that opens between them and never closes. */

.paths { margin-block: 26px }
.paths svg { display: block; width: 100%; height: auto; overflow: visible }
/* Chart labels stay left-to-right even on the Arabic page: the timeline runs one
   way, and mirroring only the words inside it reads as a fault. Same treatment
   the old chart had. */
.paths text { direction: ltr; unicode-bidi: isolate }
.paths .axis { stroke: var(--line); stroke-width: 1 }
.paths .grid { stroke: var(--line); stroke-width: 1; stroke-dasharray: 3 4 }
.paths .xlab { fill: var(--soft); font-size: 11px }
.paths-wide .xlab { font-size: 14px }
.paths .lineThem { fill: none; stroke: #A8602A; stroke-width: 3;
    stroke-linejoin: round; stroke-linecap: round }
.paths .dots circle { fill: #A8602A }
.paths .valThem { fill: #8A4E22; font-size: 12.5px; font-weight: 600 }
.paths-wide .valThem { font-size: 16px }
.paths .tolls-g text { fill: #8A4E22; font-size: 11.5px }
.paths-wide .tolls-g text { font-size: 15px }
.paths .wedge { fill: #A8602A; opacity: .1 }
.paths .diff { fill: #8A4E22; font-size: 13.5px; font-weight: 600 }
.paths-wide .diff { font-size: 17px }
.paths .lineUs { fill: none; stroke: var(--teal); stroke-width: 3;
    stroke-linejoin: round; stroke-linecap: round }
.paths .dotUs { fill: var(--teal) }
.paths .capUs { stroke: var(--teal); stroke-width: 2.5; stroke-linecap: round }
.paths .valUs { fill: var(--teal); font-size: 12.5px; font-weight: 600 }
.paths-wide .valUs { font-size: 16px }
.paths .payLab { fill: var(--teal); font-size: 11.5px }
.paths-wide .payLab { font-size: 15px }
.paths .payLab.sm { font-size: 10.5px }

.paths-narrow { display: none }
@media (max-width: 760px) { .paths-wide { display: none } .paths-narrow { display: block } }
.tolls { display: flex; flex-wrap: wrap; gap: 7px; margin-block-start: 14px; padding: 0;
    list-style: none }
/* No `content: "takes "` here. It was hardcoded English and it rendered in front of the
   translated chip on every one of the fifteen localised pages. The stations list below the
   chart already supplies the verb, in the reader's language. */
.tolls li { font-size: 12.5px; color: #8A4E22; background: rgba(168, 96, 42, .09);
    border-radius: 999px; padding: 4px 11px }

/* The steps behind the picture. Detail below it, never instead of it. */
.stations { display: grid; grid-template-columns: 1fr 1fr; gap: 0 18px;
    margin-block-start: 28px; padding-block-start: 22px;
    border-block-start: 1px solid rgba(31, 45, 40, .1) }
.stations .subh { margin: 0 0 12px; font-size: 12px; letter-spacing: .1em;
    text-transform: uppercase }
.stations .them .subh { color: #8A4E22 }
.stations .us .subh { color: var(--teal) }
.stop { position: relative; padding-inline-start: 20px; padding-block: 9px;
    font-size: 13.5px; line-height: 1.4 }
.stop > span { display: block }
.stop::before { content: ""; position: absolute; inset-inline-start: 4px; inset-block: 0;
    inline-size: 2px; background: rgba(168, 96, 42, .18) }
.us .stop::before { background: rgba(15, 98, 87, .18) }
.stop::after { content: ""; position: absolute; inset-inline-start: 0; inset-block-start: 15px;
    inline-size: 10px; block-size: 10px; border-radius: 50%; background: #A8602A;
    border: 2px solid var(--paper) }
.us .stop::after { background: var(--teal) }
.stop em { display: block; font-style: normal; font-size: 12px; color: var(--soft);
    margin-block-start: 2px }
.stop.end { font-weight: 600 }
.stop.end::before { background: none }

/* ── What was left out, beside what a reader meets instead ────────────────── */
.eyebrow { font-size: 11.5px; letter-spacing: .14em; text-transform: uppercase;
    color: var(--soft); margin: 0 0 8px }
.leftout { display: grid; grid-template-columns: 1fr 1fr; gap: 30px;
    margin-block-start: 24px }
.leftout .subh { margin: 0 0 12px; font-size: 12px; letter-spacing: .1em;
    text-transform: uppercase; color: var(--soft) }
.chips { display: flex; flex-wrap: wrap; gap: 8px; padding: 0; margin: 0; list-style: none }
.chips li { font-size: 13.5px; padding: 5px 11px; border-radius: 999px;
    border: 1px solid var(--line); color: var(--soft);
    background: rgba(255, 255, 255, .5) }
.chips.out li { text-decoration: line-through; text-decoration-color: #A8602A;
    text-decoration-thickness: 1.5px }
.chips.in li { border-color: rgba(15, 98, 87, .3); background: rgba(226, 242, 237, .6);
    color: var(--teal); text-decoration: none; font-weight: 500 }

/* ── The four seconds, on both sides of the app ───────────────────────────── */
.seconds { display: grid; grid-template-columns: 1fr 1fr; gap: 20px;
    margin-block-start: 22px }
.seconds > div { border-radius: 14px; padding: 20px 20px 18px }
.seconds .subh { margin: 0 0 14px; font-size: 12px; letter-spacing: .1em;
    text-transform: uppercase; color: var(--soft) }
.beat { display: flex; align-items: center; flex-wrap: wrap; margin: 0 0 12px; padding: 0;
    list-style: none }
.beat li { font-size: 17px; font-weight: 700; letter-spacing: -.012em; color: var(--teal);
    display: flex; align-items: center; white-space: nowrap }
.beat li:not(:last-child)::after { content: ""; inline-size: 16px; block-size: 2px;
    border-radius: 2px; background: rgba(15, 98, 87, .25); margin-inline: 10px }
.seconds p { margin: 0; font-size: 13.5px; color: var(--soft); line-height: 1.55 }

/* ── What stays on the phone, and the two things that ever leave ──────────── */
.leaves { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr);
    gap: 20px; align-items: start; margin-block-start: 24px }
.pocket { border: 2px solid rgba(15, 98, 87, .45); border-radius: 18px;
    padding: 16px 16px 14px; background: rgba(226, 242, 237, .45) }
.pocket b { display: block; font-size: 12px; letter-spacing: .09em; text-transform: uppercase;
    color: var(--teal); margin-block-end: 10px }
.pocket ul { display: flex; flex-wrap: wrap; gap: 6px; margin: 0; padding: 0; list-style: none }
.pocket li { font-size: 12.5px; background: rgba(255, 255, 255, .72); border-radius: 999px;
    padding: 3px 10px }
.pocket .all { display: block; margin-block-start: 11px; font-size: 13px; font-weight: 600;
    color: var(--teal) }
.outs { display: grid; gap: 16px }
.out { display: flex; gap: 13px; align-items: flex-start }
.out .arrow { color: var(--teal); font-size: 20px; line-height: 1.2; flex: none }
.out b { display: block; font-size: 14.5px; margin-block-end: 3px }
.out span { font-size: 13.5px; color: var(--soft); line-height: 1.5 }
.nothing { margin-block-start: 18px; padding-block-start: 16px;
    border-block-start: 1px solid rgba(31, 45, 40, .1) }

.undergrid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.25fr);
    gap: 20px; align-items: start; margin-block-start: 22px }
.child { border-radius: 14px; padding: 22px 20px; font-size: 22px; font-weight: 600;
    line-height: 1.35; color: var(--teal); display: flex; align-items: center }
.undergrid ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px }
.undergrid li { font-size: 14px; color: var(--soft); line-height: 1.5;
    padding-inline-start: 16px; position: relative }
.undergrid li::before { content: ""; position: absolute; inset-inline-start: 0;
    inset-block-start: 8px; inline-size: 6px; block-size: 6px; border-radius: 50%;
    background: var(--teal) }

/* ── The range, as an age ladder ─────────────────────────────────────────── */
.ladder { margin-block-start: 24px }
.ltrack { position: relative; block-size: 118px }
.span { position: absolute }
.lbar { block-size: 32px; border-radius: 9px; display: flex; align-items: center;
    padding-inline: 13px; font-size: 13.5px; font-weight: 600; white-space: nowrap;
    overflow: hidden }
.span .rangelab { display: block; font-size: 11.5px; color: var(--soft);
    margin-block-start: 6px; padding-inline-start: 2px; line-height: 1.3 }
/* Geometry lives here, not in a style attribute: this site's CSP is `style-src 'self'`
   with no 'unsafe-inline', so an inline style is dropped by the browser and the ladder
   would collapse to nothing. The scale is pregnancy + eight years = nine units. */
.span.baby { inset-block-start: 0; inset-inline-start: 0; inline-size: 44.4% }
.span.games { inset-block-start: 62px; inset-inline-start: 44.4%; inline-size: 55.6% }
.span.baby .lbar { background: rgba(226, 242, 237, .75); color: var(--teal) }
.span.games .lbar { background: rgba(255, 255, 255, .6); color: var(--ink);
    border: 1px solid var(--line) }
.ticks { position: relative; border-block-start: 1px solid var(--line);
    margin-block-start: 4px; block-size: 22px }
.ticks span { position: absolute; inset-block-start: 5px; transform: translateX(-50%);
    font-size: 11px; color: var(--soft); white-space: nowrap }
.ticks .t1 { inset-inline-start: 11.1% }
.ticks .t2 { inset-inline-start: 44.4% }
.ticks .t3 { inset-inline-start: 100%; transform: translateX(-100%) }

@media (max-width: 700px) {
    .stations, .leftout, .seconds, .leaves, .undergrid { grid-template-columns: 1fr }
    .leaves, .undergrid, .seconds { gap: 16px }
}
@media (max-width: 420px) {
    .stations { grid-template-columns: 1fr 1fr; gap: 0 10px }
    .stop { font-size: 12.5px; padding-inline-start: 17px }
    .stop em { font-size: 11px }
}

.legend .k { width: 14px; height: 3px; border-radius: 2px; display: inline-block }
.legend .k.them { background: #A8602A }
.legend .k.us { background: var(--teal) }
.fineprint { font-size: 12.5px; color: var(--soft) }

.q {
    margin: 26px 0 14px; padding: 20px 22px; border-radius: 12px;
    background: var(--card); border: 1px solid var(--line);
}
.q p { margin: 0 0 9px; font-size: 17px; line-height: 1.45 }
.q cite { font-style: normal; font-size: 12px; color: var(--teal) }

/* ── Glass over the day island (owner, 2026-09-14, direction A) ──────────────
   The page used to be flat paper. It now sits ON something — the island's own
   daytime palette, sand and meadow and shallow water — with the reading surfaces
   frosted above it. Drawn, not photographed: a generated image would age while
   its source still looked current, which is the trap the public-surface auditor
   found twice on our own surfaces the day this landed. */

.scene {
    position: fixed; inset: 0; z-index: -1; pointer-events: none;
    background:
        radial-gradient(120% 84% at 12% 2%, #FFFDF8 0%, rgba(255,253,248,0) 56%),
        linear-gradient(178deg, #F5F1E6 0%, #E8EADF 52%, #D6E4DD 100%);
}
.scene svg { position: absolute; inset: 0; width: 100%; height: 100%; opacity: .55 }

/* One recipe, so every reading surface is the same material. */
.glass {
    background: rgba(255, 255, 255, .52);
    border: 1px solid rgba(255, 255, 255, .86);
    backdrop-filter: blur(16px) saturate(1.2);
    -webkit-backdrop-filter: blur(16px) saturate(1.2);
    box-shadow: 0 1px 2px rgba(31, 45, 40, .05), 0 14px 30px -22px rgba(31, 45, 40, .34);
}

body { background: transparent }
.bar { border-block-end-color: rgba(31, 45, 40, .1) }

/* Blur the LARGE reading surfaces only. Measured on the S10 (Chrome 150, Android
   12, dpr 2.625) on 2026-09-14: fifteen blurred layers scrolled at p50 18.7ms /
   p90 26.9ms against 16.9 / 18.1 with blur off — an extra 8ms on the worst tenth
   of frames, which is a visible hitch on the slowest phone the apps support.
   The cost is the NUMBER of blurred layers, not the radius: halving the radius
   everywhere barely moved it (p90 25.1), while blurring only these six put it
   back to p90 18.2 — indistinguishable from no blur. The nine small step panels
   get plain translucency instead; at that size the blur was not visible anyway. */
.card, .q, .seconds > div, .child {
    background: rgba(255, 255, 255, .52);
    border: 1px solid rgba(255, 255, 255, .86);
    backdrop-filter: blur(16px) saturate(1.2);
    -webkit-backdrop-filter: blur(16px) saturate(1.2);
    box-shadow: 0 1px 2px rgba(31, 45, 40, .05), 0 14px 30px -22px rgba(31, 45, 40, .34);
}

/* The principles read as one frosted block rather than four ruled rows. */
.rules { border-block-start: 0; border-radius: 16px; padding: 4px 20px; margin-block: 44px;
    background: rgba(255, 255, 255, .46);
    border: 1px solid rgba(255, 255, 255, .8);
    backdrop-filter: blur(14px) saturate(1.15);
    -webkit-backdrop-filter: blur(14px) saturate(1.15);
}
.rule { border-block-end-color: rgba(31, 45, 40, .09) }
.rule:last-child { border-block-end: 0 }

.sec { border-block-start-color: rgba(31, 45, 40, .1) }

/* Where blur is unavailable the panels must still be readable, not milk. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
    .card, .q, .seconds > div, .child, .rules { background: rgba(255, 255, 255, .9) }
}

/* The FAQ. It used to exist only inside the JSON-LD — four questions and answers that no reader
   could see, which is both against Google's own requirement for FAQPage and pointless for an
   assistant, which reads the prose. The markup below is now the single source: `prerender.py`
   builds the FAQPage from these keys, so the two cannot drift apart. */
.qa { border-block-start: 1px solid var(--line); padding-block: 12px }
.qa:first-of-type { border-block-start: 0 }
.qa summary {
    cursor: pointer; font-weight: 600; font-size: 15px; list-style: none;
    display: flex; gap: 10px; align-items: baseline;
}
.qa summary::-webkit-details-marker { display: none }
.qa summary::before { content: "+"; color: var(--teal); font-weight: 400; inline-size: 12px }
.qa[open] summary::before { content: "\2212" }
.qa p { margin-block: 8px 0; padding-inline-start: 22px }

/* ── Movement (owner, 2026-09-21) ───────────────────────────────────────────
   Read `assets/anim.js` first: nothing below applies until that script adds
   `.anim` to <html>, so with JavaScript off every one of these elements is
   already in its finished state. The page reads the same; it just does not move. */
.anim [data-anim] .lineThem, .anim [data-anim] .lineUs {
    transition: stroke-dashoffset 2.4s cubic-bezier(.33, 0, .15, 1) }
.anim [data-anim] text, .anim [data-anim] circle { opacity: 0; transition: opacity .85s ease }
.anim [data-anim].in text, .anim [data-anim].in circle { opacity: 1 }
.anim [data-anim].in text { transition-delay: 2.1s }
/* the wedge is a faint tint, never a solid fill: it returns to .1, not to 1 */
.anim [data-anim] .wedge { opacity: 0; transition: opacity .9s ease }
.anim [data-anim].in .wedge { opacity: .1; transition-delay: 2s }
/* each toll appears as the climbing line reaches the step it is taken at */
.anim [data-anim].in .tolls-g text:nth-of-type(1),
.anim [data-anim].in .dots circle:nth-of-type(1) { transition-delay: .7s }
.anim [data-anim].in .tolls-g text:nth-of-type(2),
.anim [data-anim].in .dots circle:nth-of-type(2) { transition-delay: 1.1s }
.anim [data-anim].in .tolls-g text:nth-of-type(3),
.anim [data-anim].in .dots circle:nth-of-type(3) { transition-delay: 1.5s }
.anim [data-anim].in .tolls-g text:nth-of-type(4),
.anim [data-anim].in .dots circle:nth-of-type(4) { transition-delay: 1.9s }

.anim .stations .stop { opacity: 0; transform: translateY(10px);
    transition: opacity .8s ease, transform .8s cubic-bezier(.22, 1, .36, 1) }
.anim .stations.in .stop { opacity: 1; transform: none }
.anim .stations.in .stop:nth-of-type(1) { transition-delay: .1s }
.anim .stations.in .stop:nth-of-type(2) { transition-delay: .28s }
.anim .stations.in .stop:nth-of-type(3) { transition-delay: .46s }
.anim .stations.in .stop:nth-of-type(4) { transition-delay: .64s }
.anim .stations.in .stop:nth-of-type(5) { transition-delay: .82s }
.anim .stations.in .stop:nth-of-type(6) { transition-delay: 1s }

.anim .ladder .lbar { clip-path: inset(0 100% 0 0);
    transition: clip-path 1.35s cubic-bezier(.22, 1, .36, 1) }
.anim .ladder.in .span.baby .lbar { clip-path: inset(0 0 0 0) }
.anim .ladder.in .span.games .lbar { clip-path: inset(0 0 0 0); transition-delay: .7s }
.anim .ladder .rangelab, .anim .ladder .ticks span { opacity: 0; transition: opacity .8s ease }
.anim .ladder.in .rangelab { opacity: 1; transition-delay: 1.05s }
.anim .ladder.in .ticks span { opacity: 1; transition-delay: 1.5s }

@media (prefers-reduced-motion: reduce) {
    .anim [data-anim] text, .anim [data-anim] circle, .anim .stations .stop,
    .anim .ladder .rangelab, .anim .ladder .ticks span { opacity: 1 !important }
    .anim .stations .stop { transform: none !important }
    .anim .ladder .lbar { clip-path: none !important }
    .anim [data-anim] .wedge { opacity: .1 !important }
    .anim [data-anim] .lineThem, .anim [data-anim] .lineUs {
        stroke-dasharray: none !important; stroke-dashoffset: 0 !important }
}

/* The 404. It reuses the hero and the two cards rather than inventing a layout: someone who
   mistyped a URL wants a way onward, not an apology. `404.data.js` carries only the handful of
   strings this page shows, so the language still follows the reader without the 200 KB bundle. */
.backhome { margin-block-start: 26px }
.backhome a { color: var(--teal) }
.card h2 { margin: 0 0 4px; font-size: 21px }

/* These were h4 under an h2, which skips a level on every one of the sixteen pages. They are h3
   now and `.subh` carries the small-label look they had. */
.subh { font-weight: 600 }
