/* ============================================================
   CAPABILITIES
   ============================================================ */
/* A precision specification sheet: fine metal rules, oversized faint numerals
   set behind the type, and a single cyan index marker per column. No cards,
   no glow: the craft is in the spacing and the rules. */
.capabilities { background: linear-gradient(180deg, var(--black-abs), var(--black-near) 40%, var(--black-abs)); }
.capabilities-grid {
  display: grid;
  /* Three, because there are six disciplines: four columns leaves a widowed
     pair on the second row and reads as a grid that ran out. */
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(24px, 3vw, 52px);
  padding: 0 var(--pad-section);
  margin-top: clamp(52px, 7vh, 88px);
}
.capability-block {
  position: relative;
  padding-top: 26px;
  border-top: 1px solid rgba(154, 178, 190, 0.18);
}
/* The index marker: a short bright segment sitting on the rule. */
.capability-block::before {
  content: "";
  position: absolute;
  left: 0;
  top: -1px;
  width: 34px;
  height: 1px;
  background: var(--cyan-l3);
  box-shadow: 0 0 8px var(--cyan-l3-glow);
}
/* Oversized technical numeral, set faint and behind the heading. */
.capability-block::after {
  content: attr(data-index);
  position: absolute;
  right: -2px;
  top: 6px;
  font-family: var(--font-display);
  font-size: clamp(56px, 5vw, 88px);
  line-height: 1;
  color: rgba(154, 178, 190, 0.055);
  pointer-events: none;
  user-select: none;
}
.capability-block-title {
  position: relative;
  font-family: var(--font-display);
  font-size: clamp(24px, 2vw, 32px);
  letter-spacing: 0.04em;
  color: var(--text-1);
  margin-bottom: 20px;
}
.capability-block-num {
  display: block;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.24em;
  color: var(--cyan-2);
  margin-bottom: 12px;
}
/* The one sentence a discipline is hired for, between its title and the
   things it covers: reading size, the page's brightest text tier, held to a
   short measure so it reads as a claim rather than as the first list item. */
.capability-block-lede {
  margin: 0 0 20px;
  max-width: 30ch;
  font-size: 15.5px;
  line-height: 1.45;
  color: var(--text-1);
  text-wrap: pretty;
}
/* The sheet's own lede, under the section heading. */
.section-lede {
  margin-top: clamp(22px, 2.6vw, 38px);
  max-width: 54ch;
  font-size: clamp(15px, 1.15vw, 18px);
  line-height: 1.65;
  color: var(--text-2);
  text-wrap: pretty;
}
.capability-block ul { display: grid; gap: 9px; }
.capability-block li {
  position: relative;
  padding-left: 18px;
  font-size: 14.5px;
  color: var(--text-2);
}
.capability-block li::before {
  content: "";
  position: absolute;
  left: 0; top: 0.62em;
  width: 7px; height: 1.5px;
  background: var(--cyan-1);
}

/* The APPROACH block stood here: the section's ground, the stair of five steps
   and the index rail with a lit node at each. The section is off the page, so
   the rules for it are gone rather than left to match nothing. */

/* ============================================================
   STUDIO
   ============================================================ */
/* Sparse, but the emptiness is occupied. The studio's own mark stands in the
   black on the right at very low contrast, roughly 80% darkness, 20%
   visible structure: so the copy still leads and the void stops reading as
   unfinished. It used to be a V drawn in two CSS gradients, a stand-in for
   the mark; it is the mark now (assets/logo-mark.png, the `<img>` in the
   markup), the same object the hero's particles draw and the header wears,
   with its black keyed to alpha so it sits ON this section's ground rather
   than carrying a card of its own. */
.studio {
  position: relative;
  background: linear-gradient(180deg, var(--black-abs), var(--black-near) 50%, var(--black-abs));
  overflow: hidden;
}
.studio__mark,
.studio::before,
.studio::after {
  position: absolute;
  right: -4%;
  top: 50%;
  width: min(46vw, 620px);
  aspect-ratio: 1 / 1;
  transform: translateY(-50%);
  pointer-events: none;
}
/* The mark at rest: out of `.studio > *`'s measure (it is not type), its
   edges dissolved into the dark by the same radial mask the strokes wore. */
