/* ============================================================
   Site 2.0 - grounded sections
   After the flight lands, the page becomes normal-scrolling DOM
   for the things a camera can't carry: proof, testimony, forms.

   Converted from the old dark ground to the bright daylight
   token set in base.css. Every fill below reads as warm paper,
   not inverted void. Text never sits directly on raw --amber;
   see base.css header for the measured contrast table.

   Hover effects here follow the site's one governing idea: every
   hover is a hand reaching out, offering rather than merely
   highlighting. Each element group below gets its own distinct
   read on that idea. Pointer-tracked and CSS-hover effects alike
   are gated behind (pointer:fine) so touch never gets stuck mid
   hover; every gated effect has an ungated :focus-visible twin.
   ============================================================ */

.ground{ position:relative; z-index:10; background:var(--paper); }

.sect{ padding-block:clamp(5.5rem, 13vh, 10rem); }
.wrap{ width:min(1240px, 100% - var(--gut)*2); margin-inline:auto; }

.sect-head{ max-width:44ch; margin-bottom:clamp(2.5rem,6vh,4.5rem); }
.sect-head .tag{ margin-bottom:1.3rem; }

/* Reveal on enter.

   Visible is the resting state. The hidden state only exists once JS has
   declared it can turn it back on, which is why it hangs off .js-reveal.
   An earlier version had opacity:0 as the default, and any element the
   observer missed stayed invisible for good: both contact forms disappeared
   in 3 of 4 scroll runs. Content that only appears if a script succeeds is
   the wrong default for a contact form. */
.js-reveal .rv{ opacity:0; transform:translateY(22px);
     transition:opacity .8s var(--ease), transform .8s var(--ease); }
.js-reveal .rv.in{ opacity:1; transform:none; }

@media (prefers-reduced-motion:reduce){
  .js-reveal .rv{ opacity:1; transform:none; }
}

/* ---------- who we help ---------- */

.needs{
  display:grid; gap:1px; background:var(--hair);
  border:1px solid var(--hair);
  /* Exactly two even rows of three. auto-fit was choosing five columns at
     wide viewports, which left the sixth card alone beside a large empty
     cell: the client flagged that gap, and it was the grid, not the content. */
  grid-template-columns:1fr;
}
@media (min-width:620px){ .needs{ grid-template-columns:repeat(2,1fr); } }
@media (min-width:980px){ .needs{ grid-template-columns:repeat(3,1fr); } }
.need{
  background:var(--paper-2);
  padding:clamp(1.6rem,3vw,2.4rem);
  position:relative; overflow:hidden;
  transition:background .5s var(--ease);
}
/* cursor-origin bloom: warmth answers where you actually touched the card */
.need::before{
  content:''; position:absolute; inset:0; opacity:0;
  background:radial-gradient(340px circle at var(--bx,50%) var(--by,50%),
    color-mix(in srgb, var(--amber) 16%, transparent), transparent 62%);
  transition:opacity .45s var(--ease);
}
/* a thin line of sun arriving at the top edge, distinct from the bloom */
.need::after{
  content:''; position:absolute; top:0; left:0; height:2px; width:0;
  background:var(--accent);
  transition:width .5s var(--ease);
}
@media (pointer:fine){
  .need:hover::before{ opacity:1; }
  .need:hover::after{ width:100%; }
}
.need:focus-within::before{ opacity:1; }
.need:focus-within::after{ width:100%; }
.need > *{ position:relative; }
.need h3{ font-size:var(--t-md); margin-bottom:.4rem; }
.need p{ font-size:var(--t-sm); color:var(--ink-soft); margin:0; }

/* ---------- gallery ---------- */

.gal{
  --gap:clamp(.5rem,1.2vw,1rem);
  columns:3; column-gap:var(--gap);
}
@media (max-width:1000px){ .gal{ columns:2; } }
@media (max-width:600px){ .gal{ columns:1; } }

