/* Cellivoo · the buy page layer
   Only what the product page needs. Everything else — colour, type, the
   composition bar, the film plates, the ledger rows — is inherited from
   style.css and motion.css, so this page cannot drift from the landing page.
   The purchase panel is the only piece of new interface on the whole site,
   so it is built out of the same rules: paper ground, one green, hairlines. */

/* ---------- the product layout ---------- */
.pdp{padding-top:clamp(5.5rem,9vw,7.5rem);padding-bottom:var(--sec)}
.pdp__grid{display:grid;grid-template-columns:minmax(0,1.06fr) minmax(0,.94fr);
  gap:clamp(2rem,5vw,5rem);align-items:start}
@media(max-width:940px){.pdp__grid{grid-template-columns:1fr;gap:2.5rem}}

/* ---------- gallery ---------- */
.gal{position:sticky;top:5.5rem}
@media(max-width:940px){.gal{position:static}}
.gal__main{position:relative;aspect-ratio:4/5;background:var(--paper2);overflow:hidden}
.gal__main img{width:100%;height:100%;object-fit:cover;
  opacity:0;transition:opacity .38s var(--ease);position:absolute;inset:0}
.gal__main img.is-on{opacity:1;position:relative}
@media(prefers-reduced-motion:reduce){.gal__main img{transition:none}}
.gal__tag{position:absolute;left:0;top:0;z-index:2;background:var(--green);color:var(--paper);
  font:400 .6rem/1 var(--t);letter-spacing:.2em;text-transform:uppercase;padding:.62rem .9rem}
.gal__thumbs{display:grid;grid-template-columns:repeat(4,1fr);gap:.5rem;margin-top:.5rem}
.gal__t{padding:0;border:1px solid var(--line-soft);background:var(--paper2);cursor:pointer;
  aspect-ratio:1;overflow:hidden;transition:border-color .18s,transform .18s var(--ease)}
.gal__t img{width:100%;height:100%;object-fit:cover}
.gal__t:hover{transform:translateY(-2px)}
.gal__t[aria-selected="true"]{border-color:var(--green)}

/* ---------- purchase panel ---------- */
.buy__crumb{font:400 .64rem/1 var(--t);letter-spacing:.2em;text-transform:uppercase;
  color:var(--ink-faint);margin:0 0 1.1rem}
.buy__crumb a{color:inherit;text-decoration:none}
.buy__crumb a:hover{color:var(--green)}
.buy h1{font-size:clamp(2rem,4.2vw,3.1rem);margin-bottom:.5rem}
.buy h1 em{font-style:italic;color:var(--green)}
.buy__sub{color:var(--ink-soft);font-size:1.02rem;margin:0 0 1.6rem;max-width:46ch}

/* the measured spec strip: this page's honest replacement for a star rating */
.spx{display:flex;flex-wrap:wrap;gap:0;border:1px solid var(--line);background:var(--white);margin-bottom:1.9rem}
.spx__i{flex:1 1 7rem;padding:.85rem 1rem;border-right:1px solid var(--line-soft)}
.spx__i:last-child{border-right:0}
.spx__v{font:500 1.06rem/1 var(--m);color:var(--green);font-variant-numeric:tabular-nums;display:block}
.spx__l{font:400 .58rem/1.4 var(--t);letter-spacing:.14em;text-transform:uppercase;color:var(--ink-faint);
  display:block;margin-top:.4rem}

/* ---------- quantity ---------- */
.qty{display:flex;align-items:center;gap:0;border:1px solid var(--line);background:var(--white);
  width:max-content;margin-bottom:1rem}
.qty__b{appearance:none;border:0;background:transparent;color:var(--ink);cursor:pointer;
  font:300 1.25rem/1 var(--t);padding:.85rem 1.05rem;transition:color .16s}
.qty__b:hover{color:var(--green)}
.qty__b:disabled{color:var(--ink-faint);cursor:default}
.qty__v{font:400 .95rem/1 var(--m);min-width:2.4rem;text-align:center;font-variant-numeric:tabular-nums}
.qty__l{font:400 .62rem/1 var(--t);letter-spacing:.16em;text-transform:uppercase;color:var(--ink-faint);
  margin:0 0 .55rem}
/* Sits under the stepper it explains. Pulled up into the gap the stepper
   already leaves, so appearing does not push the whole panel down by more than
   its own line. */