.studio__mark {
  max-width: none;
  margin: 0;
  height: auto;
  object-fit: contain;
  /* The mask is shaped to a standing figure rather than to a roundel: wider,
     softer, and lifted so the falloff sits below the face instead of across
     it. The image already dissolves on its own right-hand side, so the mask's
     job on that edge is only to hand it to the section's black. */
  mask-image: radial-gradient(76% 80% at 52% 38%, #000 30%, rgba(0, 0, 0, 0.5) 62%, transparent 80%);
  -webkit-mask-image: radial-gradient(76% 80% at 52% 38%, #000 30%, rgba(0, 0, 0, 0.5) 62%, transparent 80%);
}
/* A cold pool under it, so the mark is lit from somewhere. */
.studio::before {
  content: "";
  background: radial-gradient(46% 46% at 50% 74%, rgba(0, 170, 210, 0.09), transparent 68%);
}
.studio-tagline {
  margin-top: 34px;
  font-family: var(--font-mono);
  font-size: 14px;
  letter-spacing: 0.18em;
  color: var(--cyan-2);
}

/* ============================================================
   CONTACT
   ============================================================ */
/* The culmination: an ambient cyan horizon rises behind the statement and the
   control, so the last thing the visitor sees is the system powered up.
   `overflow: hidden` is the crop the closing wave's box relies on. */
.contact {
  position: relative;
  overflow: hidden;
  background: linear-gradient(180deg, var(--black-abs), var(--black-near) 55%, var(--black-abs));
}
.contact::before {
  content: "";
  position: absolute;
  inset: auto 0 -34% 0;
  height: 78%;
  background:
    radial-gradient(52% 100% at 30% 100%, rgba(0, 178, 218, 0.16), transparent 70%),
    radial-gradient(80% 100% at 50% 116%, rgba(0, 120, 156, 0.16), transparent 72%);
  pointer-events: none;
}
/* The horizon line itself: one L3 filament, the site's last signal. */
.contact::after {
  content: "";
  position: absolute;
  left: 10%;
  right: 10%;
  bottom: 5%;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--cyan-l3) 42%, rgba(34, 230, 255, 0.35) 72%, transparent);
  box-shadow: 0 0 18px var(--cyan-l3-glow);
  opacity: 0.45;
  pointer-events: none;
}
/* The closing wave stands in the pocket this section leaves on the right, the
   statement, the control and the three lanes all run left of it, and it is
   the only layer here besides the copy (styles/wave.css owns its box).
   `.contact-inner` carries z-index 1, so every word and control sits in FRONT
   of the water with no number added anywhere else. */
.contact-inner { position: relative; z-index: 1; padding: 0 var(--pad-section); }
.contact-channels {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 320px));
  gap: 26px;
  margin-top: clamp(44px, 7vh, 70px);
}
.contact-channels li {
  display: grid;
  gap: 6px;
  padding-top: 16px;
  border-top: 1px solid var(--line-1);
}
.contact-channel-label {
  font-family: var(--font-mono);
  font-size: 11.5px;
  letter-spacing: 0.16em;
  color: var(--text-2);
  text-transform: uppercase;
}
/* These three are links, and read as captions until you happen to point at
   one. The arrow is what tells the eye at rest that a lane is somewhere to go;
   it leans out on hover so the affordance is confirmed rather than announced
   for the first time. */
.contact-channels a {
  display: inline-flex;
  align-items: baseline;
  gap: 10px;
  font-size: 15.5px;
  color: var(--text-1);
  width: fit-content;
  border-bottom: 1px solid transparent;
  transition: color var(--t-micro) var(--ease-ui), border-color var(--t-micro) var(--ease-ui);
}
.contact-channels a i {
  font-style: normal;
  color: var(--signal-hot);
  opacity: .55;
  transition: transform var(--t-micro) var(--ease-ui), opacity var(--t-micro) var(--ease-ui);
}
.contact-channels a:hover, .contact-channels a:focus-visible { color: var(--cyan-3); border-color: var(--cyan-3); }
.contact-channels a:hover i,
.contact-channels a:focus-visible i { transform: translateX(5px); opacity: 1; }

/* ============================================================
   THE BRIEF: three questions, then the reader's mail app
   ============================================================ */
