/* contact.css - /contact/ only (issue #76). Loaded via the page's own head slot; no selector here
   is referenced by any other page. Reuses site.css tokens (--paper/--sand/--green/--amber/--ink,
   --pad/--sec/--r-sec/--r-card/--r-pill, --h1/--h2/--h3) and utility classes (.wrap/.dark/.eyebrow/
   .h2/.hi/.btn/.ticks/.mask) rather than re-declaring them. Widths 360-767 are "phone" throughout;
   no rule here introduces horizontal overflow at 360/390/480/768/1024/1440/1920/2000/2560.
*/

/* ---------------------------------------------------------------- 1. hero (2.1) ------------- */
/* FIX ROUND 1 (issue #76, critics 2026-09-24/25), items 2+4+5: the cut-out floated 72-73px above
   the visible panel floor at desktop and 43-48px at phone, and was only 66% of the panel height at
   1440x900 (spec ~88%). Root cause: (a) `.contact-hero` carried its OWN bottom padding, so a
   `bottom:0`-anchored (or bottom-flex-aligned) figure landed on the PADDING edge, 48-72px above the
   panel's real border-box floor; (b) the grid's `align-items: center` centred a fixed, too-short
   `height: clamp(...)` figure inside a taller row instead of letting it fill it. Fix: the section
   itself now carries NO bottom padding (the panel's real floor and the grid's bottom coincide);
   the breathing room that padding gave the copy text moves to `.contact-hero-copy`'s own
   `padding-bottom`; `align-items: stretch` + a `min-height` on the grid (not on the figure) gives
   the row a real, viewport-anchored height so the person fills close to the whole panel instead of
   being capped by an arbitrary clamp; the image height changes from 88% of an undersized box to
   100% of the now-correctly-sized one. Verified: lab/probe-contact.mjs. */
.contact-hero {
  /* Flush with the viewport's own top edge (no gap above the fixed nav); rounds only where it
     meets §channels below - same "square at the page edge, round at the seam" rule the pinned
     .hero-card follows on the video-hero pages. */
  border-radius: 0 0 var(--r-sec) var(--r-sec);
  padding: calc(var(--nav-h) + 40px) 0 0;
  overflow: clip;
}
.contact-hero-grid {
  display: grid; grid-template-columns: minmax(0, 52fr) minmax(0, 48fr); gap: clamp(32px, 5vw, 64px);
  align-items: stretch;
  /* 88vh clamped 560-820: at 1440x900 this resolves to 792px: panel height = 136px top padding +
     792px row = 928px, image (100% of row) / panel = 792/928 = 0.853, clearing the >=0.85 floor
     measured by lab/probe-contact.mjs. */
  min-height: clamp(560px, 88vh, 820px);
}
.contact-hero-copy { display: flex; flex-direction: column; justify-content: center; align-items: flex-start; gap: 22px; max-width: 620px; padding-bottom: 72px; }
.contact-hero-copy .row { margin-top: 4px; }
.contact-chips { display: flex; flex-wrap: wrap; gap: 10px 16px; padding: 0; margin: 6px 0 0; list-style: none; }
.contact-chips li { display: inline-flex; align-items: center; gap: 8px; padding: 8px 16px; border: 1px solid var(--line-d); border-radius: var(--r-pill); font-size: 13px; color: var(--mute-d); }
.contact-chips i.tick { width: 14px; height: 14px; flex: none; border-radius: 50%; background: var(--amber); position: relative; }
.contact-chips i.tick::after { content: "\2713"; position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; font-size: 9px; line-height: 1; color: var(--green); font-weight: 700; }

/* `.contact-hero-figure` is a plain (non-absolute) grid item now: `align-items: stretch` above
   gives it the row's real, definite height, so its own `position: relative` box is a valid
   percentage-height containing block for `.contact-hero-person` below - no fixed height needed
   here any more (that fixed clamp was the 66%-of-panel bug). */
.contact-hero-figure { position: relative; }
/* Same "floor" mechanism the divorce-procedure consultant cut-out uses (dp-consultant.css): the
   image's own box has height:100% of this column with object-fit:contain, so its painted bottom
   edge is the box's bottom edge - which sits flush on the figure's own bottom (0 padding below),
   i.e. the panel's own floor. No background, radius, shadow or mask is ever added to the cut-out. */
.contact-hero-person { position: absolute; inset: 0; margin: 0; display: flex; align-items: flex-end; justify-content: center; pointer-events: none; }
.contact-hero-person img { display: block; width: auto; height: 100%; max-width: 100%; object-fit: contain; object-position: bottom; margin: 0 auto; }

