/* Self-contained on purpose.
   The token values are BizAuto's, copied rather than linked: this service must render
   correctly on 127.0.0.1:5310 with the main site stopped, and a page that breaks visually
   when someone edits the main site's stylesheet is not the isolation this was built for.
   The font is the one exception — linked, with a real fallback stack. */

/* Every show/hide on this page is the `hidden` property, and a class that sets
   `display` outranks the browser's own `[hidden] { display: none }` — which is how the
   smart-plan button stayed on screen inside a container that had been hidden. Stated once
   here so no future flex or grid rule can quietly re-open something. */
[hidden] { display: none !important; }

:root {
    --bg: #f8fafc;
    --surface: #ffffff;
    --border: rgba(15, 23, 42, 0.08);
    --text: #0f172a;
    --text-secondary: #475569;
    --text-muted: #94a3b8;
    --primary: #0f6b66;
    --primary-light: rgba(15, 107, 102, 0.08);
    --primary-hover: #0c5854;
    --primary-ring: rgba(15, 107, 102, 0.35);
    --success: #059669;
    --warning: #f59e0b;
    --danger: #dc2626;
    --dark: #0f172a;
    --radius: 16px;
    --radius-sm: 10px;
    --shadow-sm: 0 1px 2px rgba(15,23,42,.06), 0 1px 3px rgba(15,23,42,.04);
    --shadow-md: 0 1px 5px -4px rgba(15,23,42,.5), 0 6px 16px rgba(15,23,42,.07);
    --shadow-primary: 0 1px 2px rgba(15,107,102,.2), 0 8px 20px rgba(15,107,102,.22);
    --font: vazirmatn, Vazirmatn, Sahel, "Segoe UI", Tahoma, system-ui, sans-serif;
}

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

html { scroll-behavior: smooth; }
body {
    background: var(--bg);
    color: var(--text);
    font-family: var(--font);
    line-height: 1.85;
    -webkit-font-smoothing: antialiased;
    /* A face photo on a phone is the main case; nothing may push the page sideways. */
    overflow-x: hidden;
}

.wrap { width: 100%; max-width: 760px; margin: 0 auto; padding: 0 20px; }

/* ---------- hero ---------- */
.hero {
    background: var(--dark);
    color: #fff;
    padding: 40px 0 56px;
    /* The card below overlaps the hero's lower edge; the extra padding is that overlap. */
    margin-bottom: -32px;
    position: relative;
    overflow: hidden;
}
/* One ambient field so the dark block is not flat. Behind everything, and off to the side
   the illustration is not on. */
.hero::before {
    content: ''; position: absolute; z-index: 0; pointer-events: none;
    inset-block-start: -55%; inset-inline-start: -12%;
    width: 70%; aspect-ratio: 1;
    background: radial-gradient(circle, rgba(99,102,241,0.26) 0%, transparent 62%);
}
.hero .wrap { position: relative; z-index: 1; }

/* Copy on one side, the illustration on the other. Stacked on a phone with the drawing
   first, because on the screen where a person decides whether this page is worth a photo of
   their face, the picture says what it is faster than the sentence does. */
.hero-grid { display: grid; gap: 26px; align-items: center; }
@media (min-width: 860px) {
    .hero-grid { grid-template-columns: minmax(0, 1fr) 330px; gap: 44px; }
    .hero { padding: 56px 0 68px; }
}
.hero-copy { order: 2; }
.hero-art  { order: 1; justify-self: center; width: min(230px, 62vw); margin-bottom: 4px; }
@media (min-width: 860px) {
    .hero-copy { order: 1; }
    .hero-art  { order: 2; width: 100%; max-width: 330px; }
}
.hero-art svg { width: 100%; height: auto; display: block; overflow: visible; }

/* ---------- the hero illustration ----------
   What the page does, drawn: the face is measured at six points and a scan passes over it.
   The sequence runs once on load and the scan then repeats, so the page has one slow sign
   of life without ever asking for attention a second time.

   Only transform, opacity and stroke-dashoffset are animated, so none of it can move the
   layout while somebody is reading. */

.hs-rings circle {
    fill: none; stroke: rgba(255,255,255,0.10); stroke-width: 1;
    transform-origin: 160px 186px;
    animation: hs-breathe 9s ease-in-out infinite;
}
.hs-rings circle:nth-child(2) { animation-delay: -3s; stroke: rgba(129,140,248,0.30); }
.hs-rings circle:nth-child(3) { animation-delay: -6s; }
@keyframes hs-breathe {
    0%, 100% { transform: scale(1);    opacity: 0.7; }
    50%      { transform: scale(1.04); opacity: 1; }
}

