/* Act IV — the offerings procession, CARD department.
 *
 * Scoped to [data-act="offerings"] and its descendants, plus the .basket and
 * .closing-proof blocks that live in #contact (the brief explicitly extends
 * this file's scope to those two — the basket is filled by buttons in this
 * act, and the closing-proof block was relocated here from the section this
 * act now occupies).
 *
 * Nothing here changes a dimension css/stage.css already reserved. The
 * section height and the pin/static split are structural and frozen there;
 * this file is presentation and behaviour only, and the CLS gate for it is
 * exactly zero — including while a card is open and while the basket fills.
 */

/* --- the readable list -----------------------------------------------------
 * The DOM is a complete, static document; the GL wall is a treatment drawn
 * over it. With GL running the list steps out of the way visually while
 * staying in the accessibility tree and the tab order — opacity: 0.001, not
 * visibility: hidden and not display: none. With GL off (the default in the
 * markup, and what a no-WebGL or no-JS visitor always gets) it is the
 * section: a long, calm, readable run of twelve offerings. */
[data-act="offerings"] .offer-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: clamp(22px, 3vw, 40px);
  max-width: var(--measure);
  opacity: 1;
  transition: opacity 200ms ease-out;
}
html[data-gl="on"] [data-act="offerings"] .offer-list {
  opacity: 0.001;
  pointer-events: none;
}
@media (prefers-reduced-motion: reduce) {
  [data-act="offerings"] .offer-list { transition: none; }
}

[data-act="offerings"] .offer {
  position: relative;
  padding: clamp(18px, 2.4vw, 28px) clamp(18px, 2.4vw, 26px) clamp(18px, 2.4vw, 26px) clamp(52px, 7vw, 68px);
  background: var(--ink-2);
  border: 1px solid var(--line-2);
  border-radius: 4px;
  cursor: pointer;
  transform: translateY(0) scale(1);
  transition: border-color 220ms ease-out, background-color 220ms ease-out, transform 220ms ease-out;
}
[data-act="offerings"] .offer:hover,
[data-act="offerings"] .offer:focus-within {
  border-color: var(--aurora-dim);
  transform: translateY(-3px);
  transition: border-color 300ms cubic-bezier(.28,1.5,.5,1), background-color 300ms cubic-bezier(.28,1.5,.5,1),
              transform 360ms cubic-bezier(.28,1.5,.5,1);
}
[data-act="offerings"] .offer:active {
  transform: translateY(-1px) scale(0.985);
  transition: transform 120ms ease-out;
}
[data-act="offerings"] .offer[data-centre] {
  border-color: var(--aurora);
}
@media (prefers-reduced-motion: reduce) {
  [data-act="offerings"] .offer { transition: none; transform: none !important; }
}

[data-act="offerings"] .offer__n {
  position: absolute;
  top: clamp(18px, 2.4vw, 28px);
  left: clamp(18px, 2.4vw, 26px);
  margin: 0;
  font-family: var(--mono);
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--aurora-dim);
  font-variant-numeric: tabular-nums;
}

[data-act="offerings"] .offer h3 {
  margin: 0 0 8px;
  font-size: clamp(1.05rem, 1.4vw + 0.7rem, 1.4rem);
}
[data-act="offerings"] .offer h3 a {
  color: var(--paper);
  text-decoration: none;
}
[data-act="offerings"] .offer h3 a:hover,
[data-act="offerings"] .offer h3 a:focus-visible {
  color: var(--aurora);
}

[data-act="offerings"] .offer__owner {
  margin: 0 0 14px;
  color: var(--paper-dim);
  max-width: 52ch;
}

[data-act="offerings"] .offer__meta {
  margin: 0 0 14px;
  display: flex;
  flex-wrap: wrap;
  gap: 8px 14px;
}
[data-act="offerings"] .offer__pkg,
[data-act="offerings"] .offer__upkeep {
  font-family: var(--mono);
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}
[data-act="offerings"] .offer__pkg {
  color: var(--ink);
  background: var(--aurora);
  padding: 3px 8px;
  border-radius: 2px;
  font-weight: 600;
}
[data-act="offerings"] .offer__pkg--addon {
  color: var(--signal);
  background: transparent;
  border: 1px solid var(--signal);
  padding: 2px 7px;
}
[data-act="offerings"] .offer__upkeep,
[data-act="offerings"] .offer__sep {
  align-self: center;
  color: var(--paper-faint);
}