/* A panel on the section's ground rather than a card floating on it: one
   hairline, an interior a step darker than the ground so the fields read as
   cut into it, and the closing wave allowed through the top edge. Nothing
   glows at rest; the one full-strength signal element in this viewport is
   still the row above, and the brief's own control is the same `.cta`. */
.brief {
  margin-top: clamp(44px, 6vw, 72px);
  padding: clamp(24px, 3.2vw, 44px);
  border: 1px solid rgba(122, 173, 255, .2);
  border-radius: 6px;
  background: linear-gradient(180deg, rgba(5, 13, 24, .62), rgba(2, 6, 11, .78));
  box-shadow: inset 0 1px 0 rgba(202, 224, 255, .05);
  max-width: 1120px;
}
.brief__head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 10px 28px;
  margin-bottom: clamp(22px, 2.6vw, 34px);
}
.brief__kicker {
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--signal-hot);
}
.brief__title {
  font-family: var(--font-display);
  font-size: clamp(1.6rem, 2.2vw, 2.2rem);
  letter-spacing: .02em;
  line-height: 1;
  text-transform: uppercase;
  color: var(--text-1);
  /* On a phone it wrapped to "APP." alone, a last line at a eighth of the
     one above it, in display type, over the field it is introducing. */
  text-wrap: balance;
}
.brief__grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(16px, 2vw, 26px);
}
.brief__field { display: grid; gap: 9px; min-width: 0; }
.brief__field--wide { grid-column: 1 / -1; }
.brief__label {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--text-2);
}
.brief__label i { font-style: normal; text-transform: none; letter-spacing: .04em; color: var(--text-3); margin-left: .6em; }
.brief__input {
  width: 100%;
  font: inherit;
  font-size: 15.5px;
  line-height: 1.5;
  color: var(--text-1);
  padding: 13px 15px;
  border: 1px solid rgba(122, 173, 255, .24);
  border-radius: 4px;
  background: rgba(2, 6, 11, .6);
  box-shadow: inset 0 1px 0 rgba(0, 0, 0, .5);
  transition: border-color var(--t-micro) var(--ease-ui), box-shadow var(--t-micro) var(--ease-ui);
  /* The page's `img, svg, canvas` reset does not reach these; stated so a
     phone does not zoom into a 15px field. */
  -webkit-appearance: none;
  appearance: none;
}
/* The placeholder carries the example this studio is asking for, "A product, a
   world, a system", so it is read, not glanced at. At .55 over the field's own
   ground it measured 3.39:1, under the 4.5:1 this size needs; .74 clears it
   without the hint starting to read as an answer already typed. */
.brief__input::placeholder { color: rgba(159, 178, 198, .74); }
textarea.brief__input { resize: vertical; min-height: 7.5em; }
select.brief__input {
  padding-right: 40px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%2363d8ff' stroke-width='1.4'%3E%3Cpath d='M4 6 L8 10 L12 6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 14px center;
  background-size: 14px;
}
select.brief__input option { background: var(--surface); color: var(--text-1); }
.brief__input:hover { border-color: rgba(122, 173, 255, .4); }
.brief__input:focus { outline: none; border-color: var(--signal-hot); box-shadow: inset 0 1px 0 rgba(0, 0, 0, .5), 0 0 0 3px rgba(99, 216, 255, .16); }
.brief__input[aria-invalid="true"] { border-color: var(--signal-hot); }
/* A grid item, across the grid, immediately under the field it is about: the
   grid's own row gap is the space above it, so it arrives attached to the
   outlined field rather than floating over the row below. */
.brief__error {
  grid-column: 1 / -1;
  margin-top: -4px;
  padding-left: 14px;
  border-left: 2px solid var(--signal-hot);
  font-size: 14px;
  color: var(--text-1);
}
.brief__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 16px 28px;
  margin-top: clamp(20px, 2.4vw, 30px);
}
.brief__actions .cta { margin-top: 0; }
.brief__note { max-width: 44ch; font-size: 13px; line-height: 1.5; color: var(--text-2); }

/* ---------- Editorial responsive ---------- */
@media (max-width: 1024px) {
  .capabilities-grid { grid-template-columns: 1fr 1fr; }
  .contact-channels { grid-template-columns: 1fr; }
}