.hs-face, .hs-brow, .hs-mouth {
    fill: none; stroke-linecap: round; stroke-linejoin: round;
}
.hs-face  { stroke: rgba(255,255,255,0.72); stroke-width: 2;
            stroke-dasharray: 760; stroke-dashoffset: 760;
            animation: hs-draw 1.9s cubic-bezier(.22,1,.36,1) 0.2s forwards; }
.hs-brow  { stroke: rgba(255,255,255,0.5); stroke-width: 1.8;
            stroke-dasharray: 60; stroke-dashoffset: 60;
            animation: hs-draw 0.6s cubic-bezier(.22,1,.36,1) 1.5s forwards; }
.hs-brow-2{ animation-delay: 1.65s; }
.hs-mouth { stroke: rgba(255,255,255,0.5); stroke-width: 1.8;
            stroke-dasharray: 60; stroke-dashoffset: 60;
            animation: hs-draw 0.6s cubic-bezier(.22,1,.36,1) 1.8s forwards; }
@keyframes hs-draw { to { stroke-dashoffset: 0; } }

.hs-dot {
    fill: #a5b4fc; opacity: 0;
    animation: hs-pop 0.45s cubic-bezier(.22,1,.36,1) forwards;
    animation-delay: calc(2.1s + var(--n) * 0.22s);
}
.hs-ping {
    fill: none; stroke: #818cf8; stroke-width: 1.5; opacity: 0;
    transform-box: fill-box; transform-origin: center;
    animation: hs-ping 1.4s cubic-bezier(.22,1,.36,1) forwards;
    animation-delay: calc(2.2s + var(--n) * 0.22s);
}
@keyframes hs-pop  { to { opacity: 1; } }
@keyframes hs-ping {
    0%   { opacity: 0.85; transform: scale(0.5); }
    100% { opacity: 0;    transform: scale(3.2); }
}

.hs-beam { opacity: 0; animation: hs-beam 5s linear 3.4s infinite; }
@keyframes hs-beam {
    0%        { transform: translateY(-30px); opacity: 0; }
    14%       { opacity: 0.9; }
    72%       { opacity: 0.9; }
    86%, 100% { transform: translateY(350px); opacity: 0; }
}

