/* contact.css — 10 / Contact
 *
 * Full-viewport, two-column asymmetric. Reference design width 1280px.
 * No border radius anywhere in this design — keep it that way.
 */

/* RED ON THIS SECTION'S GROUND.
 * RED-CONTACT-SERVICES.md §0: this section has ONE red, the accent red
 * #ff0a32 — "All red type, marks, borders, dots and controls. Everything in
 * Contact and Services is this red." The surface red #e6002a "does not appear
 * in Contact or Services"; §4 makes any #e6002a reachable from here a bug,
 * except the global a:hover in main.css, which every red link below overrides
 * with its own explicit colour. Derived alphas come from rgb(255,10,50) only
 * (§3) — never from 230,0,42.
 *
 * The token is --red-label, which is #ff0a32. It is used rather than
 * --red-dark because --red-dark is contracted to dark grounds and this ground
 * is #e6e9eb; --red-label is the token that already records the brightness-
 * over-contrast trade this handoff makes here.
 *
 * THIS OVERRIDES THE PREVIOUS RULE ON PURPOSE, AND IT COSTS CONTRAST. The
 * section previously took --red-text (#a80017, 6.34:1) for type and --red
 * (#e6002a) for fills, because #ff0a32 measures ~3.4:1 on this ground and
 * fails AA on the 10-12px labels that carry it. tokens.css records the same
 * trade being accepted for the secondary-page labels on 2026-08-12, and notes
 * that the front page's contact labels "were out of scope for THAT change" —
 * this handoff is the change that brings them in. Do not "fix" it back to
 * --red-text without the handoff being revised first.
 */

.contact {
  position: relative;
  box-sizing: border-box;
  /* container-type gives cqw, which the headline, the float stand-off and the
     figure constant are all expressed in. */
  container-type: inline-size;
  /* min-height ONLY, never height. A fixed height caps the section below its own
     content and, with overflow hidden, clips the form: on viewports under ~737px
     the consent row and the submit button are cut away and the form cannot be
     submitted. 1366x768 and 1280x720 laptops are inside that range. */
  min-height: 100vh;
  padding: 72px 56px 0;          /* no bottom padding — the portrait is grounded */
  background: #e6e9eb;
  color: var(--near-black);
}

/* WHITE-SPACE:NOWRAP MAKES THE SIZE A WIDTH. "VISION" sets 3.63x its font-size
   wide, so at a flat 232px it was 843px of un-shrinkable type — wider than the
   section below about 850px, where it pushed a horizontal scrollbar. The word is
   decorative and pointer-events:none, so the overflow was invisible until you
   noticed the page scrolling sideways.

   min() rather than a clamp or a media query: 30cqw only wins below ~900px wide,
   so every width the design was drawn at still gets exactly 232px and nothing
   above the narrow band moves. contact.small.css sets 112px under 768, where the
   watermark is meant to bleed off both edges instead of fitting. */
.contact__watermark {
  position: absolute;
  left: -.03em; top: 24px;
  font-family: var(--display); font-weight: 900;
  font-size: min(232px, 30cqw); line-height: .78;
  letter-spacing: -.045em;
  color: rgba(18, 28, 42, .055);
  white-space: nowrap;
  user-select: none; pointer-events: none;
}

.contact__grid {
  position: relative;
  display: grid;
  /* CONTACT-DESKTOP.md §2. `minmax(0, …)` ON BOTH TRACKS IS REQUIRED — the spec
     says so and the reason is visible: without it the figure's intrinsic width
     blows the left track past its share and the form is squeezed off the grid.

     The floors it replaces were 640px and 400px, and together with the gap that
     was 1068px of hard minimum — the sole cause of the horizontal scrollbar
     between 960 and about 1136px wide. A fr track with a zero floor cannot do
     that. Measured before: 164px of overflow at 960, 100 at 1024, 24 at 1100. */
  grid-template-columns: minmax(0, 1.62fr) minmax(0, .72fr);
  column-gap: clamp(28px, 2.4cqw, 44px);
  /* §2 — stretch, not centre. This is what lets the figure reach the section
     floor, and what makes the form a stretched grid item, which §5's first
     constraint depends on. The form's own `justify-content: center` is what
     keeps it visually centred. */
  align-items: stretch;
}
/* §2 — a flex COLUMN: header at its natural height, body taking the rest.
   `align-self: start` and `margin-bottom: -80px` used to live here, and both
   fought the model the spec describes. `start` cancels the grid's
   `align-items: stretch`, which §2 says is "what lets the figure reach the
   section floor"; the negative margin was then needed to drag the composition
   back down. With the column stretched to the full row and the body flexing,
   neither is needed — and §5 depends on it: "the left column is made exactly as
   tall as the section and never taller, so the calculation settles in one pass
   instead of oscillating". */