@media (max-width: 767px) {
  .capabilities-grid { grid-template-columns: 1fr; }
  .brief__grid { grid-template-columns: 1fr; }
  .brief__actions { flex-direction: column; align-items: stretch; }
  .brief__actions .cta { justify-content: space-between; width: 100%; }
  /* One column has no right-hand pocket. The mark stands high, behind the
     eyebrow and the top of the heading, smaller and further back, rather
     than at the section's middle where it sat under the principles. */
  .studio__mark,
  .studio::before,
  .studio::after {
    /* Further out than the mark stood. A roundel behind a headline is a
       texture; a face behind one is a second thing to read, and the display
       type is set large enough here that the two were overlapping outright.
       Pushed right, only the dissolving edge falls behind the words. */
    right: -40%;
    top: 1%;
    width: min(88vw, 430px);
    transform: none;
  }
}

/* ============================================================
   EDITORIAL INTERACTION: restraint, but not stillness
   These sections stay calm. Interaction reveals confidence, not spectacle.
   ============================================================ */

/* ---------- CAPABILITIES ---------- */
.capability-block {
  transition: opacity 340ms var(--ease-ui), filter 340ms var(--ease-ui);
}
/* The index marker resolves along the rule as attention arrives. */
.capability-block::before {
  width: calc(20px + var(--prox, 0) * 46px);
  box-shadow: 0 0 calc(4px + var(--prox, 0) * 10px) var(--cyan-l3-glow);
  transition: width 480ms var(--ease-settle), box-shadow 340ms var(--ease-ui);
}
/* The oversized technical numeral becomes legible, not loud. */
.capability-block::after {
  color: rgba(154, 178, 190, calc(0.055 + var(--prox, 0) * 0.075));
  transition: color 420ms var(--ease-ui);
}
.capability-block.is-focused .capability-block-title { color: #ffffff; }
/* Inert, and left as authored rather than "corrected" to values that would
   also do nothing. `.capability-block` carries `.reveal`, and
   `html.motion-ready .reveal.is-revealed` (styles/experience.css) sets both
   `opacity: 1` and `filter: none` at a higher specificity than this, measured
   at 0.998 and no filter with the class applied. So the blocks do not actually
   recede, which is ALSO why they do not fail contrast the way the rail did:
   0.6 with that brightness cut would be 2.9:1 at this size. Enabling the effect
   and keeping it readable is one change, not two, and it is a design decision
   rather than an audit finding. */
.capability-block.is-receded { opacity: 0.6; filter: saturate(0.7) brightness(0.82); }
.capability-block-title { transition: color 300ms var(--ease-ui); }

/* The list gains hierarchy under attention: the dash becomes a signal tick. */
.capability-block li::before {
  transition: width 320ms var(--ease-settle), background 320ms var(--ease-ui);
}
.capability-block.is-focused li::before { width: 12px; background: var(--cyan-l3); }
.capability-block li { transition: color 300ms var(--ease-ui); }
.capability-block.is-focused li { color: var(--text-1); }

/* One technical motif per discipline, surfacing only on attention, the same
   language the systems above used, recalled rather than re-explained. */
.capability-block .capability-block-title::after {
  content: "";
  /* Out of flow, at its static position: right after the last word, on the
     same line. In flow it was a 14px box that fitted nowhere on a title that
     filled its column: "BROWSER & DEPLOYMENT INFRASTRUCTURE" at three
     columns: and wrapped, invisible, onto a line of its own, pushing that
     block's list a line lower than its neighbours'. */
  position: absolute;
  display: inline-block;
  width: 14px;
  height: 14px;
  margin-left: 10px;
  margin-top: .3em;
  opacity: var(--prox, 0);
  transition: opacity 380ms var(--ease-ui);
  background-repeat: no-repeat;
  background-size: contain;
}
#cap-agents .capability-block-title::after {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%232ee9ff' stroke-width='1.4'%3E%3Ccircle cx='12' cy='12' r='2'/%3E%3Ccircle cx='4' cy='6' r='1.4'/%3E%3Ccircle cx='20' cy='6' r='1.4'/%3E%3Ccircle cx='4' cy='18' r='1.4'/%3E%3Cpath d='M5.4 7 L10.4 10.8 M18.6 7 L13.6 10.8 M5.4 17 L10.4 13.2'/%3E%3C/svg%3E");
}
#cap-infrastructure .capability-block-title::after {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%232ee9ff' stroke-width='1.4'%3E%3Cpath d='M4 20 V10 M12 20 V4 M20 20 V13 M2 20 H22'/%3E%3C/svg%3E");
}
#cap-realtime .capability-block-title::after {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%232ee9ff' stroke-width='1.4'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cellipse cx='12' cy='12' rx='4' ry='9'/%3E%3Cpath d='M3 12 H21'/%3E%3C/svg%3E");
}
#cap-architecture .capability-block-title::after {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%232ee9ff' stroke-width='1.4'%3E%3Crect x='3' y='3' width='7' height='5'/%3E%3Crect x='14' y='3' width='7' height='5'/%3E%3Crect x='8.5' y='16' width='7' height='5'/%3E%3Cpath d='M6.5 8 V12 H12 V16 M17.5 8 V12 H12'/%3E%3C/svg%3E");
}
#cap-interface .capability-block-title::after {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%232ee9ff' stroke-width='1.4'%3E%3Crect x='3' y='4' width='18' height='12' rx='1'/%3E%3Cpath d='M3 8 H21'/%3E%3Cpath d='M14 17 L16 23 L17.2 20.4 L20 19.4 Z' fill='%232ee9ff' stroke='none'/%3E%3C/svg%3E");
}
#cap-quality .capability-block-title::after {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%232ee9ff' stroke-width='1.4'%3E%3Crect x='3' y='4' width='18' height='3'/%3E%3Crect x='3' y='9' width='11' height='3'/%3E%3Crect x='3' y='14' width='14' height='3'/%3E%3Cpath d='M3 20 H21' opacity='.6'/%3E%3C/svg%3E");
}