/* Frozen fully drawn: the illustration is content, the motion is the decoration. */
@media (prefers-reduced-motion: reduce) {
    .hs-rings circle { animation: none; }
    .hs-face, .hs-brow, .hs-mouth { animation: none; stroke-dashoffset: 0; }
    .hs-dot { animation: none; opacity: 1; }
    .hs-ping, .hs-beam { animation: none; opacity: 0; }
}
.brand { display: flex; align-items: center; gap: 8px; font-weight: 800; margin-bottom: 26px; }
.brand-mark { color: #a5b4fc; font-size: 1.2rem; }
.hero h1 { font-size: 1.85rem; line-height: 1.5; margin-bottom: 12px; }
/* The search term above the greeting, small enough not to compete with it. As part of
   the h1 rather than a line before it, so the heading a crawler reads is the whole
   thing; in em, so the mobile rule below carries it down too. */
.h1-kicker {
    display: block; font-size: 0.6em; font-weight: 700; color: #a5b4fc;
    letter-spacing: 0.01em; margin-bottom: 2px;
}
.lede { color: #cbd5e1; font-size: 1rem; max-width: 46ch; }
/* Chips rather than a list. Each line used to restate its own bold half after a dash, so
   the same two promises took four clauses; at this size they are read at a glance or not at
   all. */
.promises { list-style: none; margin-top: 22px; display: flex; flex-wrap: wrap; gap: 8px; }
.promises li {
    font-size: 0.84rem; font-weight: 700; color: #e2e8f0;
    background: rgba(255,255,255,0.07); border: 1px solid rgba(255,255,255,0.14);
    border-radius: 999px; padding: 6px 14px 6px 12px;
    display: inline-flex; align-items: center; gap: 7px;
}
.promises li::before { content: "✓"; color: #34d399; font-weight: 800; }

/* ---------- shell ---------- */
.card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-sm);
    padding: 24px;
    margin-bottom: 20px;
    position: relative;
}
.card h2 { font-size: 1.08rem; margin-bottom: 6px; }
.muted { color: var(--text-secondary); font-size: 0.88rem; }
/* Prose, unlike every other card on this page, which holds numbers and controls. */
.faq p { color: var(--text-secondary); line-height: 2; margin-top: 10px; }
.faq h2 { margin-bottom: 0; }
main { padding-bottom: 48px; }

/* ---------- buttons ---------- */
.btn {
    display: inline-flex; align-items: center; justify-content: center; gap: 8px;
    padding: 13px 24px; border: 1px solid transparent; border-radius: var(--radius-sm);
    font: inherit; font-weight: 700; font-size: 0.95rem; cursor: pointer;
    text-decoration: none; transition: background .18s ease, border-color .18s ease;
    /* 44px is the smallest thing a thumb hits reliably; these are the only controls on
       the page and most of the traffic will be on a phone. */
    min-height: 46px;
}
.btn:focus-visible { outline: 3px solid var(--primary-ring); outline-offset: 2px; }
.btn:disabled { opacity: .55; cursor: not-allowed; }
.btn-primary { background: var(--primary); color: #fff; box-shadow: var(--shadow-primary); }
.btn-primary:hover:not(:disabled) { background: var(--primary-hover); }
.btn-ghost { background: transparent; color: var(--text-secondary); border-color: var(--border); }
.btn-ghost:hover:not(:disabled) { border-color: var(--primary); color: var(--primary); }
.pick-actions { display: flex; gap: 12px; flex-wrap: wrap; margin-top: 18px; }
.pick-actions .btn { flex: 1 1 180px; }

/* ---------- the drop zone ---------- */
/* The one thing this page asks anybody to do, so it is built like a target rather than a
   form control. It was a dashed lavender rectangle — the default a browser draws when
   nobody has decided anything — on the page where somebody is deciding whether to hand
   over a photograph of their face. */
.drop {
    position: relative; overflow: hidden;
    border: 1.5px dashed rgba(15, 107, 102, .34);
    border-radius: var(--radius);
    background:
        radial-gradient(120% 90% at 50% -10%, rgba(99,102,241,.14) 0%, transparent 62%),
        var(--primary-light);
    padding: 46px 20px; text-align: center; cursor: pointer;
    transition: border-color .2s ease, background .2s ease, transform .2s ease,
                box-shadow .25s ease;
}
.drop:active { transform: scale(0.995); }
/* A slow sweep across it, the same gesture the illustration in the hero makes. It is the
   only motion on this half of the page, which is what makes it read as "put it here"
   rather than as decoration. */
.drop::after {
    content: ''; position: absolute; inset-block: 0; inset-inline-start: -40%;
    width: 40%; pointer-events: none;
    background: linear-gradient(90deg, transparent, rgba(99,102,241,.13), transparent);
    animation: drop-sweep 3.8s ease-in-out infinite;
}
@keyframes drop-sweep {
    0%        { transform: translateX(0); opacity: 0; }
    18%       { opacity: 1; }
    72%       { opacity: 1; }
    88%, 100% { transform: translateX(350%); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) { .drop::after { animation: none; opacity: 0; } }
.drop > * { position: relative; z-index: 1; }
.drop:hover, .drop:focus-visible, .drop.is-over {
    border-color: var(--primary); background: rgba(15, 107, 102, .13); outline: none;
}
/* A ring around the arrow, so the eye lands somewhere before it lands on the words. */
.drop-icon {
    width: 62px; height: 62px; margin: 0 auto 14px;
    display: flex; align-items: center; justify-content: center;
    font-size: 1.5rem; color: var(--primary); line-height: 1;
    border-radius: 50%; background: #fff;
    box-shadow: 0 6px 18px -8px rgba(15,107,102,.5), inset 0 0 0 1px rgba(15,107,102,.16);
}
.drop-title { font-weight: 800; font-size: 1.05rem; }
.drop-hint { font-size: 0.82rem; color: var(--text-muted); margin-top: 4px; }

.tips { margin-top: 18px; font-size: 0.88rem; }
.tips summary { cursor: pointer; color: var(--primary); font-weight: 600; }
.tips ul { margin: 12px 0 0; padding-inline-start: 20px; color: var(--text-secondary); }

/* ---------- the apparent age ---------- */
/* On the result card, not above the upload. The first version was a tick box next to the
   file picker; by the time somebody knows they want this, that screen is gone. */
.age-box {
    display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
    margin-top: 12px;
}
.btn-age { padding: 9px 16px; font-size: 0.88rem; }
.age-hint { font-size: 0.78rem; color: var(--text-secondary); }

/* The answer. Not styled as a headline: it is the least certain number on the page and
   must not out-shout the six that were actually measured. */
.age-line {
    margin-top: 10px; font-size: 0.9rem; font-weight: 600; color: var(--text);
}

/* ---------- camera ---------- */
.camera video {
    width: 100%; border-radius: var(--radius); background: #000; display: block;
    /* Mirrored, because an unmirrored self-view reads as "wrong" to everyone. */
    transform: scaleX(-1);
}

/* ---------- working ---------- */
.working { text-align: center; padding: 44px 24px; }
.spinner {
    width: 34px; height: 34px; margin: 0 auto 16px;
    border: 3px solid var(--primary-light); border-top-color: var(--primary);
    border-radius: 50%; animation: spin .8s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
    .spinner { animation-duration: 2.4s; }
    html { scroll-behavior: auto; }
}

/* ---------- a refused photo ---------- */
.problem {
    border-color: var(--warning);
    background: rgba(245, 158, 11, .07);
}
.problem p { margin-bottom: 16px; font-weight: 600; }

/* ---------- the score ---------- */
.score-card { display: flex; gap: 24px; align-items: center; flex-wrap: wrap; }
.score-ring { position: relative; width: 132px; height: 132px; flex-shrink: 0; }
.score-ring svg { width: 100%; height: 100%; transform: rotate(-90deg); }
.ring-bg, .ring-fill { fill: none; stroke-width: 10; }
.ring-bg { stroke: var(--primary-light); }
.ring-fill {
    stroke: var(--primary); stroke-linecap: round;
    stroke-dasharray: 327; stroke-dashoffset: 327;
    transition: stroke-dashoffset 1.1s cubic-bezier(.16,1,.3,1), stroke .4s ease;
}
.score-value {
    position: absolute; inset: 0; display: flex; flex-direction: column;
    align-items: center; justify-content: center; gap: 2px;
}
.score-value strong { font-size: 2.1rem; font-weight: 800; line-height: 1; }
.score-value span { font-size: 0.8rem; color: var(--text-secondary); }
.score-side { flex: 1 1 240px; min-width: 0; }
.disclaimer {
    margin-top: 12px; font-size: 0.8rem; color: var(--text-secondary);
    background: var(--bg); border-inline-start: 3px solid var(--warning);
    border-radius: var(--radius-sm); padding: 10px 12px; line-height: 1.9;
}

/* ---------- photo + heatmap ---------- */
.preview-wrap {
    position: relative; margin: 16px 0; border-radius: var(--radius);
    overflow: hidden; background: #0f172a; line-height: 0;
}
.preview-wrap img { width: 100%; display: block; }
#overlay {
    position: absolute; inset: 0; opacity: 0;
    /* Long enough to read as one map dissolving into another rather than a swap, short
       enough that pressing three chips in a row does not feel sticky. */
    transition: opacity .45s ease;
    pointer-events: none;
}
#overlay.is-on { opacity: 1; }

.chips { display: flex; flex-wrap: wrap; gap: 8px; }
.chip {
    padding: 8px 15px; border-radius: 999px; border: 1px solid var(--border);
    background: var(--surface); font: inherit; font-size: 0.85rem; font-weight: 600;
    color: var(--text-secondary); cursor: pointer; min-height: 40px;
}
.chip:focus-visible { outline: 3px solid var(--primary-ring); outline-offset: 2px; }
.chip.is-on { background: var(--primary); color: #fff; border-color: var(--primary); }

/* ---------- metric bars ---------- */
.metrics { display: grid; gap: 16px; margin-top: 16px; }
/* A button, because it opens the explanation — so it has to shed the browser's button
   chrome and take the full row width to stay a comfortable tap target on a phone. */
.metric-head {
    display: flex; justify-content: space-between; align-items: baseline;
    gap: 12px; margin-bottom: 6px;
    width: 100%; padding: 4px 0; border: 0; background: none; cursor: pointer;
    font: inherit; color: inherit; text-align: start;
}
.metric-head:disabled { cursor: default; }
.metric-head:focus-visible {
    outline: 2px solid var(--primary-ring); outline-offset: 3px; border-radius: 6px;
}
.metric-name { font-weight: 700; font-size: 0.94rem; }
.metric-caret {
    margin-inline-start: 6px; color: var(--primary); font-size: 0.86rem; opacity: 0.75;
}
.metric.is-open .metric-caret { opacity: 1; }
.metric-read { font-size: 0.82rem; color: var(--text-secondary); }
.metric-help {
    margin-top: 10px; padding: 12px 14px; border-radius: 10px;
    background: var(--primary-light); font-size: 0.86rem; line-height: 1.95;
}
.metric-help p { margin: 0 0 6px; }
.metric-help p:last-child { margin-bottom: 0; }
/* Which way is good — the first thing anyone needs and the reason this panel exists. */
.metric-direction { font-weight: 700; color: var(--primary); }
.metric-what { color: var(--text); }
.bar { height: 10px; border-radius: 999px; background: var(--primary-light); overflow: hidden; }
.bar-fill {
    height: 100%; border-radius: 999px; width: 0;
    transition: width 1s cubic-bezier(.16,1,.3,1);
}
/* Severity is carried by the words in .metric-read as well as by colour — a bar that is
   only red tells a colour-blind reader nothing. */
.bar-fill.good { background: var(--success); }
.bar-fill.mid { background: var(--warning); }
.bar-fill.bad { background: var(--danger); }

/* ---------- zones ---------- */
.zones { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 12px; margin-top: 16px; }
.zone {
    border: 1px solid var(--border); border-radius: var(--radius-sm);
    padding: 14px; background: var(--bg);
}
.zone b { display: block; font-size: 0.92rem; }
.zone span { font-size: 0.8rem; color: var(--text-secondary); }

/* ---------- cta ---------- */
.cta { background: var(--dark); color: #fff; border-color: transparent; }
.cta h2 { color: #fff; }
.cta p { color: #cbd5e1; font-size: 0.9rem; margin: 8px 0 18px; }
.cta .btn-primary { background: #fff; color: var(--dark); box-shadow: none; }
.cta .btn-primary:hover { background: #e2e8f0; }

/* ---------- footer ---------- */
.foot { background: var(--dark); color: #64748b; padding: 26px 0; font-size: 0.82rem; text-align: center; }

@media (max-width: 560px) {
    .hero h1 { font-size: 1.5rem; }
    .card { padding: 18px; }
    .score-card { gap: 16px; }
    .pick-actions .btn { flex: 1 1 100%; }
}

/* ---------- lead form ---------- */
.lead .fields { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 14px; margin: 18px 0 14px; }
.lead label { display: flex; flex-direction: column; gap: 6px; }
.lead label > span { font-size: 0.84rem; font-weight: 600; color: var(--text-secondary); }
.lead label i { font-style: normal; color: var(--text-muted); font-weight: 400; }
.lead input[type="text"], .lead input[type="tel"] {
    font: inherit; padding: 12px; border: 1px solid var(--border);
    border-radius: var(--radius-sm); background: var(--bg); color: var(--text); width: 100%;
    min-height: 46px;
}
.lead input:focus { outline: none; border-color: var(--primary); box-shadow: 0 0 0 3px var(--primary-ring); }
/* The consent box is a row, not a column: the label has to sit beside the box it belongs
   to or it reads as a separate sentence someone can skip. */
.consent { flex-direction: row !important; align-items: flex-start; gap: 10px; font-size: 0.86rem;
    color: var(--text-secondary); cursor: pointer; margin-bottom: 16px; line-height: 1.8; }
.consent input { width: 20px; height: 20px; flex-shrink: 0; margin-top: 4px; accent-color: var(--primary); }
.lead-error { color: var(--danger); font-size: 0.86rem; font-weight: 600; margin-bottom: 12px; }
.lead-done { color: var(--success); font-weight: 700; font-size: 1rem; padding: 12px 0; }

/* ---------- AI plan ---------- */
.advice-card { border-color: rgba(15, 107, 102, .3); }
/* The model returns headed sections separated by blank lines; app.js builds those into
   real headings and paragraphs, so the sections keep their shape. pre-wrap stays for the
   line breaks WITHIN a section — a routine collapsed into one run-on instruction is one
   nobody follows. */
.advice-body {
    white-space: pre-wrap; line-height: 2.1; font-size: 0.93rem;
    margin-top: 18px; padding-top: 18px; border-top: 1px solid var(--border);
}
.advice-body p { margin: 0 0 4px; }
.advice-heading {
    margin: 18px 0 6px; font-size: 0.95rem; font-weight: 700; color: var(--primary);
}
.advice-heading:first-child { margin-top: 0; }
.advice-note { font-size: 0.8rem; color: var(--text-muted); margin-top: 14px; }

/* ---- where the numbers come from ---------------------------------------------------- */
/* A <details>, so the basis is one tap away from the result rather than on another page.
   The <h2> lives inside <summary> to keep the document outline intact; the marker is
   replaced because the default triangle sits on the wrong side in RTL. */
.basis-card { padding: 0; }
.basis-card > summary {
    list-style: none; cursor: pointer; padding: 20px 22px;
    display: flex; align-items: center; justify-content: space-between; gap: 12px;
}
.basis-card > summary::-webkit-details-marker { display: none; }
.basis-card > summary h2 { margin: 0; }
.basis-card > summary::after {
    content: '+'; font-size: 1.3rem; color: var(--primary); line-height: 1;
}
.basis-card[open] > summary::after { content: '−'; }
.basis-card > summary:focus-visible {
    outline: 2px solid var(--primary-ring); outline-offset: -2px; border-radius: 14px;
}
.basis-card > *:not(summary) { padding-inline: 22px; }
.basis-card > *:last-child { padding-bottom: 20px; }

.basis-list { margin: 16px 0; display: grid; gap: 14px; font-size: 0.9rem; line-height: 1.9; }
.basis-list li { list-style: none; padding-inline-start: 14px; border-inline-start: 3px solid var(--primary-light); }
/* The citation itself: latin text inside an RTL sentence, so it needs its own direction
   or the volume and page numbers reorder into nonsense. */
.basis-ref {
    display: block; direction: ltr; text-align: start;
    font-size: 0.78rem; color: var(--text-muted); margin-top: 2px;
}
.basis-limits {
    margin: 16px 0; padding: 14px 16px; border-radius: 10px;
    background: var(--warning-light, rgba(245, 158, 11, 0.10));
    border-inline-start: 3px solid var(--warning);
    font-size: 0.86rem; line-height: 1.95;
}

/* ---- verifying a number before the AI plan ------------------------------------------- */
.otp-step { margin-top: 18px; display: grid; gap: 4px; }
.otp-step .field input { text-align: start; letter-spacing: 0.04em; }
.otp-sent {
    margin: 0 0 12px; padding: 10px 14px; border-radius: 10px;
    background: var(--primary-light); color: var(--primary);
    font-size: 0.86rem; font-weight: 600;
}
/* The number inside that sentence is latin in an RTL line, so it needs isolating or the
   digits reorder against the surrounding words. */
.otp-sent { unicode-bidi: isolate; }

/* ---------- the vector layer over the photo ---------- */
/* Everything here animates transform and opacity only. A blur or a box-shadow animation
   would look the same on this machine and drop frames on the phones this page is actually
   opened on. */
.face-svg {
    position: absolute; inset: 0; width: 100%; height: 100%;
    pointer-events: none; overflow: visible;
}
.face-svg .zone-hit { pointer-events: auto; cursor: pointer; fill: transparent; }

/* ---- the face's own outline ---- */
.face-outline {
    fill: none;
    stroke: rgba(199, 210, 254, 0.9);
    stroke-width: 2;
    vector-effect: non-scaling-stroke;   /* the viewBox is stretched; the line must not be */
    opacity: 0;
}
/* Drawn by running the dash offset down to zero. pathLength normalises the dash figures
   so one set of numbers works whatever the outline's real length turns out to be. */
.face-svg.is-traced .face-outline {
    opacity: 1;
    stroke-dasharray: 1000;
    stroke-dashoffset: 1000;
    animation: trace-face 1.15s ease-out forwards, outline-settle .5s 1.15s ease forwards;
}
@keyframes trace-face  { to { stroke-dashoffset: 0; } }
@keyframes outline-settle { to { opacity: 0.32; } }

/* ---- the sweep while the analysis runs ---- */
.scan-beam { opacity: 0; }
.face-svg.is-scanning .scan-beam {
    opacity: 1;
    animation: scan-sweep 1.5s ease-in-out infinite;
}
@keyframes scan-sweep {
    0%   { transform: translateY(-0.2px); }
    100% { transform: translateY(1px); }
}
/* translate in user units: the viewBox is 0..1, so 1 is the full height of the photo. */
.face-svg.is-scanning .scan-beam { transform-box: view-box; }

/* ---- one zone ---- */
.zone-mark {
    opacity: 0;
    transform-box: fill-box;
    transform-origin: center;
    animation: zone-in .45s ease-out forwards;
}
@keyframes zone-in {
    from { opacity: 0; transform: scale(0.72); }
    to   { opacity: 1; transform: scale(1); }
}
.zone-dot {
    fill: #fff;
    stroke: currentColor;
    stroke-width: 2;
    vector-effect: non-scaling-stroke;
}
/* The worst zone keeps moving after the others settle — the eye goes to the only thing
   still animating, which is exactly where it should go. */
.zone-mark.is-worst .zone-dot {
    animation: zone-pulse 1.9s ease-in-out .5s infinite;
    transform-box: fill-box;
    transform-origin: center;
}
@keyframes zone-pulse {
    0%, 100% { transform: scale(1); }
    50%      { transform: scale(1.55); }
}
.zone-mark.is-picked .zone-dot { fill: var(--primary); }

/* ---- the label pinned to a zone ---- */
.zone-callout {
    position: absolute;
    z-index: 3;
    transform: translate(50%, -110%);      /* RTL: translate(+50%) centres it */
    background: rgba(15, 23, 42, 0.9);
    color: #fff;
    border-radius: 10px;
    padding: 8px 11px;
    font-size: 0.78rem;
    line-height: 1.85;
    white-space: nowrap;
    pointer-events: none;
    border-bottom: 2px solid var(--callout-colour, var(--primary));
    animation: callout-in .28s ease-out;
}
.zone-callout b { display: block; font-size: 0.82rem; margin-bottom: 1px; }
.zone-callout span { display: block; opacity: 0.85; }
/* Flipped when the anchor is near an edge, so the label stays over the photo. */
.zone-callout.flip-x { transform: translate(-50%, -110%); }
.zone-callout.flip-y { transform: translate(50%, 14%); }
.zone-callout.flip-x.flip-y { transform: translate(-50%, 14%); }
@keyframes callout-in {
    from { opacity: 0; }
    to   { opacity: 1; }
}

/* ---- the colour dot on each chip ---- */
.chip-dot {
    display: inline-block; width: 9px; height: 9px; border-radius: 999px;
    margin-inline-end: 7px; vertical-align: middle;
}
.chip.is-on {
    border-color: var(--chip-colour, var(--primary));
    box-shadow: inset 0 0 0 1px var(--chip-colour, var(--primary));
}

/* Motion is decoration here; the information is in the colour, the numbers and the
   labels, all of which survive this being switched off. */
@media (prefers-reduced-motion: reduce) {
    .face-svg.is-traced .face-outline {
        animation: none; stroke-dashoffset: 0; opacity: 0.32;
    }
    .face-svg.is-scanning .scan-beam { animation: none; opacity: 0; }
    .zone-mark { animation: none; opacity: 1; }
    .zone-mark.is-worst .zone-dot { animation: none; }
    .zone-callout { animation: none; }
}

/* The choice about whether the face goes on the card. A real checkbox, sized as a proper
   tap target — this is a privacy decision and it should not be a 13px tick. */
.share-toggle {
    display: flex; align-items: center; gap: 10px;
    margin: 14px 0 4px; padding: 10px 12px;
    border-radius: 10px; background: var(--primary-light);
    font-size: 0.88rem; font-weight: 600; color: var(--text);
    cursor: pointer;
}
.share-toggle input { width: 20px; height: 20px; accent-color: var(--primary); cursor: pointer; }

#otp-phone{
    font: inherit;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--bg);
    color: var(--text);
    width: 100%;
    padding: 10px 12px;
}

/* ---------- the code sheet ---------- */
.otp-modal {
    position: fixed; inset: 0; z-index: 100;
    display: flex; align-items: center; justify-content: center;
    padding: 16px;
    background: rgba(11, 18, 32, 0.55);
    animation: sheet-fade .18s ease-out;
}
@keyframes sheet-fade { from { opacity: 0; } to { opacity: 1; } }

.otp-sheet {
    position: relative;
    width: 100%; max-width: 380px;
    background: var(--surface);
    border-radius: 18px;
    padding: 26px 22px 22px;
    box-shadow: 0 24px 60px rgba(15, 23, 42, 0.3);
    animation: sheet-rise .22s cubic-bezier(.2, .8, .3, 1);
}
@keyframes sheet-rise { from { transform: translateY(14px); } to { transform: none; } }

.otp-sheet h3 { margin: 0 0 6px; font-size: 1.05rem; font-weight: 800; }
.otp-sheet .btn { width: 100%; margin-top: 10px; }

.otp-close {
    position: absolute; top: 12px; inset-inline-end: 12px;
    background: none; border: 0; cursor: pointer; padding: 6px;
    color: var(--text-muted); line-height: 0; border-radius: 8px;
}
.otp-close:hover { color: var(--text); background: var(--primary-light); }

/* While a sheet is open the page behind it must not scroll — on a phone that is the
   difference between a dialog and a mess. */
body.has-modal { overflow: hidden; }

/* ---------- the six boxes ---------- */
.otp-digits { display: flex; gap: 8px; justify-content: center; margin: 18px 0 4px; }
.otp-digits input {
    width: 100%; max-width: 48px; aspect-ratio: 3 / 4;
    text-align: center;
    font-size: 1.35rem; font-weight: 700;
    font-variant-numeric: tabular-nums;
    border: 1.5px solid var(--border); border-radius: 12px;
    background: var(--bg); color: var(--text);
    padding: 0;
}
.otp-digits input:focus {
    outline: none;
    border-color: var(--primary);
    box-shadow: 0 0 0 3px var(--primary-ring);
}

/* ---------- the model writing ---------- */
.advice-typing {
    display: flex; align-items: center; gap: 10px;
    margin-top: 18px; padding: 14px 16px;
    border-radius: 12px; background: var(--primary-light);
    color: var(--primary); font-size: 0.88rem; font-weight: 600;
}
/* Three dots rather than an animated GIF: it is the same thing every messaging app uses,
   it costs no request and no binary in the repository, it stays sharp at any size, and it
   follows the theme colour instead of baking one in. */
.typing-dots { display: inline-flex; gap: 4px; }
.typing-dots i {
    width: 7px; height: 7px; border-radius: 999px;
    background: currentColor; display: block;
    animation: typing-bounce 1.1s ease-in-out infinite;
}
.typing-dots i:nth-child(2) { animation-delay: .15s; }
.typing-dots i:nth-child(3) { animation-delay: .3s; }
@keyframes typing-bounce {
    0%, 60%, 100% { transform: translateY(0); opacity: .45; }
    30%           { transform: translateY(-5px); opacity: 1; }
}

/* A caret at the end of the text while it is still being written. */
.advice-body.is-typing::after {
    content: '';
    display: inline-block;
    width: 2px; height: 1em;
    margin-inline-start: 2px;
    vertical-align: text-bottom;
    background: var(--primary);
    animation: caret-blink 1s steps(1) infinite;
}
@keyframes caret-blink { 50% { opacity: 0; } }

/* ---------- the plan, and copying it ---------- */
.advice-result { position: relative; }
.advice-copy {
    position: absolute; top: 14px; inset-inline-end: 0;
    z-index: 1;
    background: var(--surface); border: 1px solid var(--border);
    border-radius: 10px; cursor: pointer;
    width: 36px; height: 36px;
    display: grid; place-items: center;
    color: var(--text-secondary);
}
.advice-copy:hover { color: var(--primary); border-color: var(--primary); }
.advice-copy:focus-visible {
    outline: none; box-shadow: 0 0 0 3px var(--primary-ring); border-color: var(--primary);
}
/* Two icons in the same box, one shown at a time — so the button does not change size
   when it confirms, which would nudge the text beside it. */
.advice-copy svg { grid-area: 1 / 1; }
.advice-copy .copy-done { opacity: 0; color: var(--success); }
.advice-copy.is-done svg:not(.copy-done) { opacity: 0; }
.advice-copy.is-done .copy-done { opacity: 1; }
.advice-copy.is-done { color: var(--success); border-color: var(--success); }

@media (prefers-reduced-motion: reduce) {
    .otp-modal, .otp-sheet { animation: none; }
    .typing-dots i { animation: none; opacity: .8; }
    .advice-body.is-typing::after { animation: none; }
}

/* ==========================================================================
   The start sheet — who you are, then the code
   ========================================================================== */

/* The one button that replaced a form on the page. Given room, because it is the only
   thing being asked for and a person who has just read six numbers should not have to
   look for it. */
.advice-start { text-align: center; }
.advice-start .field-hint { margin-top: 12px; }
.btn-wide { width: 100%; }

/* Taller than the code sheet: four fields need the room, and a sheet that scrolls
   internally on a phone is better than one that runs off the bottom of the screen. */
.start-sheet { max-width: 420px; max-height: min(88vh, 720px); overflow-y: auto; }

.start-tabs {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 6px;
    margin: 16px 0 18px;
    padding: 4px;
    border-radius: 12px;
    background: var(--surface-2, #f1f5f9);
}
.start-tab {
    padding: 10px 8px;
    border: 0;
    border-radius: 9px;
    background: transparent;
    color: var(--text-muted);
    font: inherit;
    font-size: 0.9rem;
    font-weight: 700;
    cursor: pointer;
    transition: background .15s ease, color .15s ease;
}
.start-tab.is-on {
    background: var(--surface);
    color: var(--text);
    box-shadow: 0 1px 3px rgba(15, 23, 42, .12);
}

.start-form .field { display: block; margin-bottom: 14px; }
.start-form .field > span,
.start-form legend {
    display: block;
    margin-bottom: 6px;
    font-size: 0.85rem;
    font-weight: 700;
    color: var(--text);
}
.start-form input,
.start-form select {
    width: 100%;
    padding: 12px 14px;
    border: 1px solid var(--border);
    border-radius: 10px;
    background: var(--surface);
    color: var(--text);
    font: inherit;
    font-size: 0.95rem;
}
.start-form input:focus,
.start-form select:focus {
    outline: 2px solid var(--primary);
    outline-offset: 1px;
    border-color: var(--primary);
}

.field-birth { border: 0; padding: 0; margin: 0 0 14px; }
/* Year widest, day narrowest — the order they are spoken, and the widths they need. */
.birth-row { display: grid; grid-template-columns: 1.3fr 1.4fr 1fr; gap: 8px; }

@media (max-width: 380px) {
    .start-tab { font-size: 0.84rem; }
    .birth-row { grid-template-columns: 1fr 1fr; }
    .birth-row select:last-child { grid-column: 1 / -1; }
}

/* ---- carrying on in Bale ---- */
/* Separated from the plan by a rule rather than just space: it is a different kind of
   thing — an invitation, not more advice — and running it straight on from the last
   paragraph reads as though the model wrote it. */
.advice-more {
    margin-top: 22px;
    padding-top: 20px;
    border-top: 1px solid var(--border);
    text-align: center;
}
.advice-more > p:first-child {
    margin: 0 0 14px;
    font-size: .98rem;
    font-weight: 700;
    line-height: 1.9;
}
.advice-more .field-hint { margin-top: 12px; }
