/* ============================================================
   hdw site kit · COMPONENTS
   Every shape a page may use. A shape not here, and not on
   demo.html, does not exist yet: add it here first.

   Two pieces come from GAA rather than the reference site: the
   pill switch and the note card. Kept on 4 November 2026.
   ============================================================ */

/* ---- text ---- */
.title{font-size:var(--fs-title);line-height:var(--lh-tight);letter-spacing:var(--track-l);text-wrap:balance;}
.prose{max-width:var(--measure);display:grid;gap:var(--s-3);line-height:var(--lh-text);}
.link{transition:color var(--dur-s) ease;}
@media (hover:hover){ .link:hover{color:var(--ink-2);} }
.link-line{box-shadow:inset 0 -1px 0 currentColor;}
.stack{display:grid;gap:3px;justify-items:start;}
.links{display:flex;flex-wrap:wrap;gap:var(--s-2) var(--s-4);}
.prose a,.qa-a a{box-shadow:inset 0 -1px 0 currentColor;}
.prose h2{margin-top:var(--s-5);}
.prose ul{display:grid;gap:var(--s-1);list-style:disc;padding-left:1.1em;}

/* ---- a list in columns: services, what we do ---- */
.cols{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--s-5) var(--x);line-height:var(--lh-text);}
.cols.is-3{grid-template-columns:repeat(3,minmax(0,1fr));}
/* a plain list in columns: lines sit close, like a list */
ul.cols{row-gap:var(--s-2);}
.cols-group{display:grid;gap:3px;align-content:start;}
.cols-group > span:first-child{color:var(--ink-2);margin-bottom:4px;}

/* ---- records: grey first column, black second, year flush right ---- */
.records{display:grid;}
.record{
  display:grid;
  grid-template-columns:minmax(0,1fr) minmax(0,1fr) 56px;
  column-gap:var(--x);
  padding:7px 0 6px;
  line-height:var(--lh-text);
}
.record > :first-child{color:var(--ink-2);}
.record > :last-child{text-align:right;}
.records.is-ruled .record{border-top:1px solid var(--line);}
/* pairs: two columns, no year. People, where a join date would mislead. */
.records.is-pairs .record{grid-template-columns:repeat(2,minmax(0,1fr));}
.records.is-pairs .record > :last-child{text-align:left;}
/* people: the name in black, the role in grey on the right */
.records.is-people .record > :first-child{color:var(--ink);}
.records.is-people .record > :last-child{color:var(--ink-2);text-align:right;}
a.record{transition:color var(--dur-s) ease;}
@media (hover:hover){ a.record:hover > :nth-child(2){color:var(--ink-2);} }

/* ---- media: square corners, a grey wait ---- */
.media{background:var(--card);overflow:hidden;}
.media img,.media video{width:100%;height:100%;object-fit:cover;}
.media.is-portrait{aspect-ratio:4 / 5;}
.media.is-wide{aspect-ratio:16 / 9;}
.media.is-square{aspect-ratio:1;}

/* ---- work tile: the cover, then its name ----
   Two spellings of one tile. .work/.work/.work-name is the kit's own.
   .works-list/.work-index-card/.work-card/.work-row is the markup on
   work.html, which the build scripts read and write by exact
   class, so it keeps its names and takes this look. */
.works,.works-list{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--s-6) var(--x);}
.works-list{padding:0 var(--edge);}
/* a list that ends the page keeps its distance from what follows. Only here:
   a full-bleed section like the capabilities should touch the closing box. */
main > .works-list:last-child{padding-bottom:var(--row-gap);}
.work,.work-index-card{display:grid;gap:var(--s-2);align-content:start;}
.work-index-card[hidden]{display:none;}
.work-card{background:var(--card);overflow:hidden;aspect-ratio:4 / 5;}
.work-card img{width:100%;height:100%;object-fit:cover;transition:opacity .5s ease;}
.work-name,.work-row{display:flex;justify-content:space-between;gap:var(--x);line-height:var(--lh-tight);}
.work-name > :last-child:not(:first-child),.work-row > :last-child:not(:first-child){color:var(--ink-2);text-align:right;}
@media (hover:hover){ .work:hover .work-name > :first-child,.work-index-card:hover .work-row > :first-child{color:var(--ink-2);} }
.work-index-card.is-soon{pointer-events:none;}
/* the name only: .cat stays in the card for the scripts that read it */
.work-row .cat{display:none;}

