/* ==========================================================================
   sections-story.css
   --------------------------------------------------------------------------
   PHẠM VI FILE NÀY (2 section):
     - S4  #quote (.quote)  — reference SECTION5, 420×637.7
           Ảnh tràn viền + lớp phủ tối chuyển sắc + câu script trắng ở 1/3 dưới.
     - S5  #story (.story)  — reference SECTION6, 420×857.7, 8 lớp trang trí
           "Our story" + đoạn chuyện tình trong thẻ kem + con dấu sáp +
           2 thẻ hồ sơ (Cô dâu / Chú rể) lệch nhau theo đường chéo.

   CẢNH BÁO BÀN GIAO: comment stub gốc của file này còn ghi cả #invitation
   (.invitation + .families__*). Nhiệm vụ của agent này CHỈ gồm S4 + S5, nên
   #invitation HIỆN CHƯA CÓ CSS ở bất kỳ file nào. Xem báo cáo bàn giao.

   NGUYÊN TẮC ĐÃ TUÂN THỦ
   1. Không literal màu / font-family — chỉ dùng biến của tokens.css.
   2. Không định nghĩa lại utility của base.css; chỉ tinh chỉnh thuộc tính
      riêng lẻ trên phần tử của section này.
   3. Mobile-first (gốc = 390px), rồi 768px và 1024px cho hoạ tiết tràn rộng.
   4. Mọi selector đều neo dưới .quote / .story → không rò rỉ ra ngoài.
   5. KHÔNG đặt transform cố định lên phần tử mang .reveal (animations.css có
      `.reveal.is-visible { transform: none }` sẽ xoá mất). Mọi phép nghiêng
      đều đặt ở phần tử CON: .story__profile (reveal) > .story__plate >
      .story__photo. Khung giấy PNG đã nghiêng sẵn trong pixel → không xoay.
   6. Phần tử mang .drift (.story__seal) cũng KHÔNG được đặt transform tĩnh —
      keyframes drift-float ghi đè transform. Lệch vị trí bằng margin.
   ========================================================================== */

/* ==========================================================================
   S4 — #quote  (reference SECTION5: 420 × 637.7)
   Toạ độ gốc quy về phần trăm:
     - BOX5  ảnh nền:            0,0 → 420×637.7  (phủ kín 100%)
     - BOX7  lớp phủ chuyển sắc: top 311.7 = 48.9% → hết đáy,
             linear-gradient(rgba(2,2,2,0) → rgba(1,1,1,.6))
     - HEADLINE34 câu script:    top 407.75 = 63.9%, cao ~2 dòng → đáy ≈ 82%
   Vì tokens.css KHÔNG có --ink-rgb / --olive-rgb (xem báo cáo), lớp phủ phải
   pha bằng rgba(var(--sage-rgb), …). Sắc sage nhạt hơn đen nên phải tăng độ
   đục ở đúng dải chữ để chữ trắng vẫn đủ tương phản trên ảnh placeholder
   (ảnh placeholder có tâm gần trắng → đây là trường hợp xấu nhất).
   ========================================================================== */
.quote {
  /* Một cột: .quote__inner là item duy nhất trong luồng, dồn xuống đáy để
     câu script nằm ở 1/3 dưới đúng như reference. */
  display: grid;
  align-items: end;

  /* 420 × 637.7 của reference ⇒ cao ≈ 1.52 lần chiều rộng cột.
     145vw giữ đúng tỉ lệ đó ở mobile, clamp chặn hai đầu để ở desktop
     ảnh không cao vô lý. */
  min-block-size: clamp(25rem, 145vw, 38rem);

  /* Ghi đè padding-block mặc định của .section: chữ cách đáy ~14% chiều cao. */
  padding-block: var(--sp-8) var(--sp-10);
}

/* Ảnh tràn viền: phủ kín section, kể cả phần padding. Nằm dưới .content
   (z-index --z-decor = 1 < --z-content = 2). */
.quote__media {
  position: absolute;
  inset: 0;
  z-index: var(--z-decor);
  overflow: hidden;

  /* Nền dự phòng khi ảnh chưa tải xong / tải lỗi (render.js ẩn <img> lỗi):
     --sage-soft vẫn đủ tối để chữ trắng đọc được sau lớp phủ. */
  background-color: var(--sage-soft);
}