.contact__left {
  min-width: 0;
  display: flex;
  flex-direction: column;
}


/* --- header: eyebrow rule + headline --------------------------------------- */

.contact__eyebrow-row { display: flex; align-items: center; gap: 14px; }
.contact__cap-num {
  font-family: var(--hud); font-weight: 500;
  font-size: 10px; line-height: 1;
  letter-spacing: .16em; text-transform: uppercase;
  color: var(--red-label);
  white-space: nowrap;
}
.contact__rule { flex: 1 1 auto; height: 1px; background: rgba(18, 28, 42, .22); }

.contact__h2 {
  margin: 26px 0 0;
  font-family: var(--display); font-weight: 900;
  font-size: 4.2cqw; line-height: .9;
  letter-spacing: -.035em; text-transform: uppercase;
  /* nowrap: the two lines are authored breaks, not wraps. */
  white-space: nowrap;
}
.contact__hl {
  background: var(--char-lo);
  color: #fff;
  padding: .04em .16em;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}


/* --- body: the float and the copy lane ------------------------------------- */

.contact__body {
  /* §2 — flow-root is REQUIRED, not stylistic: the figure inside floats, and
     without a block formatting context the float escapes the column. */
  flex: 1;
  min-height: 0;
  display: flow-root;
  padding-top: 34px;             /* the approved head clearance */
}

/* The <picture> wrapper exists only to art-direct the two cutouts. display:contents
   removes its box entirely, so the float, the shape-outside and the JS measurement
   all still apply to the <img> itself exactly as if the wrapper were not there. */
.contact__body picture { display: contents; }

/* THE FIGURE.
   height is computed from the viewport, never inherited. `height:100%` has no
   definite containing height here — the left column is content-driven and the
   float IS that content — so Chrome falls back to the natural 567x736, the
   figure stops scaling and the section grows past one viewport.

   The constants are the section's own geometry, so grounding is exact by
   construction: 72px top padding + 36px fixed header (10px eyebrow + 26px
   margin) + 7.6cqw for the two-line headline (4.2cqw x .9 x 2).
   IF THE HEADLINE SIZE OR THE TOP PADDING CHANGES, THIS CONSTANT CHANGES TOO.

   This is the pre-script value and is correct while the section is exactly
   100vh; contact.js then measures and owns it. */
/* GROUNDED BY ALIGNMENT, NOT BY MEASUREMENT. This was a left float whose height
   contact.js computed each frame so it would reach the floor of a full-viewport
   section. That worked at 1920 and nowhere else: the height a float can take is
   bounded by the width it may occupy, and once the copy lane's 400px minimum bit
   — anywhere under ~1600px — the figure stopped growing and hung in mid-air,
   343px above the floor at 1280. Measured, not guessed.

   A float also cannot be bottom-aligned at all: it starts at the top of its
   block and ends where its image ends. Grid can. The figure spans every row of
   column 1 and align-self:end drops it onto the section's floor, whatever the
   form's height did to the section. contact.js's sizeFigure() is retired.

   WHAT WAS LOST WITH THE FLOAT: shape-outside. Only floats take a shape, so the
   copy no longer follows his silhouette — the lede and the rows share one left
   edge now. The stand-off it provided is the grid's column-gap instead. */