/* four across: a short run of related work */
.works.is-4{grid-template-columns:repeat(4,minmax(0,1fr));}

/* ---- steps: a number, a name, the line under it ----
   The svc-step class beside .step is read by scripts/build-md.py. */
.steps{display:grid;}
.step{
  display:grid;grid-template-columns:repeat(9,minmax(0,1fr));column-gap:var(--x);
  border-top:1px solid var(--line);padding:7px 0 var(--s-5);line-height:var(--lh-text);
}
.step > .n{grid-column:span 1;color:var(--ink-2);font-variant-numeric:tabular-nums;}
.step > div{grid-column:span 8;display:grid;grid-template-columns:repeat(8,minmax(0,1fr));column-gap:var(--x);}
.step h3{grid-column:span 3;}
.step p{grid-column:span 5;color:var(--ink-3);max-width:var(--measure);}

/* ---- a real list: one line each, ruled ---- */
.list-ruled{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));column-gap:var(--x);line-height:var(--lh-text);}
.list-ruled li{border-top:1px solid var(--line);padding:7px 0 var(--s-3);}

/* ---- a bar of switches above a list ---- */
.bar{display:flex;flex-wrap:wrap;justify-content:space-between;gap:var(--s-3);padding:0 var(--edge);margin-bottom:var(--s-5);}

/* ---- pill switch, from GAA: filters, sub-pages ---- */
.pills{justify-self:start;align-self:start;display:inline-flex;flex-wrap:wrap;gap:var(--s-0);padding:var(--s-0);background:var(--card-2);border-radius:var(--r-pill);}
.pills button{
  min-height:32px;
  padding:0 var(--s-3);
  border-radius:var(--r-pill);
  color:var(--ink-3);
  line-height:var(--lh-tight);
  transition:background-color var(--dur-s) ease, color var(--dur-s) ease, box-shadow var(--dur-s) ease;
}
.pills button[aria-pressed="true"]{background:var(--raise);color:var(--ink);box-shadow:var(--shadow-pill);}
@media (hover:hover){ .pills button:hover:not([aria-pressed="true"]){color:var(--ink);} }
.pills button:active{transform:scale(var(--press));}

/* ---- note card, from GAA: once a page at most ---- */
.note{background:var(--card);border-radius:var(--r);padding:var(--s-3);display:grid;gap:var(--s-3);max-width:420px;}
.note-head{background:var(--card-2);border-radius:var(--r-sm);padding:9px 10px 8px;}
.note p{color:var(--ink-3);line-height:var(--lh-text);padding:0 var(--s-1) var(--s-1);}

/* ---- button: one solid per page, the rest quiet ---- */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:var(--s-2);
  min-height:40px;padding:0 var(--s-4);
  border-radius:var(--r-pill);
  background:var(--card-2);color:var(--ink);
  line-height:var(--lh-tight);
  transition:background-color var(--dur-s) ease, opacity var(--dur-s) ease;
}
.btn.is-solid{background:var(--ink);color:var(--bg);}
@media (hover:hover){
  .btn:hover:not([disabled],[aria-disabled="true"]){background:color-mix(in srgb, var(--card-2) 82%, var(--ink));}
  .btn.is-solid:hover:not([disabled],[aria-disabled="true"]){background:color-mix(in srgb, var(--ink) 80%, var(--bg));}
}
.btn:active:not([disabled],[aria-disabled="true"]){transform:scale(var(--press));}
.btn[aria-busy="true"]{pointer-events:none;color:transparent;position:relative;}
.btn[aria-busy="true"]::after{
  content:'';position:absolute;width:14px;height:14px;border-radius:50%;
  border:1.5px solid var(--bg);border-right-color:transparent;animation:spin .7s linear infinite;
}
.btn:not(.is-solid)[aria-busy="true"]::after{border-color:var(--ink);border-right-color:transparent;}
@keyframes spin{to{transform:rotate(360deg);}}

/* ---- field: label above, a filled grey box, no outline ----
   No edge at any time. The box is told apart from the page by its
   fill, focus by the fill going one step darker, an error by the red
   words under it. */