.quote__photo {
  inline-size: 100%;
  block-size: 100%;
  /* object-fit thay cho chiều cao cứng → không bao giờ bóp méo ảnh. */
  object-fit: cover;
  object-position: center 28%;
}

/* Lớp phủ: KHÔNG phải màn nước phẳng. Trên cùng chỉ mờ nhẹ để ảnh còn "đọc"
   được, tối dần và đậm nhất đúng dải 64%–100% nơi câu script nằm.
   Kiểm tra tương phản (trường hợp xấu nhất: ảnh trắng tinh):
     α .78 → 3.96:1 · α .84 → 4.6:1 · α .88 → 4.9:1
   cộng thêm text-shadow ở .quote__script. */
.quote__scrim {
  position: absolute;
  inset: 0;
  background-image: linear-gradient(
    to bottom,
    rgba(var(--sage-rgb), 0.3) 0%,
    rgba(var(--sage-rgb), 0.12) 24%,
    rgba(var(--sage-rgb), 0.3) 44%,
    rgba(var(--sage-rgb), 0.66) 56%,
    rgba(var(--sage-rgb), 0.84) 68%,
    rgba(var(--sage-rgb), 0.88) 100%
  );
}

/* .quote__inner không cần luật riêng: .content đã lo max-inline-size 420px,
   padding-inline và z-index --z-content; align-items: end của .quote dồn nó
   xuống 1/3 dưới. */
.quote__script {
  color: var(--on-dark);
  /* reference: line-height 1.6 (utility .t-script-lg dùng 1.4). */
  line-height: var(--lh-relaxed);
  /* Bảo hiểm tương phản cho nét script mảnh ở mép trên dải chữ. */
  text-shadow: 0 2px 14px rgba(var(--sage-rgb), 0.7);
}

@media (min-width: 768px) {
  .quote {
    min-block-size: min(78vh, 42rem);
    /* Panel cao hơn ⇒ nới đáy để chữ vẫn dừng ở ~85% chiều cao như reference
       (reference: đáy khối chữ ở 82% của 637.7px). */
    padding-block-end: calc(var(--sp-10) + var(--sp-5));
  }

  .quote__photo {
    object-position: center 30%;
  }
}

@media (min-width: 1024px) {
  .quote {
    min-block-size: min(82vh, 46rem);
  }

  /* SỬA CẮT ẢNH TRÊN DESKTOP.
     Trước: .quote__media tràn viền (inset: 0) nên ở 1440px khung đo được
     1440×736 = tỉ lệ 1.957, trong khi ảnh nguồn là 750×1000 (tỉ lệ 0.75) →
     object-fit: cover chỉ giữ 38% chiều cao ảnh, tức cắt ngang qua giữa một
     bức ảnh dọc. Ở 390px vẫn giữ 92% nên lỗi chỉ hiện ra khi mở trên laptop.
     Reference #SECTION5 là 420×637.7 — không bao giờ letterbox.
     Nay: chặn ở --w-stage và canh giữa (left/right = 0 + margin-inline: auto
     khiến khối absolute tự canh giữa khi max-inline-size nhỏ hơn khoảng trống),
     nên khung giữ tỉ lệ gần reference thay vì bị bề ngang viewport kéo dẹt. */
  .quote__media {
    inset-inline: 0;
    max-inline-size: var(--w-stage);
    margin-inline: auto;
    border-radius: var(--r-lg);
  }

  .quote__scrim {
    border-radius: var(--r-lg);
  }
}

/* ==========================================================================
   S5 — #story  (reference SECTION6: 420 × 857.7)
   Toạ độ gốc quy về phần trăm (theo khung 420 × 858):
     - IMAGE27 nhánh tú cầu cao   left 0     = 0%    · top 41    = 4.8%  · w 26.5%
     - IMAGE28 dấu sáp + lan      left 188   = 44.8% · top 177.8 = 20.7% · w 26.6%
     - IMAGE29 tú cầu bản rộng    left 287.8 = 68.5% · top 440.6 = 51.4% · w 31.5%
     - GROUP26 thẻ hồ sơ trên     left 21.7  = 5.2%  · top 61    = 7.1%  · 235×259
     - GROUP25 thẻ hồ sơ dưới     left 172.5 = 41.1% · top 255.5 = 29.8% · 235×260
     - GROUP56 chữ + đoạn văn     left 21.7  · top 515.4 = 60%
   Reference xếp 2 thẻ hồ sơ TRƯỚC rồi mới tới "Our story" + đoạn văn; DOM của
   ta (hợp đồng, không được đổi) xếp ngược lại: tiêu đề → đoạn văn → dấu sáp →
   2 thẻ hồ sơ. Vì vậy giữ đúng THẦN của bố cục — đường chéo trên-trái xuống
   dưới-phải giữa hai thẻ — chứ không sao chép y nguyên toạ độ dọc.
   ========================================================================== */