.gal figure{
  margin:0 0 var(--gap); position:relative; overflow:hidden;
  break-inside:avoid; background:var(--paper-3);
  border-radius:10px;
  transition:box-shadow .5s var(--ease);
  transform-style:preserve-3d;
}
@media (pointer:fine){
  .gal figure:hover{ box-shadow:0 18px 38px rgba(10,26,47,.16); }
}
.gal figure:focus-within{ box-shadow:0 18px 38px rgba(10,26,47,.16); }
.gal img{ width:100%; height:auto; filter:saturate(.9) contrast(1.02); transition:filter .6s var(--ease); }
.gal figure:hover img,
.gal figure:focus-within img{ filter:saturate(1.08) contrast(1.04); }
.gal figcaption{
  position:absolute; inset:auto 0 0 0; padding:2.4rem .9rem .8rem;
  font:500 var(--t-xs)/1.4 var(--mono); letter-spacing:.1em; text-transform:uppercase;
  color:#fff; background:linear-gradient(0deg, rgba(10,26,47,.88), transparent);
  opacity:0; transform:translateY(8px);
  transition:opacity .4s var(--ease), transform .4s var(--ease);
}
.gal figure:hover figcaption, .gal figure:focus-within figcaption{ opacity:1; transform:none; }

/* Inserted by gallery.js after #gallery, never inside it. `.gal` above lays
   photographs out with CSS multi-column, and any extra element placed
   inside that container reads as one more column item and breaks the
   masonry flow rather than sitting below it as a footer. It only exists in
   the DOM at all once there is more than one page to move between. */
/* Built from the same parts as every other small control here: the hairline
   pill of .yn label and the uppercase mono of .socials a. The first version
   invented a rounded square on an 8px radius that appeared nowhere else in the
   build, and marked the current page with a solid block of the most saturated
   colour on the page, which made navigation furniture the loudest thing in the
   gallery. A pager should be findable and quiet. The selected state follows the
   pattern already settled on for .yn label: an accent edge and a warm tint,
   never a fill. */
/* One pager, two lists. The gallery and the testimonials must not drift into
   looking like two different controls. */
.gal-pager{
  display:flex; flex-wrap:wrap; align-items:center; justify-content:center;
  gap:.6rem;
  margin-top:clamp(1.8rem,3.4vw,2.8rem);
}
.gal-pager button{
  min-width:2.75rem; height:2.75rem; padding:0 .75rem;
  border-radius:100px; border:1px solid var(--hair);
  background:var(--paper); color:var(--ink-soft);
  font:500 var(--t-xs)/1 var(--mono);
  letter-spacing:.1em;
  cursor:pointer;
  transition:border-color .4s var(--ease), background .4s var(--ease),
             color .4s var(--ease);
}
.gal-pager button[aria-current="page"]{
  border-color:var(--accent); background:#FBF3E4; color:var(--accent-hi);
}
/* The chevrons were set at the button's own font size, which rendered them a
   fraction of the height of the digits beside them and left each one adrift in
   its pill. Sized to match the numerals they sit among. */
.gal-pager button[aria-label]{ font-size:1.15rem; letter-spacing:0;
  /* The chevron glyphs carry far less height than a numeral at the same
     size, so matching the font size still left them looking half sized
     beside the digits. Set by eye against the numerals, not by token. */
  padding-bottom:.12em; }
@media (pointer:fine){
  .gal-pager button:not([aria-current="page"]):not(:disabled):hover{
    border-color:var(--accent); color:var(--accent);
  }
}
.gal-pager button:focus-visible{ outline:2px solid var(--accent); outline-offset:2px; }
.gal-pager button:disabled{ opacity:.35; cursor:default; }

/* ---------- testimonials ---------- */

.says{ display:grid; gap:1px; grid-template-columns:repeat(auto-fit,minmax(290px,1fr));
       background:var(--hair); border:1px solid var(--hair); }
.say{ background:var(--paper-2); padding:clamp(1.7rem,3vw,2.5rem);
      transition:box-shadow .45s var(--ease); }
@media (pointer:fine){
  .say:hover{ box-shadow:0 16px 34px rgba(10,26,47,.10); }
}
.say:focus-within{ box-shadow:0 16px 34px rgba(10,26,47,.10); }
.say blockquote{ margin:0 0 1.4rem; font-size:var(--t-lg); line-height:1.34; letter-spacing:-.015em; }
.say cite{ font-style:normal; font:500 var(--t-xs)/1.6 var(--mono);
           letter-spacing:.14em; text-transform:uppercase; color:var(--ink-faint); display:block; }