/* ---------- STUDIO: the artifact is discovered by light ---------- */
/* At rest the right side is dark and the pointer carries the light that
   reveals what is standing in it.

   The floor is 0.30: present, and barely. The section is dark on the right and
   the portrait is a shape in it rather than a picture of somebody, until a hand
   arrives. That is the treatment the mark had and it is the right one for a
   photograph too, for a reason the mark made obvious: the reveal is the
   section's whole idea, and an object already at full strength has nothing left
   to be revealed. It carried 0.72 for a while and the pointer had no work to do.

   Touch keeps its own floor because those frames never fire the reveal, so
   whatever is set there is the whole of what a reader ever sees.

   The floor is a property rather than a number because three different frames
   want three different values, and the last version of this rule set them in
   three places of equal specificity that silently overrode one another. Set
   it on `.studio` and it inherits to both layers. */
.studio { --mark-rest: 0.30; }
/* The three frames that want their own floor, declared here and in this order
   rather than beside the layout rules they belong to. They are one property at
   one specificity, so the only thing deciding between them is source order,
   and spreading them through the file is how the previous version ended up
   with a narrow-frame value that never applied. */
@media (hover: none) and (min-width: 768px) {
  /* A tablet has the right-hand pocket but never a pointer, so the reveal
     never fires and the floor is all there is. */
  .studio { --mark-rest: 0.50; }
}
@media (max-width: 767px) {
  /* One column: the portrait is behind display type rather than beside it, so
     it drops back to being atmosphere. */
  .studio { --mark-rest: 0.30; }
}
.studio__mark,
.studio::before {
  opacity: calc(var(--mark-rest) + var(--prox, 0) * (1 - var(--mark-rest)));
  transition: opacity 620ms var(--ease-ui);
}
/* A travelling reveal window that follows the pointer across the dark area:
   the mark again, at full strength, seen through a circle of light 200px
   across. Its image is named only once the reader is near (`is-near`,
   scripts/studio/interactions.js), so a page is not asked for a second copy
   of a file it may never scroll to. */