[data-act="offerings"] .offer__add { margin: 0; }
[data-act="offerings"] .offer__addbtn {
  font-family: var(--mono);
  font-size: 0.7rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--paper);
  background: transparent;
  border: 1px solid var(--line-2);
  border-radius: 2px;
  padding: 9px 14px;
  cursor: pointer;
  min-height: 44px;
  transform: translateY(0) scale(1);
  transition: border-color 200ms ease-out, color 200ms ease-out,
              background-color 200ms ease-out, transform 200ms ease-out;
}
[data-act="offerings"] .offer__addbtn:hover,
[data-act="offerings"] .offer__addbtn:focus-visible {
  border-color: var(--aurora);
  color: var(--aurora);
  transform: translateY(-2px);
  transition: border-color 260ms cubic-bezier(.28,1.5,.5,1), color 260ms cubic-bezier(.28,1.5,.5,1),
              background-color 260ms cubic-bezier(.28,1.5,.5,1), transform 320ms cubic-bezier(.28,1.5,.5,1);
}
[data-act="offerings"] .offer__addbtn:active {
  transform: translateY(0) scale(0.94);
  transition: transform 120ms ease-out;
}
[data-act="offerings"] .offer__addbtn.is-added {
  border-color: var(--aurora);
  color: var(--aurora);
  background: rgba(79, 216, 196, 0.10);
}
@media (prefers-reduced-motion: reduce) {
  [data-act="offerings"] .offer__addbtn { transition: none; transform: none !important; }
}

/* --- no-WebGL ground -------------------------------------------------------
 * Set by js/acts/offerings.js's fallback(); a quiet static ground rather
 * than nothing, same idea as [data-act="work"][data-act-state="static"]. */
[data-act="offerings"][data-act-state="static"] {
  background: radial-gradient(ellipse 70% 55% at 50% 10%, rgba(79, 216, 196, 0.08), transparent 65%);
}

/* --- the overlay card -------------------------------------------------------
 * Same shape as [data-act="work"] .work-overlay in css/act-work.css: fixed,
 * built once, starts hidden so its own insertion cannot be the shift the CLS
 * gate forbids, opens/closes on the [data-open] attribute rather than a
 * class toggle mid-animation. */
[data-act="offerings"] .offer-overlay {
  position: fixed;
  inset: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: clamp(16px, 4vw, 48px);
}
[data-act="offerings"] .offer-overlay[hidden] { display: none; }

[data-act="offerings"] .offer-overlay__backdrop {
  position: absolute;
  inset: 0;
  background: rgba(5, 9, 12, 0.86);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  opacity: 0;
  transition: opacity 200ms ease-out;
}
[data-act="offerings"] .offer-overlay[data-open] .offer-overlay__backdrop {
  opacity: 1;
  transition: opacity 280ms cubic-bezier(.34,.9,.4,1);
}

/* The panel opens FROM the card that was clicked, not over the top of it.
 * card.js reads the clicked panel's on-screen rect and writes --card-ox,
 * --card-oy (its centre, relative to the viewport centre) and --card-scale
 * (its footprint against the overlay's real footprint) onto this element
 * before it sets [data-open] — so the panel's rest state below is "sitting
 * where the card was", and turning [data-open] on or off is the whole
 * transition. Transform and opacity only; the panel's box is always
 * min(560px, 100%) wide from the moment it exists, so this never touches
 * layout or the CLS gate. */