.qty__max{font:300 .82rem/1.4 var(--t);color:var(--ink-soft);margin:-.55rem 0 1rem}
/* Sits under the address block it qualifies, in the same quiet register as the
   rest of the panel's asides rather than as a warning. */
.co__note{font:300 .82rem/1.5 var(--t);color:var(--ink-soft);margin:.5rem 0 1.1rem}
.co__note a{color:var(--green);text-decoration:underline;text-underline-offset:2px}

/* ---------- the button ---------- */
.cta--full{width:100%;justify-content:center;padding-block:1.3rem;font-size:1rem;letter-spacing:.02em}
.cta--full b{font-weight:400;font-family:var(--m);margin-left:.25rem}
.cta[aria-disabled="true"]{opacity:.55;cursor:not-allowed}
.cta[aria-disabled="true"]:hover{background:var(--green);transform:none}
.buy__note{font:400 .74rem/1.6 var(--t);color:var(--ink-faint);margin:.75rem 0 0}

/* ---------- assurances ---------- */
.assure{list-style:none;margin:1.5rem 0 0;padding:0;display:grid;gap:.62rem}
.assure li{position:relative;padding-left:1.6rem;font-size:.88rem;color:var(--ink-soft);line-height:1.55}
.assure li::before{content:"";position:absolute;left:0;top:.42em;width:.62rem;height:.34rem;
  border-left:1.4px solid var(--green);border-bottom:1.4px solid var(--green);transform:rotate(-45deg)}
.pay{margin-top:1.6rem;padding-top:1.2rem;border-top:1px solid var(--line-soft);
  font:400 .62rem/1.7 var(--t);letter-spacing:.13em;text-transform:uppercase;color:var(--ink-faint)}

/* ---------- what arrives ---------- */
.kit{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:clamp(1rem,2.5vw,2rem)}
@media(max-width:820px){.kit{grid-template-columns:1fr}}
.kit__i{background:var(--white);border:1px solid var(--line-soft);padding:clamp(1.4rem,3vw,2.1rem);
  transition:border-color .18s,transform .18s var(--ease)}
.kit__i:hover{border-color:var(--green);transform:translateY(-3px)}
.kit__n{font:400 .7rem/1 var(--m);letter-spacing:.14em;color:var(--green);display:block;margin-bottom:1rem}
.kit__i h3{font-size:clamp(1.2rem,2.2vw,1.6rem);margin-bottom:.6rem}
.kit__i p{margin:0;color:var(--ink-soft);font-size:.92rem}

/* ---------- the sticky buy bar ---------- */
.sticky{position:fixed;inset:auto 0 0 0;z-index:79;display:flex;align-items:center;gap:1rem;
  padding:.7rem var(--g);padding-bottom:calc(.7rem + env(safe-area-inset-bottom));
  background:rgba(250,247,240,.94);backdrop-filter:blur(16px);
  border-top:1px solid var(--line);transform:translateY(110%);transition:transform .32s var(--ease)}
