/*
 * Paytrack product site (kirbyservice.net). Loaded after Bootstrap 5.3.8 and
 * fonts.css. Dark, natural, soft palette (contrast measured, plan.md); the
 * stage of invisible layers and frost veils; the tiny dark scrollbar.
 * Keep this file ASCII.
 */

/* ---------- palette and Bootstrap's own variables -------------------------- */
:root,
[data-bs-theme=dark] {
  --pt-night: #0E1311;
  --pt-raised: #18201C;
  --pt-bone: #ECE6DA;
  --pt-lichen: #A7AFA4;
  --pt-sage: #9DB89F;
  --pt-moss: #7D9C78;
  --pt-sand: #D9C59A;
  --pt-clay: #D09A7C;
  --pt-mist: #93B7C6;
  --pt-dusk: #B4A7CF;
  --pt-head: 'Unbounded', system-ui, sans-serif;
  --pt-text: 'Figtree', system-ui, sans-serif;
  --pt-spring: cubic-bezier(.2, 1.25, .3, 1);

  /* The type scale: every text on the site takes its size from one of these
     (Dimitar, 02/10/2026: "all text - needs to have resize breaking points",
     "scaling curve is ok"). Each is a straight line between two screen widths,
     held at both ends, and the breakpoints below reset them: short phones
     (smaller), and from 1440 wide the whole content grows instead (the zoom
     steps at the end of the stage section). The lines land on the sizes the
     layers were fitted with at 375, 992, 1280 and 1440 wide.
     h1 (the opening line): 32 to 64 at 1306.  h2: 25 to 44 at 1419.
     body: 16 (the readable floor on phones) from 768 to 17.6 at 1440; it was
     a flat 16 from a phone to 1311 wide (Dimitar: "do you have a scalling
     curve for the main text?").  ui (pointers, buttons): 14 at 360 to 16 at
     1440.  say (bubbles): 13 to 14.  micro (kickers, the question): 11 to 12.
     line (the trade line, Unbounded): 14 to 18.  brand (the wordmark): 17 to 18. */
  --pt-fs-h1: clamp(32px, 4.9vw, 64px);
  --pt-fs-h2: clamp(25px, 3.1vw, 44px);
  --pt-fs-body: clamp(16px, calc(14.17px + .238vw), 17.6px);
  --pt-fs-ui: clamp(14px, calc(13.33px + .185vw), 16px);
  --pt-fs-say: clamp(13px, calc(12.67px + .093vw), 14px);
  --pt-fs-micro: clamp(11px, calc(10.67px + .093vw), 12px);
  --pt-fs-line: clamp(14px, 1.3vw, 18px);
  --pt-fs-brand: clamp(17px, calc(16.67px + .093vw), 18px);

  --bs-body-bg: #0E1311;
  --bs-body-bg-rgb: 14, 19, 17;
  --bs-body-color: #ECE6DA;
  --bs-body-color-rgb: 236, 230, 218;
  --bs-emphasis-color: #ECE6DA;
  --bs-secondary-color: #A7AFA4;
  --bs-body-font-family: var(--pt-text);
  --bs-body-font-size: 1rem;
  --bs-link-color: #9DB89F;
  --bs-link-color-rgb: 157, 184, 159;
  --bs-link-hover-color: #D9C59A;
  --bs-link-hover-color-rgb: 217, 197, 154;
  --bs-border-color: rgba(236, 230, 218, .12);
  --bs-heading-color: #ECE6DA;
}

html, body { background: var(--pt-night); color: var(--pt-bone); }
/* Bootstrap's reboot sets :root { scroll-behavior: smooth } unless the device
   asks for reduced motion. js/stage.js scrolls the page itself (the page snap,
   the arrow down, #links) and its scrolls must land at once: with smooth on, a
   phone glided after the snap had ended and the stage went down and up again.
   Same selector, later file: this wins. */
:root { scroll-behavior: auto; }
body { font-family: var(--pt-text); -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; }