.story {
  padding-block: var(--sp-9);
}

/* .story__stage KHÔNG được đặt overflow: clip.
   .stage (base.css) đã là position: relative → đủ làm containing block cho
   .decor. Nếu clip ở đây thì hoạ tiết bleed sẽ bị CẮT THẲNG ở mép stage 520px
   thay vì chạy ra ngoài mép màn hình như reference. Việc chặn cuộn ngang là
   của .section (overflow-x: clip) — đã kiểm chứng scrollWidth === clientWidth
   ở 360/390/420/768/1024/1440. */

/* --- Hai lớp hoạ tiết hoa ----------------------------------------------
   BÊN TRÁI dùng lại đúng bó hoa bên trái của đầu thư
   (bouquet-orchid-hydrangea-left.png — lan trắng trên cụm cẩm tú cầu), BÊN PHẢI
   vẫn là chùm cẩm tú cầu bản rộng (hydrangea-spray-wide.png).
   Ảnh trái tỉ lệ 0.58 còn ảnh cũ ở chỗ này là 0.44, nên với CÙNG một
   `inline-size` bó mới THẤP hơn ~23% — cố ý giữ nguyên các mốc % bên dưới:
   chúng đã được chỉnh cho vừa khung, mà chiều cao giảm thì chỉ càng an toàn. */
/* .decor lo z-index / pointer-events / absolute; ở đây chỉ đặt inset + cỡ.
   Cỡ tính theo % của .stage nên tự co giãn; ảnh gốc xuất ở ~2× khung hiển
   thị nên thu nhỏ vẫn nét.

   ⚠ Ở BREAKPOINT GỐC (dưới 768px) HAI BÓ HOA PHẢI NẰM TRỌN TRONG KHUNG —
   KHÔNG ĐƯỢC ĐẶT OFFSET ÂM. Lý do là hình học, không phải khẩu vị:
   .stage là `inline-size: 100%; max-inline-size: 520px`, nên dưới 520px nó
   RỘNG ĐÚNG BẰNG KHUNG NHÌN, không còn lề hai bên để hoạ tiết "chảy" vào.
   Offset âm lúc đó rơi thẳng ra ngoài khung nhìn và bị `overflow-x: clip`
   của .section cắt bằng MỘT ĐƯỜNG DỌC THẲNG ĐỨNG ngay giữa chùm hoa.
   Đo ở khung nhìn 390px với bản cũ (−7% / −9%):
       bó trái  rộng 105px, mất 27px = 26% bề ngang
       bó phải  rộng 121px, mất 35px = 29% bề ngang
   Vì cắt đúng vào ĐẦU HOA (phần tròn, dày cánh) nên nhìn ra ngay là ảnh bị
   xén, khác hẳn cụm hoa ở #hero — nơi .hero__bouquet-left để
   `inset-inline-start: 0` và bó phải kết thúc ở 101.2%, tức chỉ chạm mép,
   mất khoảng 4% không ai thấy. Nay hai bó ở đây theo đúng quy ước đó.

   Từ 768px trở lên thì offset âm LẠI AN TOÀN và vẫn được giữ (xem hai khối
   @media cuối file): .stage bị chặn ở 520px và căn giữa nên hai bên đã có lề
   thật (ở 768px là 124px mỗi bên), bleed −12%/−14% của 520px chỉ ăn vào lề
   đó chứ không tới mép .section — hoa vẫn nguyên chùm. */