.field{display:grid;gap:var(--s-2);max-width:520px;}
.field > span:first-child,.field > label:first-child{color:var(--ink-2);}
.field-hint{color:var(--ink-3);line-height:var(--lh-text);}
.input{
  width:100%;min-height:44px;padding:14px var(--s-3) 13px;
  border:0;border-radius:var(--r);
  background:var(--field);
  line-height:var(--lh-text);
  caret-color:var(--ink);
  -webkit-appearance:none;appearance:none;
  transition:background-color var(--dur-s) ease;
}
textarea.input{min-height:140px;resize:none;}
.input::placeholder{color:var(--ink-3);opacity:1;transition:color var(--dur-s) ease;}
@media (hover:hover){ .input:hover:not(:focus){background:color-mix(in srgb, var(--field) 60%, var(--card-2));} }
.input:focus,.input:focus-visible{outline:none;background:var(--card-2);}
.input:focus::placeholder{color:transparent;}
.input:-webkit-autofill{-webkit-box-shadow:0 0 0 100px var(--field) inset;-webkit-text-fill-color:var(--ink);}
.field-msg{color:var(--no);line-height:var(--lh-text);}
/* a native select dressed as a field, with a small chevron of its own */
select.input:invalid{color:var(--ink-3);}
select.input{
  padding-right:var(--s-7);cursor:pointer;
  background-image:linear-gradient(45deg,transparent 50%,var(--ink-2) 50%),linear-gradient(135deg,var(--ink-2) 50%,transparent 50%);
  background-position:right 19px center,right 14px center;
  background-size:5px 5px;background-repeat:no-repeat;
}
/* a file picked by pressing the whole box */
.input.is-file{display:flex;align-items:center;cursor:pointer;color:var(--ink-3);}
.input.is-file.has-file{color:var(--ink);}
.input.is-file input{position:absolute;width:1px;height:1px;opacity:0;pointer-events:none;}

/* ---- a form laid out in two columns; .is-full takes both ---- */
.fields{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--s-5) var(--x);max-width:800px;}
.fields > .field{max-width:none;}
.fields > .is-full{grid-column:1 / -1;}
.form-end{display:grid;gap:var(--s-3);justify-items:start;}
.form-end p{color:var(--ink-3);line-height:var(--lh-text);max-width:var(--measure);}
.hp{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden;}

/* ---- choices: one of a few, as pills you press ----
   Real radio buttons underneath, so the form, its validation and the
   keyboard all work as they always did. */
.choices{display:flex;flex-wrap:wrap;gap:var(--s-1);}
.choices label{position:relative;display:inline-flex;align-items:center;min-height:36px;padding:0 var(--s-3);border-radius:var(--r-pill);background:var(--field);color:var(--ink-3);cursor:pointer;line-height:var(--lh-tight);transition:background-color var(--dur-s) ease,color var(--dur-s) ease;}
.choices input{position:absolute;opacity:0;width:1px;height:1px;}
.choices label:has(input:checked){background:var(--ink);color:var(--bg);}
.choices label:has(input:focus-visible){outline:2px solid var(--ink);outline-offset:2px;}
@media (hover:hover){ .choices label:hover:not(:has(input:checked)){color:var(--ink);} }
.choices label:active{transform:scale(var(--press));}

/* ---- questions and answers: ruled, question left, answer right ----
   The qa-* names are read by scripts/build-md.py. */
.qa{display:grid;}
.qa-row{display:grid;grid-template-columns:repeat(9,minmax(0,1fr));column-gap:var(--x);border-top:1px solid var(--line);padding:7px 0 var(--s-5);line-height:var(--lh-text);}
.qa-q{grid-column:span 3;}
.qa-a{grid-column:span 6;color:var(--ink-3);max-width:var(--measure);display:grid;gap:var(--s-2);}

/* ---- status: one line, a dot ---- */
.status{display:inline-flex;align-items:center;gap:var(--s-2);}
.status::before{content:'';width:6px;height:6px;border-radius:50%;background:var(--yes);}
.status.is-no::before{background:var(--no);}

/* ---- screen states ---- */
.skel{background:var(--card);animation:pulse 1.4s ease-in-out infinite;}
.skel.is-line{height:11px;border-radius:2px;}
@keyframes pulse{50%{opacity:.55;}}
.empty{display:grid;gap:var(--s-3);justify-items:start;line-height:var(--lh-text);max-width:var(--measure);}
