/* Components — the outro, modals, contact form, footer */

/* ===== THE OUTRO: THE SYSTEM + THE LINE IN =====
   One centred column: the sign-off, then the email address, then the Line
   In faceplate standing on its shelf.

   This section has been through three arrangements. The speakers first sat
   in a band of their own above the form, which ended the page on two
   separate sign-offs; then they flanked the faceplate as a rig, which
   fixed that but made the outro the most elaborate thing on a page about
   analytics work. They are gone. The email address — the single most
   important thing here — now has nothing competing with it. */
.contact{padding:clamp(64px,8vw,100px) 0 clamp(72px,9vw,110px);border-top:1px solid var(--rule-soft);}

/* ---- the sign-off ----
   One block, one heading. There were two: a .sec-head reading "The system
   / Thanks for listening." and then a second eyebrow + heading pair
   reading "Requests / Let's talk." twenty-odd pixels below it, with the
   hardware under that again. Three titled stacks in a row made the page
   look like it ended three separate times, and the eye had to restart at
   each one.

   The steps below are deliberately small — 12 / 18 / 26 / 30 / 24 — so the
   whole run reads as one column of related things rather than as blocks
   with air between them. The only large gap in the section is the one
   below this block, before the faceplate, because that genuinely is a
   different kind of object. */
.contact-lead{
  text-align:center;max-width:62ch;margin:0 auto clamp(44px,6vw,72px);
}
.contact-lead .eyebrow{justify-content:center;}
.contact-lead h2{
  font-family:'Bricolage Grotesque',sans-serif;font-weight:600;
  font-size:clamp(28px,4.2vw,44px);line-height:1.08;letter-spacing:-0.025em;
  margin:12px 0 0;
}
.contact-lead .lede{
  color:var(--manila-dim);font-size:17px;line-height:1.62;
  max-width:56ch;margin:18px auto 0;
}
/* The level meter sits inside the run rather than closing off a block of
   its own, so it takes a tighter margin than it had as the last thing in
   a section head. */
.contact-lead .spk-waves{margin-top:26px;}
.contact-lead .big-link{margin-top:30px;}
.contact-lead .social-row{margin-top:24px;justify-content:center;}

/* ---- the rig ----
   One centred column. This was a three-column grid with a speaker cabinet
   either side; the pair read as the loudest thing on the page and has been
   removed. Kept as a grid rather than flattened to a margin so the shelf
   still has a positioned row to sit under and the widths below still
   apply. No perspective any more — nothing in here is 3D. */
.rig-row{
  position:relative;
  display:grid;
  grid-template-columns:minmax(0,470px);
  grid-template-areas:"form";
  justify-content:center;align-items:end;
  padding-bottom:34px;
}
/* Sized to the faceplate now, not to the old three-object rig. At 940px
   it ran well past both edges of a single 470px unit and read as a stray
   rule across the page rather than as the shelf it stands on. */
.rig-shelf{
  position:absolute;left:50%;bottom:30px;
  width:min(600px,96%);height:1px;transform:translateX(-50%);
  background:linear-gradient(90deg,transparent,var(--rule) 14%,var(--rule) 86%,transparent);
  pointer-events:none;
}
.rig-shelf::after{
  content:'';position:absolute;left:0;right:0;top:1px;height:28px;
  background:linear-gradient(180deg,var(--fill-2),transparent);
}
.line-in{grid-area:form;position:relative;z-index:1;}

/* The .speaker / .spk-baffle / .tweeter / .woofer / .spk-badge blocks used
   to live here — a matched pair of walnut cabinets either side of the
   faceplate. Removed at Kyle's request: they were the loudest object in
   the outro and pulled attention off the work above it.
   .spk-waves below is NOT part of that — it is the little level meter
   under "Thanks for listening." and it stays. */
.spk-waves{display:flex;align-items:flex-end;justify-content:center;gap:4px;height:20px;margin-top:18px;}
.spk-waves i{
  width:3px;border-radius:2px;background:var(--brass-ink);display:block;
  animation:spkBar ease-in-out infinite alternate;opacity:.7;
}
@keyframes spkBar{from{height:4px;}to{height:18px;}}

/* Full width on a phone, and no shelf — a 1px rule under a full-bleed
   faceplate reads as a stray line rather than as a shelf. */
@media(max-width:860px){
  .rig-row{
    grid-template-columns:minmax(0,1fr);
    justify-content:stretch;
    padding-bottom:30px;
  }
  .rig-shelf{display:none;}
}