/* ---------- the tiny dark scrollbar (Dimitar: no scroll buttons) ----------- */
::-webkit-scrollbar { width: 6px; height: 6px; background: transparent; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { border-radius: 6px; border: 1px solid transparent; background-clip: padding-box;
  background-image: linear-gradient(180deg, #3F5446, #34505B); }
::-webkit-scrollbar-thumb:hover { background-image: linear-gradient(180deg, #5E7A5A, #4A6B78); }
@supports not selector(::-webkit-scrollbar) {
  html { scrollbar-width: thin; scrollbar-color: #3F5446 transparent; }
}

/* ---------- type ------------------------------------------------------------ */
h1, h2 { font-family: var(--pt-head); font-weight: 500; color: var(--pt-bone); letter-spacing: -.02em; }
/* The opening's line takes the other pages' headline size, "Service System"
   above it takes the h1 size (Dimitar, 02/10/2026: "service system is too
   big, get it the size of Built to fit your business and the Built to fit
   your business - make it the size of the headers on the other pages"). */
.pt-open h1 { font-size: var(--pt-fs-h2); line-height: 1.14; margin: 0 0 22px; }
.pt-layer h2 { font-size: var(--pt-fs-h2); line-height: 1.14; margin: 0 0 18px; }
.pt-layer p { font-size: var(--pt-fs-body); line-height: 1.6; color: var(--pt-lichen); max-width: 34em; }
.pt-layer .pt-kicker { margin: 0 0 14px; font-size: var(--pt-fs-micro); font-weight: 600; letter-spacing: .18em; text-transform: uppercase; color: var(--tone, var(--pt-sage)); }
[data-tone=sage] { --tone: var(--pt-sage); }
[data-tone=sand] { --tone: var(--pt-sand); }
[data-tone=clay] { --tone: var(--pt-clay); }
[data-tone=mist] { --tone: var(--pt-mist); }
[data-tone=dusk] { --tone: var(--pt-dusk); }

/* ---------- the small arrow down, bottom centre, on every page but the last -- */
/* Dimitar, 02/10/2026: "small arrow down button fixed at the bottom of each but
   the last page". It takes the visitor to the next page with the page spring
   (js/stage.js) and fades out on the last one. Only with JS (it needs it). */
.pt-next { display: none; position: fixed; z-index: 900; left: 50%; bottom: max(14px, env(safe-area-inset-bottom));
  width: 40px; height: 40px; margin-left: -20px; padding: 0; border: 0; border-radius: 50%; cursor: pointer;
  background: rgba(236, 230, 218, .06); color: var(--pt-sage); transition: opacity .35s ease, background .25s; }
html.js .pt-next { display: grid; place-items: center; }
.pt-next svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round;
  animation: pt-nudge 2.6s ease-in-out infinite; }
.pt-next:hover { background: rgba(157, 184, 159, .16); }
.pt-next:focus-visible { outline: 2px solid var(--pt-sand); outline-offset: 3px; }
html[data-current=talk] .pt-next { opacity: 0; pointer-events: none; }
/* Very short screens (360x640): a smaller arrow, closer to the edge. */
@media (max-height: 660px) {
  .pt-next { width: 32px; height: 32px; margin-left: -16px; bottom: max(6px, env(safe-area-inset-bottom)); }
  .pt-next svg { width: 15px; height: 15px; }
  html.js .pt-layer { padding-bottom: 44px; }
  .pt-points li:nth-child(n+3) { display: none; }
}
@keyframes pt-nudge { 0%, 60%, 100% { translate: 0 0; } 75% { translate: 0 4px; } }

/* ---------- the brand, top left (not a menu: one link back to the start) ---- */
.pt-defs { position: absolute; width: 0; height: 0; overflow: hidden; }
.pt-brand { position: fixed; z-index: 1000; left: max(20px, env(safe-area-inset-left)); top: max(18px, env(safe-area-inset-top));
  display: flex; align-items: center; gap: .5em; text-decoration: none; color: var(--pt-bone);
  font-family: var(--pt-head); font-weight: 500; font-size: var(--pt-fs-brand); letter-spacing: -.03em; }
.pt-brand svg { width: 1.556em; height: 1.556em; }   /* 28px at 18px */
.pt-brand > span > span { color: var(--pt-sage); }
.pt-brand:hover { color: var(--pt-bone); }
.pt-brand:focus-visible { outline: 2px solid var(--pt-sand); outline-offset: 6px; border-radius: 8px; }

/* ---------- the stage (only with JS; without it the layers simply stack) ---- */
.pt-layer { min-height: 100vh; min-height: 100svh; display: flex; align-items: center; padding: 96px 0 64px; position: relative; }
.pt-veil, .pt-track { display: none; }
.pt-room { position: fixed; inset: -30%; pointer-events: none; z-index: 0;
  background:
    radial-gradient(36% 30% at 30% 30%, rgba(157, 184, 159, .12), rgba(157, 184, 159, 0) 70%),
    radial-gradient(32% 28% at 72% 68%, rgba(147, 183, 198, .09), rgba(147, 183, 198, 0) 70%); }

/* No CSS scroll-snap: js/stage.js snaps each page itself, with a small
   overshoot (Dimitar, 02/10/2026); the two would fight. */
/* The stage is as tall as the SMALL viewport (the screen with the browser's
   bars showing), not inset: 0. On a phone the address bar slides away or back
   at the end of a swipe; with inset: 0 the stage grew or shrank with it and
   the centred content moved by half the bar (28 to 40 px) just after the snap
   (Dimitar, 02/10/2026: "on the mobile there is a second annoying bounce
   after the scroll self complete"). 100svh never changes with the bars. */
html.js .pt-stage { position: fixed; left: 0; right: 0; top: 0; height: 100vh; height: 100svh; overflow: hidden;
  perspective: 1400px; perspective-origin: 50% 45%; }
html.js .pt-layer { position: absolute; inset: 0; min-height: 0; padding: 84px 0 40px; visibility: hidden;
  transform-style: preserve-3d; will-change: transform, opacity; }
html.js .pt-layer.is-current { visibility: visible; }
html.js .pt-veil { display: block; position: absolute; left: 0; right: 0; top: -35vh; height: 170vh; visibility: hidden;
  pointer-events: none; will-change: transform;
  background: rgba(14, 19, 17, .42);
  -webkit-backdrop-filter: blur(20px) saturate(1.1) brightness(.8); backdrop-filter: blur(20px) saturate(1.1) brightness(.8);
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 30vh); mask-image: linear-gradient(to bottom, transparent 0, #000 30vh); }
html.js .pt-track { display: block; position: relative; z-index: -1; pointer-events: none; }
.pt-step { height: 100vh; height: 100svh; }

/* ---------- big screens: the content grows as one ---------------------------- */
/* The type scale stops growing at 1440 wide (every size is at its cap there),
   and above that the whole content block, the logo and the arrow grow
   together in steps, so the 1440 layout (checked page by page) is the one a
   big screen sees, larger: text, Ai and Db, the components alike (Dimitar,
   02/10/2026: "all text - needs to have resize breaking points"). A step
   needs the width (1440 x zoom) and the height: the tallest page, the
   opening, is 580px at 1440, plus its 112px of padding and 40 to spare, so
   580 x zoom + 152. A maximised browser on a 1920x1080 screen (about
   1920x940) gets 1.2, on 2560x1440 (about 2560x1300) 1.75. */
@media (min-width: 1584px) and (min-height: 790px) { .pt-layer > .container, .pt-brand, .pt-next { zoom: 1.1; } }
@media (min-width: 1728px) and (min-height: 850px) { .pt-layer > .container, .pt-brand, .pt-next { zoom: 1.2; } }
@media (min-width: 1944px) and (min-height: 935px) { .pt-layer > .container, .pt-brand, .pt-next { zoom: 1.35; } }
@media (min-width: 2160px) and (min-height: 1025px) { .pt-layer > .container, .pt-brand, .pt-next { zoom: 1.5; } }
@media (min-width: 2520px) and (min-height: 1170px) { .pt-layer > .container, .pt-brand, .pt-next { zoom: 1.75; } }
@media (min-width: 2880px) and (min-height: 1315px) { .pt-layer > .container, .pt-brand, .pt-next { zoom: 2; } }

/* ---------- layer 0: the promise, Ai and Db, the trade picker -------------- */
.pt-open .container { position: relative; text-align: center; }
/* Ai, Db and the copy below the large title: the bots are placed against this
   block (not the container), so they always stand under it. */
.pt-open-main { position: relative; }
/* "Service System", above the bots, in the logo's sage to mist (Dimitar,
   02/10/2026: "main page on top of the bot large text - Service System",
   "that text to resize depends on the screen size"). It was first sized on
   its own (min(9vw, 14vh, 128px)), then (Dimitar: "service system is too big,
   get it the size of Built to fit your business") it takes the h1 curve, and
   the line under it the other pages' h2. Each word is an inline block as tall
   as its line: as plain inline text its box rose 30% above the line (this
   font's tall ascent). */
.pt-open .pt-mega { margin: 0 0 clamp(8px, 1.6vh, 18px); font: 600 var(--pt-fs-h1)/1.05 var(--pt-head); letter-spacing: -.035em;
  white-space: nowrap; color: var(--pt-sage);
  background: linear-gradient(90deg, #9DB89F, #93B7C6); -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; }
.pt-open .pt-mega span { display: inline-block; }
/* With "Service System" on top, the opening was the tallest page (554px at
   1280x720 at its first, larger size, 7px from the arrow). The logo takes
   only the top left corner and the title is centred, so on desktop this page
   sits higher: less room above, more for the arrow below. */
@media (min-width: 992px) {
  html.js .pt-layer.pt-open { padding-top: 46px; padding-bottom: 66px; }
}
/* Phones: two lines, "Service" over "System" (Dimitar's first word on it),
   at the h1 size (32px, 26 on short phones). */
@media (max-width: 575.98px) {
  .pt-open .pt-mega { margin-bottom: 8px; }
  .pt-open .pt-mega span { display: block; }
  /* This page on a phone: less room above (the logo is in the corner, the
     title is centred and starts below it), more below for the arrow. Its own
     selector, so it wins over the phone rule further down whatever the order
     (the generic short-phone room for the arrow loses to that rule). */
  html.js .pt-layer.pt-open { padding: 54px 0 66px; }
}
.pt-open-copy { position: relative; z-index: 2; max-width: 820px; margin: 0 auto; }
/* On desktop the copy keeps to the room between Ai and Db (at 1100 wide Ai's
   antenna touched the headline, 02/10/2026). */
@media (min-width: 992px) {
  .pt-open-copy { max-width: min(820px, calc(100% - 2 * clamp(150px, 15vw, 220px) - 32px)); }
}
.pt-open-copy > p { margin-left: auto; margin-right: auto; }
.pt-layer .pt-ask { margin: 30px auto 14px; font-size: var(--pt-fs-micro); font-weight: 600; letter-spacing: .18em; text-transform: uppercase; }
.pt-trades { display: flex; flex-wrap: wrap; justify-content: center; gap: 10px; }
.pt-trades button { height: 3.15em; padding: 0 1.3em; border: 0; border-radius: 999px; cursor: pointer;   /* 48 x 20 at 15px; never under 44 high on a phone */
  min-height: 44px; background: rgba(236, 230, 218, .07); color: var(--pt-bone); font: 600 var(--pt-fs-ui)/1 var(--pt-text);
  transition: background .25s, color .25s, transform .35s var(--pt-spring); }
.pt-trades button:hover { background: rgba(157, 184, 159, .18); transform: translateY(-2px); }
.pt-trades button[aria-pressed=true] { background: var(--pt-sage); color: var(--pt-night); }
.pt-trades button:focus-visible { outline: 2px solid var(--pt-sand); outline-offset: 3px; }
.pt-layer .pt-line { margin: 22px auto 0; min-height: 1.6em; font-family: var(--pt-head); font-weight: 400;
  font-size: var(--pt-fs-line); line-height: 1.5; color: var(--pt-sand); }

/* Every character: bobs gently, and Ai can be pointed at (he jumps, js/stage.js). */
.pt-char { position: relative; }
.pt-char-ai { animation: pt-bob 4.2s ease-in-out infinite; pointer-events: none; }
/* Only the head (and the antennae above it) starts a jump (Dimitar, 02/10/2026:
   "only when the mouse is over the head or on the head"): an invisible hit
   area drawn last in Ai's SVG; the rest of him lets the pointer through. */
.pt-head-hit * { fill: none; stroke: none; pointer-events: all; cursor: pointer; }
.pt-arm-left { transform-box: view-box; transform-origin: 50px 112px; }
.pt-char-db { animation: pt-bob 5.1s ease-in-out -1.3s infinite; }
.pt-char-ai.is-jumping .pt-bulb { animation-duration: .35s; }
.pt-char-body { perspective: 600px; transition: transform .22s cubic-bezier(.2, 1.32, .3, 1), scale .28s var(--pt-spring); }

/* The opening pair stands either side of the copy on desktop. */
.pt-chars { position: absolute; inset: 0; pointer-events: none; z-index: 3; }
.pt-chars .pt-char { position: absolute; top: 50%; width: clamp(150px, 15vw, 220px); }
.pt-chars .pt-char-ai { left: -2%; margin-top: -170px; }
.pt-chars .pt-char-db { right: -1%; margin-top: -120px; width: clamp(140px, 14vw, 205px); }
.pt-eyes { transition: transform .1s ease-out; }
/* "Local Ai" straight on the body, no patch behind it (Dimitar: "on transparent not white bg") */
.pt-belly-t { font-family: var(--pt-head); font-weight: 600; font-size: 6.2px; letter-spacing: .02em; fill: #16242A; }
.pt-belly-big { font-size: 9.5px; font-weight: 700; fill: #0E1311; }

/* Ai pulling data from Db: the arc and its dots (js/stage.js draws them). It
   sits behind the text (z 1, the copy is z 2, the characters z 3) and is
   blurred on desktop, where it crosses behind the headline. */
.pt-stream { position: absolute; inset: 0; width: 100%; height: 100%; z-index: 1; pointer-events: none; overflow: visible;
  opacity: 0; transition: opacity .5s ease; }
.pt-stream.is-on { opacity: 1; }
.pt-stream-path { fill: none; stroke: rgba(147, 183, 198, .22); stroke-width: 2; stroke-linecap: round; stroke-dasharray: 1 9; }
.pt-packet { stroke-width: 7; stroke-opacity: .28; }
@media (min-width: 992px) { .pt-stream { filter: blur(1.6px); } }
@media (max-width: 991.98px) { .pt-stream { filter: blur(.6px); } }
/* While they talk: Ai points at Db, its antennae glow fast; Db opens its mouth. */
.pt-char-ai.is-talking .pt-arm-right { animation: none; rotate: 24deg; transition: rotate .3s var(--pt-spring); }
.pt-char-ai.is-talking .pt-bulb { animation-duration: .5s; }
.pt-char-db.is-sending .pt-mouth { d: path('M61 91.5 Q70 101.5 79 91.5'); }
.pt-char svg { display: block; width: 100%; height: auto; overflow: visible; }
.pt-char.is-hop .pt-char-body { scale: 1.12; }
/* Ai, the little alien: antennae whose balls glow in turn (it is thinking),
   stubby arms with round hands (the right one waves), short legs. */
.pt-stalk { fill: none; stroke: #6F93A2; stroke-width: 3.2; stroke-linecap: round; }
.pt-bulb { fill: var(--pt-sand); animation: pt-glow 1.8s ease-in-out infinite; }
.pt-bulb:last-child { animation-delay: .9s; }
.pt-limb { fill: none; stroke: #5E8190; stroke-width: 7.5; stroke-linecap: round; }
.pt-limb-hi { fill: none; stroke: #CFE3EA; stroke-width: 2.2; stroke-linecap: round; opacity: .75; }
.pt-arm-right { transform-box: view-box; transform-origin: 90px 110px; animation: pt-wave 2.6s ease-in-out infinite; }
.pt-antennae { transform-box: view-box; transform-origin: 70px 34px; animation: pt-sway 3.4s ease-in-out infinite; }
@keyframes pt-glow { 0%, 100% { fill: #D9C59A; filter: none; } 50% { fill: #F4E6C8; filter: drop-shadow(0 0 5px rgba(244, 230, 200, .9)); } }
@keyframes pt-wave { 0%, 60%, 100% { rotate: 0deg; } 70% { rotate: -16deg; } 80% { rotate: 8deg; } 90% { rotate: -12deg; } }
@keyframes pt-sway { 0%, 100% { rotate: -3deg; } 50% { rotate: 3deg; } }
.pt-eye { fill: var(--pt-night); transform-box: fill-box; transform-origin: center; animation: pt-blink 5s ease-in-out infinite; }
.pt-char-db .pt-eye { animation-delay: -2.2s; }
.pt-glint { fill: #fff; }
.pt-mouth { fill: none; stroke: var(--pt-night); stroke-width: 3; stroke-linecap: round; transition: d .25s; }
.pt-char-db.is-hop .pt-mouth { d: path('M60 92.5 Q70 100.5 80 92.5'); }
.pt-axis { fill: #8E774C; }

@keyframes pt-bob { 0%, 100% { translate: 0 0; } 50% { translate: 0 -12px; } }
@keyframes pt-blink { 0%, 92%, 100% { scale: 1 1; } 95% { scale: 1 .1; } }

/* Just above the phone layout the -2% / -1% offsets left the screen (992 wide:
   Ai's box at -6px). Must come after the rules above to win. */
@media (min-width: 992px) and (max-width: 1199.98px) {
  .pt-chars .pt-char-ai { left: 0; }
  .pt-chars .pt-char-db { right: 0; }
}

/* On phones the two stand side by side above the headline. */
@media (max-width: 991.98px) {
  .pt-chars { position: relative; inset: auto; display: flex; justify-content: center; gap: 28px; margin: 0 0 8px; }
  .pt-chars .pt-char { position: relative; top: auto; left: auto; right: auto; margin: 0; width: 104px; }
  .pt-chars .pt-char-db { width: 96px; }
}
/* Short phones (375x667): Ai's antennae reached the logo's line. */
@media (max-width: 991.98px) and (max-height: 720px) {
  .pt-chars .pt-char { width: 84px; }
  .pt-chars .pt-char-db { width: 78px; }
}

/* ---------- the cast of every other layer (lib/cast_lib.php) --------------- */
/* Who fits the copy, what they say in a bubble, sometimes a prop; in front of
   the pointers in depth. Dimitar, 02/10/2026: "use those characters across
   the content depending on the copy". */
.pt-cast { display: flex; align-items: flex-end; gap: 14px; margin: 0 0 22px; pointer-events: none; transform: translateZ(70px); }
.pt-cast .pt-char { flex: 0 0 auto; width: 112px; }
.pt-cast .pt-char-db { width: 100px; }
.pt-cast-both .pt-char { width: 94px; }
.pt-cast-both .pt-char-db { width: 84px; }
.pt-copy-center .pt-cast { justify-content: center; }
.pt-bubble { position: relative; align-self: flex-start; margin: 8px 0 0 4px; max-width: 16.4em; padding: .79em 1.07em;   /* 230 wide, 11 x 15 at 14px */
  border-radius: 18px 18px 18px 6px; background: rgba(236, 230, 218, .09); color: var(--pt-bone);
  font: 500 var(--pt-fs-say)/1.4 var(--pt-text); text-align: left;
  opacity: 0; transform: translateY(8px) scale(.94); transform-origin: 0 100%;
  transition: opacity .4s ease .45s, transform .5s var(--pt-spring) .45s; }
.pt-bubble::before { content: ""; position: absolute; left: -6px; bottom: 6px; width: 12px; height: 12px;
  background: inherit; border-radius: 2px; transform: rotate(45deg); clip-path: polygon(0 0, 0 100%, 100% 100%); }
.pt-layer.is-current .pt-bubble { opacity: 1; transform: none; }
/* A warning bubble, in a soft natural red (Dimitar: "Order more parts by Friday ... and in red tint"). */
.pt-bubble.is-alert { background: rgba(214, 112, 98, .24); color: #F6D3CC; }

/* Props, drawn in CSS: a fan of customer cards (Control), bars with a forecast (Measure). */
.pt-prop { position: relative; flex: 0 0 auto; align-self: center; }
.pt-prop-cards { width: 74px; height: 64px; }
.pt-prop-cards span { position: absolute; left: 6px; top: 12px; width: 58px; height: 40px; border-radius: 8px;
  background:
    linear-gradient(var(--pt-sand), var(--pt-sand)) 8px 9px / 18px 4px no-repeat,
    linear-gradient(rgba(236, 230, 218, .5), rgba(236, 230, 218, .5)) 8px 19px / 36px 3px no-repeat,
    linear-gradient(rgba(236, 230, 218, .3), rgba(236, 230, 218, .3)) 8px 27px / 28px 3px no-repeat,
    #22302A;
  box-shadow: 0 6px 14px rgba(0, 0, 0, .35); transform-origin: 50% 120%; }
.pt-prop-cards span:nth-child(1) { transform: rotate(-14deg); opacity: .7; }
.pt-prop-cards span:nth-child(2) { transform: rotate(-2deg); opacity: .85; }
.pt-prop-cards span:nth-child(3) { transform: rotate(11deg); }
.pt-prop-chart { display: flex; align-items: flex-end; gap: 4px; width: 78px; height: 64px; padding-bottom: 2px;
  border-bottom: 2px solid rgba(236, 230, 218, .25); }
.pt-prop-chart i { display: block; width: 9px; height: var(--h); border-radius: 3px 3px 0 0; background: var(--pt-sage); }
.pt-prop-chart i.pt-fc { background: transparent; border: 1.5px dashed var(--pt-sand); border-bottom: 0; }

/* Measure: Ai stands behind the chart. The bars cover him and he is cut off
   at the chart's baseline (.pt-peek-clip), so he reads as behind it; he rises
   from below the baseline when the order alert shows (just after the bubble)
   and waves both hands between the bars. No background (Dimitar: "chart with
   no bg, ai lower"): only the bars and their axis line. */
/* Then (Dimitar: "ai bot head and half body just above the empty bars - use
   bg tile same color as the bg behind the bars to hide the ai's body"): Ai
   stands behind the two empty (forecast) bars, his head and the upper half of
   his body above them; a tile in the page's own night colour, between him and
   the bars, hides the rest. Its sides fade out, so the tile never shows as a
   shape against the room's soft light. Layers, back to front: Ai (z 0), the
   tile (z 1), the bars (z 2). The clip still cuts him at the baseline while
   he is down, before he rises. */
.pt-prop-chartcard { width: 124px; height: 80px; margin-top: 56px; }
.pt-peek-clip { position: absolute; left: -20px; right: -20px; bottom: 2px; height: 180px; overflow: hidden; z-index: 0; }
.pt-peek { position: absolute; left: 84.6px; bottom: 28.8px; width: 76px;   /* centred on the empty bars (x 102.6 of the chart); chin (y 100 of 176) at their tops, so the tummy hides ("lower to hide the tommy") */
  transform: translateY(72px); transition: transform .8s cubic-bezier(.2, 1.3, .3, 1) .75s; }
.pt-layer.is-current .pt-peek { transform: none; }
.pt-cast .pt-peek .pt-char { width: 76px; animation: pt-bob-sm 4.2s ease-in-out infinite; }   /* beats the phone sizes of .pt-cast .pt-char below; the prop's own scale shrinks it there */
/* The tile cuts him at the chin (y 100 of 176) at rest: bottom 28.8 = tile top 70 - 100/176 x 95.5 + ... ;
   his own small bob (5px, not 12) keeps the whole head out and "Local Ai" always in. */
@keyframes pt-bob-sm { 0%, 100% { translate: 0 0; } 50% { translate: 0 -5px; } }
/* Behind all the bars, not only the empty two (Dimitar: "spread the bg from the 2 bars across all the bars"). */
.pt-hide-tile { position: absolute; left: -8px; right: -8px; bottom: 2px; height: 68px; z-index: 1; background: var(--pt-night);
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 8px, #000 calc(100% - 8px), transparent 100%);
  mask-image: linear-gradient(90deg, transparent 0, #000 8px, #000 calc(100% - 8px), transparent 100%); }
.pt-chartcard { position: absolute; inset: 0; z-index: 2; display: flex; align-items: flex-end; gap: 6px; padding: 0 4px;
  border-bottom: 2px solid rgba(236, 230, 218, .28); }
/* His speech bubble shows with him (just as he finishes rising) and points
   at his face (Dimitar: "speach bubble to point and show with it"). */
/* Level with his face: the chart is drawn at full size on desktop (56px of
   room above it), at .72 about its centre on phones with no room above (the
   phone rule below sets the prop's margin to 0 -10px), and with 20px of room
   on short phones; so each gets its own offset (checked by script, face to
   bubble middle). */
.pt-prop-chartcard + .pt-bubble { margin-top: 30px; transition-delay: 1.15s; }
@media (max-width: 991.98px) { .pt-prop-chartcard + .pt-bubble { margin-top: -20px; } }
@media (max-width: 991.98px) and (max-height: 720px) { .pt-prop-chartcard + .pt-bubble { margin-top: -6px; } }
.pt-prop-chartcard + .pt-bubble::before { bottom: auto; top: 50%; margin-top: -6px; clip-path: polygon(0 0, 0 100%, 100% 100%); }
.pt-chartcard i { display: block; flex: 1 1 0; height: var(--h); border-radius: 3px 3px 0 0; background: var(--pt-sage); }
.pt-chartcard i.pt-fc { background: transparent; border: 1.5px dashed var(--pt-sand); border-bottom: 0; }
/* both hands up over the edge, waving */
.pt-peek .pt-arm-right { animation: pt-wave-up 1.3s ease-in-out infinite; }
.pt-peek .pt-arm-left { animation: pt-wave-up-left 1.3s ease-in-out -.65s infinite; }
@keyframes pt-wave-up { 0%, 100% { rotate: -32deg; } 50% { rotate: -58deg; } }
@keyframes pt-wave-up-left { 0%, 100% { rotate: 92deg; } 50% { rotate: 116deg; } }
.pt-layer:not(.is-current) .pt-peek .pt-arm { animation-play-state: paused; }

@media (max-width: 991.98px) {
  .pt-cast { margin-bottom: 12px; gap: 10px; }
  .pt-cast .pt-char { width: 62px; }
  .pt-cast .pt-char-db { width: 56px; }
  .pt-cast-both .pt-char { width: 56px; }
  .pt-cast-both .pt-char-db { width: 50px; }
  .pt-bubble { max-width: 16em; padding: .62em .92em; }   /* 210 wide, 8 x 12 at 13px; the size is --pt-fs-say */
  .pt-prop { scale: .72; margin: 0 -10px; }
}
@media (max-width: 991.98px) and (max-height: 720px) {
  .pt-cast .pt-char { width: 50px; }
  .pt-cast .pt-char-db { width: 46px; }
}
/* Short phones (375x667): the arrow down sat on the last line of four pages.
   Room for it at the bottom, three pointers, a tighter opening. */
@media (max-width: 991.98px) and (max-height: 720px) {
  /* The type scale's short-phone step. (The trade buttons keep 44px of
     height, the touch minimum; a rule meant to make them 38 had been losing
     to the phone rule below it all along.) */
  :root { --pt-fs-h1: 26px; --pt-fs-body: 15px; --pt-fs-ui: 13px; }
  html.js .pt-layer { padding-bottom: 62px; }
  .pt-points li:nth-child(n+4) { display: none; }
  .pt-layer p { line-height: 1.45; }
  .pt-cast { margin-bottom: 8px; }
  .pt-prop-chartcard { margin-top: 20px; }   /* drawn at .72 about its centre, so Ai's head needs only this much room above */
  .pt-layer .row { --bs-gutter-y: .75rem; }
  .pt-chars .pt-char { width: 72px; }
  .pt-chars .pt-char-db { width: 66px; }
  .pt-open h1 { margin-bottom: 10px; }
  .pt-layer .pt-ask { margin: 12px auto 8px; }
  .pt-trades { gap: 6px; }
  .pt-trades button { padding: 0 1em; }
  .pt-layer .pt-line { margin-top: 10px; }
}

/* ---------- the other layers: copy and floating pointers ------------------- */
.pt-copy-center { text-align: center; }
.pt-copy-center p { margin-left: auto; margin-right: auto; }
.pt-copy-center .pt-kicker { margin-left: auto; margin-right: auto; }   /* .pt-layer .pt-kicker's margin: 0 outranked the line above, so "Let's talk" sat left of centre */
/* Let's talk: the real QR code to the quote form (img/qr/talk.svg; no address
   in this public file) with its caption beside it, between Ai and the heading
   (Dimitar, 02/10/2026: "also put a qr code there", then "move the qr code on
   the last page between the ai bot and the header"). Scan only: not a link
   and not a button, so bots never find the form (Dimitar: "request a quote
   button is a qr code not a button, to protect us from bots", "c scan only").
   On a touch screen the caption says to scan it from another device. */
.pt-talk-qr { display: inline-flex; align-items: center; gap: 1em; margin: 0 0 24px; padding: .75em 1.4em .75em .75em;
  border-radius: 22px; background: rgba(236, 230, 218, .06); color: var(--pt-bone); text-align: left;
  font: 500 var(--pt-fs-say)/1.35 var(--pt-text); }
.pt-talk-qr-code { flex: 0 0 auto; width: 112px; height: 112px; border-radius: 10px; overflow: hidden; }
.pt-talk-qr-code svg { display: block; width: 100%; height: 100%; }
.pt-talk-qr-t b { display: block; margin-bottom: .2em; font-size: var(--pt-fs-ui); font-weight: 600; color: var(--pt-bone); }
.pt-talk-qr-t .pt-scan { display: block; color: var(--pt-lichen); }
.pt-talk-qr-t .pt-scan-touch { display: none; color: var(--pt-lichen); }
@media (hover: none) {
  .pt-talk-qr-t .pt-scan { display: none; }
  .pt-talk-qr-t .pt-scan-touch { display: block; }
}
@media (max-width: 991.98px) { .pt-talk-qr { margin-bottom: 18px; } .pt-talk-qr-code { width: 88px; height: 88px; border-radius: 8px; } }
@media (max-width: 991.98px) and (max-height: 720px) { .pt-talk-qr { margin-bottom: 14px; } .pt-talk-qr-code { width: 72px; height: 72px; } }
.pt-points { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; align-items: flex-start; gap: 12px;
  transform-style: preserve-3d; }
.pt-points li { position: relative; display: inline-flex; align-items: center; gap: .625em; padding: .75em 1.25em .75em 1em;   /* 12 20 12 16 at 16px */
  margin-left: calc(var(--i, 0) * 26px); border-radius: 999px; background: rgba(236, 230, 218, .06);
  color: var(--pt-bone); font-size: var(--pt-fs-ui); font-weight: 500; line-height: 1.3;
  transform: translateZ(var(--z, 0px)); transition: transform .35s var(--pt-spring), background .25s;
  animation: pt-float 6s ease-in-out infinite; animation-delay: calc(var(--i, 0) * -1.1s); }
.pt-points li::before { content: ""; flex: 0 0 auto; width: 8px; height: 8px; border-radius: 50%; background: var(--tone, var(--pt-sage));
  box-shadow: 0 0 0 4px rgba(236, 230, 218, .05); }
.pt-points li:hover, .pt-points li.is-lit { background: rgba(236, 230, 218, .12); transform: translateZ(calc(var(--z, 0px) + 40px)); }
@keyframes pt-float { 0%, 100% { translate: 0 0; } 50% { translate: 0 -6px; } }

/* Nothing moves in a layer that is not the one in front. */
.pt-layer:not(.is-current) .pt-points li,
.pt-layer:not(.is-current) .pt-char,
.pt-layer:not(.is-current) .pt-bulb,
.pt-layer:not(.is-current) .pt-arm-right,
.pt-layer:not(.is-current) .pt-antennae,
.pt-layer:not(.is-current) .pt-eye { animation-play-state: paused; }

@media (max-width: 991.98px) {
  .pt-points { align-items: center; flex-direction: row; flex-wrap: wrap; justify-content: flex-start; gap: 10px; }
  .pt-points li { margin-left: 0; padding: .67em 1.07em .67em .87em; }   /* 10 16 10 13 at 15px; the size is --pt-fs-ui */
}
@media (max-width: 575.98px) {
  html.js .pt-layer { padding: 72px 0 24px; }
  .pt-layer .container { padding-left: 20px; padding-right: 20px; }
  .pt-layer h2 { margin-bottom: 12px; }
  .pt-layer p { line-height: 1.5; }
  .pt-points li { padding: .64em 1em .64em .86em; }   /* 9 14 9 12 at 14px */
  .pt-points li:nth-child(n+5) { display: none; }
  .pt-trades button { padding: 0 1.07em; }            /* 15px at 14px */
  .pt-layer .pt-ask { margin-top: 18px; }
}