.say cite b{ display:block; color:var(--accent); font-weight:500; }

.stars{ display:flex; align-items:center; gap:.5rem; margin-bottom:1.2rem; }
.stars .s{ display:flex; gap:.18rem; }
/* Amber at rest, not on hover. The fill used to live only inside
   @media (pointer:fine) :hover, so a "5.0" sat beside five near invisible grey
   stars on load, and permanently on every touch device: it read as a broken
   widget or a zero rating. The hover stagger below is now a re-animation of
   something already there, which is what it was always meant to be. */
.stars i{ width:11px; height:11px; background:var(--amber); font-style:normal;
          clip-path:polygon(50% 0,61% 35%,98% 35%,68% 57%,79% 91%,50% 70%,21% 91%,32% 57%,2% 35%,39% 35%);
          transition:background .4s var(--ease); }
/* stars fill in sequence, the way a look lands one beat at a time */
@media (pointer:fine){
  .say:hover .stars i{ background:var(--amber); }
}
.say:focus-within .stars i{ background:var(--amber); }
.say:hover .stars i:nth-child(2), .say:focus-within .stars i:nth-child(2){ transition-delay:.06s; }
.say:hover .stars i:nth-child(3), .say:focus-within .stars i:nth-child(3){ transition-delay:.12s; }
.say:hover .stars i:nth-child(4), .say:focus-within .stars i:nth-child(4){ transition-delay:.18s; }
.say:hover .stars i:nth-child(5), .say:focus-within .stars i:nth-child(5){ transition-delay:.24s; }
.stars b{ font:500 var(--t-xs)/1 var(--mono); color:var(--ink-soft); }

/* ---------- join paths ---------- */

.paths{ display:grid; gap:1px; grid-template-columns:1fr; background:var(--hair);
        border:1px solid var(--hair); }
@media (min-width:820px){ .paths{ grid-template-columns:1fr 1fr; } }

/* Services reuse the join-path card wholesale, hover behaviour included.
   The only difference is that there are three of them, not two. */
@media (min-width:980px){ .svc-grid{ grid-template-columns:repeat(3,1fr); } }

.path{
  display:block; background:var(--paper-2);
  padding:clamp(2rem,4.5vw,3.4rem);
  position:relative; overflow:hidden;
  transition:background .5s var(--ease), opacity .5s var(--ease);
}
.path.is-dim{ opacity:.5; }
.path::after{
  content:''; position:absolute; left:0; right:0; bottom:0; height:1px;
  background:var(--accent); transform:scaleX(0); transform-origin:left;
  transition:transform .6s var(--ease);
}
@media (pointer:fine){
  .path:hover::after{ transform:scaleX(1); }
}
.path:focus-visible::after{ transform:scaleX(1); }
/* The cards are a grid, so make each one a column and push the link to the
   bottom. Without this the three CTAs landed at three different heights the
   moment one label wrapped, which is the first thing anyone checks in a
   three-up. */
.path{ display:flex; flex-direction:column; }
.path p{ flex:1 1 auto; }
.path h3{ font-size:var(--t-lg); margin:.9rem 0 .6rem; }
.path p{ color:var(--ink-soft); margin-bottom:1.6rem; max-width:38ch; }
/* Line height 1 was fine while every label fitted on one line. "Ask about
   personal assistance" does not, and set solid in tracked-out uppercase the two
   lines closed up against each other and read as a mistake rather than a link. */
/* Inline, not inline-flex. As a flex line the wrapped label filled the row and
   stranded the arrow far to the right of a text block it was supposed to be
   part of. Inline lets the arrow follow the last word whatever the label says.
   Transform still applies: the svg is a replaced element made inline-block. */
.path .go{ display:inline;
           font:500 var(--t-xs)/1.45 var(--mono); letter-spacing:.2em; text-transform:uppercase;
           color:var(--accent); }
.path .go svg{ width:18px; display:inline-block; vertical-align:-.22em;
               margin-left:.5rem; transition:transform .45s var(--ease); }
/* The arrow is tied to the last word so it can never wrap onto a line of its
   own, which is how it read once the label was long enough to break. */