/* HAI BÓ HOA VẼ ĐÈ LÊN NỘI DUNG, GIỐNG CỤM HOA Ở ĐẦU THƯ.
   `.decor` (base.css) đặt sẵn z-index: var(--z-decor) = 1, tức THẤP HƠN
   --z-content = 2 → hoa bị tấm thẻ giấy kem và hai khung ảnh che mất.
   Nâng lên đúng BẰNG giá trị của hai bó hoa ở #hero — .hero__bouquet-left /
   -right dùng calc(var(--z-decor) + 5) = 6 — để cả thiệp chỉ có MỘT quy ước
   "hoa nằm trước" thay vì hai con số rời nhau.
   An toàn về tương tác: `.decor` đã có pointer-events: none, nên dù hoa phủ
   lên .story__plate thì hiệu ứng lắc lư khi trỏ chuột vào ảnh vẫn nhận được
   chuột như thường.
   ⚠ ĐÁNH ĐỔI phải biết: từ giờ tấm thẻ kem KHÔNG còn che được hoa nữa, nên bó
   trái quét qua góc trên-trái của thẻ chữ. Cánh hoa rất nhạt (trắng ngà) nên
   chữ sage vẫn đọc được, nhưng nếu thấy rối thì hạ `inset-block-start` của
   .story__spray-left xuống ~2% cho nó lùi lên ngang dải tiêu đề, chỗ chỉ có
   ảnh chữ script chứ không có chữ nhỏ. */
.story__spray-left {
  inline-size: 21%;
  inset-block-start: 7%;
  inset-inline-start: 0;
  opacity: 0.85;
  z-index: calc(var(--z-decor) + 5);
}

.story__spray-right {
  inline-size: 24%;
  inset-block-start: 52%;
  inset-inline-end: 0;
  opacity: 0.85;
  z-index: calc(var(--z-decor) + 5);
}

/* --- Tiêu đề "Our story" (ảnh chữ script sage) -------------------------- */
/* .story__heading mang .reveal.reveal--down → KHÔNG đặt transform ở đây. */
.story__heading {
  margin-block-end: var(--sp-4);
}

.story__heading-img {
  /* reference: 257.4 / 420 = 61% cột nội dung. */
  inline-size: min(100%, 16rem);
  block-size: auto;
  margin-inline: auto;
}

/* --- Đoạn chuyện tình (thẻ giấy kem) ----------------------------------- */
/* .card của base.css đã lo nền --cream / bo góc / đổ bóng / padding.
   Ở đây chỉ thêm viền lông mày mảnh và nhịp cách giữa các <p>
   (data-multiline="p" ⇒ render.js sinh nhiều thẻ <p>). */
.story__body {
  border: 1px solid rgba(var(--sage-rgb), 0.12);
  text-wrap: pretty;
}

.story__body p + p {
  margin-block-start: var(--sp-3);
}

/* --- Con dấu sáp + hoa lan --------------------------------------------- */
/* Không phải .decor: là phần tử TRONG luồng của .story__inner. Kéo lên bằng
   margin âm để "dán" vào mép dưới thẻ giấy như một dấu sáp thật.
   Mang .drift ⇒ transform thuộc về keyframes, chỉ được lệch bằng margin. */
.story__seal {
  display: block;
  inline-size: clamp(4.5rem, 24%, 6.5rem);
  block-size: auto;
  /* reference: tâm dấu sáp ở ~58% chiều ngang cột → hơi lệch phải. */
  margin-inline-start: 45%;
  margin-inline-end: auto;
  margin-block: calc(var(--sp-6) * -1) var(--sp-5);
  pointer-events: none;
  user-select: none;
  -webkit-user-select: none;

  /* position + z-index là BẮT BUỘC, không phải thừa.
     Dấu sáp là phần tử TĨNH trong luồng, còn anh em liền trước nó — .story__body
     mang .card của base.css — là `position: relative` + nền --cream ĐẶC. Theo
     thứ tự vẽ của CSS (khối trong luồng ở bước 4, khối positioned z-auto ở bước
     8), tấm thẻ phải nằm TRÊN dấu sáp. Hiện nó không nằm trên chỉ vì .drift
     đang gán transform cho dấu sáp, mà transform thì tự tạo stacking context và
     đẩy nó lên bước 8. Nhưng animations.css có
     `@media (prefers-reduced-motion: reduce) { .drift { transform: none } }` —
     nghĩa là ĐÚNG những khách bật "giảm chuyển động" sẽ thấy lớp xếp lộn ngược:
     32px trên của dấu sáp (nhánh lan + 3 nụ, ~14% ảnh) bị mép dưới thẻ cắt
     ngang bằng một đường thẳng. Đã kiểm bằng elementsFromPoint ở cả hai trạng
     thái. Neo lớp bằng chính CSS thay vì mượn transform của animation. */
  position: relative;
  z-index: var(--z-content);
}