[data-act="offerings"] .offer-overlay__panel {
  position: relative;
  z-index: 1;
  width: min(560px, 100%);
  max-height: 88vh;
  overflow-y: auto;
  padding: clamp(28px, 4vw, 44px) clamp(24px, 4vw, 40px);
  background: var(--ink-2);
  border: 1px solid var(--line-2);
  border-radius: 4px;
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.45);
  opacity: 0;
  transform-origin: center center;
  transform: translate(var(--card-ox, 0), var(--card-oy, 0)) scale(var(--card-scale, 0.4));
  /* Leaving: faster than it arrives, plain ease-out. */
  transition: opacity 220ms ease-out, transform 260ms ease-out;
}
[data-act="offerings"] .offer-overlay[data-open] .offer-overlay__panel {
  opacity: 1;
  transform: translate(0, 0) scale(1);
  /* Arriving: the house overshoot from mascot.css. */
  transition: opacity 340ms cubic-bezier(.34,.9,.4,1), transform 560ms cubic-bezier(.28,1.5,.5,1);
}
@media (prefers-reduced-motion: reduce) {
  [data-act="offerings"] .offer-overlay__panel,
  [data-act="offerings"] .offer-overlay__backdrop { transition: none; opacity: 1; transform: none; }
}

[data-act="offerings"] .offer-overlay__close {
  position: absolute;
  top: 16px;
  right: 16px;
  width: 40px;
  height: 40px;
  min-width: 44px;
  min-height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1rem;
  line-height: 1;
  color: var(--paper-dim);
  background: transparent;
  border: 1px solid var(--line-2);
  border-radius: 2px;
  cursor: pointer;
  transform: scale(1);
  transition: border-color 200ms ease-out, color 200ms ease-out, transform 200ms ease-out;
}
[data-act="offerings"] .offer-overlay__close:hover,
[data-act="offerings"] .offer-overlay__close:focus-visible {
  border-color: var(--aurora);
  color: var(--aurora);
  transform: scale(1.08);
  transition: border-color 260ms cubic-bezier(.28,1.5,.5,1), color 260ms cubic-bezier(.28,1.5,.5,1),
              transform 300ms cubic-bezier(.28,1.5,.5,1);
}
[data-act="offerings"] .offer-overlay__close:active {
  transform: scale(0.9);
  transition: transform 120ms ease-out;
}
@media (prefers-reduced-motion: reduce) {
  [data-act="offerings"] .offer-overlay__close { transition: none; transform: none !important; }
}

[data-act="offerings"] .offer-overlay__n {
  margin: 0 0 6px;
  font-family: var(--mono);
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--aurora-dim);
  font-variant-numeric: tabular-nums;
}
[data-act="offerings"] .offer-overlay__name {
  margin: 0 0 14px;
  padding-right: 40px;
  font-size: clamp(1.4rem, 2vw + 1rem, 1.9rem);
}
[data-act="offerings"] .offer-overlay__owner {
  margin: 0 0 20px;
  color: var(--paper-dim);
}
[data-act="offerings"] .offer-overlay__meta {
  margin: 0 0 26px;
  display: flex;
  flex-wrap: wrap;
  gap: 8px 14px;
}
[data-act="offerings"] .offer-overlay__add {
  width: 100%;
  min-height: 48px;
  justify-content: center;
}
[data-act="offerings"] .offer-overlay__add.is-added {
  background: transparent;
  border-color: var(--aurora);
  color: var(--aurora);
}
[data-act="offerings"] .offer-overlay__add:active {
  transform: scale(0.97);
  transition: transform 120ms ease-out;
}
@media (prefers-reduced-motion: reduce) {
  [data-act="offerings"] .offer-overlay__add { transform: none !important; }
}

/* --- tap targets ------------------------------------------------------------
 * 44px minimum on coarse pointers, per the standing rule this site has
 * already failed once. */
@media (pointer: coarse) {
  [data-act="offerings"] .offer { padding-block: 20px; }
  [data-act="offerings"] .offer h3 a { display: inline-block; min-height: 44px; padding-block: 8px; }
  [data-act="offerings"] .offer__addbtn { min-height: 48px; padding-inline: 18px; }
}

/* --- the basket, in #contact -------------------------------------------- *
 * Filled by the "Add to my project" buttons above, in this document — never
 * anywhere else. It is above the contact form and the CLS gate is exactly
 * zero, so its footprint is reserved from first paint whether or not it has
 * ever been used: [hidden] here means invisible, not display: none, and its
 * list scrolls internally past a fixed number of rows rather than growing
 * the box as items are added. Un-hiding it on first add and filling it
 * therefore never changes document height. */