.studio::after {
  content: "";
  background-position: center;
  background-size: contain;
  background-repeat: no-repeat;
  mask-image: radial-gradient(
    circle 200px at calc(var(--px, 0.5) * 100%) calc(var(--py, 0.5) * 100%),
    #000 0%, rgba(0, 0, 0, 0.55) 35%, transparent 72%
  );
  -webkit-mask-image: radial-gradient(
    circle 200px at calc(var(--px, 0.5) * 100%) calc(var(--py, 0.5) * 100%),
    #000 0%, rgba(0, 0, 0, 0.55) 35%, transparent 72%
  );
  opacity: var(--prox, 0);
  transition: opacity 520ms var(--ease-ui);
}
/* The portrait is a point field (scripts/studio/portrait.js); no photograph is painted here. */
/* Conceptual closure: the tagline brings the object to its clearest state. */
.studio.is-revealed::after { opacity: 1; }
.studio.is-revealed .studio__mark,
.studio.is-revealed::before { opacity: 0.85; }
.studio-tagline { transition: color 320ms var(--ease-ui), text-shadow 320ms var(--ease-ui); cursor: default; }
.studio.is-revealed .studio-tagline {
  color: #9df5ff;
  text-shadow: 0 0 16px rgba(46, 233, 255, 0.45);
}

/* ---------- CONTACT: the environment converges on the control ---------- */
.contact::before { transition: opacity 620ms var(--ease-ui); opacity: 0.55; }
.contact::after { transition: opacity 620ms var(--ease-ui), left 720ms var(--ease-settle), right 720ms var(--ease-settle); }
.contact.is-converging::before { opacity: 1; }
.contact.is-converging::after { opacity: 0.9; left: 4%; right: 4%; }
.contact-channels li { transition: opacity 420ms var(--ease-ui); }
/* Secondary paths stay subdued while the primary action is being considered. */
.contact.is-converging .contact-channels li { opacity: 0.6; }

/* No pointer, no proximity: on touch the discovered-by-light artifact would
   stay at its resting ghost forever and the studio's right half reads as
   reserved emptiness. The mark is simply present instead, still quiet,
   still behind the copy, just not waiting for a cursor that never comes. */
@media (prefers-reduced-motion: reduce) {
  .studio::after { display: none; }
  .capability-block::before { width: 34px; }
}

/* ============================================================
   BUILT: THE LAUNCHER, IN A WINDOW
   ============================================================ */
/* The window is a tool panel in this page's own idiom rather than a browser
   chrome or an operating system's: a rail that reads as an instrument label, a
   stage, and a deck of cards under it. What runs inside is carried from
   omryv/visigence-games (scripts/showcase/), so the geometry here has a
   contract to keep: `.screen__art` is what the weather is drawn over and what
   the pointer is mapped against, `.deck` is what the cards are measured from,
   and a card that is lifted is taken out of the flow by the physics rather than
   by a rule below. */
.work { background: linear-gradient(180deg, var(--black-abs), var(--black-near) 45%, var(--black-abs)); }
.showcase {
  display: grid;
  grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr);
  grid-template-areas: "screen aside" "deck aside";
  gap: clamp(20px, 2.4vw, 34px) clamp(28px, 3.6vw, 60px);
  align-content: start;
  padding: 0 var(--pad-section);
  margin-top: clamp(46px, 6vh, 78px);
  --accent: #FF812B;
}

/* ---------- the window ---------- */
.screen {
  grid-area: screen;
  position: relative;
  border: 1px solid var(--edge-metal);
  background: var(--black-graphite);
  box-shadow: var(--glass-thick);
  /* NOT `overflow: hidden`. A thrown card crosses this boundary on its way in,
     and clipping it would cut the one gesture the window exists to receive. */
  border-radius: 2px;
}
.screen::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 1px;
  background: var(--specular-line);
  z-index: 3;
}
.screen__rail {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 12px;
  border-bottom: 1px solid rgba(154, 178, 190, 0.14);
  background: linear-gradient(180deg, rgba(22, 30, 38, 0.9), rgba(12, 18, 24, 0.9));
}
.screen__mark {
  width: 8px; height: 8px; flex: none;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 10px var(--accent);
  transition: background 420ms var(--ease-ui), box-shadow 420ms var(--ease-ui);
}
.screen__title {
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.2em;
  color: var(--text-2);
}
.screen__title i { font-style: normal; color: var(--text-3); margin: 0 2px; }
.screen__state {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--text-3);
}
.screen__motion {
  margin-left: auto;
  padding: 5px 10px;
  border: 1px solid rgba(154, 178, 190, 0.2);
  background: transparent;
  font-family: var(--font-mono);
  font-size: 9.5px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-3);
  cursor: pointer;
  transition: color 260ms var(--ease-ui), border-color 260ms var(--ease-ui);
}
.screen__motion:hover, .screen__motion:focus-visible { color: var(--text-1); border-color: var(--accent); }