/* --- Hai thẻ hồ sơ ------------------------------------------------------ */
/* Bố cục "sắp bằng tay": thẻ Cô dâu ảnh bên TRÁI (chữ bên phải) và nhích về
   mép trái; thẻ Chú rể ảnh bên PHẢI (chữ bên trái) và nhích về mép phải.
   Xếp dọc + soi gương như vậy tái tạo đúng đường chéo trên-trái → dưới-phải
   của reference (top 61/left 22 và top 255/left 173) và GIỮ được độ lệch đó
   ở mọi bề rộng, kể cả 360px. */
.story__profiles {
  /* Hai biến để tinh chỉnh theo breakpoint mà không lặp lại luật.
     --story-plate = bề rộng khung ảnh, phần còn lại là cột chữ.

     45%, KHÔNG phải 50%. Ghi chú cũ ở đây khẳng định 50% giữ cho tên "không bị
     vỡ thành 3 dòng" — ĐO LẠI THÌ SAI: ở 50% cột chữ chỉ được 147px (390px) và
     155px (1440px), trong khi tên đầy đủ in hoa 23px cần 281–284px, nên CẢ HAI
     tên đều vỡ 3 dòng ở desktop. Đã đổi markup sang shortName (xem ghi chú ở
     index.html) và nới cột chữ: 45% cho 163px ở 390px, 179px ở 1440px, đủ cho
     "QUANG DANH" (150–168px) nằm gọn MỘT dòng.
     Khung ảnh nhỏ đi ~11% — giá phải trả, đổi lại hai thẻ hồ sơ cân nhau.
     Ở 320px cột chữ còn 124px nên "QUANG DANH" vẫn xuống 2 dòng; muốn sạch cả
     320px thì phải hạ thêm cỡ chữ .story__name, không đáng. */
  --story-plate: 45%;
  --story-shift: var(--sp-5);

  display: grid;
  gap: var(--sp-6);
}

.story__profile {
  display: grid;
  grid-template-columns: var(--story-plate) minmax(0, 1fr);
  grid-template-rows: auto auto auto;
  column-gap: var(--sp-3);
  align-content: center;
  /* reference: cả hai nhãn đều canh trái. */
  text-align: start;
}

/* Thẻ Cô dâu: ảnh cột 1, chữ cột 2, cả khối nhích về mép trái. */
.story__profile--bride {
  margin-inline-end: var(--story-shift);
}

/* Thẻ Chú rể: soi gương — ảnh cột 2, chữ cột 1, khối nhích về mép phải. */
.story__profile--groom {
  grid-template-columns: minmax(0, 1fr) var(--story-plate);
  margin-inline-start: var(--story-shift);
}

/* --- Khung giấy + ảnh chân dung ---------------------------------------- */
.story__plate {
  position: relative;
  grid-column: 1;
  grid-row: 1 / -1;
  align-self: center;
}

.story__profile--groom .story__plate {
  grid-column: 2;
}

/* Ảnh PNG khung giấy ĐÃ nghiêng sẵn trong pixel (±6°) và đã có bóng đổ →
   tuyệt đối không xoay lại, chỉ để nó quyết định chiều cao của .story__plate. */
.story__plate-img {
  inline-size: 100%;
  block-size: auto;
}

/* Ảnh chân dung đặt vào đúng ô giấy trắng của khung.
   reference (BOX8/BOX9 trong khung 235×259):
     left 28.5/235 = 12.1% · top 25/259 = 9.6% · w 178.7/235 = 76%
     tỉ lệ ảnh 178.7/205.9 ≈ 7/8 · nghiêng +9° (khung phải) / −10° (khung trái)
   Dùng aspect-ratio thay chiều cao cứng nên ảnh không bao giờ bị bóp méo. */
.story__photo {
  position: absolute;
  inset-block-start: 10%;
  inset-inline-start: 12.4%;
  inline-size: 75%;
  aspect-ratio: 7 / 8;
  object-fit: cover;
  object-position: center 22%;

  /* Viền giấy mảnh + bóng nhẹ để ảnh nổi khỏi mặt thẻ trắng
     (reference dùng viền 2px màu trắng ngà). */
  border: 0.1875rem solid var(--ivory);
  box-shadow: var(--shadow-sm);
}