#contact .basket {
  display: block;
  min-height: 168px;
  margin-bottom: var(--rhythm);
  padding: 16px clamp(18px, 2.4vw, 26px);
  background: var(--ink-2);
  border: 1px solid var(--line-2);
  border-radius: 4px;
  opacity: 0;
  pointer-events: none;
  transition: opacity 220ms ease-out;
}
#contact .basket[hidden] { display: block; }
#contact .basket:not([hidden]) {
  opacity: 1;
  pointer-events: auto;
  transition: opacity 320ms cubic-bezier(.34,.9,.4,1);
}
@media (prefers-reduced-motion: reduce) {
  #contact .basket { transition: none; }
}

#contact .basket__head {
  margin: 0 0 10px;
  font-family: var(--mono);
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--aurora);
}
#contact .basket__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  max-height: 108px;
  overflow-y: auto;
}
#contact .basket__item {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 6px 6px 12px;
  background: var(--ink);
  border: 1px solid var(--line-2);
  border-radius: 999px;
  font-size: 0.86rem;
  opacity: 1;
  transform: scale(1) translateY(0);
  transition: opacity 320ms cubic-bezier(.34,.9,.4,1), transform 460ms cubic-bezier(.28,1.5,.5,1);
}
/* The chip a card.js just added — held here at its pre-arrival size for one
 * frame, then released (see js/offerings/card.js), so it always plays the
 * transition above rather than simply existing. Every OTHER chip in the list
 * gets recreated on the same render pass with no modifier class at all, so it
 * never replays an arrival it already had. */
#contact .basket__item--enter {
  opacity: 0;
  transform: scale(0.5) translateY(8px);
  transition: none;
}
@media (prefers-reduced-motion: reduce) {
  #contact .basket__item { transition: none; }
  #contact .basket__item--enter { opacity: 1; transform: none; }
}
#contact .basket__remove {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  color: var(--paper-faint);
  background: transparent;
  border: 0;
  border-radius: 50%;
  cursor: pointer;
  font-size: 0.9rem;
  line-height: 1;
}
#contact .basket__remove {
  transition: color 200ms ease-out, background-color 200ms ease-out, transform 200ms ease-out;
}
#contact .basket__remove:hover,
#contact .basket__remove:focus-visible {
  color: var(--aurora);
  background: rgba(79, 216, 196, 0.12);
  transform: scale(1.12);
  transition: color 260ms cubic-bezier(.28,1.5,.5,1), background-color 260ms cubic-bezier(.28,1.5,.5,1),
              transform 300ms cubic-bezier(.28,1.5,.5,1);
}
#contact .basket__remove:active {
  transform: scale(0.85);
  transition: transform 120ms ease-out;
}
#contact .basket__empty {
  color: var(--paper-faint);
  font-size: 0.86rem;
}
@media (prefers-reduced-motion: reduce) {
  #contact .basket__remove { transition: none; transform: none !important; }
}

/* --- the basket ghost -----------------------------------------------------
 * The chip's "having travelled" cue: a small pill cloned from the button that
 * was pressed, appended to <body> so it can cross the whole page in position:
 * fixed (out of flow, no layout, no CLS), flown to roughly where the new chip
 * lands, and removed once it arrives. Purely decorative — aria-hidden, no
 * pointer-events, gone from the DOM well before anything could tab to it. */
.basket-ghost {
  position: fixed;
  z-index: 60;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
  font-family: var(--mono);
  font-size: 0.7rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink);
  background: var(--aurora);
  border-radius: 999px;
  padding: 0 4px;
  opacity: 0.95;
  transform: translate(0, 0) scale(1);
  will-change: transform, opacity;
}
.basket-ghost[data-fly] {
  transform: translate(var(--fly-dx, 0), var(--fly-dy, 0)) scale(0.35);
  opacity: 0;
  /* Departing fast, the same weight logic as everything else that leaves. */
  transition: transform 560ms cubic-bezier(.5,0,.6,1), opacity 460ms ease-out 100ms;
}
@media (prefers-reduced-motion: reduce) {
  .basket-ghost { display: none; }
}

/* --- the closing proof, demoted to a footnote --------------------------- *
 * The two concept builds and the measured-numbers panel are still true and
 * still important; they just moved out of the headline and into a compact
 * footnote to the contact section, so it should not read as a second full
 * section competing with "Tell us what the job is." */