.contact__figure {
  grid-area: 1 / 1 / -1 / 2;
  align-self: end;
  /* HEIGHT-DRIVEN, NOT WIDTH-DRIVEN, and that ordering is the whole trick. Ask
     for the block's full height and let the width follow the ratio: the portrait
     then reaches the floor by construction at any section height, whatever the
     form did to it. A fixed px cap on the column cannot do that — it grounded at
     1366 and left 204px of air at 1920, because the right cap is a function of
     the form's height and nothing here knows it.

     max-width is the guard, and the column is what sets it: when the derived
     width will not fit, the width clamps, aspect-ratio pulls the height down
     with it, and align-self:end lands what is left on the floor. That is the old
     JS ceiling — legible contact details outrank the grounding — expressed as
     two declarations instead of a measured frame loop. */
  height: 100%;
  width: auto;
  max-width: 100%;
  aspect-ratio: 567 / 736;
  /* THE BOX MAY BE THE WRONG SHAPE; THE PICTURE MAY NOT BE. The note above is
     wrong on one point: aspect-ratio only supplies a MISSING dimension, so when
     max-width clamps the width, height:100% holds and the box goes narrow and
     tall. Default object-fit:fill then squashes the portrait into it - measured
     16% off at 1440 and 29% at 1285 once a taller form stretched the section.
     contain keeps the ratio; bottom keeps the grounding the box still provides. */
  object-fit: contain;
  object-position: bottom;
  margin: 0;
  user-select: none;
  -webkit-user-drag: none;
}

/* §3 — display:contents, so the lede, the rows and the meta block are grid
   items in their own right rather than one block that would place as a unit.
   They are placed on consecutive rows at the top of column 2. */
.contact__lane { display: contents; }

/* THE GRID HAS TO FILL THE SECTION, or nothing inside it can be grounded.
   .contact is min-height:100vh and display:block, so this grid — the only thing
   between the section and the portrait — took the height of its tallest item,
   which is the form. The form shrinks as the viewport narrows because its type
   and padding are in cqw, so the grid floated above the section floor by 17px at
   1440 and 92px at 1280, carrying the grounded portrait up with it. Everything
   below aligns correctly and always did; it had nothing to align against.

   Flex on the section rather than a height on the grid: the note at the top of
   this file rules out a fixed height, which caps the section below its own
   content and clips the form on 1366x768 and 1280x720 laptops. `flex: 1 1 auto`
   takes the slack when there is some and gives up nothing when there is not —
   verified unclipped at both of those sizes. */
.contact { display: flex; flex-direction: column; }
.contact__grid { flex: 1 1 auto; }

/* The left column already stretches to the section's floor as a grid item; it
   has to pass that height on, which a block child cannot take. Flex column +
   flex:1 on the body is what gives align-self:end something to align against. */
.contact__left { display: flex; flex-direction: column; }

.contact__body {
  flex: 1 1 auto;
  min-height: 0;
  display: grid;
  /* col 1 the portrait, col 2 the copy.

     COLUMN 2 HAS A ZERO FLOOR, AND MUST KEEP ONE. It carried minmax(380px, 1fr)
     to stop a contact row's CALL/WRITE wrapping under the value — measured fine
     at 390 and wrapped at 337 — but a track whose minimum exceeds the space
     available does not shrink, it OVERFLOWS. At 1280 the left column is 789px
     and the tracks demanded 434 + 43 gap + 380 = 857, so the rows ran 65px past
     their own column and 37px of that landed on top of the form. It was already
     21px over at 1440; it simply had not reached the form yet.

     This is the same fault the OUTER grid had and already fixed — see the note
     on .contact__grid, where 640px and 400px floors were the sole cause of a
     horizontal scrollbar between 960 and 1136px.

     The wrap the floor defended against does not happen with the real rows:
     heights are 51/52px at 1440, 1366, 1280 and 1200 with the floor gone. If a
     longer address ever does need to wrap, .crow already carries flex-wrap and
     will drop CALL/WRITE onto its own line, which is the better failure. */
  grid-template-columns: min(55%, 700px) minmax(0, 1fr);
  /* The copy packs at the TOP of column 2 and the slack falls to the bottom.
     Zsolt, 2026-08-19: the lede and the details read as one block, and the void
     that used to sit between them was worse than the void below them.

     THE COST, SO IT IS NOT REDISCOVERED AS A BUG: the portrait is still grounded
     at the foot of column 1, so the hand no longer points at the contact rows —
     they are up here and it is down there. Putting a 1fr between the lede and
     the rows is what kept the two together, and it is what was removed. */
  grid-template-rows: auto auto auto 1fr;
  column-gap: 3.4cqw;
  align-items: start;
}
.contact__lede { grid-area: 1 / 2 / 2 / -1; }
.contact__rows { grid-area: 2 / 2 / 3 / -1; }
.contact__meta { grid-area: 3 / 2 / 4 / -1; }