/* Nghiêng ảnh THEO chiều nghiêng của khung, lệch thêm ~3° cho ra vẻ dán tay.
   Đặt ở phần tử con nên không đụng tới transform của .reveal ở <article>. */
.story__profile--bride .story__photo {
  transform: rotate(-9deg);
}

.story__profile--groom .story__photo {
  transform: rotate(9deg);
}

/* Khi trỏ chuột vào, ảnh chân dung LẮC LƯ nhẹ quanh CHÍNH góc nghiêng gốc
   (±3.5° so với −9° / +9°) thay vì duỗi thẳng về 0° — giữ được vẻ "dán tay"
   mà vẫn sinh động. Chỉ bật ở thiết bị có con trỏ thật; prefers-reduced-motion
   ở cuối file tắt hẳn animation. */
@media (hover: hover) {
  .story__photo {
    transition: transform var(--dur-base) var(--ease-out);
  }

  .story__profile--bride .story__plate:hover .story__photo {
    animation: story-sway-bride calc(var(--dur-slow) * 2) var(--ease-in-out) infinite;
  }

  .story__profile--groom .story__plate:hover .story__photo {
    animation: story-sway-groom calc(var(--dur-slow) * 2) var(--ease-in-out) infinite;
  }
}

/* Lắc lư quanh góc gốc: mốc 0%/100% ĐÚNG bằng góc nghiêng tĩnh nên khi rời
   chuột ảnh trở lại vị trí cũ mượt, không giật. */
@keyframes story-sway-bride {
  0%, 100% { transform: rotate(-9deg); }
  25%      { transform: rotate(-12.5deg); }
  75%      { transform: rotate(-5.5deg); }
}

@keyframes story-sway-groom {
  0%, 100% { transform: rotate(9deg); }
  25%      { transform: rotate(12.5deg); }
  75%      { transform: rotate(5.5deg); }
}

/* --- Chữ trong thẻ hồ sơ ------------------------------------------------ */
/* Cột chữ nằm ở cột 2 (Cô dâu) hoặc cột 1 (Chú rể). Ba dòng = ba hàng grid,
   dồn giữa theo chiều dọc so với ảnh. */
.story__role {
  grid-column: 2;
  grid-row: 1;
  align-self: end;
  /* UVNHoaTay có nét bay cao/thấp → nới nhẹ so với .t-hand. */
  line-height: var(--lh-snug);
}

.story__name {
  grid-column: 2;
  grid-row: 2;
  /* reference: 23px ⇒ --fs-xl (utility .t-heading chỉ 16.8–19.2px).
     Dùng clamp RIÊNG thay vì var(--fs-xl): cùng nhịp 5vw và cùng trần 1.45rem,
     chỉ hạ SÀN 1.3rem → 1.05rem. Lý do: ở khổ 320px cột chữ chỉ còn 124px,
     mà "QUANG DANH" ở sàn cũ rộng 150px ⇒ tên gọi bị cắt đôi thành
     "QUANG" / "DANH". Không chữa được bằng dấu cách không ngắt — chữ sẽ tràn
     ra ngoài cột.
     Sàn 1rem (16px) cho "QUANG DANH" rộng 119px, dư 5px. Đã thử 1.05rem trước:
     ra đúng 125px, THIẾU 1px so với cột 124px và vẫn vỡ đôi — nhắc lại đây để
     đừng ai chỉnh ngược lên. Từ 390px trở lên nhịp 5vw đã vượt sàn nên KHÔNG
     có gì đổi so với trước. */
  font-size: clamp(1rem, 5vw, 1.45rem);
  margin-block-start: var(--sp-1);
  /* Tên 2–3 từ trong cột hẹp: chia dòng cho đều thay vì bỏ 1 chữ xuống cuối. */
  text-wrap: balance;
}

/* Màu là --sage, KHÔNG phải --sage-soft. Đo trên ảnh chụp thật:
   --sage-soft (#7e8a6c) ở 13px trên nền ngà chỉ 3.31:1, trượt ngưỡng AA 4.5:1
   cho chữ dưới 18.66px — mà đây lại đúng là hai câu riêng tư nhất của thiệp.
   Reference cũng để nguyên rgb(82,97,62) cho mọi câu nội dung. Bậc thị giác
   so với tên phía trên lấy bằng CỠ CHỮ (13px vs 23px), không lấy bằng cách
   làm nhạt màu. */