#contact .closing-proof {
  margin-top: calc(var(--rhythm) * 1.4);
  padding-top: calc(var(--rhythm) * 1.1);
  border-top: 1px solid var(--line-2);
}
#contact .closing-proof__head {
  margin: 0 0 var(--rhythm);
  font-size: clamp(1rem, 1vw + 0.7rem, 1.2rem);
  color: var(--paper-dim);
  font-weight: 600;
}
/* The two concept builds.
 *
 * Three things were wrong with these and all three said the same thing about
 * the studio, which is the opposite of what is true:
 *
 *   1. Only the TITLE was clickable — a 200px target inside a 600px card. A
 *      visitor who clicked the screenshot, which is the obvious thing to
 *      click, got nothing. Fixed with a stretched link: the <a> is still one
 *      real <a href> that works with JS and CSS off, and its ::after covers
 *      the card, so the whole card is the target without a single extra
 *      element or a div pretending to be a button.
 *
 *   2. They were small, and small reads as a thumbnail of a template rather
 *      than a build you can open. They are now one per row, the screenshot
 *      sitting in a browser frame with the real URL in it, because what makes
 *      a screenshot read as a live site is the chrome around it.
 *
 *   3. They led with the framework. The framework is the least interesting
 *      thing about either of them. They now lead with what is behind the
 *      page — the endpoint, the server-side pricing, the lead that survives a
 *      dead inbox — because that is the half being paid for. The front end is
 *      table stakes and this section should stop implying otherwise.
 */
#contact .closing-proof__lede {
  margin: -6px 0 calc(var(--rhythm) * 0.9);
  max-width: 68ch;
  color: var(--paper-dim);
  font-size: clamp(0.95rem, 0.5vw + 0.82rem, 1.05rem);
  line-height: 1.62;
}

#contact .closing-proof .work-list {
  list-style: none;
  margin: 0 0 calc(var(--rhythm) * 0.9);
  padding: 0;
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(18px, 2.4vw, 30px);
}

#contact .closing-proof .work-card {
  position: relative;          /* the stretched link's containing block */
  padding: 0;
  background: var(--ink-2);
  border: 1px solid var(--line-2);
  border-radius: 6px;
  overflow: hidden;
  display: grid;
  grid-template-columns: 1fr;
  cursor: pointer;
  transition:
    border-color 220ms cubic-bezier(.22,.61,.36,1),
    transform 260ms cubic-bezier(.22,.61,.36,1),
    box-shadow 260ms cubic-bezier(.22,.61,.36,1);
}
#contact .closing-proof .work-card:hover,
#contact .closing-proof .work-card:focus-within {
  border-color: var(--aurora);
  transform: translateY(-2px);
  box-shadow: 0 18px 46px -28px rgba(0, 0, 0, 0.9);
}

/* Side by side once there is room for the screenshot to be worth seeing.
   Below that the screen sits on top, full width, which is the better shape on
   a phone anyway. */
@media (min-width: 860px) {
  #contact .closing-proof .work-card {
    grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
    align-items: stretch;
  }
}

/* --- the screen ---------------------------------------------------------- */
#contact .closing-proof .work-card__screen {
  position: relative;
  background: #0a0f14;
  border-bottom: 1px solid var(--line-2);
  min-width: 0;
}
@media (min-width: 860px) {
  #contact .closing-proof .work-card__screen {
    border-bottom: 0;
    border-right: 1px solid var(--line-2);
  }
}

/* The browser frame. Purely decorative and aria-hidden, but it is the thing
   that makes the image below read as a site rather than as a picture. */
#contact .closing-proof .work-card__chrome {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 9px 12px;
  background: rgba(255, 255, 255, 0.045);
  border-bottom: 1px solid var(--line-2);
}
#contact .closing-proof .work-card__dot {
  width: 8px; height: 8px; border-radius: 50%;
  background: rgba(232, 239, 242, 0.22);
  flex: none;
}
#contact .closing-proof .work-card__url {
  margin-left: 8px;
  font-family: var(--mono);
  font-size: 0.66rem;
  letter-spacing: 0.02em;
  color: var(--paper-faint);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* The capture is a whole page and the frame shows the top of it, so the cut at
   the bottom lands wherever it lands — mid-headline, as often as not. A short
   fade turns that from a bad crop into the obvious truth: the page carries on
   below, and clicking is how you see the rest. */