.path .go .nb{ white-space:nowrap; }
@media (pointer:fine){
  .path:hover .go svg{ transform:translateX(7px); }
}
.path:focus-visible .go svg{ transform:translateX(7px); }

/* ---------- contact ---------- */

.cols{ display:grid; gap:clamp(2.5rem,6vw,5rem); grid-template-columns:1fr; }
@media (min-width:900px){ .cols{ grid-template-columns:1.1fr 1fr; } }

.dl{ margin:0; display:grid; }
.dl dt{ font:500 var(--t-xs)/1.5 var(--mono); letter-spacing:.2em; text-transform:uppercase;
        color:var(--accent); margin-top:1.5rem; }
.dl dd{ margin:0; font-size:var(--t-md); }
.dl dd a{ position:relative; }
/* underline morphs from a rule into the logo's split horizon */
.dl dd a::after, .dl dd a::before{
  content:''; position:absolute; bottom:-3px; height:1px; background:var(--accent);
  transition:width .45s var(--ease), left .45s var(--ease), right .45s var(--ease);
}
.dl dd a::before{ left:0; width:100%; }
.dl dd a::after{ right:0; width:0; }
@media (pointer:fine){
  .dl dd a:hover::before{ width:42%; }
  .dl dd a:hover::after{ width:42%; }
}
.dl dd a:focus-visible::before{ width:42%; }
.dl dd a:focus-visible::after{ width:42%; }

.sub label{ display:block; font:500 var(--t-xs)/1 var(--mono);
            letter-spacing:.2em; text-transform:uppercase; color:var(--accent); margin-bottom:.8rem; }
/* Textarea is styled alongside input rather than left to the browser
   default, which looked like a different site's control. */
.frm input, .frm textarea, .sub input{
  flex:1 1 220px; min-width:0; width:100%; padding:1rem 1.1rem;
  background:var(--paper); border:1px solid var(--hair); border-radius:2px;
  color:var(--ink); font:300 var(--t-md)/1.4 var(--sans);
  transition:border-color .4s var(--ease);
}
.frm textarea{ resize:vertical; min-height:7rem; }
.frm input:focus, .frm textarea:focus, .sub input:focus{ border-color:var(--accent); }

/* The border alone is not a focus indicator: it is a 1px colour change and
   it also fires on mouse click. An earlier version set outline:none here,
   which removed the only real keyboard cue on the subscribe field. */
.frm input:focus-visible, .frm textarea:focus-visible, .sub input:focus-visible{
  outline:2px solid var(--accent); outline-offset:2px;
}
.frm input::placeholder, .frm textarea::placeholder,
.sub input::placeholder{ color:var(--ink-faint); }

.note{ font-size:var(--t-sm); color:var(--ink-faint); font-style:italic; margin-top:2rem; }

/* ---------- footer ---------- */

.foot{ border-top:1px solid var(--hair); padding-block:clamp(3rem,7vh,5rem); }
.foot-in{ display:flex; flex-wrap:wrap; gap:1.6rem; align-items:center; justify-content:space-between; }
.foot p{ margin:0; font-size:var(--t-xs); color:var(--ink-faint); line-height:1.8; }


/* ---------- lightbox ---------- */
/* The container is `.lbx`, NOT `.lb`. `.lb` is this site's form label class,
   and a bare `.lb` rule carrying position:fixed and inset:0 turned every label
   into a full screen sheet over the page: nothing was clickable, no hover
   fired anywhere, and the labels themselves vanished because the rule also
   carries display:none. Never name a container after an existing utility. */
/* The photographs are of people the charity supports, so this is deliberately
   calm: a deep neutral ground rather than pure black, generous controls, and
   nothing that moves faster than the rest of the site. */
.lbx{
  position:fixed; inset:0; z-index:900;
  display:none; align-items:center; justify-content:center;
  padding:clamp(1rem,4vw,3rem);
  background:rgba(8,12,18,.86);
  backdrop-filter:blur(7px); -webkit-backdrop-filter:blur(7px);
  opacity:0; transition:opacity .45s var(--ease);
}
.lbx.is-on{ display:flex; opacity:1; }
html.lb-locked{ overflow:hidden; }