.contact__lede {
  margin: 1.7cqw 0 0;
  /* Heavier and larger than the body default: this line is the section's voice,
     and at 400/2.05cqw it read as a caption rather than a lede. 500 is a real
     loaded cut of Bai Jamjuree (see fonts.css), not a synthesised bold, and the
     leading tightens a notch because the size went up. */
  font-family: var(--body); font-weight: 500;
  font-size: 2.3cqw; line-height: 1.34;
  color: var(--ink-body);
  text-wrap: pretty;
}


/* --- right column: the form ------------------------------------------------
   §2. There was no rule for this at all — the form was centred only by the
   grid's `align-items: center`, which §2 replaces with `stretch` so the figure
   can reach the floor. Stretch makes this a full-height grid item, so the
   centring has to move here, onto its own content. Without it the form sits at
   the top of a full-height column.

   `min-width: 0` lets the column shrink below its content's intrinsic width;
   the inputs are `width: 100%` and would otherwise hold the track open. */
.contact__right {
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-width: 0;
  padding-bottom: 72px;
}


/* --- contact rows ----------------------------------------------------------
   Their own BFC so they clear the float's margin box. `flex-wrap` and the
   anywhere-wrapping value are what let the row survive a squeezed lane;
   white-space:nowrap here converts that wrap into an overflow that paints
   across the form's inputs.

   The label column used to be fluid for the same reason — the lane could fall
   to ~78px at 1024 wide because the figure is uncapped. It is fixed now, and
   the narrow-desktop band at the end of this file is why: below 1280 the form
   moves under the section, so the lane no longer collapses. */

/* §3 — bare cqw, uncapped. The left column's rhythm is paired with the figure,
   which is width-driven, so a px value or a cap would break the pairing. */
.contact__rows { margin-top: 2.2cqw; display: flow-root; }
.crow {
  display: flex; flex-wrap: wrap; align-items: baseline;
  gap: 6px 16px;
  padding: 15px 0;
  border-top: 1px solid rgba(18, 28, 42, .13);
  color: inherit; text-decoration: none;
  max-width: 520px;
}
.crow:last-child { border-bottom: 1px solid rgba(18, 28, 42, .13); }
/* 78px, FLAT. `01 · PHONE` measures 76px at this size and letter-spacing, so
   the old clamp(58px, 5.2cqw, 78px) only cleared it above ~1560px wide and
   wrapped the label onto two lines everywhere below — including at the 1280
   reference width. cqw is the SECTION's inline size, so the grid change below
   could not have fixed this on its own. contact.small.css sets width:auto
   under 768, where the label sits above the value instead. */
.crow__k {
  width: 78px;
  flex: none;
  font-family: var(--hud); font-weight: 400;
  font-size: 10px; line-height: 1;
  letter-spacing: .16em; text-transform: uppercase;
  color: var(--grey-stat);
}
.crow__v {
  flex: 1 1 auto;
  /* rem, not cqw — §1: the two row values inherit the root size rather than the
     container, so they hold while the column around them scales. */
  font-family: var(--body); font-weight: 400;
  font-size: 1.02rem; line-height: 1.2;
  overflow-wrap: anywhere;
  /* NO text-transform, DELIBERATELY. The row value prints the address exactly as
     it is stored in the Customizer, which is lower-case, and Zsolt asked for it
     to read that way at both widths. An uppercase rule lived here briefly, back
     when the value was a copy.js string typed in caps; it is gone rather than
     overridden so nothing has to fight it in contact.small.css. The phone row
     shares this class and is unaffected either way. */
}
.crow__a {
  flex: none;
  font-family: var(--hud); font-weight: 400;
  font-size: .6rem; line-height: 1;
  letter-spacing: .18em; text-transform: uppercase;
  color: var(--red-label);
  transition: transform 200ms var(--ease-io);
}
/* THE ROW'S OWN HOVER COLOUR, and it has to be stated here.
   .crow is the <a>, and it carries `color: inherit` with no hover of its own —
   so the global `a:hover { color: var(--red) }` in main.css was winning and the
   value went #e6002a. That is the surface red, which RED-CONTACT-SERVICES.md §4
   makes a bug anywhere in this section; the header at the top of this file
   grants main.css's rule an exemption only on the grounds that every red link
   here overrides it, and this one did not. The result was both reds on screen
   at once, 8px apart: the value at #e6002a beside its own CALL/WRITE at
   #ff0a32.

   Only .crow__v changes. .crow__k and .crow__a both set their own colour, so
   the inherited value reaches the row value and nothing else. */