#contact .closing-proof .work-card__screen::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 44px;
  background: linear-gradient(to bottom, rgba(7, 11, 15, 0), rgba(7, 11, 15, 0.92));
  pointer-events: none;
}

#contact .closing-proof .work-card__poster {
  display: block;
  width: 100%;
  max-width: none;
  height: auto;
  margin: 0;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  object-position: top center;
  border: 0;
  opacity: 0.92;
  transition: opacity 260ms cubic-bezier(.22,.61,.36,1);
}
#contact .closing-proof .work-card:hover .work-card__poster,
#contact .closing-proof .work-card:focus-within .work-card__poster { opacity: 1; }

/* --- the body ------------------------------------------------------------ */
#contact .closing-proof .work-card__body {
  padding: clamp(18px, 2vw, 26px);
  min-width: 0;
  display: flex;
  flex-direction: column;
}
#contact .closing-proof .work-card h3 { margin: 6px 0 6px; font-size: clamp(1.1rem, 0.6vw + 0.95rem, 1.35rem); }

/* The stretched link. One real <a href> — no JS, no role="link" on a div —
   whose overlay turns the entire card into the hit area. */
#contact .closing-proof .work-card h3 a::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
}

#contact .closing-proof .work-card__job {
  margin: 0 0 14px;
  color: var(--paper-dim);
  font-size: 0.95rem;
}

#contact .closing-proof .work-card__behind-h {
  margin: 0 0 8px;
  font-family: var(--mono);
  font-size: 0.62rem;
  text-transform: uppercase;
  letter-spacing: 0.16em;
  color: var(--aurora);
}
#contact .closing-proof .work-card__behind {
  list-style: none;
  margin: 0 0 16px;
  padding: 0;
  display: grid;
  gap: 7px;
}
#contact .closing-proof .work-card__behind li {
  position: relative;
  margin: 0;
  padding-left: 16px;
  color: var(--paper-dim);
  font-size: 0.875rem;
  line-height: 1.5;
}
#contact .closing-proof .work-card__behind li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.58em;
  width: 5px; height: 5px;
  border-radius: 50%;
  background: var(--aurora);
  opacity: 0.7;
}
#contact .closing-proof .work-card__behind code {
  font-family: var(--mono);
  font-size: 0.92em;
  color: var(--paper);
}

#contact .closing-proof .work-card__tech {
  margin: auto 0 12px;
  padding-top: 12px;
  border-top: 1px solid var(--line-2);
  font-family: var(--mono);
  font-size: 0.68rem;
  color: var(--paper-faint);
}

/* The affordance. Not a button — the whole card is already the control — just
   the visible promise that clicking does something. */
#contact .closing-proof .work-card__open {
  margin: 0;
  font-family: var(--mono);
  font-size: 0.7rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--aurora);
}
#contact .closing-proof .work-card__open span::after {
  content: " \2192";
  display: inline-block;
  transition: transform 220ms cubic-bezier(.22,.61,.36,1);
}
#contact .closing-proof .work-card:hover .work-card__open span::after {
  transform: translateX(4px);
}

@media (prefers-reduced-motion: reduce) {
  #contact .closing-proof .work-card,
  #contact .closing-proof .work-card__poster,
  #contact .closing-proof .work-card__open span::after { transition: none; }
  #contact .closing-proof .work-card:hover,
  #contact .closing-proof .work-card:focus-within { transform: none; }
}

#contact .closing-proof .proof {
  padding: 18px clamp(18px, 2.4vw, 26px);
  background: var(--ink-2);
  border: 1px solid var(--line-2);
  border-radius: 4px;
}
#contact .closing-proof .proof h3 { margin: 0 0 10px; font-size: 1rem; }
#contact .closing-proof .proof__table { font-size: 0.72rem; }

/* --- the concept-build overlay --------------------------------------------
 * js/panels.js builds this once inside .closing-proof and it had no styling
 * anywhere in the stylesheet chain until now — an unstyled dialog is not a
 * degraded state, it is a bug, so this is a full treatment, not a patch.
 * Same shape and the same house curves as [data-act="offerings"] .offer-overlay
 * just above: fixed, backdrop-blurred, opens FROM the work card that was
 * clicked via --card-ox/--card-oy/--card-scale (written by js/panels.js), and
 * animates on the [data-open] attribute rather than a class toggle mid-flight.
 */