.lb-stage{ margin:0; max-width:min(1180px,94vw); max-height:86vh;
           display:flex; flex-direction:column; gap:.9rem; }
.lb-stage img{
  max-width:100%; max-height:78vh; width:auto; height:auto;
  border-radius:3px; display:block; margin:0 auto;
  box-shadow:0 30px 90px rgba(0,0,0,.5);
}
.lb-stage figcaption{
  color:#F3F1EE; text-align:center;
  font:300 var(--t-md)/1.5 var(--sans);
}
.lb-count{
  position:absolute; bottom:clamp(.8rem,2.4vw,1.5rem); left:0; right:0;
  margin:0; text-align:center; color:rgba(243,241,238,.66);
  font:500 var(--t-xs)/1 var(--mono); letter-spacing:.22em;
}

.lb-close, .lb-nav{
  position:absolute; z-index:2;
  display:grid; place-items:center;
  width:52px; height:52px; padding:0;
  border-radius:50%; cursor:pointer;
  color:#FBF8F3;
  background:rgba(255,255,255,.10);
  border:1px solid rgba(255,255,255,.24);
  backdrop-filter:blur(9px); -webkit-backdrop-filter:blur(9px);
  transition:background .4s var(--ease), transform .4s var(--ease);
}
.lb-close{ top:clamp(.8rem,2.4vw,1.6rem); right:clamp(.8rem,2.4vw,1.6rem); }
.lb-prev{ left:clamp(.5rem,2vw,1.6rem); top:50%; transform:translateY(-50%); }
.lb-next{ right:clamp(.5rem,2vw,1.6rem); top:50%; transform:translateY(-50%); }
.lb-close svg, .lb-nav svg{ width:21px; height:21px; }
@media (pointer:fine){
  .lb-close:hover, .lb-nav:hover{ background:rgba(255,255,255,.2); }
  .lb-prev:hover{ transform:translateY(-50%) translateX(-3px); }
  .lb-next:hover{ transform:translateY(-50%) translateX(3px); }
}
.lb-close:focus-visible, .lb-nav:focus-visible{
  outline:2px solid var(--amber); outline-offset:3px;
}

/* The thumbnails are controls now, so they have to say so. */
.gal figure{ cursor:zoom-in; }
.gal figure:focus-visible{ outline:2px solid var(--accent); outline-offset:3px; }


/* ============================================================
   The application form.
   Two routes through one form. Volunteering and paid work ask for
   different things, so the form reshapes rather than showing
   everyone every field.
   ============================================================ */
.frm.apply{ max-width:62rem; }

/* ---- the route choice ---- */
.rolepick{ border:0; margin:0 0 2.4rem; padding:0; }
.rolepick legend{
  padding:0; margin-bottom:.9rem;
  font:500 var(--t-xs)/1 var(--mono); letter-spacing:.2em; text-transform:uppercase;
  color:var(--accent);
}
.rolepick-opts{ display:grid; gap:.9rem; }
@media (min-width:720px){ .rolepick-opts{ grid-template-columns:1fr 1fr; } }

.rolecard{ position:relative; display:block; cursor:pointer; }
.rolecard input{
  position:absolute; opacity:0; width:0; height:0;
}
.rolecard-in{
  display:block; padding:1.25rem 1.4rem;
  border:1px solid var(--hair); border-radius:4px;
  background:var(--paper);
  transition:border-color .45s var(--ease), background .45s var(--ease),
             box-shadow .45s var(--ease), transform .45s var(--ease);
}
.rolecard-t{
  display:block; font:400 var(--t-lg)/1.2 var(--sans); letter-spacing:-.015em;
  color:var(--ink); margin-bottom:.35rem;
}
.rolecard-d{ display:block; font-size:var(--t-sm); color:var(--ink-soft); }
@media (pointer:fine){
  .rolecard:hover .rolecard-in{ border-color:var(--accent); transform:translateY(-2px); }
}
.rolecard input:checked + .rolecard-in{
  border-color:var(--accent); background:#FBF3E4;
  box-shadow:0 6px 18px rgba(154,91,0,.12);
}
.rolecard input:focus-visible + .rolecard-in{ outline:2px solid var(--accent); outline-offset:3px; }