/* FIX ROUND 1 item 2, then item C (code review): was `top: 6%`, which the desktop critic measured
   tight against the hair at 1024, and the reviewer then measured actually OVERLAPPING the head/face
   by 106-164px at 768/390/1024 once the figure grew to fill the panel. >=1024 keeps the "beside the
   shoulder" absolute placement but moved well past the head: 44% clears the reviewer's own assert
   (bubbles rect must not intersect the top 40% of the img rect) with margin. <1024 stops using
   position at all - see the media query below, which puts the whole stack in normal flow above the
   figure instead, so overlap is impossible by construction rather than by a percentage guess. */
.contact-bubbles { position: absolute; top: 44%; right: 5%; display: flex; flex-direction: column; align-items: flex-end; gap: 10px; max-width: 280px; pointer-events: none; }
.bubble { position: relative; padding: 12px 16px; border-radius: 18px 18px 4px 18px; font-size: 14px; line-height: 1.5; box-shadow: 0 12px 30px rgba(8,57,52,.18); }
.bubble p { margin: 0; }
.bubble-in { align-self: flex-start; background: var(--white); color: var(--ink); border-radius: 18px 18px 18px 4px; opacity: 0; transform: translateY(8px); animation: bubbleIn .5s ease-out .3s forwards; }
/* Typing indicator and the outgoing bubble occupy the SAME grid cell (issue #76 build note): the
   indicator fades out exactly as the real bubble fades in, at the same position, so one visually
   "replaces" the other instead of leaving a gap where the dots used to sit. */