#contact .work-overlay {
  position: fixed;
  inset: 0;
  z-index: 45;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: clamp(16px, 4vw, 40px);
}
#contact .work-overlay[hidden] { display: none; }

#contact .work-overlay__backdrop {
  position: absolute;
  inset: 0;
  background: rgba(5, 9, 12, 0.86);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  opacity: 0;
  transition: opacity 200ms ease-out;
}
#contact .work-overlay[data-open] .work-overlay__backdrop {
  opacity: 1;
  transition: opacity 280ms cubic-bezier(.34,.9,.4,1);
}

#contact .work-overlay__panel {
  position: relative;
  z-index: 1;
  width: min(960px, 100%);
  height: min(720px, 86vh);
  display: flex;
  flex-direction: column;
  background: var(--ink-2);
  border: 1px solid var(--line-2);
  border-radius: 4px;
  overflow: hidden;
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.45);
  opacity: 0;
  transform-origin: center center;
  transform: translate(var(--card-ox, 0), var(--card-oy, 0)) scale(var(--card-scale, 0.4));
  transition: opacity 220ms ease-out, transform 260ms ease-out;
}
#contact .work-overlay[data-open] .work-overlay__panel {
  opacity: 1;
  transform: translate(0, 0) scale(1);
  transition: opacity 340ms cubic-bezier(.34,.9,.4,1), transform 560ms cubic-bezier(.28,1.5,.5,1);
}
@media (prefers-reduced-motion: reduce) {
  #contact .work-overlay__panel,
  #contact .work-overlay__backdrop { transition: none; opacity: 1; transform: none; }
}
@media (max-width: 640px) {
  #contact .work-overlay__panel { height: min(560px, 88vh); }
}

#contact .work-overlay__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 14px clamp(16px, 2.4vw, 24px);
  border-bottom: 1px solid var(--line-2);
  background: var(--ink);
}
#contact .work-overlay__bar .work-card__kind { margin: 0; }
#contact .work-overlay__actions { display: flex; align-items: center; gap: 10px; }

#contact .work-overlay__open,
#contact .work-overlay__close {
  font-family: var(--mono);
  font-size: 0.72rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  border: 1px solid var(--line-2);
  border-radius: 2px;
  padding: 8px 12px;
  min-height: 36px;
  background: transparent;
  cursor: pointer;
  transform: scale(1);
  transition: border-color 200ms ease-out, color 200ms ease-out, transform 200ms ease-out;
}
#contact .work-overlay__open { color: var(--aurora); text-decoration: none; }
#contact .work-overlay__close { color: var(--paper-dim); }
#contact .work-overlay__open:hover,
#contact .work-overlay__open:focus-visible {
  border-color: var(--aurora); color: var(--paper);
  transform: translateY(-1px);
  transition: border-color 260ms cubic-bezier(.28,1.5,.5,1), color 260ms cubic-bezier(.28,1.5,.5,1),
              transform 300ms cubic-bezier(.28,1.5,.5,1);
}
#contact .work-overlay__close:hover,
#contact .work-overlay__close:focus-visible {
  border-color: var(--aurora); color: var(--aurora);
  transform: translateY(-1px);
  transition: border-color 260ms cubic-bezier(.28,1.5,.5,1), color 260ms cubic-bezier(.28,1.5,.5,1),
              transform 300ms cubic-bezier(.28,1.5,.5,1);
}
#contact .work-overlay__open:active,
#contact .work-overlay__close:active {
  transform: scale(0.93);
  transition: transform 120ms ease-out;
}
@media (prefers-reduced-motion: reduce) {
  #contact .work-overlay__open,
  #contact .work-overlay__close { transition: none; transform: none !important; }
}
@media (pointer: coarse) {
  #contact .work-overlay__open,
  #contact .work-overlay__close { min-height: 44px; padding-inline: 16px; }
}

#contact .work-overlay__frame {
  flex: 1;
  width: 100%;
  border: 0;
  background: var(--ink);
}
