/* Survey 28: the H world of build_v7.py / build_v6_info.py, ported from inline styles to classes.
   Mobile first at the 390 px artboard; desktop (>= 768 px) is the same column on white, zoomed 1.2x / 1.3x (owner 13.09).
   Tokens: NAVY #152642 · CHIP #0f1b2f · PILL #0e1520 · INK #1a1a1a · LINE #dcdcdc · PALE #f0f3f8 · EDGE #cfcfcf · MARK #949494
           DIS #ededed · COLD #4a7bd0 · HOT #d9463e · GREEN #2fbf71 · radii 24 / 12
           MUTED #4a4a4a: the board's grey (#6b6b6b) lifted to ink at 75 % for the 45+ readers (owner 13.09); placeholders keep #6b6b6b.
   Readability floor (owner 13.09, raised again after he walked staging on his phone 13.09): copy never under 18 px (was 17,
   the board's 16), headlines 28 (the board's 26), weight 500 where the board had 400, line-height 1.5 on paragraphs and on
   option rows (was 1.45 / 1.35). Montserrat is a brand lock and its x-height is short, so the compensation is size and leading,
   never the palette: the greys stay exactly as they were. The consent print is 16 (was 13). Smaller only in the header Google
   block (12 / 13, chrome, not copy). Exception (owner 25.09): the consent checkbox on screen 22 is 11 px in a bordered box,
   «doesn't have to be readable, just fit it in». Screen 1's option subs are 14 px on one line (board A1, owner 25.09).
   Motion: every keyframe of the board with its ramp and delay (--d, --dur); the board loops every 6 s for the canvas, the app plays
   the same entrance on every screen injection. Selection feedback = the board's `sel` / `fill` ramps (.45 s). */

@font-face {
  /* Self-hosted, one file, every weight 400-700 from the variable axis.
     Replaces a render-blocking stylesheet on fonts.googleapis.com plus up to
     five files on fonts.gstatic.com: two extra DNS lookups and TLS handshakes
     on the critical path, on a third-party origin. Subset to exactly what this
     quiz renders (Latin, Cyrillic, Ukrainian ґїєі, ₴, the í in Clínica), 59 KB.
     swap keeps text visible while it loads; the fallback stack below matches. */
  font-family: 'Montserrat';
  src: url('/static/fonts/montserrat-uk.woff2') format('woff2-variations'),
       url('/static/fonts/montserrat-uk.woff2') format('woff2');
  font-weight: 400 700;
  font-style: normal;
  font-display: swap;
}

:root {
  --navy: #152642; --chip: #0f1b2f; --pill: #0e1520; --ink: #1a1a1a; --muted: #4a4a4a; --ph: #6b6b6b; --line: #dcdcdc;
  --pale: #f0f3f8; --edge: #cfcfcf; --mark: #949494; --dis-bg: #ededed; --cold: #4a7bd0; --hot: #d9463e;
  --green: #2fbf71; --sep: rgba(0,0,0,.12); --rc: 24px; --ri: 12px;
  --bounce: cubic-bezier(.34,1.56,.64,1);
}

* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body { margin: 0; font-family: 'Montserrat', 'Helvetica Neue', Arial, sans-serif; color: var(--ink); background: #fff;
       -webkit-font-smoothing: antialiased; font-size: 18px; line-height: 1.5; }
a { color: var(--navy); }
a:hover { color: var(--ink); }
button { font: inherit; color: inherit; }
img { display: block; max-width: 100%; }
[hidden] { display: none !important; }
/* the back chevron keeps its grid cell when hidden (screens 1 and 24), so the wordmark stays centred like the board's empty first cell */
.hdr-back[hidden] { display: flex !important; visibility: hidden; pointer-events: none; }