/* The stage. The atmosphere canvas is appended here and sized to it, and the
   pointer is mapped against this rect, so its aspect has to be stable. */
.screen__art {
  position: relative;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  background: #05080c;
  isolation: isolate;
}
.screen__plate {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  object-fit: contain;
  display: block;
}
.screen__composition {
  position: absolute;
  left: 50%; top: 50%;
  width: 100%; height: 100%;
  transform: translate(-50%, -50%);
  overflow: hidden;
}
.showcase[data-active-world="wildgence"] .screen__logo { width: min(42%, 300px); }
.card[data-world="wildgence"] .card-logo { width: 68%; }
.card[data-world="wildgence"] .card-art { object-position: 66% center; }
.screen__fx {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 2;
}
.screen__logo {
  position: absolute;
  left: clamp(16px, 3%, 34px);
  bottom: clamp(14px, 5%, 34px);
  z-index: 3;
  width: min(46%, 260px);
  height: auto;
  pointer-events: none;
  filter: drop-shadow(0 4px 18px rgba(0, 0, 0, 0.8));
}
.screen__foot {
  display: flex;
  align-items: center;
  padding: 9px 12px;
  border-top: 1px solid rgba(154, 178, 190, 0.14);
  background: linear-gradient(180deg, rgba(14, 20, 26, 0.9), rgba(9, 14, 19, 0.9));
}
.screen__hint {
  margin: 0;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-3);
}

/* ---------- the deck ---------- */
/* Four cards in a row under the window. The physics writes `transform` on each
   one every frame it is moving, so nothing here may animate transform: a rule
   that did would be fighting the solver for the same property. */
.deck {
  grid-area: deck;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(8px, 1vw, 14px);
}
.card {
  position: relative;
  /* The solver lifts a card by raising this. Left to the stacking order, a
     lifted card would slide under its neighbour on the way past it. */
  z-index: 1;
  will-change: transform;
}
.card.is-lifted { z-index: 20; }
.card-select {
  display: block;
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 10;
  padding: 0;
  border: 1px solid rgba(154, 178, 190, 0.16);
  background: #070b10;
  overflow: hidden;
  cursor: grab;
  /* The card is grabbed, so the browser must not also try to scroll or select
     with the same finger. */
  touch-action: none;
  -webkit-user-select: none;
  user-select: none;
  transition: border-color 300ms var(--ease-ui);
}
.card.is-current .card-select { border-color: color-mix(in srgb, var(--accent) 62%, transparent); }
.card-art {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  opacity: 0.62;
  transition: opacity 300ms var(--ease-ui);
}
.card.is-current .card-art, .card-select:hover .card-art { opacity: 0.92; }
.card-logo {
  position: absolute;
  left: 9px; top: 8px;
  width: min(52%, 108px);
  height: auto;
  z-index: 2;
  filter: drop-shadow(0 2px 10px rgba(0, 0, 0, 0.85));
}
.card-text {
  position: absolute;
  left: 9px; right: 9px; bottom: 8px;
  z-index: 2;
  display: grid;
  gap: 2px;
  text-align: left;
  /* The art behind a caption is photographic and changes per world, so the
     caption carries its own ground rather than trusting the picture. */
  background: linear-gradient(180deg, transparent, rgba(4, 8, 12, 0.86) 40%);
  padding-top: 14px;
}
.card-name {
  font-family: var(--font-display);
  font-size: clamp(13px, 1.2vw, 17px);
  letter-spacing: 0.05em;
  color: var(--text-1);
}
.card-kind {
  font-family: var(--font-mono);
  font-size: 8.5px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-3);
}
.card-play {
  position: absolute;
  right: 7px; top: 7px;
  z-index: 3;
  width: 26px; height: 26px;
  display: grid;
  place-items: center;
  border: 1px solid rgba(154, 178, 190, 0.28);
  background: rgba(4, 8, 12, 0.7);
  color: var(--text-1);
  transition: color 260ms var(--ease-ui), border-color 260ms var(--ease-ui);
}
/* The drawn control is 26px; the touch target is 44. The pad is a pseudo
   element rather than a larger box, so the mark stays the small instrument
   it is drawn as and a thumb still lands on it. */