.bubble-slot { display: grid; justify-items: end; }
.bubble-slot > * { grid-area: 1 / 1; }
.bubble-out { background: #F6E7C4; color: var(--ink); opacity: 0; transform: translateY(8px); animation: bubbleIn .5s ease-out 1.6s forwards; }
.bubble-typing { align-self: start; display: inline-flex; gap: 5px; padding: 12px 16px; border-radius: 18px 18px 18px 4px; background: var(--white); opacity: 0; animation: bubbleTyping .7s ease .9s forwards; }
.bubble-typing i { width: 6px; height: 6px; border-radius: 50%; background: rgba(16,32,27,.4); }
.bubble-caption { margin-top: 2px; font-size: 11px; color: var(--mute-d); opacity: 0; animation: bubbleIn .5s ease-out .3s forwards; }
@keyframes bubbleIn { to { opacity: 1; transform: translateY(0); } }
@keyframes bubbleTyping { 0% { opacity: 0; } 15% { opacity: 1; } 85% { opacity: 1; } 100% { opacity: 0; } }
@media (prefers-reduced-motion: reduce) {
  .bubble-in, .bubble-out, .bubble-caption { opacity: 1; transform: none; animation: none; }
  .bubble-typing { display: none; }
}

@media (max-width: 1023px) {
  /* FIX ROUND 1 item 5: section carries no bottom padding here either (was 48px) - the figure is
     the grid's last item with nothing after it, so it now lands flush on the panel's real floor. */
  .contact-hero { padding: calc(var(--nav-h) + 28px) 0 0; }
  .contact-hero-grid { grid-template-columns: 1fr; min-height: 0; text-align: center; }
  .contact-hero-copy { align-items: center; max-width: none; margin-inline: auto; padding-bottom: 24px; }
  .contact-hero-copy .row { justify-content: center; }
  .contact-chips { justify-content: center; }
  /* FIX ROUND 1 item C (code review): under 1024 the bubbles+caption stop being absolutely
     positioned over the image altogether (that is what let them land on the head/face at 768 and
     390 once the figure grew) - the whole figure becomes a small flex column with the bubble stack
     as a normal-flow block ABOVE the image, so overlap is impossible by construction, not by a
     percentage guess that only happened to work at one width. */
  .contact-hero-figure { display: flex; flex-direction: column; align-items: center; margin-top: 8px; order: 2; }
  .contact-hero-person { position: static; order: 2; height: 360px; width: 100%; }
  .contact-hero-person img { height: 100%; }
  .contact-bubbles { position: static; order: 1; align-items: center; max-width: 78%; margin: 0 auto 16px; top: auto; right: auto; }
  .bubble, .bubble-typing { align-self: center; font-size: 13px; }
  .bubble-caption { text-align: center; }
}

/* --------------------------------------------------------- 2. channels bento (2.2) ---------- */
.channels { padding: var(--sec) 0; }
.channels-head { max-width: 640px; margin-bottom: 40px; }
.channels-grid { display: grid; grid-template-columns: minmax(0, 34fr) repeat(2, minmax(0, 33fr)); grid-template-rows: repeat(2, auto); gap: 20px; }
.channel-card { border-radius: var(--r-card); padding: 28px; display: flex; flex-direction: column; gap: 14px; }
.channel-card.feature { grid-column: 1; grid-row: 1 / 3; background: var(--green); color: var(--paper); justify-content: space-between; }
.channel-card:not(.feature) { background: var(--white); border: 1px solid var(--line); }
.channel-card h3 { margin: 0; font-size: 19px; }
.channel-card .value { font-family: var(--serif); font-weight: 500; font-size: clamp(20px, 1.6vw, 24px); }
.channel-card p { margin: 0; font-size: 14px; line-height: 1.6; color: var(--mute); }
.channel-card.feature p { color: var(--mute-d); }
.channel-icon { width: 28px; height: 28px; flex: none; color: var(--green); }
.channel-card.feature .channel-icon { color: var(--amber); }
.channel-card .btn { align-self: flex-start; margin-top: 4px; }
/* The three white cards' outline buttons need ink-on-white, not `.btn-outline`'s paper-on-dark
   default (site.css) - same scoped-override pattern Faq.astro's own `.faq .btn-outline` already
   uses for the identical problem. */
.channel-card:not(.feature) .btn-outline { color: var(--ink); border-color: var(--line); }
/* FIX ROUND 1 item 1 (critic, desktop BLOCK): the chevron carried no size rule outside the <768
   media query, so at every desktop width it rendered at its raw/stretched SVG box (~366x366px).
   It is a phone-row affordance only - fixed 20x20 at every width it's shown, hidden at >=768. */
.channel-chevron { width: 20px; height: 20px; flex: none; color: var(--mute); }
@media (min-width: 768px) { .channel-chevron { display: none; } }
.channel-qr { display: none; }
/* FIX ROUND 1 item G (code review): was showing at 768-1023 at 96px; spec is hidden below 1024,
   148px (matching the img's own width/height attributes) at >=1024 only. */
.channel-card.feature .channel-qr-panel { display: none; align-items: center; gap: 14px; margin-top: 6px; }
.channel-card.feature .channel-qr-panel img { width: 148px; height: 148px; background: var(--white); border-radius: 12px; padding: 8px; }
.channel-card.feature .channel-qr-panel span { font-size: 12px; color: var(--mute-d); max-width: 140px; }
@media (min-width: 1024px) { .channel-card.feature .channel-qr-panel { display: flex; } }
.channel-wechat-qr { width: 112px; height: 112px; border-radius: 12px; border: 1px solid var(--line); padding: 6px; background: var(--white); flex: none; }
.channel-wechat-caption { font-size: 12px; color: var(--mute); }
.nowrap { white-space: nowrap; }
/* WORK-ORDER §2.2 card 4: the QR + a caption stay visible at EVERY width (unlike the other three
   compact cards' `p`/button, hidden under 768 below); only the caption's wording swaps. */
.channel-caption-desktop { display: inline; }
.channel-caption-phone { display: none; }
@media (max-width: 767px) {
  .channel-caption-desktop { display: none; }
  .channel-caption-phone { display: inline; }
}
/* FIX ROUND 1 item B (code review): WeChat has no tap-through URL, so its own head row (icon +
   title/value) sits apart from the QR-plus-caption media row, which is always full width and on
   its own line - at EVERY width, not just phone (this replaces round-1 item 6's since-superseded
   72px inline-QR idea). */
.channel-wechat-head { display: flex; align-items: center; gap: 16px; }
.channel-wechat-media { display: flex; align-items: center; gap: 12px; margin-top: 4px; }

/* Desktop (>=1024): `.channel-others` is a plain wrapper - `display: contents` removes it from
   the box tree so its 4 <a>/<article> children become direct items of `.channels-grid` itself and
   auto-place into the two remaining column tracks x two rows (2x2), beside the feature card. */
.channel-others { display: contents; }

@media (min-width: 768px) and (max-width: 1023px) {
  /* WhatsApp feature full width on top, four cards 2x2 below (WORK-ORDER §2.2). */
  .channels-grid { display: block; }
  .channel-others { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; margin-top: 20px; }
}
@media (max-width: 767px) {
  /* WhatsApp feature full width, then the four as compact full-width rows (WORK-ORDER §2.2):
     `.channel-others` stays `display: contents` so each card becomes its own row in this column. */
  .channels-grid { display: flex; flex-direction: column; gap: 14px; }
  .channel-card:not(.feature):not(.channel-wechat) { flex-direction: row; align-items: center; gap: 16px; padding: 14px 16px; min-height: 64px; border-radius: var(--r-sm); }
  .channel-card:not(.feature) .channel-icon { width: 24px; height: 24px; }
  .channel-card:not(.feature) .channel-row-copy { display: flex; flex-direction: column; gap: 2px; flex: 1; min-width: 0; }
  .channel-card:not(.feature) h3 { font-size: 15px; }
  .channel-card:not(.feature) .value { font-size: 15px; flex: 1 1 auto; min-width: 0; }
  .channel-card:not(.feature) > p, .channel-card:not(.feature) > .btn { display: none; }
  .channel-wechat-caption { font-size: 11px; }
  /* WeChat keeps its own column layout at phone width: head row (icon+title/value) on top, then
     the QR-plus-caption media row below, full width - never squeezed into the 64px tap-row shape
     the other three cards use, which is what forced the 3-line "QR code" wrap this replaces. */
  .channel-card.channel-wechat { flex-direction: column; align-items: stretch; padding: 16px; border-radius: var(--r-sm); gap: 10px; }
}

/* -------------------------------------------------------------- 3. visit office (2.3) ------- */
/* FIX ROUND 1 item 3: same bug and same fix as the hero (§1 above) - `padding: var(--sec) var(--pad)`
   gave the section its OWN bottom padding, so the flex-bottom-aligned figure landed on the padding
   edge, 97-114px above the sand panel's real floor, and `align-items: center` on the grid could add
   further slack around a fixed-height figure. The section now carries top+side padding only; the
   copy column gets its own `padding-bottom` for breathing room, and `align-items: stretch` + a
   `min-height` on the grid gives the (now non-absolute) figure a real row height to fill, so its
   flex-bottom-aligned image lands exactly on the section's true bottom edge. Re-fit for the retaken
   952x1400 -> 1218x1400 art (wider now - the grid's own column width already comfortably clears the
   new aspect ratio at every tested width, verified by lab/probe-contact.mjs). */
.visit { background: var(--sand); border-radius: var(--r-sec); padding: var(--sec) var(--pad) 0; margin: 0 var(--pad); }
.visit-grid { display: grid; grid-template-columns: minmax(0, 6fr) minmax(0, 6fr); gap: clamp(32px, 5vw, 64px); align-items: stretch; min-height: clamp(380px, 44vh, 520px); }
.visit-copy { max-width: 480px; display: flex; flex-direction: column; justify-content: center; padding-bottom: var(--sec); }
.visit-address { font-family: var(--serif); font-weight: 500; font-size: var(--h3); line-height: 1.4; margin: 16px 0; }
.visit-copy .lead { color: var(--mute); margin-bottom: 18px; }
.visit-copy .ticks { margin-bottom: 24px; }
.visit-figure { position: relative; display: flex; align-items: flex-end; justify-content: center; margin: 0; }
.visit-figure img { display: block; width: auto; height: 100%; max-width: 100%; object-fit: contain; object-position: bottom; margin: 0 auto; }

@media (max-width: 1023px) {
  .visit { margin: 0 12px; padding: 56px 24px 0; }
  .visit-grid { grid-template-columns: 1fr; text-align: center; min-height: 0; }
  .visit-copy { margin-inline: auto; padding-bottom: 32px; }
  .visit-copy .ticks { text-align: left; display: inline-block; }
  .visit-figure { order: 2; height: 320px; margin-top: 8px; }
}

/* --------------------------------------------------------- 4. next steps (2.4) -------------- */
.next-steps { background: var(--bg-loop-process); border-radius: var(--r-sec); padding: var(--sec) var(--pad); margin: 0 var(--pad); }
.next-steps-head { max-width: 640px; margin-bottom: 44px; }
.next-steps-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: clamp(28px, 4vw, 48px); }
.next-step { display: flex; flex-direction: column; gap: 14px; }
.next-step figure { margin: 0; background: var(--bg-loop-process); aspect-ratio: 4/3; display: flex; align-items: center; justify-content: center; }
.next-step figure img { width: 100%; height: 100%; object-fit: contain; }
.next-step .num { font-family: var(--serif); font-size: 15px; color: var(--mute); }
.next-step h3 { margin: 0; }
.next-step p { margin: 0; color: var(--mute); font-size: 14px; line-height: 1.7; }
/* FIX ROUND 1 item 7: measured 23.8px tall (14px font x the body's 1.7 line-height, no padding of
   its own) - under the 44px minimum tap target. padding-block adds the missing height around the
   text; the matching negative inline margin cancels the padding's effect on where the text itself
   sits, so the line does not visibly move. */
.next-steps-link { display: inline-block; margin: 24px 0 0 -4px; padding: 12px 4px; font-size: 14px; font-weight: 600; text-decoration: underline; text-underline-offset: 4px; }

@media (max-width: 767px) {
  .next-steps { margin: 0 12px; padding: 48px 20px; }
  .next-steps-grid { grid-template-columns: 1fr; gap: 32px; }
}