/* ---- grouped fields ---- */
.fs{ margin:0 0 2.4rem; }
.fs-t{
  font:400 var(--t-lg)/1.2 var(--sans); letter-spacing:-.015em;
  margin:0 0 1.1rem; padding-bottom:.7rem;
  border-bottom:1px solid var(--hair);
}
.fs-note{ margin:-.4rem 0 1.2rem; }
.pair{ display:grid; gap:0 1.4rem; }
@media (min-width:720px){ .pair{ grid-template-columns:1fr 1fr; } }

/* ---- yes / no ---- */
.yn{ border:0; margin:0 0 1.1rem; padding:0; }
.yn legend{ padding:0; margin-bottom:.55rem; }
.yn label{
  display:inline-flex; align-items:center; gap:.5rem;
  /* A two word answer must never stack into a column. Without this "No, or not
     yet" broke onto four lines inside its own pill. */
  white-space:nowrap;
  margin:0 .7rem .5rem 0; padding:.6rem 1.1rem;
  border:1px solid var(--hair); border-radius:100px;
  background:var(--paper); cursor:pointer;
  font:400 var(--t-sm)/1 var(--sans);
  transition:border-color .4s var(--ease), background .4s var(--ease);
}
.yn input{ width:auto; margin:0; accent-color:var(--amber); }
.yn label:has(input:checked){ border-color:var(--accent); background:#FBF3E4; }
.yn label:focus-within{ outline:2px solid var(--accent); outline-offset:2px; }
.yn .note{ display:block; margin-top:.2rem; }

/* ---- documents ---- */
.docs{ display:grid; gap:.8rem; }
@media (min-width:720px){ .docs{ grid-template-columns:1fr 1fr; } }

.doc{ position:relative; display:block; cursor:pointer; }
/* The real input is invisible but still focusable, so the keyboard and the
   file picker behave exactly as they normally would. */
.doc input{
  position:absolute; inset:0; width:100%; height:100%;
  opacity:0; cursor:pointer;
}
.doc-in{
  display:block; padding:1.1rem 1.2rem;
  border:1px dashed var(--hair); border-radius:4px;
  background:var(--paper);
  transition:border-color .45s var(--ease), background .45s var(--ease);
}
.doc-t{
  display:flex; align-items:center; gap:.6rem; flex-wrap:wrap;
  font:400 var(--t-md)/1.3 var(--sans); color:var(--ink); margin-bottom:.3rem;
}
.doc-t .req{
  font:500 var(--t-xs)/1 var(--mono); letter-spacing:.14em; text-transform:uppercase;
  color:var(--accent-hi); background:#F7E7C8; padding:.28rem .5rem; border-radius:3px;
}
.doc-d{ display:block; font-size:var(--t-sm); color:var(--ink-soft); margin-bottom:.7rem; }
.doc-file{
  display:inline-flex; align-items:center; gap:.5rem;
  font:500 var(--t-xs)/1 var(--mono); letter-spacing:.12em; text-transform:uppercase;
  color:var(--accent-hi);
}
.doc-file::before{
  content:""; width:13px; height:13px; flex:none;
  border:1.5px solid currentColor; border-radius:2px;
}
@media (pointer:fine){
  .doc:hover .doc-in{ border-color:var(--accent); background:#FDF7EC; }
}
.doc input:focus-visible + .doc-in{ outline:2px solid var(--accent); outline-offset:3px; }

/* Chosen: the dashes become a solid edge, which is the clearest possible
   signal that the box now holds something. */
.doc.has-file .doc-in{ border-style:solid; border-color:var(--accent); background:#FBF3E4; }
.doc.has-file .doc-file::before{
  background:var(--accent-hi); border-color:var(--accent-hi);
}
.doc.is-bad .doc-in{ border-style:solid; border-color:#9B1C1C; background:#FBEDEC; }
.doc.is-bad .doc-file{ color:#9B1C1C; }

.privacy{ margin:0 0 1.4rem; max-width:60ch; }

/* ---------- draft preview bar ----------

   Fixed to the bottom rather than the top, because the top of this site is a
   full bleed film and a band across it would wreck the one thing the client is
   previewing. It is deliberately loud: the whole purpose is to make it
   impossible to mistake a draft for the live site. Nothing here loads unless
   the page was opened with ?preview=1. */

.has-pv-bar body{ padding-bottom:7.5rem; }

.pv-bar{
  position:fixed; left:0; right:0; bottom:0; z-index:9000;
  display:flex; flex-wrap:wrap; align-items:center; justify-content:center;
  gap:.7rem 1.4rem;
  padding:.95rem clamp(1rem,3vw,2rem);
  background:#0A1A2F; color:#FDFBF7;
  border-top:3px solid var(--amber,#F2A72D);
  box-shadow:0 -14px 34px rgba(10,26,47,.30);
  font:400 var(--t-sm)/1.45 var(--sans);
}
.pv-bar.is-done{ border-top-color:#3FA46A; }
.pv-say{ margin:0; max-width:52ch; }
.pv-say b{ color:var(--amber,#F2A72D); }
.pv-bar.is-done .pv-say b{ color:#7BD7A2; }
.pv-acts{ display:flex; flex-wrap:wrap; align-items:center; gap:.6rem; }

/* The publish control is the largest thing on the bar on purpose. It is the
   one decision this page exists to let somebody make. */
.pv-btn{
  display:inline-flex; align-items:center; justify-content:center;
  min-height:52px; padding:0 1.6rem;
  border:0; border-radius:100px; cursor:pointer;
  font:600 var(--t-sm)/1 var(--sans); letter-spacing:.02em;
  text-decoration:none; white-space:nowrap;
  transition:background .4s var(--ease), color .4s var(--ease),
             border-color .4s var(--ease), opacity .3s var(--ease);
}
.pv-go{ background:var(--amber,#F2A72D); color:#0A1A2F; }
.pv-ghost{
  background:none; color:#FDFBF7; border:1px solid rgba(253,251,247,.42);
}
@media (pointer:fine){
  .pv-go:hover{ background:#FFC152; }
  .pv-ghost:hover{ border-color:#FDFBF7; }
}
.pv-btn:focus-visible{ outline:2px solid #FDFBF7; outline-offset:3px; }
.pv-btn:disabled{ opacity:.6; cursor:default; }
.pv-warn{ color:#F6C9C9; }
.pv-msg{ margin:0; flex-basis:100%; text-align:center; color:#F6C9C9; }
.pv-msg:empty{ display:none; }

@media (max-width:640px){
  .pv-bar{ flex-direction:column; align-items:stretch; text-align:center; }
  .pv-acts{ justify-content:center; }
  .pv-btn{ flex:1 1 auto; }
}

/* The testimonial pager sits under a grid of cards rather than a masonry
   column, so it needs its own breathing room above. */
.says-pager{ margin-top:clamp(1.4rem,2.6vw,2rem); }

/* ---------- the rating control on the testimonial form ----------

   Radio buttons, not a script. The star shapes are labels sitting after their
   own input, which is why the markup runs 5 down to 1: `~` only reaches
   forward, so a checked star can light the ones printed after it, and reversing
   the row with flex puts them back in the order a person expects.

   Built this way it works with a keyboard and a screen reader for nothing: the
   arrow keys move through the group, each label carries its value in words, and
   the whole thing still submits with javascript switched off. */

.rate{ border:0; margin:0 0 .5rem; padding:0; }
.rate legend{ padding:0; font:inherit; color:var(--ink-soft); }
.rate-stars{ display:flex; flex-direction:row-reverse; justify-content:flex-end; gap:.15rem; }
.rate-stars input{ position:absolute; width:1px; height:1px; opacity:0; }
.rate-stars label{
  cursor:pointer; line-height:1;
  font-size:1.7rem; color:var(--hair);
  transition:color .2s var(--ease), transform .2s var(--ease);
}
.rate-stars label::before{ content:"\2605"; }
/* the chosen star, and every star to its left, which is printed after it */
.rate-stars input:checked ~ label,
.rate-stars label:hover,
.rate-stars label:hover ~ label{ color:var(--amber,#F2A72D); }
.rate-stars label:active{ transform:scale(.92); }
.rate-stars input:focus-visible + label{ outline:2px solid var(--accent); outline-offset:3px; }