.sticky.is-on{transform:none}
@media(prefers-reduced-motion:reduce){.sticky{transition:none}}
.sticky__l{min-width:0;flex:1 1 auto}
.sticky__n{font-family:var(--d);font-size:1rem;line-height:1.2;display:block;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.sticky__p{font:400 .68rem/1 var(--m);color:var(--ink-soft);display:block;margin-top:.35rem}
.sticky .cta{padding:.9rem 1.6rem;font-size:.85rem;white-space:nowrap}
@media(min-width:941px){.sticky{display:none}}

/* the sticky bar sits over the last thing on the page, so give the footer room
   to clear it on the widths where the bar actually appears */
@media(max-width:940px){footer{padding-bottom:calc(5.5rem + env(safe-area-inset-bottom))}}

/* ---------- checkout ----------
   The ClickFunnels SDK renders its address fields into this document with no
   stylesheet of its own, so they inherit whatever we set here. The card fields
   are different: they live in the gateway's iframe, across a PCI boundary our
   CSS cannot reach, so the design has to be handed over as the
   --cfsdk-checkout-* custom properties below. Both halves read from the same
   tokens, which is what keeps the card box looking like the rest of the page. */
:root{
  --cfsdk-checkout-color-scheme:light;
  --cfsdk-checkout-color-primary:#0F4A32;
  --cfsdk-checkout-color-text:#14231C;
  --cfsdk-checkout-color-danger:#8F2A1C;
  --cfsdk-checkout-color-placeholder:#8A9890;
  --cfsdk-checkout-color-background:#FFFFFF;
  --cfsdk-checkout-color-border:rgba(20,35,28,.14);
  --cfsdk-checkout-input-shadow:none;
  --cfsdk-checkout-border-radius:0px;
  --cfsdk-checkout-font-family:Geist,system-ui,sans-serif;
  --cfsdk-checkout-font-size:15px;
  --cfsdk-checkout-spacing-unit:4px;
}

/* the running total, priced by ClickFunnels rather than by this page */
/* The order summary. Line items sit quietly above a ruled-off total, so the
   total reads as the sum of things the buyer can see rather than as a number
   that arrived on its own. */
.sum{margin:0 0 1.1rem;padding-bottom:.9rem;border-bottom:1px solid var(--line)}
.sum__r{display:flex;align-items:baseline;justify-content:space-between;gap:1rem;margin:0 0 .55rem}
.sum__r[hidden]{display:none}
.sum__l{font:400 .62rem/1 var(--t);letter-spacing:.16em;text-transform:uppercase;color:var(--ink-faint)}
.sum__n{font:400 .95rem/1 var(--m);color:var(--ink-soft);font-variant-numeric:tabular-nums}
/* Waiting on the buyer, not reporting an amount - so it is set as prose. */
.sum__n--wait{font:300 .82rem/1 var(--t);color:var(--ink-faint);letter-spacing:0}
.sum__t{display:flex;align-items:baseline;justify-content:space-between;gap:1rem;
  margin:.85rem 0 0;padding-top:.85rem;border-top:1px solid var(--line)}
.sum__v{font:400 1.25rem/1 var(--m);color:var(--green);font-variant-numeric:tabular-nums}

/* Errors are rendered rather than logged on purpose: a gateway that refuses a
   card says why, and the console message does not carry the reason. */
.err{margin:0 0 1rem;padding:.8rem 1rem;background:var(--white);
  border:1px solid var(--line);border-left:2px solid #8F2A1C;
  font:400 .84rem/1.6 var(--t);color:var(--ink)}

.co{display:block;margin:0}
.co[hidden]{display:none}
.co__h{font-size:1.15rem;margin:0 0 1.1rem}
.co__h3{font:400 .62rem/1 var(--t);letter-spacing:.16em;text-transform:uppercase;
  color:var(--ink-faint);margin:1.5rem 0 .6rem}
.co__row{margin-bottom:.75rem}
.co__two{display:grid;grid-template-columns:1fr 1fr;gap:.75rem}
@media(max-width:460px){.co__two{grid-template-columns:1fr}}
.co__lab{display:block;font:400 .62rem/1 var(--t);letter-spacing:.14em;text-transform:uppercase;
  color:var(--ink-faint);margin-bottom:.4rem}

/* One rule for our inputs and the SDK's alike, so the address fields it mounts
   arrive already matching the two we wrote by hand. */
.co__in,
.cf-sdk-address-field input,.cf-sdk-address-field select{
  width:100%;background:var(--white);color:var(--ink);
  border:1px solid var(--line);border-radius:0;
  font:300 .95rem/1 var(--t);padding:.85rem .9rem;
  transition:border-color .16s}
.co__in:focus,.cf-sdk-address-field input:focus,.cf-sdk-address-field select:focus{
  border-color:var(--green);outline:2px solid var(--green);outline-offset:1px}
.cf-sdk-address-field{margin-bottom:.75rem}
.cf-sdk-address-field label{display:block;font:400 .62rem/1 var(--t);letter-spacing:.14em;
  text-transform:uppercase;color:var(--ink-faint);margin-bottom:.4rem}

.co__card{margin-bottom:1.2rem}
.cf-sdk-card-field{min-width:0;background:var(--white);border:1px solid var(--line);padding:.2rem .4rem}
.cf-sdk-card-field:focus-within{outline:2px solid var(--green);outline-offset:1px}

/* The SDK toggles `hidden` on the mount points as the cart decides whether an
   address is needed, so the headings around them have to follow without any
   JavaScript of ours. A digital cart hides both; the bottle shows shipping. */
#shipSec,#billSec{display:none}
#shipSec:has([data-cf-element="shipping"] *):not(:has([data-cf-element="shipping"][hidden])){display:block}
#billSec:has([data-cf-element="billing"] *):not(:has([data-cf-element="billing"][hidden])){display:block}

/* the hairline "or" between the two ways to pay */
.co__or{display:flex;align-items:center;gap:1rem;margin:1.6rem 0 1.1rem;
  font:400 .6rem/1 var(--t);letter-spacing:.2em;text-transform:uppercase;color:var(--ink-faint)}
.co__or::before,.co__or::after{content:"";flex:1;height:1px;background:var(--line-soft)}

#paypalBtn{min-height:3rem}

/* Google Places suggestions on the street field. Positioning is not optional:
   the dropdown ships with none at all, so left alone it renders in flow and
   shoves the rest of the checkout down every time the buyer types. */
.cf-places-dropdown{position:absolute;top:100%;left:0;right:0;z-index:10;
  background:var(--white);border:1px solid var(--line);
  box-shadow:0 4px 18px rgba(20,35,28,.10);max-height:16rem;overflow-y:auto}
.cf-places-item{padding:.6rem .9rem;cursor:pointer;font-size:.9rem}
.cf-places-item--active{background:var(--paper2)}
.cf-places-item-main{display:block}
.cf-places-item-secondary{display:block;font-size:.82em;color:var(--ink-faint)}


/* ---------- the mineral rail ----------
   A sideways scroller of the nineteen assayed elements. The filters hide
   cards with [hidden] rather than rebuilding the track, so every card keeps
   its data-edit key and the editor never sees the list change. */
/* ---------- the mineral rail, laid over the water ----------
   The one section on the site that is not on paper ground. Cards are frosted
   glass so the sea keeps moving underneath them, which is the whole reason
   this section sits here rather than in a grid like science.html. Everything
   else — the green, the hairlines, the mono figures, the grade chips — is the
   same system, so it reads as Cellivoo and not as a widget bolted on.

   It is a plain overflow-x scroller first. With JavaScript off you can still
   drag it, swipe it, and tab through every card; the buttons and the progress
   bar are the enhancement, not the mechanism. */
.plate--rail{min-height:0;display:block;align-items:initial;
  padding-block:clamp(4rem,9vw,8rem);color:var(--ink)}
.wash--rail{inset:0;height:100%;
  background:linear-gradient(180deg,rgba(250,247,240,.92) 0%,rgba(250,247,240,.62) 26%,
    rgba(250,247,240,.42) 55%,rgba(250,247,240,.88) 100%)}
.rail__head{position:relative;z-index:2}
.rail__head h2{font-size:clamp(2.2rem,5.6vw,4.4rem);margin-bottom:1.4rem}
.rail__head h2 em{font-style:italic;color:var(--green)}
.rail__head .lede{max-width:50ch}
/* ---------- filter chips ---------- */
.rail__filters{position:relative;z-index:2;display:flex;flex-wrap:wrap;gap:.5rem;
  margin-top:clamp(1.8rem,4vw,2.6rem)}
.chip{appearance:none;cursor:pointer;background:rgba(255,255,255,.62);
  border:1px solid var(--line);color:var(--ink-soft);
  font:400 .62rem/1 var(--t);letter-spacing:.14em;text-transform:uppercase;
  padding:.62rem .9rem;transition:color .16s,border-color .16s,background .16s}
.chip:hover{color:var(--green);border-color:var(--green)}
.chip.is-on{background:var(--green);border-color:var(--green);color:var(--paper)}
/* ---------- the rail itself ---------- */
.rail{position:relative;z-index:2;margin-top:clamp(1.6rem,3.5vw,2.4rem)}
.rail__track{display:flex;gap:clamp(.8rem,1.6vw,1.2rem);
  overflow-x:auto;overscroll-behavior-x:contain;
  scroll-snap-type:x proximity;scroll-behavior:smooth;
  padding:.4rem var(--g) 1.6rem;
  /* without this the mandatory snap eats the left gutter: card one would
     snap its own edge to the container edge and sit flush against it */
  scroll-padding-inline:var(--g);
  /* the fade at each end says "there is more" without a second scrollbar */
  -webkit-mask-image:linear-gradient(90deg,transparent 0,#000 3%,#000 97%,transparent 100%);
  mask-image:linear-gradient(90deg,transparent 0,#000 3%,#000 97%,transparent 100%)}
.rail__track::-webkit-scrollbar{height:0}
.rail__track{scrollbar-width:none}
@media(prefers-reduced-motion:reduce){.rail__track{scroll-behavior:auto}}
@media(max-width:640px){.rail__track{-webkit-mask-image:none;mask-image:none}}
/* ---------- one element ---------- */
.mn{flex:0 0 clamp(15.5rem,23vw,18.5rem);scroll-snap-align:start;
  display:flex;flex-direction:column;
  background:rgba(255,255,255,.82);backdrop-filter:blur(14px) saturate(1.1);
  -webkit-backdrop-filter:blur(14px) saturate(1.1);
  border:1px solid rgba(255,255,255,.9);outline:1px solid var(--line-soft);outline-offset:-1px;
  transition:transform .2s var(--ease),background .2s}
.mn:hover,.mn:focus-within{transform:translateY(-4px);background:rgba(255,255,255,.94)}
@media(prefers-reduced-motion:reduce){.mn{transition:none}.mn:hover{transform:none}}
.mn[hidden]{display:none}
.mn__img{aspect-ratio:16/9;overflow:hidden;background:var(--sand)}
.mn__img img{width:100%;height:100%;object-fit:cover}
.mn__img--glyph{display:grid;place-items:center;background:var(--sea);
  background:linear-gradient(160deg,var(--sea),#DCEEF5)}
.mn__img--glyph span{font-family:var(--d);font-weight:300;font-size:2.6rem;line-height:1;color:var(--sea-dk)}
.mn__b{padding:1rem 1.05rem 1.15rem;display:flex;flex-direction:column;flex:1 1 auto}
.mn__s{display:flex;justify-content:space-between;align-items:baseline;gap:.5rem}
.mn__sym{font-family:var(--d);font-size:1.5rem;line-height:1;color:var(--green)}
.mn__no{font:400 .58rem/1 var(--m);letter-spacing:.1em;color:var(--ink-faint)}
.mn__n{font-size:1.28rem;margin:.5rem 0 .8rem}
.mn__f{margin:0 0 .85rem;padding:.7rem 0;display:grid;gap:.45rem;
  border-top:1px solid var(--line-soft);border-bottom:1px solid var(--line-soft)}
.mn__f>div{display:flex;justify-content:space-between;align-items:baseline;gap:.6rem}
.mn__f dt{font:400 .56rem/1.3 var(--t);letter-spacing:.13em;text-transform:uppercase;color:var(--ink-faint)}
.mn__f dd{margin:0;font:400 .78rem/1 var(--m);color:var(--green);
  font-variant-numeric:tabular-nums;white-space:nowrap}
.mn__role{margin:0 0 .8rem;font-size:.84rem;line-height:1.62;color:var(--ink-soft)}
.mn__cite{margin:auto 0 .85rem;font:400 .66rem/1.55 var(--t);color:var(--ink-faint)}
.mn__cite i{font-style:italic}
.mn__g{align-self:flex-start;text-align:left;justify-self:start;font-size:.55rem}
/* ---------- controls under the rail ---------- */
.rail__ui{display:flex;align-items:center;gap:1.2rem;margin-top:.4rem}
.rail__nav{display:flex;gap:.4rem}
.rail__b{appearance:none;cursor:pointer;background:rgba(255,255,255,.72);border:1px solid var(--line);
  color:var(--ink);font:300 1rem/1 var(--t);padding:.7rem .95rem;
  transition:color .16s,border-color .16s,opacity .16s}
.rail__b:hover{color:var(--green);border-color:var(--green)}
.rail__b:disabled{opacity:.38;cursor:default;color:var(--ink-faint);border-color:var(--line-soft)}
.rail__pg{flex:1 1 auto;height:1px;background:var(--line);position:relative;overflow:hidden}
.rail__pgf{position:absolute;inset:0 auto 0 0;width:14%;background:var(--green);
  transition:width .18s var(--ease),transform .18s var(--ease)}
@media(prefers-reduced-motion:reduce){.rail__pgf{transition:none}}
.rail__ct{margin:0;font:400 .62rem/1 var(--m);letter-spacing:.1em;color:var(--ink-soft);
  white-space:nowrap;font-variant-numeric:tabular-nums}
/* no JavaScript, no fake controls */
.rail__ui{display:none}
.js-rail .rail__ui{display:flex}
.rail__honest{margin-top:clamp(2.2rem,5vw,3.4rem);position:relative;z-index:2;
  background:rgba(255,255,255,.9);backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px)}
@media(max-width:640px){.rail__filters{gap:.4rem}.chip{padding:.55rem .7rem;font-size:.58rem}}

/* ---------- the one-time offer ----------
   A decision page. It carries no navigation, because every link off it is a
   way to leave without answering, and the layout holds the offer and the two
   answers in one view on a laptop without scrolling. */
/* With the header CTA gone the bar has two children instead of three, and
   space-between would fling the nav against the right edge. An auto inline
   margin beats justify-content, so the nav keeps the centre it already had and
   the removal reads as deliberate rather than as something falling off. */
.bar--nocta nav{margin-inline:auto}

.bar--bare{justify-content:center}
.bar--bare .bar__m{cursor:default}

.oto{padding-top:clamp(5.5rem,9vw,7.5rem)}
.oto__paid{font:400 .62rem/1 var(--t);letter-spacing:.16em;text-transform:uppercase;
  color:var(--green);margin:0 0 2rem;padding-bottom:1rem;border-bottom:1px solid var(--line-soft)}

.oto__grid{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);
  gap:clamp(2rem,5vw,4.5rem);align-items:center}
@media(max-width:900px){.oto__grid{grid-template-columns:1fr;gap:2rem}}

.oto__shot img{width:100%;height:auto;background:var(--paper2)}
@media(max-width:900px){.oto__shot{order:-1}}

.oto__h{font-size:clamp(1.9rem,3.8vw,2.9rem);margin:0 0 1rem}
.oto__h em{font-style:italic;color:var(--green)}

/* The three numbers, in the order a buyer checks them: what it usually costs,
   what it costs here, and the difference between the two. */
.oto__price{display:flex;flex-wrap:wrap;align-items:baseline;gap:.5rem 1.4rem;
  margin:1.7rem 0;padding:1.1rem 0;border-block:1px solid var(--line)}
.oto__was,.oto__now,.oto__save{margin:0}
.oto__was span,.oto__now span{font:400 .58rem/1 var(--t);letter-spacing:.16em;
  text-transform:uppercase;color:var(--ink-faint);display:block;margin-bottom:.35rem}
.oto__was s{font:400 1rem/1 var(--m);color:var(--ink-faint)}
.oto__now b{font:400 1.5rem/1 var(--m);color:var(--green);font-variant-numeric:tabular-nums}
.oto__save{margin-left:auto;align-self:center;background:var(--green);color:var(--paper);
  font:400 .62rem/1 var(--t);letter-spacing:.14em;text-transform:uppercase;padding:.6rem .9rem}

/* The decline is a real, readable way out rather than a greyed-out trick. It
   is quieter than the accept, and no quieter than that. */
.oto__no{margin:1.1rem 0 0;text-align:center}
.oto__decline{appearance:none;background:none;border:0;cursor:pointer;padding:.5rem;
  font:400 .86rem/1.5 var(--t);color:var(--ink-soft);text-decoration:underline;
  text-underline-offset:3px;transition:color .16s}
.oto__decline:hover{color:var(--green)}


footer{align-items:flex-start}


/* ---------- the processing curtain ---------- */
/* Covers the checkout while a payment is in flight. Paper rather than the usual
   black scrim, because the rest of this site is paper and a black wash over it
   reads as an error state rather than as work in progress. */
.proc{position:fixed;inset:0;z-index:200;display:grid;place-items:center;
  background:rgba(250,247,240,.92);backdrop-filter:blur(3px);padding:2rem}
.proc[hidden]{display:none}
.proc__in{text-align:center;max-width:22rem}
.proc__spin{display:block;width:2.4rem;height:2.4rem;margin:0 auto 1.4rem;
  border:2px solid var(--line);border-top-color:var(--green);border-radius:50%;
  animation:procspin .9s linear infinite}
.proc__t{font:400 1.05rem/1.4 var(--t);color:var(--ink);margin:0 0 .5rem}
.proc__s{font:300 .85rem/1.5 var(--t);color:var(--ink-soft);margin:0}
@keyframes procspin{to{transform:rotate(360deg)}}

/* A spinner is decoration; the sentence is the message. Anyone who has asked
   for less movement gets a mark that breathes instead of one that turns. */
@media(prefers-reduced-motion:reduce){
  .proc__spin{animation:procpulse 1.6s ease-in-out infinite;border-top-color:var(--line)}
  @keyframes procpulse{0%,100%{opacity:.35}50%{opacity:1}}
}