/* ===== MODALS ===== */
/* The "now playing" card that used to sit between a selector press and the
   project itself is gone — selectors open the project directly, so its
   styles went with its markup. .full-overlay below is the project view. */
.full-overlay{
  position:fixed;inset:0;background:var(--wax);z-index:300;overflow-y:auto;
  opacity:0;pointer-events:none;transition:opacity .4s var(--ease);
}
.full-overlay.is-open{opacity:1;pointer-events:auto;}
.full-close{
  position:fixed;top:20px;right:26px;width:38px;height:38px;border-radius:50%;
  background:var(--fill-2);border:1px solid var(--rule);
  color:var(--manila);font-size:16px;display:flex;align-items:center;justify-content:center;z-index:310;
}
.full-inner{max-width:740px;margin:0 auto;padding:86px 26px 96px;}
.full-code{
  font-family:'Courier Prime',monospace;font-size:12px;letter-spacing:.18em;
  text-transform:uppercase;margin-bottom:14px;
  /* A project's accent is picked to glow on a lamp, not to be read on
     paper. Mixing it toward the ink keeps each project's identity
     while making the label legible. */
  color:color-mix(in srgb, var(--accent,var(--brass)) 64%, var(--ink-mix));
}
.full-inner h2{
  font-family:'Bricolage Grotesque',sans-serif;font-weight:800;
  font-size:clamp(28px,5vw,46px);line-height:1.08;letter-spacing:-0.03em;margin-bottom:8px;
}
.full-real{font-family:'Courier Prime',monospace;font-size:13.5px;color:var(--manila-soft);margin-bottom:28px;}
.full-art{
  width:100%;height:220px;border-radius:6px;margin-bottom:34px;
  background:linear-gradient(140deg,var(--accent,var(--brass)) 0%,transparent 72%),
             linear-gradient(180deg,#241C17,#171210);
  opacity:.9;
}
/* Project pictures. Set images:[...] on a project in 02-data.js and the
   banner becomes a gallery. Nothing is cropped: the frame follows the
   picture rather than forcing every screenshot into one shape. */
.full-art.has-img{
  height:auto;background:none;opacity:1;border:0;margin-bottom:14px;
}
.full-art:not(.has-img) .art-frame{display:none;}

.art-frame{
  position:relative;display:flex;align-items:center;justify-content:center;
  width:fit-content;max-width:100%;margin:0 auto;
  border-radius:6px;overflow:hidden;
  background:#171210;
  border:1px solid rgba(227,211,179,.14);
  box-shadow:0 18px 44px rgba(0,0,0,.45);
}
.art-frame.is-loading{min-height:200px;width:100%;}
.art-img{display:block;width:auto;height:auto;max-width:100%;}

/* Wide shots fill the column; tall ones are capped by height so a phone
   screenshot can't push the write-up off the screen. Both keep their own
   proportions — max-width and max-height together never distort. */
.art-frame.is-landscape .art-img{max-height:min(58vh,540px);}
.art-frame.is-portrait  .art-img{max-height:min(74vh,760px);}

/* Arrows only exist when there is more than one picture to move between. */
.art-nav{
  position:absolute;top:50%;transform:translateY(-50%);
  width:40px;height:40px;border-radius:50%;
  display:none;align-items:center;justify-content:center;
  font-size:24px;line-height:1;padding-bottom:3px;
  color:var(--panel-ink);
  background:rgba(12,10,8,.72);
  border:1px solid rgba(227,211,179,.22);
  -webkit-backdrop-filter:blur(3px);backdrop-filter:blur(3px);
  cursor:pointer;z-index:2;
  transition:background .16s ease,border-color .16s ease,transform .16s ease;
}
.full-art.is-multi .art-nav{display:flex;}
.art-prev{left:10px;}
.art-next{right:10px;}
.art-nav:hover{background:rgba(12,10,8,.94);border-color:var(--accent,var(--brass));}
.art-nav:active{transform:translateY(-50%) scale(.94);}

.art-count{
  position:absolute;top:10px;right:10px;display:none;z-index:2;
  font-family:'Courier Prime',monospace;font-size:11px;letter-spacing:.1em;
  padding:4px 9px;border-radius:999px;
  color:var(--panel-ink);
  background:rgba(12,10,8,.72);
  border:1px solid rgba(227,211,179,.18);
}
.full-art.is-multi .art-count{display:block;}

@media(max-width:620px){
  .art-nav{width:34px;height:34px;font-size:20px;}
  .art-prev{left:6px;}
  .art-next{right:6px;}
  .art-frame.is-portrait .art-img{max-height:min(66vh,640px);}
}
@media(prefers-reduced-motion:reduce){
  .art-nav{transition:none;}
}
.full-cap{
  font-family:'Courier Prime',monospace;font-size:11.5px;line-height:1.6;
  color:var(--manila-soft);margin:-4px 0 32px;
}
.full-cap[hidden]{display:none;}
.full-block{margin-bottom:30px;}
.full-block h3{
  font-family:'Courier Prime',monospace;font-size:11px;letter-spacing:.18em;
  text-transform:uppercase;color:var(--brass-ink);margin-bottom:10px;
}
.full-block p{font-size:17px;color:var(--manila-dim);line-height:1.72;max-width:62ch;}
.full-block ul{list-style:none;display:flex;flex-direction:column;gap:9px;}
.full-block li{font-size:16.5px;line-height:1.6;color:var(--manila-dim);padding-left:20px;position:relative;}
.full-block li::before{
  content:'';position:absolute;left:0;top:10px;width:7px;height:7px;border-radius:50%;
  background:color-mix(in srgb, var(--accent,var(--brass)) 70%, var(--ink-mix));
}
.full-tags{display:flex;gap:9px;flex-wrap:wrap;margin-bottom:34px;}
.full-tags span{
  font-family:'Courier Prime',monospace;font-size:11.5px;padding:6px 13px;border-radius:3px;
  background:var(--fill-2);border:1px solid var(--rule);
}
.full-actions{display:flex;gap:13px;flex-wrap:wrap;}

/* ===== CONTACT (metal + wood) ===== */
/* .contact-grid is gone: the outro is one centred column with the rig
   at the bottom, so there is no two-column split any more. */
.big-link{
  font-family:'Bricolage Grotesque',sans-serif;font-weight:600;font-size:clamp(19px,2.6vw,26px);
  display:inline-flex;align-items:center;gap:12px;border-bottom:1px solid var(--rule-strong);
  padding-bottom:7px;transition:gap .3s var(--ease),border-color .3s var(--ease);
  letter-spacing:-0.02em;word-break:break-all;
}
.big-link:hover{gap:20px;border-color:var(--brass-ink);}
/* Icons as well as words — the row was three identical pieces of text and
   people skimming for a resume link slid straight past it. Generated by
   03-utils.js from LINKS in 01-config.js. */
.social-row{
  display:flex;gap:10px;margin-top:26px;flex-wrap:wrap;
  font-family:'Courier Prime',monospace;font-size:13px;
}
.soc-link{
  display:inline-flex;align-items:center;gap:9px;
  padding:9px 15px;border-radius:100px;line-height:1;
  border:1px solid var(--rule);
  background:var(--fill-1);
  color:var(--manila);
  transition:transform .2s var(--ease),background .25s var(--ease),
             border-color .25s var(--ease),color .25s var(--ease),
             box-shadow .25s var(--ease);
}
/* Brand colour on the glyph, neutral pill. On paper these can be the
   real brand values — the lightened set they used to carry only existed
   because they were sitting on near-black. */
.soc-link[data-key="linkedin"]{--brand:#0A66C2;}
.soc-link[data-key="github"]  {--brand:#1B1F23;}
.soc-link[data-key="resume"]  {--brand:#6E5A32;}
.soc-link[data-key="email"]   {--brand:#9A6E1C;}
.soc-link[data-key="discogs"] {--brand:#333333;}
.soc-link svg{
  width:18px;height:18px;display:block;flex-shrink:0;
  color:var(--brand,var(--manila));
  fill:none;stroke:currentColor;stroke-width:1.7;
  stroke-linecap:round;stroke-linejoin:round;
  transition:color .25s var(--ease);
}
.soc-link:hover,.soc-link:focus-visible{
  transform:translateY(-2px);
  color:var(--brass-ink);border-color:var(--brass-line);
  background:var(--brass-tint);
  box-shadow:0 8px 20px -12px rgba(138,99,20,.55);
}
/* The hover rule used to end in outline:none, which silently took the
   focus ring off these links as well — the one place a keyboard user
   most needs one, since they are the contact links. */
.soc-link:focus-visible{
  outline:2px solid var(--brass-ink);outline-offset:3px;
}
.soc-link:active{transform:translateY(0);}
@media (prefers-reduced-motion:reduce){
  .soc-link:hover,.soc-link:focus-visible{transform:none;}
}
form{display:flex;flex-direction:column;gap:17px;position:relative;z-index:2;}
.field{display:flex;flex-direction:column;gap:6px;}
.field label{
  font-family:'Barlow Semi Condensed',sans-serif;text-transform:uppercase;
  letter-spacing:.2em;font-size:9.5px;font-weight:600;color:var(--engrave-dim);
}
/* No outline:none here. It used to be, and at (0,1,1) it beat the global
   :focus-visible rule at (0,1,0) — so the three fields a keyboard user
   has to get through were the only controls on the page with no focus
   ring, and the box-shadow standing in for it measured about 1.4:1
   against the aluminium. Third time this exact accident has turned up. */
.field input,.field textarea{
  background:linear-gradient(180deg,#8E9298,#A8ACB1);border:1px solid rgba(0,0,0,.4);
  border-radius:2px;padding:11px 12px;font-family:'Karla',sans-serif;font-size:15px;
  color:#16181A;resize:none;box-shadow:inset 0 2px 5px rgba(0,0,0,.35);
  transition:box-shadow .3s var(--ease);
}
.field input::placeholder,.field textarea::placeholder{color:rgba(22,24,26,.45);}
.field input:focus,.field textarea:focus{
  box-shadow:inset 0 2px 5px rgba(0,0,0,.35),0 0 0 2px rgba(26,26,23,.65);
}
.field input:focus-visible,.field textarea:focus-visible{
  outline:2px solid #1A1A17;outline-offset:1px;
}
.btn-plate{
  font-family:'Barlow Semi Condensed',sans-serif;text-transform:uppercase;
  letter-spacing:.16em;font-size:11.5px;font-weight:600;padding:13px 24px;border-radius:3px;
  background:linear-gradient(180deg,#F3BC5E,#D08F2E);color:#241703;
  border:1px solid rgba(0,0,0,.45);align-self:flex-start;
  box-shadow:0 1px 0 rgba(255,255,255,.5) inset,0 3px 8px rgba(0,0,0,.35);
  transition:transform .12s var(--ease),opacity .2s var(--ease);
}
.btn-plate:hover{transform:translateY(-1px);}
.btn-plate:active{transform:translateY(2px);box-shadow:0 1px 4px rgba(0,0,0,.5) inset;}
.btn-plate:disabled{opacity:.55;cursor:not-allowed;transform:none;}
.form-status{
  font-family:'Barlow Semi Condensed',sans-serif;text-transform:uppercase;
  letter-spacing:.14em;font-size:10px;font-weight:600;min-height:15px;
  color:var(--engrave-dim);display:flex;align-items:center;gap:7px;
}
.form-status.ok{color:#1E6B45;}
.form-status.err{color:#8E2B23;}
.form-status .fs-dot{width:6px;height:6px;border-radius:50%;background:currentColor;flex-shrink:0;}

footer{border-top:1px solid var(--rule);padding:30px 0;font-family:'Courier Prime',monospace;font-size:11.5px;color:var(--manila-soft);}
footer .wrap{display:flex;justify-content:space-between;flex-wrap:wrap;gap:12px;align-items:center;}
.foot-disc{
  width:14px;height:14px;border-radius:50%;display:inline-block;vertical-align:-2px;margin-right:7px;
  background:repeating-radial-gradient(circle at center,#0b0908 0 2px,#241d19 2px 4px);
  animation:grooveSpin 4s linear infinite;
}

:focus-visible{outline:2px solid var(--brass-ink);outline-offset:3px;}
/* --brass-ink is #7A5B22 on paper and #D9A74C in dark mode. On paper that
   ring is fine everywhere. In dark mode it lands on the controls that are
   mounted on metal — the scope panel and the faceplate, neither of which
   flips — where #D9A74C over #BCC0C5 is about 1.2:1 and the ring is
   effectively gone. Those get the dark engraved ring in both modes. */
.sc-chip:focus-visible,.sc-knob:focus-visible,
.sc-toggle:focus-visible,.sc-min:focus-visible,
.btn-plate:focus-visible{
  outline:2px solid #1A1A17;outline-offset:2px;
}
/* Brand logos are filled paths, not strokes. */
.soc-link svg.ico-solid{stroke:none;}
.soc-link svg.ico-solid path{fill:currentColor;stroke:none;}