.crow:hover { color: var(--red-label); }
.crow:hover .crow__a { transform: translateX(4px); }


/* --- name / location / role ------------------------------------------------
   overflow:hidden makes this its own BFC too, so it clears the float at the
   same left edge as the rows above it. The 92px label column is what puts all
   three values on one vertical line. */

/* §3 — three rows in plain inline flow. THE ROW RHYTHM IS THE LINE HEIGHT, not
   margins: line-height 2 on 1.02rem body copy is what spaces them. overflow
   closes the float so all three clear it at one shared left edge. */
.contact__meta {
  overflow: hidden;
  margin-top: 2.1cqw;
  font-family: var(--body); font-weight: 400;
  font-size: 1.02rem; line-height: 2;
}
/* The 92px label column is what puts all three values on one vertical line. It
   is fixed px on purpose (§1: every mono label is), so the column edge holds
   while the copy beside it scales. */
.cmeta__k {
  display: inline-block;
  width: 92px;
  font-family: var(--hud); font-weight: 400;
  font-size: 10px; line-height: 1;
  letter-spacing: .16em; text-transform: uppercase;
  color: var(--grey-stat);
}
/* The label is a mono key; the value is a name, a city and a job title, so it
   takes the body face and its own case. Uppercasing it turned "Zsolt Földesi"
   into a label too and the pair stopped reading as key/value. */
.cmeta__v {
  font-family: var(--body); font-weight: 500;
  font-size: 14px; letter-spacing: 0; text-transform: none;
  color: var(--ink-head);
}


/* --- form ----------------------------------------------------------------- */

.contact__eyebrow {
  font-family: var(--hud); font-weight: 500;
  font-size: 11px; letter-spacing: .2em; text-transform: uppercase;
  color: var(--red-label);
  margin-bottom: 14px;
}