.story__note {
  grid-column: 2;
  grid-row: 3;
  color: var(--sage);
  margin-block-start: var(--sp-2);
  text-wrap: pretty;
}

.story__profile--groom .story__role,
.story__profile--groom .story__name,
.story__profile--groom .story__note {
  grid-column: 1;
}

/* --- ≥768px: hoạ tiết tràn rộng ra .stage (520px), cột chữ vẫn 420px ---- */
@media (min-width: 768px) {
  .story {
    padding-block: var(--sp-10) var(--sp-9);
  }

  /* Nhỏ hơn bản trước (32%/36%) cùng lý do với breakpoint gốc: hoa là lớp nền,
     không được to tới mức phải cắt mới vừa khung. Bleed âm giữ nguyên vì ở đây
     .stage đã bị chặn 520px và căn giữa nên phần âm chỉ ăn vào lề, không tới
     mép .section — kiểm lại với cỡ mới ở khung nhìn 768px:
       bó trái  rộng 24%×520 = 125px, mép trong cùng ở x 61.6 (>0)   → nguyên
       bó phải  rộng 27%×520 = 140px, mép ngoài cùng ở x 716.8 (<768) → nguyên */
  .story__spray-left {
    inline-size: 24%;
    inset-block-start: 5%;
    inset-inline-start: -12%;
    opacity: 0.9;
  }

  .story__spray-right {
    inline-size: 27%;
    inset-block-start: 50%;
    inset-inline-end: -14%;
    opacity: 0.9;
  }

  .story__heading-img {
    inline-size: min(100%, 18rem);
  }

  .story__profiles {
    /* Cột rộng hơn ⇒ đẩy độ lệch ngang mạnh hơn cho đường chéo rõ nét,
       đồng thời thu khoảng cách dọc lại để hai thẻ "ăn" vào nhau hơn.
       --story-plate hạ 51% → 45% cùng lý do với rule gốc: cột chữ ở 51% chỉ
       được 155px, không đủ cho "QUANG DANH" (168px ở cỡ chữ 23.2px của
       breakpoint này). --story-shift cũng lùi về --sp-5: ở --sp-7 (40px) cột
       chữ chỉ còn 171px, dư 3px — sát quá, thêm một chữ là vỡ. */
    --story-plate: 45%;
    --story-shift: var(--sp-5);

    gap: var(--sp-5);
  }
}

/* --- ≥1024px: bleed sâu nhất, hai thẻ gần ngang hàng hơn --------------- */
@media (min-width: 1024px) {
  /* Nhỏ hơn bản trước (34%/38%). Kiểm ở khung nhìn 1024px: bó trái nằm trong
     x 158.4–293.4, bó phải x 725–876 — cả hai còn cách mép .section (0 và 1024)
     rất xa, nên vẫn nguyên chùm. */
  .story__spray-left {
    inline-size: 26%;
    inset-inline-start: -18%;
  }

  .story__spray-right {
    inline-size: 29%;
    inset-inline-end: -20%;
  }

  .story__profiles {
    /* Ở bề rộng lớn, độ lệch quá mạnh sẽ trông như lỗi canh lề → giảm bớt. */
    --story-shift: var(--sp-6);

    gap: var(--sp-4);
  }
}

/* ==========================================================================
   TÔN TRỌNG prefers-reduced-motion
   File này chỉ có 1 chuyển động riêng: LẮC LƯ ảnh chân dung khi hover.
   Tắt hẳn: bỏ transition, TẮT animation lắc lư VÀ giữ nguyên góc nghiêng khi
   hover (không có gì nhảy nhót). Không phần tử nào bị bỏ lại ở opacity 0 —
   toàn bộ nội dung S4/S5 vẫn hiện đầy đủ.
   ========================================================================== */
@media (prefers-reduced-motion: reduce) and (max-width: 0px) { /* guard tắt theo yêu cầu: thiệp LUÔN chạy animation. Xoá ' and (max-width: 0px)' để bật lại. */
  .story__photo {
    transition: none;
  }

  .story__profile--bride .story__plate:hover .story__photo {
    animation: none;
    transform: rotate(-9deg);
  }

  .story__profile--groom .story__plate:hover .story__photo {
    animation: none;
    transform: rotate(9deg);
  }
}
