/* SERVICE CARDS — the pricing card and its in-card enquiry panel.
 *
 * Shared by services.html (.card-grid) and index.html (#services-preview).
 * Moved here verbatim from services.html on 2026-08-04 rather than copied:
 * the homepage About port is the standing reminder that a second copy stops
 * matching the original the first time either one is touched.
 *
 * Loaded AFTER site.css (which owns the tokens) and BEFORE each page's own
 * <style>, so a page can override anything here without a specificity fight.
 * Every rule below is byte-identical to what services.html shipped.
 */
.svc-card{
  --card-r:40px;
  background:var(--surface);
  border:1px solid var(--line-2);border-radius:var(--card-r);
  padding:16px;
  display:flex;flex-direction:column;
  position:relative;
  isolation:isolate;
  transition:border-color .4s,background .4s,transform .12s;
}
.svc-card pixel-canvas{
  position:absolute;inset:0;z-index:0;
  pointer-events:none;
  border-radius:var(--card-r);overflow:hidden;
}
.svc-card::before{
  content:'';
  position:absolute;inset:0;z-index:1;
  background:radial-gradient(ellipse 110% 90% at 50% 55%, rgba(8,8,8,0) 0%, rgba(8,8,8,.04) 52%, rgba(8,8,8,.34) 74%, rgba(8,8,8,.78) 90%, var(--bg) 100%);
  border-radius:var(--card-r);
  pointer-events:none;
}
.svc-card > * { position: relative; z-index: 2; }
.svc-card:hover{border-color:rgba(184,255,0,.25);background:rgba(14,14,14,.8)}
.svc-card:active{transform:scale(.985)}
/* BADGE — .sc-badge, not .badge, and it must stay that way.
   This was `.badge` while the component lived only in services.html. index.html
   already owns an unrelated `.badge` (the pills inside #how's narration), which
   is declared in that page's own <style> — i.e. AFTER this file — and wins at
   equal specificity. Among the things it sets is `--k:0`, so the tier badge
   came out as 9px x 0 type in a 1x1 box: present in the DOM, invisible on
   screen, and silent. A component in a shared sheet cannot claim a name this
   generic. */
.sc-badge{
  position:absolute;top:-10px;right:20px;
  font-family:var(--fm);font-size:9px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--bg);background:var(--accent);
  padding:4px 10px;border-radius:6px;font-weight:600;z-index:3;
}
/* Outlined rather than filled — "Custom" is an invitation to talk, not a tier
   badge like Most Popular, and the solid lime read as the louder of the two.
   Padding drops by the border width so both badges stay the same size. */