/* ---- page + chrome ------------------------------------------------------------------ */
.page { min-height: 100dvh; display: flex; flex-direction: column; background: #fff; overflow: hidden; }
.hdr { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; padding: 14px 24px 0; height: 58px; }
.hdr-back { width: 44px; height: 44px; margin-left: -14px; display: flex; align-items: center; justify-content: center;
            background: none; border: 0; padding: 0; border-radius: 22px; cursor: pointer; justify-self: start; }
.hdr-back:hover { background: var(--pale); }
.hdr-logo { height: 17px; width: auto; }
.hdr-rating { justify-self: end; min-height: 44px; display: flex; flex-direction: column; align-items: flex-end; justify-content: center; gap: 3px; line-height: 1; }
.hdr-rating-row { display: flex; align-items: baseline; gap: 4px; }
.hdr-g { font-size: 12px; color: var(--muted); }
.hdr-score { font-size: 13px; font-weight: 600; color: var(--ink); }
.hdr-stars { display: flex; gap: 2px; }
.hdr-stars svg { flex-shrink: 0; }

/* the bar: the board's `pf` keyframe fills from the previous value over 12 % of the 6 s loop = .72 s ease-out */
.bar { display: flex; align-items: center; gap: 6px; padding: 10px 24px 0; }
.bar-seg { width: 26px; height: 6px; border-radius: 999px; background: var(--navy); flex-shrink: 0; }
.bar-track { flex: 1; height: 6px; border-radius: 999px; background: var(--line); overflow: hidden; }
.bar-fill { width: 100%; height: 100%; border-radius: 999px; background: var(--navy); transform-origin: left; transform: scaleX(var(--p, 0)); transition: transform .72s ease-out; }

/* one grid cell holds the outgoing and the incoming .scr for the 260 ms of the hand-over, so they overlap instead of stacking */
.screen { display: grid; grid-template-columns: 100%; align-content: start; padding: 0 24px 24px; margin-top: 20px; flex: 1; }
.scr { grid-area: 1 / 1; align-self: start; display: flex; flex-direction: column; gap: 12px; }

.nojs { padding: 40px 24px; text-align: center; }

/* ---- type ------------------------------------------------------------------------------- */
.h1 { margin: 0; font-size: 28px; font-weight: 600; line-height: 1.25; letter-spacing: -0.01em; text-wrap: pretty; color: var(--navy); }
.h1-white { color: #fff; }
.grey { margin: 0; font-size: 18px; line-height: 1.5; font-weight: 500; color: var(--muted); text-wrap: pretty; }
.body { margin: 0; font-size: 18px; line-height: 1.5; font-weight: 500; color: var(--ink); text-wrap: pretty; }
.navy-line { margin: 0; font-size: 18px; line-height: 1.5; font-weight: 600; color: var(--navy); }
.label { font-size: 18px; line-height: 1.4; font-weight: 600; color: var(--ink); }
.muted { color: var(--muted); }
.consent { margin: 0; font-size: 16px; line-height: 1.5; font-weight: 500; color: var(--muted); text-wrap: pretty; }
.consent a { color: var(--muted); }
/* the consent as a checkbox on screen 22 (owner 25.09): the real input is visually hidden, the box is the multi screen's */
.consent-row { display: flex; gap: 12px; align-items: center; cursor: pointer; margin-top: 4px;
               border: 1px solid var(--line); border-radius: 12px; padding: 12px 14px; }
.consent-row input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.consent-row .consent { font-size: 11px; line-height: 1.35; }   /* owner 25.09: fits the box, readability not required */
.consent-row input:checked + .opt-box { border-color: var(--navy); background: var(--navy); }
.consent-row input:checked + .opt-box .ic { opacity: 1; }
.consent-row input:focus-visible + .opt-box { outline: 2px solid var(--navy); outline-offset: 2px; }
.lock { display: flex; gap: 8px; align-items: flex-start; font-size: 18px; line-height: 1.5; font-weight: 500; color: var(--muted); }
.lock .ic { flex-shrink: 0; margin-top: 3px; }
.issue { margin: 0; font-size: 18px; line-height: 1.5; font-weight: 500; color: var(--hot); }
/* the plastics verdict (board A3, owner 25.09): the whole screen, button included, on one phone screen; the photo
   is his 349 x 207 crop (flow.json card_w / card_h / photo_pos), the copy the board's 17 / 16 / 15 */
.scr-fit .portrait { border-radius: 24px; }
.screen:has(> .scr-fit) { align-content: stretch; }      /* the button rests at the foot of the phone, as on the board */
.scr-fit { align-self: stretch; }
.scr-fit .pill { margin-top: auto; }
.scr-fit .body { font-size: 17px; line-height: 1.6; }
.scr-fit .navy-line { font-size: 16px; line-height: 1.45; }
.scr-fit .grey { font-size: 15px; line-height: 1.45; }
/* her answer words in the verdict sentence (owner 25.09, board A3) */
mark.ans { background: #dfe6f3; color: var(--navy); border-radius: 5px; padding: 1px 5px; font-weight: 600;
           -webkit-box-decoration-break: clone; box-decoration-break: clone; }
/* a failed answer or a failed screen: the line she reads and the one control she taps to try again */
.notice { display: flex; flex-direction: column; gap: 8px; margin-top: 12px; }
.err { color: var(--hot); }
.group { display: flex; flex-direction: column; gap: 8px; }
.stack { display: flex; flex-direction: column; gap: 12px; }
.plain { max-width: 560px; margin: 0 auto; padding: 40px 24px; display: flex; flex-direction: column; gap: 12px; }
.sep { height: 1px; background: var(--sep); }
.hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

/* ---- options (build_v7 row): 56 px rows, 72 with a tile; the ring is the board's `sel` ramp ------------- */
.opts { display: flex; flex-direction: column; gap: 8px; }
.opt { display: flex; align-items: center; gap: 12px; min-height: 56px; padding: 8px 17px; border: 1px solid var(--edge); border-radius: var(--ri);
       font-size: 18px; line-height: 1.5; color: var(--ink); background: #fff; text-align: left; width: 100%; cursor: pointer;
       font-weight: 500; -webkit-tap-highlight-color: transparent; }
.opt-slot { min-height: 72px; padding: 7px 16px 7px 7px; }
.opt.sel { border-color: var(--navy); box-shadow: inset 0 0 0 1px var(--navy); font-weight: 600; animation: sel .45s ease-out both; }
.opt:focus-visible { outline: 2px solid var(--navy); outline-offset: 2px; }
.opt-text { flex: 1; }
.opt-sub { display: block; font-size: 18px; line-height: 1.5; font-weight: 500; color: var(--muted); margin-top: 2px; }
.opt-thumb { width: 56px; height: 56px; border-radius: var(--ri); object-fit: cover; flex-shrink: 0; background: var(--pale); }
.opt-tile { width: 56px; height: 56px; border-radius: var(--ri); background: var(--pale); flex-shrink: 0; display: flex; align-items: center; justify-content: center; }
/* screen 1 (board A1, owner 25.09): lighter rows, a 17 px label and a 14 px sub on one line */
.scr-compact .opts { gap: 12px; }
.scr-compact .opt-slot { min-height: 72px; padding: 10px 14px; gap: 14px; }
.scr-compact .opt-thumb { width: 52px; height: 52px; border-radius: 10px; }
.scr-compact .opt-text { font-size: 17px; line-height: 1.3; font-weight: 600; }
.scr-compact .opt-sub { font-size: 14px; line-height: 1.4; font-weight: 400; margin-top: 2px; white-space: nowrap; }
.opt-box { width: 22px; height: 22px; border-radius: 6px; border: 1.5px solid var(--mark); background: #fff; flex-shrink: 0;
           display: flex; align-items: center; justify-content: center; }
.opt-box .ic { opacity: 0; }
.opt.sel .opt-box { border-color: var(--navy); background: var(--navy); }
.opt.sel .opt-box .ic { opacity: 1; }

/* chips of two kinds: the dark answer chip (info screens) and the pick chip (screens 23, 24); `fill` is the board's ramp */
.chip { padding: 10px 14px; border-radius: var(--ri); background: var(--chip); color: #fff; font-size: 18px; line-height: 1.2; font-weight: 600;
        display: inline-flex; align-items: center; white-space: nowrap; flex-shrink: 0; }
.picks { display: flex; gap: 8px; flex-wrap: wrap; }
.pick { padding: 9px 13px; border: 1px solid var(--edge); border-radius: var(--ri); font-size: 18px; line-height: 1.2; display: inline-flex; align-items: center;
        white-space: nowrap; background: #fff; color: var(--ink); font-weight: 500; cursor: pointer; -webkit-tap-highlight-color: transparent; }
.pick.sel { background: var(--navy); color: #fff; border-color: var(--navy); font-weight: 600; animation: fill .45s ease-out both; }
.pick:focus-visible { outline: 2px solid var(--navy); outline-offset: 2px; }

/* ---- fields ------------------------------------------------------------------------------- */
.field { min-height: 56px; width: 100%; border: 1px solid var(--edge); border-radius: var(--ri); padding: 0 17px; display: flex; align-items: center; gap: 8px;
         font: inherit; font-size: 18px; line-height: 1.4; font-weight: 500; color: var(--ink); background: #fff; margin: 0; -webkit-appearance: none; appearance: none; }
.field::placeholder { color: var(--ph); font-weight: 500; }
.field:focus, .field:focus-within { outline: none; border-color: var(--navy); box-shadow: inset 0 0 0 1px var(--navy); }
.field-select { position: relative; padding: 0; }
.field-select select { flex: 1; min-height: 54px; border: 0; background: transparent; padding: 0 44px 0 17px; font: inherit; font-size: 18px; font-weight: 500; color: var(--ink);
                       -webkit-appearance: none; appearance: none; outline: none; width: 100%; }
.field-select .ic { position: absolute; right: 16px; top: 50%; transform: translateY(-50%); pointer-events: none; }
input[type=number].field::-webkit-outer-spin-button, input[type=number].field::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
input[type=number].field { -moz-appearance: textfield; }
.head-avatar { display: flex; align-items: flex-start; gap: 12px; }
.head-avatar .h1 { flex: 1; }
.avatar62 { width: 62px; height: 62px; border-radius: 50%; overflow: hidden; flex-shrink: 0; background: var(--pale); position: relative; display: block; }
.avatar62 img { position: absolute; left: -17px; top: -10px; width: 103px; height: 103px; max-width: none; }
/* The offsets above are a hand-tuned crop for the plastics portrait, whose file is not cropped
   to the circle. An avatar that is already a centred square (the maxillofacial one) must simply
   fill the circle instead, or it is zoomed a further 1.66x and pushed up and left. Opt in per
   screen with `"avatar_fit": true` in the flow. */
.avatar62.avatar-fit img { position: static; width: 100%; height: 100%; object-fit: cover; }

/* ---- slider (build_v7 slider): 12 px hot-to-cold track, 28 px white handle; the entrance travel is app.js slideIn (the board's `slide`)
   The track runs red on the left to blue on the right on both sliders (owner 13.09, walking staging); the board had it the other way. */
.slider { display: flex; flex-direction: column; gap: 8px; }
.range { -webkit-appearance: none; appearance: none; width: 100%; height: 28px; margin: 8px 0 0; background: transparent; cursor: pointer; }
.range:focus { outline: none; }
.range::-webkit-slider-runnable-track { height: 12px; border-radius: 999px; background: linear-gradient(90deg, var(--cold) 0%, var(--hot) 100%); }
.range::-moz-range-track { height: 12px; border-radius: 999px; background: linear-gradient(90deg, var(--cold) 0%, var(--hot) 100%); }
/* Screen 6 «Наскільки це вам заважає зараз?» runs cold to hot: the right anchor is the worse end.
   Screen 10 «Наскільки ви розглядаєте втручання?» is the other way round, because there the LEFT
   anchor «уникаю втручань» is the worse end. The flow file marks that one with reverse_track. */
.range-rev::-webkit-slider-runnable-track { background: linear-gradient(90deg, var(--hot) 0%, var(--cold) 100%); }
.range-rev::-moz-range-track { background: linear-gradient(90deg, var(--hot) 0%, var(--cold) 100%); }
.range::-webkit-slider-thumb { -webkit-appearance: none; width: 28px; height: 28px; margin-top: -8px; border-radius: 50%; background: #fff;
                               border: 2px solid var(--navy); box-shadow: 0 2px 6px rgba(21,38,66,.25); }
.range::-moz-range-thumb { width: 24px; height: 24px; border-radius: 50%; background: #fff; border: 2px solid var(--navy); box-shadow: 0 2px 6px rgba(21,38,66,.25); }
.range:focus-visible::-webkit-slider-thumb { outline: 2px solid var(--navy); outline-offset: 2px; }
.anchors { display: flex; justify-content: space-between; gap: 12px; font-size: 18px; line-height: 1.5; font-weight: 500; color: var(--muted); }

/* ---- the pill ------------------------------------------------------------------------------- */
.pill { display: flex; align-items: center; justify-content: center; gap: 8px; height: 48px; margin-top: 8px; border-radius: 999px; background: var(--pill);
        color: #fff; font-size: 18px; font-weight: 600; border: 0; width: 100%; cursor: pointer;
        transition: background-color .15s, color .15s, opacity .15s; }
.pill:hover { background: #1b2a44; }
.pill:focus-visible { outline: 2px solid var(--navy); outline-offset: 2px; }
.pill[disabled] { background: var(--dis-bg); color: var(--muted); cursor: default; }
.pill.busy { opacity: .7; cursor: wait; }
/* screen 23 only (owner 13.09): the submit button is never disabled. While a required field is empty it
   wears the board's disabled grey instead, and a tap on it says in words which field is missing. The
   button still presses; app.js drops .warn the moment both fields hold something and the dark pill is back. */
.pill.warn { background: var(--dis-bg); color: var(--muted); }
.pill.warn:hover { background: var(--dis-bg); color: var(--muted); }

/* ---- cards: the board's fixed heights kept as aspect ratios, so a wider column shows the same picture, only larger ----

   The button is never allowed below the fold (owner 13.09, walking staging on his phone): the picture gives up
   height before the button does. Each card keeps the board's ratio until the viewport is too short for it, and
   only then the clamp bites, so nothing changes on a tall phone. The offsets are measured, not guessed: they are
   everything the screen carries besides the card, at the 390 px artboard (520 on 20b with the longest verdict,
   299 on 24), plus the 24 px the page ends with; the narrow block below re-measures them at 320.
   `100svh` is the viewport with the browser toolbar SHOWING, which is exactly the height that has to hold the
   button, and it does not move when the toolbar retracts. `100vh` is declared first for the engines that know
   neither svh nor dvh; they get the toolbar-less height, which is the old behaviour, never worse than it.
   .portrait and .thanks-photo clamp their HEIGHT and let object-fit: cover crop, which keeps them full-bleed;
   there is no overlay on either to knock out of place.
   Screen 8 has no clamp of any kind: it is a square at the full column width, and the square is what buys
   the height its button needs (owner 13.09 on staging: «I want it to still fill up the entire width, if it
   is a square it should fit perfectly»). */
.card { border-radius: var(--rc); overflow: hidden; position: relative; }
.card-navy { background: var(--navy); color: #fff; }
.card-pale { background: var(--pale); }
.portrait { aspect-ratio: 342 / 300; min-height: 120px; max-height: calc(100vh - 520px); max-height: calc(100svh - 520px); }
.portrait img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: 50% 12%; }
.thanks-photo { aspect-ratio: 342 / 192; min-height: 96px; max-height: calc(100vh - 299px); max-height: calc(100svh - 299px); }
.thanks-photo img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.thanks-src { margin-top: 8px; }

/* screen 8: the 342 x 342 square window on the zone with the dashed box drawn on over 600 ms at 1.2 s, then
   the faint slow pulse. The card was 342 x 430 until 13.09: the owner asked for the original crop as a square
   at the full column width, so the photograph keeps its scale and object-fit: cover simply shows 88 px less of
   it, 44 off the top and 44 off the bottom. The dashed boxes in data/assets.json are recomputed for the shorter
   card, so every one of them still sits on the same feature of the same face. */
.zone { aspect-ratio: 1 / 1; width: 100%; }
.zone-img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.zone-eyes .zone-img { inset: auto; max-width: none; object-fit: fill; }   /* placed by the inline per-cent style */
.zone-box { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.zb-draw { animation: draw .6s ease-in-out 1.2s both; }
.zb-pulse { animation: pulse 6s ease-in-out 1.8s infinite; }

/* screen 3: «1 з 3» */
.one3 { padding: 30px 24px 26px; }
.one3-num { display: flex; align-items: flex-end; gap: 12px; line-height: 1; }
.one3-roll { height: 120px; overflow: hidden; }
.one3-digits { font-size: 120px; font-weight: 600; letter-spacing: -0.05em; animation: roll .6s cubic-bezier(.3,.9,.35,1.06) .4s both; }
.one3-digits > div { height: 120px; }
.one3-of { font-size: 40px; font-weight: 500; letter-spacing: -0.02em; margin-bottom: 21px; }
.one3-faces { display: flex; gap: 14px; margin-top: 26px; padding-top: 50px; }
.one3-face { width: 56px; height: 56px; border-radius: 50%; overflow: hidden; flex-shrink: 0; position: relative; background: rgba(255,255,255,.15);
             box-shadow: 0 0 0 1.5px rgba(255,255,255,.9); display: block; }
.one3-face img { width: 100%; height: 100%; object-fit: cover; }
.one3-third { overflow: visible; }
.one3-third img { border-radius: 50%; }
.one3-third .rej { animation: reject .5s ease-in-out 1.75s both; }
.one3-chip { position: absolute; left: 50%; bottom: 64px; transform: translateX(-50%); }
.one3-line { margin: 24px 0 0; font-size: 18px; line-height: 1.5; font-weight: 500; text-wrap: pretty; }

/* screen 15: the story card */
.story { background: var(--pale); padding: 4px; }
.pair { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.shot { position: relative; aspect-ratio: 1 / 1; border-radius: var(--ri); overflow: hidden; background: var(--line); }
.shot img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.cap { font-size: 18px; line-height: 1.4; font-weight: 600; color: var(--muted); margin: 6px 0 0 8px; }
.facts { display: flex; flex-direction: column; gap: 8px; padding: 14px 12px 12px; }
.fact { display: flex; gap: 10px; align-items: flex-start; font-size: 18px; line-height: 1.5; font-weight: 500; color: var(--ink); }
.fact .ic { flex-shrink: 0; margin-top: 3px; }

/* screen 16: the day rows and the growing line */
.tl { position: relative; display: flex; flex-direction: column; gap: 16px; }
.tl-line { position: absolute; left: 6px; top: 36px; bottom: 36px; width: 2px; background: var(--line); }
.tl-grow { width: 100%; height: 100%; background: var(--navy); transform-origin: top; animation: grow 1.6s ease-in-out 1s both; }
.tl-row { display: flex; align-items: center; gap: 14px; min-height: 72px; }
.tl-dotcol { width: 14px; flex-shrink: 0; display: flex; justify-content: center; }
.tl-dot { width: 14px; height: 14px; border-radius: 50%; background: var(--navy); box-shadow: 0 0 0 3px #fff; display: block; }
.tl-text { flex: 1; }
.tl-day { font-size: 18px; line-height: 1.4; font-weight: 700; color: var(--ink); }
.tl-cap { font-size: 18px; line-height: 1.5; font-weight: 500; color: var(--muted); margin-top: 2px; }
.tl-thumb { width: 72px; height: 72px; border-radius: var(--ri); object-fit: cover; background: var(--line); flex-shrink: 0; }

/* screen 20a: the checklist card */
.loading { padding: 26px 24px 28px; min-height: 360px; }
.loading .h1 { margin-top: 22px; }
.spinner { border-radius: 50%; border: 2px solid rgba(255,255,255,.3); border-top-color: #fff; animation: spin 1s linear infinite; }
.spinner-36 { width: 36px; height: 36px; border-width: 3px; }
.checklist { display: flex; flex-direction: column; gap: 14px; margin-top: 22px; }
.check-line { display: flex; align-items: center; gap: 12px; font-size: 18px; line-height: 1.5; font-weight: 500; }
.check-line .ic { flex-shrink: 0; }
.dot-green { width: 12px; height: 12px; border-radius: 50%; background: var(--green); box-shadow: 0 0 0 4px rgba(47,191,113,.28); margin: 0 3px; flex-shrink: 0; }

/* arm A handoff page */
.handoff { max-width: 560px; margin: 0 auto; padding: 60px 24px; text-align: center; display: flex; flex-direction: column; gap: 12px; }
.handoff-text { margin: 0; font-size: 18px; color: var(--muted); }
.handoff-link { font-weight: 600; }

/* ---- motion: the board's keyframes; one entrance per element on every injection, resting after it ------------------- */
.fu { animation: fadeUp var(--dur, .45s) ease-out both; animation-delay: var(--d, 0s); }
.pop { animation: popIn var(--dur, .45s) var(--bounce) both; animation-delay: var(--d, 0s); }
.ph { animation: fadeIn .6s ease-out .2s both; }
@keyframes fadeUp { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
@keyframes popIn { from { opacity: 0; transform: scale(.6); } to { opacity: 1; transform: scale(1); } }
@keyframes spin { to { transform: rotate(360deg); } }
@keyframes draw { from { stroke-dashoffset: 100; } to { stroke-dashoffset: 0; } }
@keyframes pulse { 0%, 32% { opacity: 1; } 52% { opacity: .78; } 72% { opacity: 1; } 92%, 100% { opacity: 1; } }
@keyframes roll { from { transform: translateY(0); } to { transform: translateY(-120px); } }
@keyframes reject { from { filter: none; opacity: 1; } to { filter: grayscale(1) brightness(.6); opacity: .85; } }
@keyframes grow { from { transform: scaleY(0); } to { transform: scaleY(1); } }
@keyframes sel { from { border-color: var(--edge); box-shadow: inset 0 0 0 0 var(--navy); } to { border-color: var(--navy); box-shadow: inset 0 0 0 1px var(--navy); } }
@keyframes fill { from { background: #fff; color: var(--ink); border-color: var(--edge); } to { background: var(--navy); color: #fff; border-color: var(--navy); } }
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition: none !important; }
  .zb-draw { stroke-dashoffset: 0; }
  .one3-digits { transform: translateY(-120px); }
  .one3-sm .one3-digits { transform: translateY(-96px); }
  .one3-third .rej { filter: grayscale(1) brightness(.6); opacity: .85; }
  .tl-grow { transform: none; }
}

/* a 320 px phone wraps one line more in the headline and in the read-back, so the same three screens
   need more room for their copy; measured the same way at 320. */
@media (max-width: 359px) {
  .portrait { max-height: calc(100vh - 604px); max-height: calc(100svh - 604px); }
  .thanks-photo { max-height: calc(100vh - 340px); max-height: calc(100svh - 340px); }
}

/* ---- desktop: white, the same single column centred, everything scaled with the column (RemedyMeds; owner 13.09) ------
   zoom scales type, spacing and images together, so the 390 px layout is reproduced at 468 px (>= 768) and 507 px (>= 1200). */
@media (min-width: 768px) {
  body { background: #fff; }
  .page { max-width: 390px; margin: 0 auto; zoom: 1.2; min-height: calc(100dvh / 1.2); }
  .opt:hover, .pick:hover { border-color: var(--navy); }
  .plain { padding: 60px 24px; }
  /* zoom scales the used value of every length inside the column, viewport units included, so the clamps
     have to be divided by the same factor to keep meaning the height of the real window. */
  .portrait { max-height: calc(100vh / 1.2 - 520px); max-height: calc(100svh / 1.2 - 520px); }
  .thanks-photo { max-height: calc(100vh / 1.2 - 299px); max-height: calc(100svh / 1.2 - 299px); }
}
@media (min-width: 1200px) {
  .page { zoom: 1.3; min-height: calc(100dvh / 1.3); }
  .portrait { max-height: calc(100vh / 1.3 - 520px); max-height: calc(100svh / 1.3 - 520px); }
  .thanks-photo { max-height: calc(100vh / 1.3 - 299px); max-height: calc(100svh / 1.3 - 299px); }
}

/* ---- maxillofacial: the two screens the plastics quiz has no shape for (build_mfs2 s07, s17b) --------
   The honest-number card on MFS screen 4 reuses .one3 above, minus the faces. */
/* The honest number (MFS screen 4) is the same navy card as «1 з 3», at the board's own
   smaller scale: build_mfs.big_card uses a 96 px digit where build_v7's one3 uses 120. */
.one3-sm .one3-roll { height: 96px; }
.one3-sm .one3-digits { font-size: 96px; letter-spacing: -0.04em; animation-name: roll-sm; }
.one3-sm .one3-digits > div { height: 96px; }
.one3-sm .one3-of { font-size: 32px; margin-bottom: 14px; }
.one3-sm .one3-line { margin-top: 22px; }
@keyframes roll-sm { from { transform: translateY(0); } to { transform: translateY(-96px); } }

/* The next button never leaves the screen (owner, 13.09 evening): on an information screen
   that carries more than a phone holds, the button pins to the bottom of the viewport on a
   white pad and the content scrolls under it, instead of the screen's photos being shrunk.
   That is the board's own mechanism (flow-v3-mfs.md §1). Opt in per screen with
   `"sticky_button": true` in the flow, so a screen that already fits is untouched, and so the
   plastics quiz, whose data sets the flag nowhere, keeps the behaviour it has. `:has()` is the
   only part an old engine can miss, and missing it leaves today's behaviour, never worse.
   The white halo belongs to a button that is really floating over content: on a screen that
   fits the viewport it washed the bottom of the element above the button. app.js appends a
   1 px probe as the last child of the section and watches it: while the probe is out of view
   there is content under the button, the section gets .pinned and the halo with it. The probe
   cancels the column's 12 px gap with its negative margin, so it adds no height. */
.page:has(.scr-sticky) { overflow: visible; }
.scr-sticky .pill { position: sticky; bottom: 16px; z-index: 2; }
.scr-sticky.pinned .pill { box-shadow: 0 10px 0 10px #fff, 0 -12px 20px 12px rgba(255, 255, 255, .92); }
.pin-probe { display: block; height: 1px; margin-top: -13px; visibility: hidden; pointer-events: none; }
/* A pinned button needs no room from the photograph, so the height clamps that buy that room
   are off here: the picture keeps its size and the content scrolls (owner 13.09: «keep the
   height adequate, you cannot even see the doctor»). */
.scr-sticky .portrait, .scr-sticky .thanks-photo, .scr-sticky .zone { max-height: none; max-width: none; }

.duo { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.duo-cell { position: relative; height: 132px; border-radius: var(--ri); overflow: hidden; background: var(--pale); }
.duo-cell img { width: 100%; height: 100%; object-fit: cover; }
.doc { display: flex; gap: 12px; align-items: center; padding: 10px; border: 1px solid #e6e9ef; border-radius: var(--ri); background: #fff; }
.doc-av { width: 62px; height: 62px; border-radius: 50%; overflow: hidden; flex-shrink: 0; background: var(--pale); }
.doc-av img { width: 62px; height: 62px; object-fit: cover; }
.doc-txt { flex: 1; }
.doc-name { display: block; font-size: 18px; line-height: 1.4; font-weight: 700; color: var(--ink); }
.doc-txt .body { display: block; }
.stats { display: flex; gap: 12px; }
.stat { flex: 1; }
.stat-n { font-size: 22px; font-weight: 700; color: var(--navy); letter-spacing: -0.02em; line-height: 1.1; }
.stat-l { font-size: 16px; line-height: 1.3; color: var(--muted); margin-top: 4px; }

/* ---- screen 24 with booking (lead-to-consult flow H, owner 25.09): artboards H1-list with F1-pick's day rows,
   H2-calendar, H3a-lock, ported from their inline styles. Only with BOOKING_ON_THANKS on (thanks_booking.html).
   Times, dates and the price are IBM Plex Mono 500 as on the board: self-hosted, subset to digits, «:.», the
   weekday abbreviations and «грн», 3 KB. Where the artboard leaves line-height unset it is `normal`, kept. */
@font-face {
  font-family: 'IBM Plex Mono';
  src: url('/static/fonts/ibm-plex-mono-500-uk.woff2') format('woff2');
  font-weight: 500; font-style: normal; font-display: swap;
}
.mono { font-family: 'IBM Plex Mono', ui-monospace, Menlo, monospace; font-weight: 500; }
.thanks-photo-short { aspect-ratio: 342 / 140; min-height: 0; border-radius: 20px; }
/* page 29, «Ви записані» after a paid return (owner 25.09, review 3): the verdict screen's photo (his 349 x 207 crop,
   radius 24) and its 17 / 1.6 body, so the flow ends on the same system it ran on */
.book-final .thanks-photo { aspect-ratio: 349 / 207; border-radius: 24px; }
.book-final .body { font-size: 17px; line-height: 1.6; }
/* owner 25.09: the booking screen has no motion at all, no entrance and no selection ramp */
.scr-book, .scr-book * { animation: none !important; transition: none !important; }
.scr-book .book-more { justify-content: center; text-align: center; font-weight: 600; color: var(--navy); }

/* H1: F1's day rows on the quiz's .opt, a radio on the right; the open day's times as .pick chips under it */
.book-days { display: flex; flex-direction: column; gap: 12px; }
.opt-day { min-height: 60px; padding: 12px 16px; line-height: normal; }
.opt-day .opt-title { display: block; }
.opt-day .opt-sub { font-size: 14px; line-height: normal; margin-top: 2px; }
/* board A4 (owner 25.09): 17 px day titles, the question in grey 16 px, 17 px time chips */
.scr-book .opt-day .opt-title { font-size: 17px; font-weight: 600; }
.opt-fmt { min-height: 60px; padding: 12px 16px; line-height: normal; }   /* the format rows (owner 28.09) read as the day rows */
.opt-fmt .opt-title { display: block; font-size: 17px; font-weight: 600; }
.opt-fmt .opt-sub { font-size: 14px; line-height: normal; margin-top: 2px; }
.scr-book [data-view="h1"] .h1 + .body { font-size: 16px; line-height: 1.45; color: var(--muted); margin-top: -4px; }
.scr-book .book-times .pick { padding: 10px 16px; font-size: 17px; border-radius: 12px; }
.scr-book .book-more { min-height: 54px; font-size: 17px; }
.opt-radio { width: 22px; height: 22px; border-radius: 50%; border: 1.5px solid var(--mark); flex-shrink: 0; transition: border .2s ease-out; }
.opt.sel .opt-radio { border: 7px solid var(--navy); }
.book-times { padding-left: 4px; }
.pick.mono, .pick.mono.sel { font-weight: 500; line-height: normal; }
/* owner 28.09: weekends and full days are greyed rows; taken times are greyed and crossed out, never tappable */
.opt-day.opt-full { background: #f3f4f6; border-color: #e5e6ec; cursor: default; }
.opt-day.opt-full .opt-title, .opt-day.opt-full .opt-sub { color: #9aa3ae; }
.opt-day.opt-full .opt-radio { border-color: #d7dbe1; }
.pick.pick-taken, .cal-time.taken { color: #b3bac4; background: #f3f4f6; border-color: #e5e6ec; text-decoration: line-through; cursor: default; }
.opt-day.opt-full:hover, .pick.pick-taken:hover { border-color: #e5e6ec; }
/* owner 25.09: the schedule line under «Коли вам зручно прийти?» */
.book-note { display: flex; gap: 12px; align-items: flex-start; margin: 0; padding: 12px 14px; border-radius: 12px;
             background: var(--navy); color: #fff; font-size: 14px; line-height: 1.45; font-weight: 500; }
.book-note .ic { flex-shrink: 0; margin-top: 2px; }
.book-note b { font-weight: 700; }

/* H2 month tabs (owner 25.09): both names underlined and tappable, the shown month in navy */
.cal-tabs { display: flex; gap: 20px; }
.cal-tab { background: none; border: 0; padding: 6px 0; min-height: 44px; font-size: 18px; font-weight: 600; line-height: normal; color: var(--muted);
           text-decoration: underline; text-underline-offset: 5px; text-decoration-thickness: 1px; cursor: pointer; }
.cal-tab.on { color: var(--navy); text-decoration-thickness: 2px; }
.cal-out { visibility: hidden; }
/* H2: this week and the next two; free days pale with a dot, past and Sundays pale grey, empty days grey */
.cal-months { font-size: 18px; font-weight: 600; line-height: normal; color: var(--navy); }
.cal { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 4px; line-height: normal; }
.cal-wd { text-align: center; font-size: 13px; font-weight: 600; color: #5b6472; }
.cal-day { height: 42px; border-radius: 12px; display: flex; flex-direction: column; align-items: center; justify-content: center;
           font-size: 16px; color: #9aa3ae; background: none; border: 0; padding: 0; margin: 0; -webkit-tap-highlight-color: transparent; }
.cal-day::after { content: ""; display: block; width: 4px; height: 4px; border-radius: 2px; margin: 2px auto 0; }
.cal-off { color: #c3cad4; }
.cal-free { color: #0f1722; background: var(--pale); cursor: pointer; }
.cal-free::after { background: var(--navy); }
.cal-day.sel { background: var(--navy); color: #fff; font-weight: 600; }
.cal-day.sel::after { background: transparent; }
.cal-day:focus-visible, .cal-time:focus-visible { outline: 2px solid var(--navy); outline-offset: 2px; }
.cal-label { font-size: 15px; font-weight: 600; line-height: normal; color: #5b6472; }
.cal-times { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 8px; }
.cal-time { font-size: 17px; line-height: normal; text-align: center; padding: 11px 0; border-radius: 12px; border: 1.5px solid #e5e6ec;
            background: #fff; color: #0f1722; cursor: pointer; -webkit-tap-highlight-color: transparent; }
.cal-time.sel { border-color: var(--navy); background: var(--navy); color: #fff; }
.pill-52 { height: 52px; margin-top: 4px; }

/* H3: the navy ticket with the dashed tear and the white button inside, two reasons, the outline button */
/* owner 25.09: the notches are real holes (the page shows through) and the shadow follows them, so the ticket is two
   masked halves and the shadow is a drop-shadow filter on the wrapper, which traces the visible shape, not the box */
.ticket { color: #fff; line-height: normal; filter: drop-shadow(0 1px 2px rgba(21,38,66,.06)) drop-shadow(0 6px 14px rgba(21,38,66,.12)); }
.ticket-top, .ticket-bot { background: var(--navy); }
/* flow-root (owner 25.09, review 3): without it the hold strip's 18 px top margin collapsed out through the card,
   so the strip sat flush on the card's top edge and the gap moved above the card; board A5 has 18 px inside */
.ticket-top { display: flow-root; border-radius: 18px 18px 0 0;
  -webkit-mask: radial-gradient(circle 9px at 0 100%, #0000 97%, #000 100%) left / 51% 100% no-repeat,
                radial-gradient(circle 9px at 100% 100%, #0000 97%, #000 100%) right / 51% 100% no-repeat;
          mask: radial-gradient(circle 9px at 0 100%, #0000 97%, #000 100%) left / 51% 100% no-repeat,
                radial-gradient(circle 9px at 100% 100%, #0000 97%, #000 100%) right / 51% 100% no-repeat; }
.ticket-bot { border-radius: 0 0 18px 18px;
  -webkit-mask: radial-gradient(circle 9px at 0 0, #0000 97%, #000 100%) left / 51% 100% no-repeat,
                radial-gradient(circle 9px at 100% 0, #0000 97%, #000 100%) right / 51% 100% no-repeat;
          mask: radial-gradient(circle 9px at 0 0, #0000 97%, #000 100%) left / 51% 100% no-repeat,
                radial-gradient(circle 9px at 100% 0, #0000 97%, #000 100%) right / 51% 100% no-repeat; }
/* owner 25.09: the hold's countdown, from the engine's expires_at */
.ticket-hold { display: flex; justify-content: space-between; align-items: center; gap: 8px; margin: 18px 20px 0; padding: 8px 12px;
               border-radius: 10px; background: rgba(255,255,255,.1); font-size: 13px; font-weight: 400; }
.ticket-hold .mono { font-size: 18px; font-weight: 500; }
/* owner 25.09, review 3: one 20 px step above and below the ticket (the stack's 12 + 8), in every ticket state */
.scr-book .ticket { margin: 8px 0; }
.ticket-doc { padding: 18px 20px 14px; display: flex; gap: 14px; align-items: center; }
.ticket-doc[hidden] + .ticket-grid { padding-top: 18px; }
.ticket-hold:not([hidden]) + .ticket-doc { padding-top: 14px; }
.ticket-av { width: 52px; height: 52px; border-radius: 50%; overflow: hidden; flex-shrink: 0; position: relative; background: rgba(255,255,255,.15); }
/* the plastics portrait is not cropped to the circle: .avatar62's hand crop scaled to 52 px; a square one fills it */
.ticket-av img { position: absolute; left: -14.26px; top: -8.39px; width: 86.39px; height: 86.39px; max-width: none; }
.ticket-av.avatar-fit img { position: static; width: 100%; height: 100%; object-fit: cover; }
.t-lab { display: block; font-size: 13px; font-weight: 600; color: rgba(255,255,255,.8); }
.t-name { display: block; font-size: 17px; font-weight: 700; }
.ticket-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px 12px; padding: 0 20px 16px; }
.t-val { display: block; font-size: 19px; color: #fff; white-space: nowrap; }
.t-val s { font-size: 14px; opacity: .55; margin-right: 6px; }
.t-where { display: block; font-size: 14px; font-weight: 600; color: #fff; white-space: nowrap; }
.ticket-tear { border-top: 2px dashed rgba(255,255,255,.28); margin: 0 12px; }
.ticket-foot { padding: 16px 20px 20px; }
.ticket-pay { width: 100%; height: 50px; border: 0; border-radius: 12px; background: #fff; color: var(--navy); font-size: 16px; font-weight: 700; cursor: pointer; }
.why { display: flex; gap: 14px; align-items: flex-start; line-height: normal; }
.why-ic { width: 44px; height: 44px; border-radius: 12px; background: var(--pale); flex-shrink: 0; display: flex; align-items: center; justify-content: center; }
.why-t { display: block; font-size: 17px; font-weight: 700; color: #0f1722; }
.why-s { display: block; font-size: 16px; line-height: 1.45; font-weight: 500; color: var(--muted); }
.btn-line { width: 100%; height: 50px; border: 2px solid var(--navy); border-radius: 12px; background: #fff; color: var(--navy);
            font-size: 15px; font-weight: 700; cursor: pointer; }
.ticket-pay.busy, .btn-line.busy { opacity: .7; cursor: wait; }
.ticket-pay:focus-visible, .btn-line:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
.btn-line:focus-visible { outline-color: var(--navy); }

/* ---- the callback form (/callback, the Tally pop-up's replacement), scoped to its own screen ----
   owner 26.09: simple and readable, the whole form on a phone's pop-up with no scroll. One size of body
   text (15px), one field height, the call-back line as a quiet caption under the promises. */
.scr-callback { gap: 10px; }
.scr-callback .h1 { font-size: 21px; line-height: 1.25; letter-spacing: -0.015em; }
.scr-callback .cb-lines { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 4px; }
.scr-callback .cb-lines li { display: flex; gap: 8px; align-items: flex-start; font-size: 15px; line-height: 1.4; font-weight: 500; color: var(--ink); }
.scr-callback .cb-lines .ic, .scr-callback .cb-note .ic { flex-shrink: 0; margin-top: 2px; }
.scr-callback .cb-note { margin: 0; display: flex; gap: 8px; align-items: center; padding: 8px 12px; border-radius: 10px;
                         background: var(--pale); font-size: 14px; line-height: 1.3; font-weight: 600; color: var(--navy); }
.scr-callback .group { gap: 8px; }
.scr-callback .field { min-height: 46px; font-size: 16px; }
.scr-callback .consent-row { margin-top: 0; border: 0; padding: 0 2px; align-items: flex-start; gap: 10px; }
.scr-callback .consent-row .opt-box { margin-top: 1px; }
/* owner 26.09: on a screen with room (desktop, tall phones) the text matches the site's size */
html.roomy .scr-callback { gap: 12px; }
html.roomy .scr-callback .h1 { font-size: 26px; }
html.roomy .scr-callback .cb-lines li { font-size: 17px; }
html.roomy .scr-callback .cb-note { font-size: 16px; padding: 10px 14px; }
html.roomy .scr-callback .field { min-height: 52px; font-size: 17px; }
html.roomy .scr-callback .consent-row .consent { font-size: 12px; }
.scr-callback .field.gap { border-color: var(--hot); box-shadow: inset 0 0 0 1px var(--hot); }
.scr-callback .consent-row.gap .opt-box { border-color: var(--hot); }

/* ---- the callback form inline on clinica28.org's procedure pages (?inline=1), in place of the Tally
   inline form wkzKZR (owner 28.09, option A of the inline board): the page's navy section keeps its title
   and dashes, this frame holds only the fields, the consent, the white button and the one-day caption, on
   the section's navy, two columns where there is room. The screens after it (booking, thanks) keep the
   pop-up's white card with its header, so their back button stays. */
html.inline, html.inline body { background: #152642; }
html.inline .page { max-width: none; margin: 0; zoom: 1; min-height: 0; background: transparent; }
html.inline .page:has(.scr-callback) .hdr, html.inline .page:has(.scr-callback) .bar { display: none; }
html.inline .page:has(.scr-callback) .screen { padding: 0 0 4px; margin-top: 0; }
html.inline .page:not(:has(.scr-callback)) { background: #fff; border-radius: var(--rc); min-height: 100dvh; }
html.inline .scr-callback .h1, html.inline .scr-callback .cb-lines { display: none; }
html.inline .scr-callback { gap: 12px; }
html.inline .scr-callback .group { display: grid; grid-template-columns: 100%; gap: 10px; }
html.inline .scr-callback .field { min-height: 48px; font-size: 16px; border-radius: 8px; color: #fff;
  background: rgba(255,255,255,.07); border-color: rgba(255,255,255,.22); }
html.inline .scr-callback .field::placeholder { color: rgba(255,255,255,.62); }
html.inline .scr-callback .field:focus { border-color: #fff; box-shadow: inset 0 0 0 1px #fff; }
html.inline .scr-callback .field.gap { border-color: #ff8a82; box-shadow: inset 0 0 0 1px #ff8a82; }
html.inline .scr-callback .consent-row .consent, html.inline .scr-callback .consent-row .consent a { color: rgba(255,255,255,.75); }
html.inline .scr-callback .consent-row .consent { font-size: 12px; }
html.inline .scr-callback .opt-box { background: transparent; border-color: rgba(255,255,255,.6); }
html.inline .scr-callback .consent-row input:checked + .opt-box { background: transparent; border-color: #fff; }
html.inline .scr-callback .consent-row input:focus-visible + .opt-box { outline-color: #fff; }
html.inline .scr-callback .consent-row.gap .opt-box { border-color: #ff8a82; }
html.inline .scr-callback .issue { order: 8; font-size: 15px; color: #ffb4ae; }
html.inline .scr-callback .pill, html.inline .scr-callback .pill.warn { order: 9; align-self: flex-start; width: auto; height: 44px; margin-top: 4px;
  padding: 0 16px; border-radius: 8px; background: #fff; color: #111; font-size: 16px; font-weight: 700; }
html.inline .scr-callback .pill:hover { background: #e9ecf2; }
html.inline .scr-callback .pill:focus-visible { outline-color: #fff; }
html.inline .scr-callback .cb-note { order: 10; padding: 0; background: none; color: rgba(255,255,255,.62); font-size: 13px; font-weight: 500; }
html.inline .scr-callback .cb-note .ic { display: none; }
@media (min-width: 640px) {
  html.inline .scr-callback .group { grid-template-columns: 1fr 1fr; }
  html.inline .scr-callback .consent-row { max-width: 640px; }
}

/* owner 29.09: three legal links under the ticket, quiet, each opens a new tab */
.book-legal { display: flex; flex-wrap: wrap; justify-content: center; gap: 4px 16px; margin: 14px 0 0;
  font-size: 13px; line-height: 20px; }
.book-legal a { color: var(--muted, #6b7280); text-decoration: underline; text-underline-offset: 2px; }