.card-play::before { content: ""; position: absolute; inset: -9px; }
.card-play:hover, .card-play:focus-visible { color: var(--accent); border-color: var(--accent); }

/* While a card is in the air the section must not scroll under it. Set on the
   section rather than on <body>, or dragging a card would lock the whole page. */
.showcase.is-deck-locked, .work.is-deck-locked { overscroll-behavior: contain; }

/* ---------- what the window is evidence of ---------- */
.showcase__aside { grid-area: aside; align-self: center; }
.showcase__kind {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--cyan-2);
  margin-bottom: 18px;
}
.showcase__kind i { font-style: normal; color: var(--text-3); margin: 0 4px; }
.showcase__copy {
  margin: 0;
  max-width: 46ch;
  font-size: 15.5px;
  line-height: 1.6;
  color: var(--text-2);
  text-wrap: pretty;
}

@media (max-width: 900px) {
  .showcase { grid-template-columns: 1fr; grid-template-areas: "screen" "deck" "aside"; }
}
@media (max-width: 680px) {
  .deck { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (prefers-reduced-motion: reduce) {
  /* The physics never starts and the weather never draws. What is left is the
     key art, the wordmark and four cards that are still buttons, which is a
     complete thing to look at rather than a degraded one. */
  .card-select { cursor: pointer; }
}

/* ============================================================
   CASE STUDIES
   ============================================================ */
/* Two, side by side, and each one a document rather than a card: a head, a
   definition list of the four questions a buyer actually asks, and the numbers
   under it. The pair is the only place on the page where prose runs long
   enough to need a real reading measure. */
.cases { background: var(--black-abs); }
.cases-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: clamp(32px, 4vw, 72px);
  padding: 0 var(--pad-section);
  margin-top: clamp(52px, 7vh, 88px);
}
.case-study {
  position: relative;
  padding: clamp(26px, 2.6vw, 40px);
  background: linear-gradient(180deg, rgba(18, 26, 36, 0.55), rgba(10, 15, 22, 0.35));
  border: 1px solid rgba(154, 178, 190, 0.14);
}
/* The lit segment again, this time on the panel's own top edge. */
.case-study::before {
  content: "";
  position: absolute;
  left: -1px;
  top: -1px;
  width: 46px;
  height: 1px;
  background: var(--cyan-l3);
  box-shadow: 0 0 8px var(--cyan-l3-glow);
}
.case-study__head { margin-bottom: clamp(24px, 2.4vw, 34px); }
.case-study__kicker {
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--cyan-2);
  margin-bottom: 14px;
}
.case-study__title {
  font-family: var(--font-display);
  font-size: clamp(30px, 2.8vw, 44px);
  letter-spacing: 0.03em;
  color: var(--text-1);
  margin-bottom: 12px;
}
.case-study__line {
  margin: 0;
  max-width: 42ch;
  font-size: 16px;
  line-height: 1.5;
  color: var(--text-1);
  text-wrap: pretty;
}
.case-study__body { display: grid; gap: 22px; }
.case-study__body dt {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--text-3);
  margin-bottom: 8px;
}
.case-study__body dd {
  margin: 0;
  max-width: 52ch;
  font-size: 15px;
  line-height: 1.62;
  color: var(--text-2);
  text-wrap: pretty;
}
.case-study__code {
  font-family: var(--font-mono);
  font-size: 0.88em;
  color: var(--cyan-2);
}
/* Three numbers, on the rule, closing the document. */
.case-study__facts {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 16px;
  margin-top: clamp(26px, 2.6vw, 36px);
  padding-top: 22px;
  border-top: 1px solid rgba(154, 178, 190, 0.14);
}
.case-study__facts b {
  display: block;
  font-family: var(--font-display);
  font-size: clamp(28px, 2.4vw, 38px);
  font-weight: 400;
  line-height: 1;
  color: var(--cyan-l3);
  margin-bottom: 8px;
}
.case-study__facts span {
  display: block;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-3);
  line-height: 1.4;
}

/* ---------- The editorial sections in one column ---------- */
/* The same breakpoint the capability sheet turns at, so the whole editorial
   half of the page reflows on one line rather than two. */
@media (max-width: 900px) {
  .cases-grid { grid-template-columns: 1fr; }
}