.cform__stack {
  display: grid; gap: 32px;
  padding-top: 22px;
  border-top: 1px solid rgba(18, 28, 42, .08);
}
.cform__label {
  display: block;
  font-family: var(--hud); font-weight: 500;
  font-size: 10px; letter-spacing: .14em; text-transform: uppercase;
  color: #6f767e;
  margin-bottom: 10px;
}
.cform__input {
  width: 100%;
  box-sizing: border-box;
  background: none;
  border: none;
  border-bottom: 1px solid rgba(18, 28, 42, .13);
  color: var(--banner-black);
  font-family: var(--body);
  /* 16px keeps iOS from zooming the page on focus. */
  font-size: 16px;
  line-height: 1.4;
  padding: 12px 12px 12px 0;
  /* §4 — "the accessible hit target and is not negotiable". 16px is also
     load-bearing: below it, mobile browsers zoom the page on focus. */
  min-height: 48px;
  transition: border-color 220ms var(--ease-io);
}
.cform__input--area { resize: none; line-height: 1.6; }
.cform__input::placeholder { color: #a2a8af; }
.cform__input:focus { outline: none; border-bottom-color: var(--red-label); }
/* The design removes the default outline, so keyboard users get an explicit ring
   on top of the red underline — item 5 on the handoff's not-yet-designed list. */
.cform__input:focus-visible {
  outline: 2px solid var(--red-label);
  outline-offset: 4px;
}

.cform__err {
  margin: 8px 0 0;
  font-family: var(--hud); font-weight: 500;
  font-size: 10px; letter-spacing: .12em;
  color: var(--red-label);
}
.cform__input.is-invalid { border-bottom-color: var(--red-label); }

/* Off-screen rather than display:none — some bots skip hidden fields. */
.cform__hp {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.cform__consent {
  display: flex; align-items: flex-start; gap: 12px;
  margin-top: 34px;
  cursor: pointer;
}
.cform__check {
  appearance: none; -webkit-appearance: none;
  width: 18px; height: 18px; flex: none;
  margin: 1px 0 0;
  border: 1px solid rgba(18, 28, 42, .28);
  background: #fff;
  cursor: pointer;
  transition: background 160ms var(--ease-io), border-color 160ms var(--ease-io);
}
/* Red ring around a core the colour of the section ground — §1.7 gives the
   inset as #e6e9eb, not #fff, so the checked box reads as a ring cut out of
   the page rather than a white chip sitting on it. */
.cform__check:checked {
  background: var(--red-label);
  border-color: var(--red-label);
  box-shadow: inset 0 0 0 3px #e6e9eb;
}
.cform__check.is-invalid { border-color: var(--red-label); }
.cform__consent span {
  font-family: var(--body); font-weight: 400;
  font-size: 12px; line-height: 1.6;
  color: #5c6672;
  max-width: 52ch;
}
.cform__privacy {
  color: var(--red-label);
  border-bottom: 1px solid rgba(var(--red-accent-rgb), .4);
  text-decoration: none;
}
.cform__privacy:hover { color: var(--red-label); }

.cform__actions { margin-top: 30px; }
.cform__submit {
  border: none;
  cursor: pointer;
  background: var(--red-label);
  color: #fff;
  font-family: var(--hud); font-weight: 700;
  font-size: 12px; letter-spacing: .16em; text-transform: uppercase;
  padding: 19px 36px;
  box-shadow: 0 10px 24px -12px rgba(var(--red-accent-rgb), .5);
  transition: transform 220ms var(--ease-io), box-shadow 220ms var(--ease-io);
}
.cform__submit:hover {
  transform: translateY(-2px);
  box-shadow: 0 14px 30px -12px rgba(var(--red-accent-rgb), .5);
}
.cform__submit.is-busy { pointer-events: none; opacity: .7; }

.cform__note {
  margin: 14px 0 0;
  font-family: var(--hud); font-weight: 500;
  font-size: 10px; letter-spacing: .12em;
  color: #6f767e;
}


/* --- staggered reveal -----------------------------------------------------
   Four beats, fired once on entering view and then playing on their own
   timeline. Named data-cv because data-rv and data-ts-rv are already taken. */

.contact [data-cv] {
  opacity: 0;
  transform: translateY(22px);
  transition: opacity 780ms cubic-bezier(.16, .84, .24, 1),
              transform 780ms cubic-bezier(.16, .84, .24, 1);
}
.contact [data-cv="1"] { transform: translateY(34px); }   /* the headline travels further */
.contact [data-cv].is-in { opacity: 1; transform: none; }


/* THE SEND BUTTON LANDS LAST — the closing beat of the reveal. It rides the
   form's own [data-cv="4"] class, so contact.js stays the only thing that
   decides when a beat fires; this is just a later arrival inside that beat.

   `translate`, NOT `transform`. The button already uses transform for its hover
   lift, and a reveal written in transform would either be overridden by the
   hover or override it — the two would fight for one property. `translate` is a
   separate property that composes with it, so the lift keeps working mid-reveal
   and afterwards. Both forms are covered: the hand-built button and
   Forminator's, which are the same design and take the same beat. */
.contact [data-cv="4"] .cform__submit,
.contact [data-cv="4"] .cform-wrap .forminator-button-submit {
  opacity: 0;
  translate: 0 10px;
  transition: opacity 620ms var(--ease-out) 260ms,
              translate 620ms var(--ease-out) 260ms;
}
.contact [data-cv="4"].is-in .cform__submit,
.contact [data-cv="4"].is-in .cform-wrap .forminator-button-submit {
  opacity: 1;
  translate: none;
}


@media (prefers-reduced-motion: reduce) {
  .contact [data-cv] { opacity: 1; transform: none; transition: none; }
  /* The button's landing goes with the rest of the reveal. The scramble stops
     itself — NF_ANIM.decode() checks the same query before it starts. */
  .contact [data-cv="4"] .cform__submit,
  .contact [data-cv="4"] .cform-wrap .forminator-button-submit {
    opacity: 1; translate: none; transition: none;
  }
  /* Parallax is skipped in contact.js; the plate keeps its base framing. */
}


/* ===========================================================================
   Forminator
   ---------------------------------------------------------------------------
   The form is rendered by Forminator with its design set to "none", so the
   plugin ships no CSS of its own and these rules are the only thing styling it.
   Values are not re-derived: every one is lifted from the .cform__* block above,
   so the Forminator form and the hand-built fallback are the same design.

   Forminator's own markup is what it is — .forminator-col wrappers, a checkbox
   split into an <input> plus a decorative <span>, a submit inside a "row". These
   rules map that structure onto the design rather than fighting it.
   =========================================================================== */

/* Forminator hides the form inline and reveals it from JS. If its script fails
   the section would be an empty column, so the form is forced visible and the
   plugin's reveal becomes a no-op. */
.cform-wrap form.forminator-ui { display: block !important; }

/* LAYOUT OVERRIDE — read the specificity before editing.
   Forminator's grid sheet lays the rows out with
     .forminator-ui.forminator-custom-form:not(…)[data-grid=open] .forminator-row
   which is five classes/attributes. A plain `.cform-wrap .forminator-row` is two
   and loses, and the fields come out as one horizontal strip. These two rules
   deliberately mirror that selector shape so they win by one, rather than
   reaching for !important or dequeuing a stylesheet the plugin's own JS may
   expect to be present. Keep the shape if you touch them. */
.contact .cform-wrap .forminator-ui.forminator-custom-form[data-grid] .forminator-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 32px;
  padding-top: 22px;
  border-top: 1px solid rgba(18, 28, 42, .08);
}
/* The columns are a flex-basis system underneath; in a grid they must simply
   fill their track. */
.contact .cform-wrap .forminator-ui.forminator-custom-form[data-grid] .forminator-row > [class*="forminator-col"] {
  width: auto;
  max-width: none;
  flex-basis: auto;
}
/* The submit sits in its own trailing row, which takes no rule and less air.
   Same specificity shape as the layout override above, for the same reason. */
.contact .cform-wrap .forminator-ui.forminator-custom-form[data-grid] .forminator-row-last {
  border-top: none;
  padding-top: 0;
  margin-top: 30px;
}
.cform-wrap .forminator-col { min-width: 0; }

.cform-wrap .forminator-label {
  display: block;
  font-family: var(--hud); font-weight: 500;
  font-size: 10px; letter-spacing: .14em; text-transform: uppercase;
  color: #6f767e;
  margin-bottom: 12px;
}
/* The design marks no field as required on screen — the labels are single words
   and the asterisk reads as noise. Validation still enforces it. */
.cform-wrap .forminator-required { display: none; }

.cform-wrap .forminator-input,
.cform-wrap .forminator-textarea {
  width: 100%;
  box-sizing: border-box;
  background: none;
  border: none;
  border-bottom: 1px solid rgba(18, 28, 42, .13);
  border-radius: 0;
  color: var(--banner-black);
  font-family: var(--body);
  font-size: 16px;              /* 16px keeps iOS from zooming on focus */
  line-height: 1.4;
  padding: 12px 12px 12px 0;
  min-height: 48px;             /* §4 — the accessible hit target */
  transition: border-color 220ms var(--ease-io);
}
.cform-wrap .forminator-textarea {
  resize: none; line-height: 1.6;
  min-height: 96px;             /* the design's 3-row textarea */
}
.cform-wrap .forminator-input::placeholder,
.cform-wrap .forminator-textarea::placeholder { color: #a2a8af; }
.cform-wrap .forminator-input:focus,
.cform-wrap .forminator-textarea:focus { outline: none; border-bottom-color: var(--red-label); }
.cform-wrap .forminator-input:focus-visible,
.cform-wrap .forminator-textarea:focus-visible {
  outline: 2px solid var(--red-label);
  outline-offset: 4px;
}

/* --- submit -------------------------------------------------------------- */

.cform-wrap .forminator-button-submit {
  border: none;
  border-radius: 0;
  cursor: pointer;
  background: var(--red-label);
  color: #fff;
  font-family: var(--hud); font-weight: 700;
  font-size: 12px; letter-spacing: .16em; text-transform: uppercase;
  padding: 19px 36px;
  box-shadow: 0 10px 24px -12px rgba(var(--red-accent-rgb), .5);
  transition: transform 220ms var(--ease-io), box-shadow 220ms var(--ease-io);
}
.cform-wrap .forminator-button-submit:hover {
  transform: translateY(-2px);
  box-shadow: 0 14px 30px -12px rgba(var(--red-accent-rgb), .5);
}
.cform-wrap .forminator-button-submit[disabled] { pointer-events: none; opacity: .7; }

/* --- validation and response --------------------------------------------- */

.cform-wrap .forminator-error-message {
  margin: 8px 0 0;
  font-family: var(--hud); font-weight: 500;
  font-size: 10px; letter-spacing: .12em;
  color: var(--red-label);
}
.cform-wrap .forminator-has_error .forminator-input,
.cform-wrap .forminator-has_error .forminator-textarea { border-bottom-color: var(--red-label); }

/* The success and error banners. NOT a designed state — the handoff lists both
   as outstanding — so this is deliberately plain: legible, on-brand, and easy to
   replace once the real states exist. */
.cform-wrap .forminator-response-message {
  margin: 0 0 18px;
  padding: 14px 16px;
  font-family: var(--hud); font-weight: 500;
  font-size: 11px; letter-spacing: .1em; line-height: 1.6;
}
.cform-wrap .forminator-response-message[aria-hidden="true"] { display: none; }
.cform-wrap .forminator-response-message.forminator-error {
  color: var(--red-label);
  background: rgba(var(--red-accent-rgb), .06);
}
.cform-wrap .forminator-response-message.forminator-success {
  color: var(--banner-black);
  background: rgba(18, 28, 42, .05);
}
.cform-wrap .forminator-response-message p { margin: 0; }


/* ===========================================================================
   NARROW DESKTOP — the form stacks under the section
   ---------------------------------------------------------------------------
   A SECOND BREAKPOINT, AND A DELIBERATE ONE. The rest of the theme has exactly
   one, at 768px, and CONTACT-DESKTOP.md says "No breakpoints. One layout from
   768px up". This is an approved exception, scoped to this section and to the
   grid — it does not introduce a small-screen design, it only stops the
   two-column one from being squeezed.

   WHY 1280. It is the reference design width named at the top of this file. At
   exactly 1280 the form column measures 351px, the width it is drawn at.
   Everything below that was shrinkage: 326px at 1200, 295px at 1100, 234px at
   900. Putting the edge any higher would mean the design as drawn never
   rendered on a 1280 screen.

   MEASURED, NOT EYEBALLED. Two columns at 1100 wide: copy lane 665px, CALL and
   WRITE wrapped onto their own line, form 295px. Stacked at the same width:
   lane 988px, rows back on one line. The section grows from 900px to about
   1675px tall, which is the cost and is why min-height goes.

   WHAT THIS DOES NOT FIX. The label column. `01 · PHONE` sizes from cqw, which
   is the SECTION's width and is unchanged by the grid, so it wrapped at every
   width below ~1560 and no breakpoint could have helped. It is fixed on
   .crow__k above, independently of this block.
   =========================================================================== */

@media (max-width: 1279.98px) {

  /* Content-driven now: two stacked blocks, not one screen. The form carries
     its own 72px bottom padding, so the section needs nothing here. */
  .contact { min-height: 0; }

  .contact__grid {
    grid-template-columns: minmax(0, 1fr);
    row-gap: 56px;
  }

  /* The form keeps roughly its drawn width instead of running the full section,
     and stays on the left edge so it lines up with the copy above it. */
  .contact__right { max-width: 560px; }

  /* CSS-SIZED HERE, NOT JS-SIZED. contact.js targets max(viewport, form height)
     so the portrait can reach the floor of a full-viewport section; with the
     form below it neither term means anything, and the form's height would make
     the portrait enormous. contact.js stops measuring at 1280 for that reason —
     that edge and this one are the same breakpoint written twice and must not
     disagree.

     Driven by WIDTH, because width is what decides whether the rows still fit
     beside it. 38% keeps it proportional; the 420px ceiling stops it dominating
     at the top of the band; the calc leaves the lane its ~300px so CALL and
     WRITE never wrap. aspect-ratio replaces the height the JS used to set —
     without it, a width cap against a fixed height would squash the cutout. */
  /* The base grid still applies; only the tracks tighten. The figure needs no
     rule of its own here any more — it is sized by its column. */
  /* Zero floor for the same reason as the base rule above: the 340px floor had
     44px of headroom at 768 and would overflow, not shrink, if it ever ran out.
     .crow carries flex-wrap, and that is what defends CALL and WRITE, not this. */
  .contact__body { grid-template-columns: min(38%, 420px) minmax(0, 1fr); }
}