.sc-badge.custom{
  background:rgba(184,255,0,.06);
  -webkit-backdrop-filter:blur(8px) saturate(130%);
  backdrop-filter:blur(8px) saturate(130%);
  border:1px solid var(--accent);
  color:var(--accent);
  padding:3px 9px;
}
/* CARD CONTENT */
.sc-name{
  font-family:var(--fh);font-weight:900;
  font-size:clamp(18px,2vw,24px);
  text-transform:uppercase;letter-spacing:-.02em;
  line-height:1.15;
  /* Two lines reserved on every card. Only two of six titles wrapped, so the
     price block below started on a different line in each and the closed
     panels came out different heights. Same idiom as .hiw3-title below. */
  min-height:2.3em;
  margin-bottom:16px;
}
.sc-features{
  list-style:none;margin-bottom:24px;flex:1;padding:0 8px;
}
.sc-features li{
  font-size:14px;line-height:1.6;color:#999;
  padding:4px 0;border-bottom:1px solid var(--line);
}
.sc-features li:last-child{border-bottom:none}
.sc-features li::before{
  content:'+';color:var(--accent);margin-right:10px;font-family:var(--fm);font-size:12px;
}
/* Add .no to a li for a feature the tier does NOT include. */
.sc-features li.no{color:#6b6b6b}
.sc-features li.no::before{content:'×';color:#6b6b6b}
.sc-pricing{margin-top:auto;padding-top:20px}
.sc-old-price{
  font-family:var(--fm);font-size:13px;color:#9a9a9a;
  text-decoration:line-through;margin-bottom:4px;
}
.sc-price{
  font-family:var(--fh);font-weight:900;
  font-size:clamp(28px,3vw,40px);
  color:var(--accent);letter-spacing:-.03em;line-height:1;
}
.sc-price-sub{
  font-family:var(--fm);font-size:10px;letter-spacing:.12em;color:var(--muted);
  margin-top:4px;text-transform:uppercase;
}
.sc-timeline{
  font-family:var(--fm);font-size:10px;letter-spacing:.12em;color:#9a9a9a;
  margin-top:8px;
}

/* CTA BUTTON */
.sc-cta{
  display:inline-block;margin-top:20px;
  font-family:var(--fm);font-size:10px;letter-spacing:.16em;text-transform:uppercase;
  color:var(--bg);background:var(--accent);
  padding:12px 24px;border:none;border-radius:calc(var(--card-r) - 32px);cursor:pointer;
  transition:background .3s,transform .12s;
  text-decoration:none;text-align:center;
  position:relative;
  min-width:120px;
}
/* Own element so the label can crossfade while the button around it travels.
   The ghost is the outgoing copy, out of flow so it cannot affect the width
   the morph is animating toward. */
.sc-cta-label{display:inline-block}
.sc-cta-ghost{
  position:absolute;left:0;right:0;top:50%;transform:translateY(-50%);
  pointer-events:none;white-space:nowrap;overflow:hidden;
}
.sc-cta:hover{background:var(--accent-dim);transform:translateY(-1px)}
.sc-cta:active{transform:scale(.97)}
.sc-cta-note{margin-top:10px;font-family:var(--fm);font-size:9px;letter-spacing:.14em;text-transform:uppercase;color:var(--muted);line-height:1.7}
.sc-cta:disabled{opacity:.5;cursor:not-allowed;transform:none}
.sc-cta.loading{
  color:transparent;pointer-events:none;
}
.sc-cta.loading::after{
  content:'';
  position:absolute;top:50%;left:50%;
  width:14px;height:14px;margin-top:-7px;margin-left:-7px;
  border:2px solid rgba(8,8,8,.3);
  border-top-color:var(--bg);
  border-radius:50%;
  animation:spinner .6s linear infinite;
}
@keyframes spinner{to{transform:rotate(360deg)}}
.sc-cta.error-state{
  background:transparent;color:var(--danger);
  border:1px solid rgba(239,68,68,.3);
}
.sc-cta.custom{background:transparent;color:var(--accent);border:1px solid rgba(184,255,0,.3)}
.sc-cta.custom:hover{background:rgba(184,255,0,.1)}
/* IN-CARD ENQUIRY FORM
   The panel fills the card's padding box and never changes the card's size.
   Radius stays concentric: card 40 - 16px padding = 24; panel 24 - 12px
   padding = 12, which is already the radius of .form-group inputs. */
/* There is only ever one panel: .sc-top. It already carries the frost blur,
   border, shadow, radius and padding, so the form simply lives inside it and
   the panel grows downward. On open .sc-top is lifted out of flow (its exact
   measured geometry is pinned in JS) so it can grow over the feature list
   without the card changing size. */
/* Pinning is driven by its own class, NOT by .form-open. If it hung off
   .form-open the panel would drop back into static flow the instant close was
   clicked — snapping to its flow position while the inline offsets lingered,
   and losing the transition at the same time. .is-pinned is removed only once
   the close animation has finished. */
.sc-top.is-pinned{
  position:absolute;z-index:5;
  display:flex;flex-direction:column;overflow:hidden;
  transition:height .45s cubic-bezier(.23,1,.32,1);
}
/* Pinning makes .sc-top a flex column, and flex stretches its children. These
   are inline-block in the closed card, so without this the button snapped from
   222px to the full 285px panel width the instant the panel was pinned, and
   snapped back the instant it was unpinned — 460ms later, after everything
   else had finished. It also meant the FLIP measured identical start and end
   widths and animated no morph at all. */
.sc-top.is-pinned>.sc-cta,
.sc-top.is-pinned>.sc-cta-secondary,
.sc-top.is-pinned>.stripe-badge{align-self:flex-start}
.sc-form{
  display:flex;flex-direction:column;gap:10px;
  height:0;margin-top:0;overflow:hidden;
  opacity:0;transform:translateY(-10px);
  /* Exit timing. Slightly quicker than the panel's 450ms shrink so the fields
     are gone before the panel finishes closing over them. */
  transition:opacity .24s ease-in,transform .3s cubic-bezier(.4,0,.6,1);
}
/* Laid out for as long as the panel is PINNED, which spans the close animation
   too. Hanging this off .form-open collapsed it to height:0 the instant close
   was clicked, so the fields vanished in one frame instead of sliding away
   behind the shrinking panel. */
.sc-top.is-pinned .sc-form{
  height:auto;flex:1 1 auto;min-height:0;overflow:hidden;margin-top:16px;
}
/* Entry timing, held back just long enough for the panel to have started
   opening — the fields arrive into space that already exists. */
.svc-card.form-open .sc-form{
  opacity:1;transform:none;
  transition:opacity .38s .1s ease-out,transform .5s .06s cubic-bezier(.23,1,.32,1);
}
/* Only the FIELDS scroll. The panel and the form are fixed frames: scrolling
   was declared on .sc-form, which contains the CTA too, so on any card whose
   content outgrew the panel the button scrolled out of reach. */
.sc-form .sc-form-body{flex:1 1 auto;min-height:0;overflow:hidden}
/* 0 1 auto, never 1: growing let the box stretch past its content and left
   52px of nothing under the last row. It shrinks and scrolls only when the
   panel has been capped at the card's height. */
.sc-form .sc-fields,.svc-card.form-sent .sc-sent{
  flex:0 1 auto;min-height:0;overflow-y:auto;
  /* 10 on top of the form's 12px gap = 22px, the same gap the note has under
     the button, so the button sits evenly between the two. */
  margin-bottom:10px;
  /* Bottom fade = the only hint that there is more below; --fade-b is driven
     from JS and sits at 0 once scrolled to the end. */
  --fade-b:0px;
  -webkit-mask-image:linear-gradient(to bottom,#000 calc(100% - var(--fade-b)),transparent);
  mask-image:linear-gradient(to bottom,#000 calc(100% - var(--fade-b)),transparent);
  scrollbar-width:thin;scrollbar-color:rgba(184,255,0,.28) transparent;
}
.sc-form .sc-fields::-webkit-scrollbar{width:4px}
.sc-form .sc-fields::-webkit-scrollbar-track{background:transparent}
.sc-form .sc-fields::-webkit-scrollbar-thumb{background:rgba(184,255,0,.28);border-radius:2px}
/* No margin-top:auto. The panel is sized to its content now, so there is no
   slack to push the button into — and an auto margin would silently reopen
   the gap the moment the panel got capped. */
/* .sc-top .sc-cta sets margin-top:18px for the closed card, and it is declared
   later in this sheet at equal specificity — so this needs the extra class to
   win. 18 on top of the form's own 12px gap is what read as dead space. */
.svc-card .sc-form .sc-cta{flex:0 0 auto;margin-top:0}
.sc-form .sc-cta-note{flex:0 0 auto}
/* Kept in the form so the shared handler can flip it (that is what the card
   script watches), but moved off-screen — the handler sets display:block
   inline, so it has to be positioned away rather than merely transparent.
   The visible confirmation is the .sc-sent state change below. */
.sc-form .form-success{
  position:absolute!important;left:-9999px!important;top:auto!important;
  width:1px;height:1px;overflow:hidden;pointer-events:none;
}
/* Toasts live on <body>, not in the card: any ancestor with backdrop-filter
   becomes the containing block for position:fixed, which is why they were
   landing between the cards instead of at the viewport edge. */
.toast{
  position:fixed;left:50%;bottom:24px;transform:translate(-50%,12px);
  z-index:99999;max-width:min(420px,90vw);width:max-content;
  padding:12px 18px;border-radius:14px;
  font-family:var(--fm);font-size:11px;line-height:1.5;text-align:center;
  background:rgba(10,10,10,.94);
  box-shadow:var(--shadow-2);
  opacity:0;pointer-events:none;
  transition:opacity .28s,transform .28s cubic-bezier(.23,1,.32,1);
}
.toast.show{opacity:1;transform:translate(-50%,0)}
.toast.err{border:1px solid rgba(255,90,90,.45);color:#ff8f8f}
.toast.ok{border:1px solid rgba(184,255,0,.45);color:var(--accent)}
/* Confirmation replaces the fields so it is obvious the send happened. */
.sc-fields{display:flex;flex-direction:column;gap:10px}
.sc-sent{display:none;font-family:var(--fm);font-size:11px;line-height:1.6;color:var(--muted)}
.sc-sent strong{color:var(--accent);font-weight:400}
.svc-card.form-sent .sc-fields{display:none}
.svc-card.form-sent .sc-sent{display:block}
/* Only these give way — the name and price panel stay exactly where they are.
   The CTA and its note are not faded: they physically move into the panel. */
.sc-includes,.sc-features{transition:opacity .3s .05s}
/* .panel-busy spans the whole animation, open through close, and cuts them out
   instantly rather than fading. The panel only covers this area once it has
   finished growing, so a fade left the feature list legible underneath and
   alongside it for the entire transition — and visible again on the way back
   down while the panel was still shrinking over it. */
.svc-card.panel-busy .sc-includes,
.svc-card.panel-busy .sc-features{
  opacity:0;visibility:hidden;pointer-events:none;transition:none;
}
.sc-form .sc-cta{margin-bottom:0;width:100%;min-width:0}
.sc-form .sc-cta-note{margin-top:10px;margin-bottom:0;text-align:center}
/* Hold the hover treatment while the form is open so the card stays "live". */
.svc-card.form-open{border-color:rgba(184,255,0,.25);background:rgba(14,14,14,.8)}
/* Circled X, pinned to the panel's top-right corner in line with the tier
   name, so it costs no vertical space inside the expanded panel. */
.sc-form-close{
  position:absolute;top:14px;right:14px;z-index:2;
  width:26px;height:26px;padding:0;
  display:none;align-items:center;justify-content:center;
  background:rgba(255,255,255,.04);
  border:1px solid rgba(255,255,255,.12);border-radius:50%;
  cursor:pointer;line-height:1;
  color:var(--muted);
  transition:color .25s,border-color .25s,background .25s,transform .12s;
}
/* A drawn cross, not the ✕ glyph. That character carries its own side bearings
   and sits above its own baseline, so no amount of flex centring put it in the
   middle of the circle — it read low and left. */
.sc-form-close svg{width:11px;height:11px;display:block}
/* Present for the whole pinned window so it can fade out with the fields
   instead of blinking away the moment close is pressed. */
.sc-top.is-pinned .sc-form-close{
  display:flex;opacity:0;
  transition:opacity .2s ease-in,color .25s,border-color .25s,background .25s,transform .12s;
}
.svc-card.form-open .sc-form-close{opacity:1;transition-delay:.14s}
.sc-form-close:hover{color:var(--accent);border-color:rgba(184,255,0,.4);background:rgba(184,255,0,.08)}
.sc-form-close:active{transform:scale(.92)}
.sc-form .form-group{gap:4px}
.sc-form .form-group label{font-size:9px}
.sc-form .form-group input,.sc-form .form-group select,.sc-form .form-group textarea{
  padding:9px 12px;font-size:12px;
}
.sc-form .form-row{gap:10px}
/* Needs .form-group in the selector to outrank `.form-group textarea` further
   down the sheet, which sets resize:vertical at equal specificity and wins on
   source order. The panel is a fixed frame — a drag handle that resizes a
   field inside it has nowhere to go. */
/* Base floor only — sizePanel grows it to whatever is left over, so the panel
   lands exactly on the card's bottom padding. */
.sc-form .form-group textarea{resize:none;min-height:84px}
/* The custom select's trigger is a <button>, so the input sizing above skips
   it: it stayed at 16px while everything around it was 12px, and a selected
   range like "£1,000 – £2,000" wrapped to a second line and grew the control
   from 46px to 67px. One line, clipped with an ellipsis. */
.sc-form .csel-btn{padding:9px 12px;font-size:12px;gap:6px}
/* Tight enough that every range fits the height the panel can actually give
   the list, so it opens as a full list rather than a scrolling stub. */
.sc-form .csel-opt{padding:6px 10px;font-size:12px;line-height:1.3}
.sc-form .csel-list{border-radius:12px}
.sc-form .form-submit{width:100%;padding:12px 20px;margin-top:auto}
.sc-form .form-error,.sc-form .form-success{font-size:11px;line-height:1.5}
@media(prefers-reduced-motion:reduce){
  .sc-form,.sc-cta,.sc-cta-note,.sc-includes,.sc-features{transition-duration:.01ms}
}
.sc-cta-secondary{
  display:inline-block;margin-top:10px;
  font-family:var(--fm);font-size:9px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--muted);text-decoration:none;
  transition:color .25s;
}
.sc-cta-secondary:hover{color:var(--accent)}
.sc-cta-secondary.loading{color:transparent;pointer-events:none}
.sc-cta-secondary.loading::after{
  content:'';position:absolute;top:50%;left:50%;width:10px;height:10px;margin-top:-5px;margin-left:-5px;
  border:2px solid rgba(138,138,138,.3);border-top-color:var(--muted);border-radius:50%;
  animation:spinner .6s linear infinite;
}
/* MAINTENANCE INCLUDES BADGE */
.sc-includes{
  display:inline-block;
  font-family:var(--fm);font-size:9px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--accent);
  background:rgba(184,255,0,.06);
  border:1px solid rgba(184,255,0,.2);
  padding:6px 10px;border-radius:6px;
  margin-bottom:16px;
  align-self:flex-start;
}
/* SC-TOP — frosted price panel (name + pricing + CTA), sits above the flat section */
.sc-top{
  position:relative;z-index:2;
  padding:16px;margin-bottom:16px;
  background:rgba(255,255,255,.04);
  -webkit-backdrop-filter:blur(2px) saturate(120%);
  backdrop-filter:blur(2px) saturate(120%);
  border:1px solid var(--line-2);
  border-radius:calc(var(--card-r) - 16px);
  box-shadow:var(--shadow-2);
}
.sc-top .sc-name{margin-bottom:14px}
.sc-top .sc-pricing{margin-top:0;padding-top:0}
.sc-top .sc-cta{margin-top:18px}
.sc-top .sc-cta-secondary{margin-top:8px}
.sc-top .stripe-badge{margin-top:12px}
/* FEATURED CARD VARIANT */
.svc-card.featured{
  border-color:rgba(184,255,0,.4);
  background:rgba(14,14,14,.9);
  box-shadow:0 0 0 1px rgba(184,255,0,.15),var(--shadow-3);
}
.svc-card.featured .sc-badge.popular{
  background:var(--accent);
  color:var(--bg);
  font-weight:600;
}
/* Arrived from a homepage preview card.
   Drawn as a ::after ring rather than a border or box-shadow, because both of
   those lose here: .svc-card.featured sets its own lime border at the same
   (0,2,0) specificity and wins on source order, and the tab switcher writes
   `animation` and `transform` as INLINE styles on every [data-category] card,
   which beat any class rule outright. Nothing touches ::after. */
@keyframes svc-target-ring{
  0%,100%{opacity:0}
  15%,60%{opacity:1}
}
.svc-card.is-targeted::after{
  content:'';position:absolute;inset:-2px;
  border:2px solid var(--accent);border-radius:calc(var(--card-r) + 2px);
  pointer-events:none;z-index:6;opacity:0;
  animation:svc-target-ring 1.15s ease-out 2;
}
@media(prefers-reduced-motion:reduce){
  .svc-card.is-targeted::after{animation:none;opacity:1}
}
/* FORM */
.contact-form{display:flex;flex-direction:column;gap:16px}
.form-row{display:grid;grid-template-columns:1fr 1fr;gap:16px}
.form-group{display:flex;flex-direction:column;gap:6px;min-width:0}
.form-group input,.form-group select,.form-group textarea{width:100%;min-width:0}
.form-group label{
  font-family:var(--fm);font-size:9px;letter-spacing:.18em;text-transform:uppercase;
  color:var(--muted);
}
.form-group label[for="cf-name"]::after,
.form-group label[for="cf-email"]::after,
.form-group label[for="cf-service"]::after,
.form-group label[for="cf-desc"]::after{
  content:' *';
  color:var(--accent);
}
.form-group input,.form-group select,.form-group textarea{
  background:rgba(255,255,255,.03);border:1px solid var(--line-2);
  border-radius:12px;padding:12px 14px;
  font-family:var(--fh);font-size:16px;color:var(--text);
  transition:border-color .3s,box-shadow .3s;outline:none;
}
.form-group input:focus,.form-group select:focus,.form-group textarea:focus{
  border-color:var(--accent);box-shadow:0 0 0 1px rgba(184,255,0,.12);
}
.form-group input.error,.form-group select.error,.form-group textarea.error{
  border-color:var(--danger);box-shadow:0 0 0 1px rgba(239,68,68,.12);
}
.form-group input.valid,.form-group select.valid,.form-group textarea.valid{
  border-color:var(--success);
}
.form-group select{appearance:none;cursor:pointer;
  text-overflow:ellipsis;white-space:nowrap;overflow:hidden;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23666' stroke-width='2'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right 14px center;padding-right:40px;
}

/* CUSTOM SELECT — styled listbox synced to the hidden native select */
.csel{position:relative;min-width:0}
.csel-btn{
  width:100%;display:flex;align-items:center;justify-content:space-between;gap:8px;
  background:rgba(255,255,255,.03);border:1px solid var(--line-2);border-radius:12px;
  color:var(--text);font-size:16px;padding:12px 14px;cursor:pointer;text-align:left;
  transition:border-color .3s,box-shadow .3s;font-family:inherit;
}
/* The label must be allowed to shrink: as a flex item its automatic minimum
   is min-content, so a long option pushed the caret out and forced a wrap. */
.csel-btn>span{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.csel-btn:hover{border-color:rgba(184,255,0,.3)}
.csel-btn:focus-visible{outline:none;border-color:var(--accent);box-shadow:0 0 0 3px rgba(184,255,0,.1)}
.csel-btn .csel-caret{width:14px;height:14px;flex-shrink:0;color:var(--muted);transition:transform .25s}
.csel.open .csel-caret{transform:rotate(180deg)}
.csel-btn.is-placeholder{color:#555}
.csel:has(select.error) .csel-btn{border-color:rgba(239,68,68,.5)}
.csel:has(select.valid) .csel-btn{border-color:rgba(34,197,94,.4)}
/* display:none while closed, not merely transparent. Absolutely positioned or
   not, a laid-out box still contributes scrollable overflow to its nearest
   scrolling ancestor: inside a service card these phantom lists added 147px
   each, so the fields box measured 409px of "content" against 262px of real
   fields — which is what made the panel think it had to scroll. JS flips it to
   block one reflow before opening, so the fade still runs. */
.csel-list{
  display:none;
  position:absolute;left:0;right:0;top:calc(100% + 6px);z-index:50;
  background:rgba(12,12,12,.94);-webkit-backdrop-filter:blur(16px);backdrop-filter:blur(16px);
  border:1px solid var(--line-2);border-radius:14px;padding:4px;
  max-height:240px;overflow:auto;
  opacity:0;transform:translateY(-6px);pointer-events:none;
  transition:opacity .2s,transform .2s;
  box-shadow:var(--shadow-2);
}
.csel.open .csel-list{opacity:1;transform:translateY(0);pointer-events:auto}
/* viewport-aware: flip above when space below is tight */
.csel.flip .csel-list{top:auto;bottom:calc(100% + 6px);transform:translateY(6px)}
.csel.flip.open .csel-list{transform:translateY(0)}
.csel-opt{
  display:flex;align-items:center;gap:8px;width:100%;
  padding:10px 12px;border-radius:10px;border:none;background:transparent;
  color:#ccc;font-size:14px;text-align:left;cursor:pointer;
  transition:background .15s,color .15s;font-family:inherit;
}
.csel-opt:hover{background:rgba(184,255,0,.08);color:var(--accent)}
.csel-opt.is-selected{color:var(--accent)}
.csel-opt.is-selected::after{content:'';margin-left:auto;width:6px;height:6px;border-radius:50%;background:var(--accent)}
/* top/left pin it inside the wrapper. Left at its static position it sat below
   the trigger and, being 18px tall, hung past the bottom of the scrolling
   fields box — 17px of phantom scrollable overflow on a form that fits. */
select.csel-native{position:absolute!important;top:0;left:0;opacity:0;pointer-events:none;width:1px!important;height:1px!important;padding:0;border:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0)}
.form-group select option{background:var(--surface);color:var(--text)}
.form-group textarea{resize:vertical;min-height:100px}
.form-submit{
  font-family:var(--fm);font-size:10px;letter-spacing:.16em;text-transform:uppercase;
  color:var(--bg);background:var(--accent);
  padding:14px 28px;border:none;border-radius:12px;cursor:pointer;
  transition:background .3s,transform .2s;align-self:flex-start;
  position:relative;min-width:140px;
}
.form-submit:hover{background:var(--accent-dim);transform:translateY(-1px)}
.form-submit:disabled{opacity:.5;cursor:not-allowed;transform:none}
.form-submit.loading{
  color:transparent;pointer-events:none;
}
.form-submit.loading::after{
  content:'';
  position:absolute;top:50%;left:50%;
  width:14px;height:14px;margin-top:-7px;margin-left:-7px;
  border:2px solid rgba(8,8,8,.3);
  border-top-color:var(--bg);
  border-radius:50%;
  animation:spinner .6s linear infinite;
}
.form-submit.error-state{
  background:transparent;color:#ff4444;
  border:1px solid rgba(255,68,68,.3);
}
.form-success{
  font-family:var(--fm);font-size:12px;color:var(--success);
  padding:16px;border:1px solid rgba(34,197,94,.2);border-radius:12px;
  background:rgba(34,197,94,.04);display:none;
  animation:msgIn .3s cubic-bezier(.23,1,.32,1) forwards;
}
.form-error{
  font-family:var(--fm);font-size:11px;color:var(--danger);
  padding:10px;border:1px solid rgba(239,68,68,.2);border-radius:12px;
  background:rgba(239,68,68,.04);display:none;
  animation:msgIn .3s cubic-bezier(.23,1,.32,1) forwards;
}
@keyframes msgIn{
  from{opacity:0;transform:translateY(-6px)}
  to{opacity:1;transform:translateY(0)}
}
@keyframes shake{
  0%,100%{transform:translateX(0)}
  20%{transform:translateX(-4px)}
  40%{transform:translateX(4px)}
  60%{transform:translateX(-3px)}
  80%{transform:translateX(2px)}
}
.shake{animation:shake .4s cubic-bezier(.36,0,.66,-.26)}
