/* ============================================================
   Dual Period Prototype Phase 1.5 CSS
   Visual reference ONLY: the 6-product screenshot provided by the
   user is the visual source of truth. The old 9-product formal
   page is NOT the visual reference.
   Scope: #dp-root and .dp-* classes only. No conflict with formal
   style.css because formal CSS never uses .dp-* prefix.
   ============================================================ */

*, *::before, *::after { box-sizing: border-box; }

#dp-root, .dp-root {
  min-height: 100vh;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
               "Helvetica Neue", Arial, "PingFang SC", "Microsoft YaHei",
               sans-serif;
  background: #F5F7FB;       /* very light blue tint like screenshot */
  color: #1F2937;
  font-size: 14px;
  line-height: 1.5;
}

.dp-hidden { display: none !important; }

/* ---------- Shared typography (pixels tuned vs screenshot) ---------- */
.dp-period-chip {
  position: sticky;
  top: 0;
  z-index: 20;
  max-width: 1280px;
  margin: 0 auto;
  padding: 10px 24px 0;
  font-size: 12px;
  color: #5B6A8A;
  font-weight: 500;
  letter-spacing: 0.02em;
  text-align: right;
}
@media (max-width: 820px) { .dp-period-chip { padding: 8px 16px 0; } }

/* =================================================================
   MENU PHASE — top header (title/subtitle + page-note card)
   ================================================================= */
.dp-menu-phase {
  max-width: 1280px;
  margin: 0 auto;
  padding: 4px 24px 64px;
}
@media (max-width: 820px) { .dp-menu-phase { padding: 4px 16px 48px; } }

.dp-page-header {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 360px;
  gap: 24px;
  align-items: start;
  padding: 14px 0 24px;
}
@media (max-width: 1100px) {
  .dp-page-header { grid-template-columns: 1fr; }
}

.dp-page-title {
  margin: 6px 0 10px;
  font-size: 30px;
  line-height: 1.25;
  font-weight: 800;
  color: #1F2937;
  letter-spacing: -0.01em;
}

/* -------- Shopping Rules Panel (UI Tier 2 optimization) --------
   Display shopping rule as TWO lines instead of one dim subtitle,
   clearly stronger in visual hierarchy than the old subtitle,
   but intentionally softer than the page title (no alert box).
   Line 1 is whole-sentence bold (self-choice framing).
   Line 2 emphasizes three key points only (no whole-line bold). */
.dp-shopping-rules {
  margin-top: 4px;
  padding: 12px 16px;
  background: #F2F6FF;              /* very light blue-gray tint, not alert */
  border: 1px solid #E1E9FB;
  border-radius: 12px;
}
.dp-shopping-rules-line {
  margin: 0;
  padding: 2px 0;
  font-size: 16.5px;                  /* ~16–17px target per spec */
  line-height: 1.6;                   /* ~1.5–1.7 target per spec */
  color: #2F3B5A;                     /* deeper gray-blue, not the old light #5B6A8A */
}
.dp-shopping-rules-line + .dp-shopping-rules-line { margin-top: 2px; }
.dp-shopping-rules-line-1 strong {
  font-weight: 800;
  color: #1C2B4D;
  letter-spacing: -0.005em;
}
.dp-shopping-rules-line-2 .dp-rule-emph {
  font-weight: 700;
  color: #163990;                     /* saturated deep blue for 3 key phrases */
}
/* Keep old subtitle selector harmless (future-proof) but unused for now. */
.dp-page-subtitle {
  margin: 0;
  color: #5B6A8A;
  font-size: 14px;
  line-height: 1.65;
}

.dp-page-note {
  background: linear-gradient(180deg, #EEF3FF 0%, #F7F9FF 100%);
  border: 1px solid #DCE5FF;
  border-radius: 14px;
  padding: 14px 16px;
}
.dp-page-note-title {
  font-weight: 700;
  font-size: 15px;
  color: #1E3A8A;
  margin-bottom: 6px;
}
.dp-page-note-body {
  color: #3A4B6D;
  font-size: 13px;
  line-height: 1.65;
}
.dp-page-note.is-rule-card-upgraded {
  padding: 16px 18px 17px;
  border-color: #C9D8FF;
  box-shadow: 0 4px 16px rgba(47, 107, 255, 0.08);
}
.dp-page-note.is-rule-card-upgraded .dp-page-note-title {
  margin-bottom: 10px;
  font-size: 16px;
  font-weight: 700;
  color: #1E3A8A;
  letter-spacing: 0.01em;
}
.dp-page-note.is-rule-card-upgraded .dp-page-note-body {
  font-size: 14px;
  line-height: 1.6;
}
.dp-page-note-paragraph {
  margin: 0;
}
.dp-page-note-paragraph + .dp-page-note-paragraph {
  margin-top: 10px;
}
.dp-page-note.is-rule-card-upgraded .dp-page-note-paragraph.is-key-rule {
  color: #1E3A8A;
  font-weight: 700;
}
.dp-page-note.is-rule-card-upgraded .dp-page-note-paragraph.is-choice-autonomy {
  color: #2A3855;
  font-weight: 700;
}
.dp-page-note-inline-emphasis {
  display: inline;
  font-weight: 700;
  color: #2A3855;
}
.dp-page-note-amount {
  font-weight: 700;
}

/* =================================================================
   MENU BODY: 2 columns (left = category sections, right = order summary)
   ================================================================= */
.dp-menu-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 360px;
  gap: 24px;
  align-items: start;
}
.dp-menu-main {
  min-width: 0;
  width: 100%;
  max-width: 100%;
}
/* On medium/large screens, make the right order-summary column truly sticky
   at the side (not below the body) by attaching it to the right of the
   shopping page — this mimics the 6-product screenshot layout where the
   summary is a persistent right-hand panel even on 1100~1280px widths. */
.dp-order-summary-wrap {
  position: sticky;
  top: 40px;
  align-self: start;
  min-width: 0;
}
@media (max-width: 1100px) {
  .dp-menu-body { grid-template-columns: 1fr; }
  .dp-order-summary-wrap {
    position: static;
    width: 100%;
    max-width: 100%;
  }
}

/* --- category sections (screenshot 主食 / 小食 / 饮品 白色大卡片) --- */
.dp-section {
  background: #FFFFFF;
  border: 1px solid #E6ECF5;
  border-radius: 18px;
  padding: 18px 20px 20px;
  margin-bottom: 20px;
  box-shadow: 0 2px 10px rgba(37, 56, 104, 0.04);
  min-width: 0;
  width: 100%;
  max-width: 100%;
}
.dp-section-title {
  margin: 2px 0 14px;
  font-size: 22px;
  font-weight: 800;
  color: #1F2937;
  letter-spacing: 0.01em;
}
.dp-section-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px 16px;
  /* Fix "one card expands → neighbour forced to same height → huge blank" issue.
     align-items:start lets each card size to its own natural content, while
     grid row auto expands only to fit the tallest card in that row. */
  align-items: start;
}
@media (max-width: 680px) {
  .dp-section-grid { grid-template-columns: 1fr; }
}

/* =================================================================
   PRODUCT CARD — horizontal (image left | text + button right)
   Matches screenshot's 地三鲜饭 / 鸡胸肉沙拉 等样式
   ================================================================= */
.dp-product-card {
  display: flex;
  align-items: flex-start;
  gap: 14px;
  background: #FBFCFF;
  border: 1px solid #E7EEFA;
  border-radius: 14px;
  padding: 12px;
  transition: border-color .15s ease, background .15s ease;
  min-width: 0;
  width: 100%;
  max-width: 100%;
}
.dp-product-card:hover {
  border-color: #C8D6FB;
  background: #F7FAFF;
}
.dp-product-card.is-selected {
  /* NO heavy orange border in Phase 1.5 — subtle highlight only (per screenshot) */
  border-color: #98B7FF;
  background: #F2F6FF;
}

.dp-product-image {
  flex: 0 0 auto;
  width: 86px;
  height: 86px;
  border-radius: 12px;
  background: #EEF2FA;
  overflow: hidden;
}
.dp-product-image img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.dp-product-body {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.dp-product-name {
  font-size: 16px;
  font-weight: 700;
  color: #1F2937;
  line-height: 1.3;
}
.dp-product-name-row {
  display: flex;
  flex-wrap: wrap;     /* narrow/mobile allows natural wrapping (spec B) */
  align-items: baseline;
  gap: 8px;            /* small visual gap between title & spec */
  line-height: 1.3;
}
.dp-product-spec {
  font-size: 12.5px;   /* smaller than product name */
  font-weight: 400;    /* NOT bold */
  color: #6B7280;      /* muted gray */
  white-space: nowrap; /* keep spec itself one token; wrap at row level */
}
.dp-product-price {
  font-size: 15px;
  font-weight: 500;
  color: #1F2937;
  margin-top: 0;
}
.dp-product-delivery {
  color: #1F2937;
  font-size: 15px;
  font-weight: 500;
  line-height: 1.35;
}
/* placeholder area for Phase 2: nutrition panel / carbon panel / info button */
.dp-product-info-area {
  min-height: 0;     /* Control state — empty, takes no vertical space */
  margin: 2px 0 0;
  /* Phase 1.11.2 §II: guarantee the info block lives strictly inside its
     parent product card (never stretches horizontally outside, never
     pushes the 加入 button out of the card's right edge). */
  width: 100%;
  max-width: 100%;
  box-sizing: border-box;
}
.dp-product-actions {
  margin-top: 0;
  display: flex;
  flex-direction: column;    /* stacked (matches old Nutrition Free screenshot):
                                 nutrition info button ON TOP, then 加入 button BELOW.
                                 Control regime has only the 加入 button → still works. */
  gap: 8px;
  align-items: flex-start;
}

/* --- Nutrition Free secondary button (NOT a primary action) ---
   Visual weight strictly below 加入 (the solid blue button).
   Mirrors old Nutrition Free screenshot "查看营养信息" button. */
/* --- Phase 1.9c: Unified lightweight on-demand text entry --------------
 * Replaces the old 3 capsule buttons (dp-nutrition-info-btn /
 * dp-carbon-info-btn / dp-delivery-info-btn) with a single shared low-
 * prominence visual language: transparent/ultra-weak background, no or
 * ultra-weak border, muted neutral blue-gray, reasonable padding hitbox,
 * thin chevron arrow.  Applies equally to:
 *   • Free  Nutrition / Carbon  on-demand info entry  (fold → expand)
 *   • Low/High Nutrition / Carbon on-demand info entry (+ price tag)
 *   • Space Delivery on-demand entry (配送信息 folded / expanded)
 *
 * Structural business rules (NOT CHANGED per spec §8):
 *   • dp-nutrition-info-btn class still present → existing toggle +
 *     unlock/fee/方案C listener bindings unchanged.
 *   • dp-carbon-info-btn   class still present → existing listeners
 *     unchanged.
 *   • dp-delivery-info-btn class still present → existing Space-only
 *     toggle (with regime guard inside) + delivery_info_open/close events
 *     unchanged.
 *   • Both / Control regimes continue to render zero on-demand entries
 *     (spec §6 — secondaryButtonHtml = "" already on those paths).
 */
.dp-on-demand-text-btn {
  display: inline-flex;
  align-items: baseline;
  gap: 4px;
  padding: 5px 10px 5px 6px;   /* reasonable click hitbox, not a huge capsule */
  border: none;
  border-radius: 6px;
  background: transparent;
  color: #1F2937;             /* near-black, core anchor visual weight */
  font-size: 15px;
  font-weight: 500;
  line-height: 1.35;
  cursor: pointer;
  user-select: none;
  white-space: nowrap;
  /* keep hitbox crisp without heavy border; use mild hover tint. */
  transition: background .15s ease, color .15s ease, fill .15s ease;
}
.dp-on-demand-text-btn:hover {
  background: #F1F4FA;
  color: #3F4B68;
}
.dp-on-demand-text-btn:active {
  background: #E6ECF6;
}
/* Expanded / "收起" state: very subtle tint so user can see which entries
 * have been revealed; still stays secondary vs 加入 / the info panels. */
.dp-on-demand-text-btn.is-open {
  background: #F1F4FA;
  color: #3F4B68;
}
/* Inner semantic spans (label · action · [price] · chevron).  Using spans
 * instead of plain text keeps individual hover / emphasis easy without
 * behavioural coupling. */
.dp-on-demand-text-btn .dp-od-label {
  color: inherit;
  font-weight: 500;
}
.dp-on-demand-text-btn .dp-od-dot {
  color: #B0B8CD;
  font-weight: 500;
  margin: 0 1px;
}
.dp-on-demand-text-btn .dp-od-action {
  color: inherit;
  font-weight: 500;
  margin-right: 1px;
}
/* Price — Low/High on-demand info only.
 * Spec §5 explicitly demands price clarity; keep crisp + semibold. */
.dp-on-demand-text-btn .dp-od-price,
.dp-info-price-tag {
  color: #2F4F9E;
  font-weight: 600;
  font-size: 12.5px;
  letter-spacing: 0;
  white-space: nowrap;
  display: inline-flex;
  align-items: baseline;
}
/* Chevron arrows — folded: right ›  /  expanded (收起): left ‹ */
.dp-on-demand-text-btn .dp-od-chevron {
  color: #8D98B5;
  font-size: 14px;
  line-height: 1;
  margin-left: 3px;
  transform: translateY(1px);
  transition: color .15s ease, transform .15s ease;
}
.dp-on-demand-text-btn:hover .dp-od-chevron {
  color: #5B6A8B;
}
.dp-on-demand-text-btn .dp-od-chevron-left {
  /* 收起 arrow points the other way; keep same overall scale. */
  margin-left: 4px;
  margin-right: 0;
}

/* Legacy per-family class selectors kept for backwards compatibility.  New
 * visual weight is driven by .dp-on-demand-text-btn above; these only
 * exist so that existing CSS specificity hooks / future overrides still
 * work, and so older stub selectors continue to match. */
.dp-nutrition-info-btn { /* unified by base .dp-on-demand-text-btn */ }
.dp-carbon-info-btn    { /* unified by base .dp-on-demand-text-btn */ }
.dp-delivery-info-btn  { /* unified by base .dp-on-demand-text-btn */ }

/* Phase 1.19 final two-issue fix #1: domain collapsed-entry optical match.
 * STRICTLY SCOPED to Nutrition/Carbon on-demand DOMAIN info buttons ONLY,
 * closed / not-yet-unlocked state (:not(.is-open)).
 *
 * EXPLICITLY EXCLUDED from this rule (hence untouched):
 *   - .dp-delivery-info-btn   → Space delivery folded entry (§3 / §9 check 7)
 *   - .dp-od-inline-slot      → Layered detail inline CTA (§3)
 *   - :is-open / .is-open     → Expanded "收起" grey state (§4 / §9 check 8)
 *   - .dp-od-price            → Low/High info-fee tag (§14 last round)
 *
 * Goal: collapsed Nutrition/Carbon entry visually ≈ Delivery row ≈ Product Price
 * (same salience, natural baseline, no shrinking / no offset).
 * Sequence per §2 user priority:
 *   (1) font-family reset (UA button != document body)
 *   (2) appearance/line-height/alignment reset for button-box baseline
 *   (3) +0.5px optical correction because an inline-flex button with
 *       chevron child renders smaller to the eye than a plain <div> at
 *       the same declared 15px.  Kept STRICTLY below product title 16px.
 *
 * ---- Phase 1.19 follow-up micro-fix: geometric alignment final ----
 * Horizontal: redistribute horizontal padding while keeping button box
 *   position + total width + clickable rect exactly unchanged:
 *   padding-left:  6 ->  0   (visible text left edge now flush with
 *                             Delivery / Product Price 0-offset)
 *   padding-right: 10 -> 16   (total horizontal padding = 16px still,
 *                             so inline-flex border-box width = same;
 *                             clickable rect width unchanged)
 * Vertical: match Delivery line-height exactly while keeping total button
 *   height (hence clickable area height) completely unchanged:
 *   line-height:        1.5      (= 15.5 * 1.5 = 23.25px) -> 20.25px exact
 *   padding-top:          5  ->  6.5
 *   padding-bottom:       5  ->  6.5
 *   Total height = 20.25 + 6.5 + 6.5 = 33.25px unchanged (was 23.25+5+5)
 *
 * align-items: center RETAINED (no cross-axis change to chevron).
 * font-size 15.5px RETAINED.
 * appearance:none / font-family docroot stack RETAINED. */
.dp-on-demand-text-btn.dp-nutrition-info-btn:not(.is-open),
.dp-on-demand-text-btn.dp-carbon-info-btn:not(.is-open) {
  /* (1) font family inheritance forced to doc-root stack; defeat UA
   *     "-apple-system-button" that makes buttons render a different face. */
  -webkit-appearance: none;
  appearance: none;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
               "Helvetica Neue", Arial, "PingFang SC", "Microsoft YaHei",
               sans-serif;
  /* (2) align + lh reset so text-baseline of the whole inline-flex
   *     container sits naturally next to surrounding plain-text siblings.
   *     align-items:center stops the 14px chevron (translateY 1px) from
   *     pulling the whole row's cross-axis down by 1px.
   *     line-height: 20.25px  EXACT MATCH vs Delivery row
   *     (Delivery = 15px * 1.35 = 20.25px).
   *     vertical-align: baseline  keeps container on the text baseline
   *     of its enclosing flex row. */
  align-items: center;
  line-height: 20.25px;
  vertical-align: baseline;
  /* (3) optical size parity.  15 -> 15.5 (+0.5px only); still < title 16px.
   *     RETAINED (not touched in geometric follow-up per user §I-C). */
  font-size: 15.5px;
  font-weight: 500;
  /* (4) geometric redistribution ONLY for closed domain entry:
   *       pl 0 + pr 16  =  16 total (was pl 6 + pr 10 — same sum)
   *       pt 6.5 + pb 6.5 = 13 total vertical padding
   *     Net effect:
   *       visible glyphs left edge = button-box left edge + pl = 0px,
   *       matching Delivery / Product Price 0-padding plain text.
   *       Overall button rect: LEFT / WIDTH / HEIGHT completely unchanged
   *       (same inline-flex border-box; same clickable area size/pos). */
  padding-left: 0px;
  padding-right: 16px;
  padding-top: 6.5px;
  padding-bottom: 6.5px;
}

/* (the 加入 / 已加入 primary button is kept exactly as-is below) */

/* Blue rounded "加入 / 已加入" button, screenshot-like */
.dp-join-btn {
  min-width: 138px;
  border: none;
  border-radius: 999px;
  padding: 8px 22px;
  background: #2F6BFF;
  color: #FFFFFF;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  transition: background .15s ease, transform .05s ease;
}
.dp-join-btn:hover { background: #1F59F0; }
.dp-join-btn:active { transform: translateY(1px); }
.dp-join-btn.is-joined {
  background: #0F3FAE;   /* darker blue when already selected */
}
.dp-join-btn.is-joined::before {
  content: "✓ ";
  opacity: 0.9;
}

/* --- Expanded in-card nutrition info block (Nutrition Free: 热量/脂肪/钠 3D) ---
   Rendered inside dp-product-info-area (reserved placeholder).
   Inline expand — stays on the menu page, no modal. 3 columns equal width.
   (Old 4D 2x2 layout was retired when "糖" was removed per spec §1.) */
.dp-nutrition-expand {
  margin-top: 8px;
  padding: 11px 12px;
  border-radius: 12px;
  background: #F4F8FF;
  border: 1px solid #DCE5FF;
  display: grid;
  /* Three equal-width columns; each has its own vertical stack of
     [label + value/unit] so all 3 metrics have identical visual weight. */
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 4px 12px;
  font-size: 13px;
  /* Phase 1.11.2 §II: keep the disclosure always fits the product card;
     padding must be counted inside width (never bleed outside). */
  width: 100%;
  max-width: 100%;
  box-sizing: border-box;
}
/* Each metric occupies ONE column; dot+label on top row, value on bottom row.
   This keeps three items horizontally aligned with equal weight (no 4th empty). */
.dp-nutri-cell {
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
  grid-row: 1;            /* all 3 metric labels share the first row */
}
.dp-nutri-cell-val {
  /* Second row: value/unit placed directly below its label/metric column.
     Uses same col-start trick in JS DOM (nth-child offset) or nested sub-divs.
     We use a simpler layout: flex-column per column (see below). */
  grid-row: 2;
  display: flex;
  align-items: baseline;
  gap: 4px;
  min-width: 0;
  padding-left: 15px;    /* indent under dot+label above (9+6gap) */
}
/* Actually simpler & more robust: render each 3-column as a 1-column
   flex-stack (<div class="dp-nutri-stack"> + labelLine + valueLine),
   so the row stays perfectly equal weight even with long value strings. */
.dp-nutri-stack {
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 0;
}
.dp-nutri-stack-label {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: #5B6A8A;
  font-weight: 500;
  font-size: 12.5px;
}
.dp-nutri-stack-value {
  display: inline-flex;
  align-items: baseline;
  gap: 4px;
  padding-left: 15px;    /* horizontally under the label line (skip 9dot+6gap) */
}
.dp-nutri-stack-value .dp-nutri-value {
  font-size: 15px;       /* slightly larger values for readability vs old 13px */
  color: #1F2937;
  font-weight: 700;
}
.dp-nutri-stack-value .dp-nutri-unit {
  font-size: 12.5px;
  color: #5B6A8A;
  font-weight: 500;
}

.dp-nutri-dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  flex-shrink: 0;
  /* TEMP levels only — not frozen formal thresholds. Kept as CSS vars so core
     logic never hard-codes thresholds. JS assigns .dp-nutri-level-LOW/MED/HIGH. */
  background: #98A3C0;
}
.dp-nutri-level-LOW  { background: #22A06B; }   /* TEMP green placeholder */
.dp-nutri-level-MED  { background: #D97706; }   /* TEMP yellow placeholder */
.dp-nutri-level-HIGH { background: #B91C1C; }   /* TEMP red placeholder */
/* Legacy classes retained in case old JS code paths still reference them;
   kept harmless so future regimes can reuse the same label/value vocabulary. */
.dp-nutri-label {
  color: #5B6A8A;
  font-weight: 500;
  flex-shrink: 0;
}
.dp-nutri-value {
  color: #1F2937;
  font-weight: 700;
  margin-left: auto;   /* (unused in flex-stack, kept for compatibility) */
  flex-shrink: 0;
  text-align: right;
}

/* --- Expanded in-card CARBON info block (Carbon Free: 碳等级 + kg CO₂e/份) ---
   Same inline-expand pattern as nutrition, same neutral tint, so the two
   domains share one common visual language (spec §III: no "green eco" tint).
   Single horizontal metric: [levelDot + levelText on left | kg CO₂e value right] */
.dp-carbon-expand {
  margin-top: 8px;
  padding: 11px 14px;
  border-radius: 12px;
  background: #F4F8FF;          /* same neutral pale blue as dp-nutrition-expand */
  border: 1px solid #DCE5FF;    /* same neutral blue border as nutrition */
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  font-size: 13px;
  /* Phase 1.11.2 §II: same containment as nutrition — never stretch outside
     the parent product card regardless of inner content width. */
  width: 100%;
  max-width: 100%;
  box-sizing: border-box;
}
.dp-carbon-left {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
}
.dp-carbon-level-dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  flex-shrink: 0;
  /* Same 3-tier color scheme as nutrition — LOW=green, MED=amber, HIGH=red.
     TEMP only; actual carbon thresholds not frozen. */
  background: #98A3C0;
}
.dp-carbon-level-LOW  { background: #22A06B; }
.dp-carbon-level-MED  { background: #D97706; }
.dp-carbon-level-HIGH { background: #B91C1C; }
.dp-carbon-level-text {
  font-weight: 600;
  color: #1F2937;
  font-size: 13.5px;
}
.dp-carbon-right {
  display: inline-flex;
  align-items: baseline;
  gap: 4px;
  flex-shrink: 0;
}
.dp-carbon-value {
  font-size: 16px;
  font-weight: 800;
  color: #1F2937;
}
.dp-carbon-unit {
  font-size: 12.5px;
  color: #5B6A8A;
  font-weight: 500;
}

/* =================================================================
   RIGHT-HAND ORDER SUMMARY COLUMN
   ================================================================= */
.dp-order-summary {
  background: #FFFFFF;
  border: 1px solid #E6ECF5;
  border-radius: 18px;
  padding: 18px 18px 20px;
  box-shadow: 0 2px 10px rgba(37, 56, 104, 0.04);
  width: 100%;
  max-width: 100%;
  min-width: 0;
}

.dp-order-summary-title {
  font-size: 22px;
  font-weight: 800;
  color: #1F2937;
  margin: 2px 0 14px;
}
.dp-order-selected-box {
  background: #F9FBFF;
  border: 1px solid #E7EEFA;
  border-radius: 14px;
  padding: 10px 12px;
  min-height: 58px;
  width: 100%;
  max-width: 100%;
  min-width: 0;
}
.dp-order-selected-empty {
  color: #7A86A5;
  font-size: 14px;
  font-weight: 500;
  padding: 6px 2px;
}
.dp-order-selected-outside-active {
  border-radius: 10px;
  background: #EEF3FF;
  border: 1px solid #2F6BFF;
  padding: 10px 12px;
}
.dp-order-outside-label {
  color: #0F3FAE;
  font-weight: 700;
  font-size: 14px;
}
.dp-order-outside-sub {
  color: #5B6A8A;
  font-size: 12.5px;
  margin-top: 4px;
}
.dp-order-item {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  align-items: center;
  gap: 10px;
  padding: 6px 2px;
  border-bottom: 1px dashed #EEF2FA;
}
.dp-order-item:last-child { border-bottom: none; }
.dp-order-item-name {
  color: #1F2937;
  font-weight: 600;
  font-size: 13.5px;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.dp-order-item-price {
  color: #1F2937;           /* Phase 1.19 fix #2: neutral near-black; was red #B91C1C */
  font-weight: 700;
  font-size: 13.5px;
}
.dp-order-item-remove {
  border: none;
  background: transparent;
  color: #98A3C0;
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.dp-order-item-remove:hover {
  background: #EFF3FB;
  color: #3A4B6D;
}

/* --- price rows (食品小计 / 订单合计) ---
   NOTE: Control intentionally has no "information service fee" rows,
   not even a ¥0 placeholder. Only 2 rows per Control spec. */
.dp-order-price-rows {
  margin-top: 14px;
  padding: 10px 12px;
  background: #FAFCFF;
  border: 1px solid #E7EEFA;
  border-radius: 14px;
  width: 100%;
  max-width: 100%;
  min-width: 0;
}
.dp-order-price-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  padding: 5px 0;
}
.dp-order-price-row + .dp-order-price-row { border-top: 1px dashed #EEF2FA; }
.dp-order-price-row-muted .dp-order-price-label,
.dp-order-price-row-muted .dp-order-price-value {
  color: #98A3C0;
}
.dp-order-price-label {
  color: #5B6A8A;
  font-size: 13.5px;
}
.dp-order-price-value {
  color: #1F2937;
  font-weight: 600;
  font-size: 14px;
}
.dp-order-total-row {
  padding-top: 10px;
  margin-top: 2px;
  border-top: 1.5px solid #E7EEFA !important;
}
.dp-order-total-row .dp-order-price-label {
  font-weight: 700;
  color: #1F2937;
  font-size: 14px;
}
.dp-order-total-value {
  color: #1F2937;           /* Phase 1.19 fix #2: neutral near-black; was red #B91C1C.
                               Bold tier (font-weight:800, font-size:17px) preserved per §7. */
  font-size: 17px;
  font-weight: 800;
}

/* --- 方案C Info-Fee collapsible block (Low/High ONLY) ---
   All classes below are participant-facing billing language (spec §15:
   信息查看费 / 查看明细 — no internal research jargon like "信息篮子").

   Visual layering goal (spec §17):
     - Food basket items = primary editable basket.
     - 食品小计 / 信息查看费 / 订单合计 = three clearly separated tiers.
     - Fee detail list = tertiary ("弱但可识别"): not greyed out to the
       point of illegibility, but definitely not a second shopping basket.
   Never red / never green — always neutral cool blue-grey (spec §4). */
.dp-fee-details-toggle-row {
  display: flex;
  justify-content: flex-end;
  padding: 1px 2px 4px;
  min-width: 0;
}
.dp-fee-details-toggle {
  border: none;
  background: transparent;
  color: #5B6A8A;
  font-size: 12.5px;
  font-weight: 500;
  cursor: pointer;
  padding: 2px 6px;
  border-radius: 6px;
  letter-spacing: 0.01em;
}
.dp-fee-details-toggle:hover {
  background: #EEF3FF;
  color: #2F4F9E;
}
.dp-fee-details-list {
  background: #F7FAFF;
  border: 1px dashed #DCE5FF;
  border-radius: 10px;
  padding: 6px 10px;
  margin: 1px 0 6px;
  width: 100%;
  max-width: 100%;
  min-width: 0;
}
.dp-fee-details-item {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  padding: 4px 2px;
  gap: 8px;
  min-width: 0;
}
.dp-fee-details-item + .dp-fee-details-item {
  border-top: 1px dashed #E7EEFA;
}
.dp-fee-details-name {
  color: #4B5A7D;
  font-size: 12.5px;
  font-weight: 500;
  flex: 1 1 auto;
  min-width: 0;
  max-width: 100%;
  white-space: normal;
  overflow-wrap: anywhere;
  word-break: break-word;
}
.dp-fee-details-fee {
  color: #3E5A9E;
  font-size: 13px;
  font-weight: 600;
  white-space: nowrap;
  flex: 0 0 auto;
}

/* Outside option block — two-level decision layout:
   (1) short hint line ("若您本轮不想购买任何商品：")
   (2) secondary outlined action button (NOT a solid blue primary button)
   Visual weight: discoverable but below the primary confirm button.
   Unselected: white bg + blue-gray solid outline + hollow circle glyph on left.
   Selected  : light-blue bg + solid blue border + filled checkmark on left. */
.dp-outside-decision-wrap {
  margin-top: 18px;              /* spacing vs price rows above */
}
.dp-outside-hint {
  font-size: 12.5px;
  color: #5B6A8A;
  font-weight: 500;
  margin: 0 2px 8px;             /* small gap between hint and outside button */
  letter-spacing: 0.01em;
}
.dp-outside-option-btn {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  border: 1.5px solid #AAB7D6;       /* blue-gray solid stroke (not disabled gray) */
  border-radius: 12px;
  padding: 11px 14px;
  background: #FFFFFF;                /* white / very light bg */
  color: #2F3B5A;                     /* deep dark text */
  font-size: 14px;
  font-weight: 600;
  text-align: left;
  cursor: pointer;
  transition: background .15s ease, color .15s ease, border-color .15s ease, box-shadow .15s ease;
}
.dp-outside-option-btn:hover {
  background: #F4F8FF;
  border-color: #2F6BFF;
  color: #1E3A8A;
}
.dp-outside-glyph {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  font-size: 15px;
  line-height: 1;
  color: #6B7AA0;
  flex-shrink: 0;
}
.dp-outside-text {
  flex: 1 1 auto;
  min-width: 0;
  overflow-wrap: anywhere;
}

/* Selected state: ✓ + light-blue bg + solid blue border */
.dp-outside-option-btn.is-outside {
  background: #EEF3FF;
  border: 1.5px solid #2F6BFF;
  color: #0F3FAE;
  box-shadow: 0 0 0 2px rgba(47, 107, 255, 0.06);
}
.dp-outside-option-btn.is-outside .dp-outside-glyph { color: #0F3FAE; }

/* Submit button (order summary). Default = disabled (gray), only enable when:
   - user selected >=1 product, OR
   - user explicitly toggled the outside-option row */
.dp-submit-btn {
  display: block;
  width: 100%;
  margin-top: 14px;
  border: none;
  border-radius: 14px;
  padding: 14px 18px;
  background: #C8D2DF;
  color: #FFFFFF;
  font-size: 16px;
  font-weight: 700;
  cursor: not-allowed;
  transition: background .15s ease, cursor .15s ease;
}
.dp-submit-btn:not(.is-disabled) {
  background: #2F6BFF;
  cursor: pointer;
}
.dp-submit-btn:not(.is-disabled):hover { background: #1F59F0; }
.dp-submit-btn.is-disabled {
  background: #C8D2DF;
  cursor: not-allowed;
}

/* =================================================================
   TRANSITION PHASE (P1 → P2) — lightweight card only
   ================================================================= */
.dp-transition-phase {
  max-width: 820px;
  margin: 0 auto;
  padding: 32px 24px 80px;
}
.dp-transition-card {
  background: #FFFFFF;
  border: 1px solid #E6ECF5;
  border-radius: 18px;
  padding: 44px 32px 36px;
  text-align: center;
  box-shadow: 0 6px 24px rgba(37, 56, 104, 0.06);
}
.dp-transition-title {
  font-size: 26px;
  font-weight: 800;
  color: #1E3A8A;
  margin-bottom: 14px;
}
.dp-transition-body {
  color: #3A4B6D;
  font-size: 15px;
  line-height: 1.75;
  margin: 0 0 28px;
}
.dp-continue-btn {
  border: none;
  border-radius: 14px;
  padding: 12px 40px;
  background: #2F6BFF;
  color: #FFFFFF;
  font-size: 15px;
  font-weight: 700;
  cursor: pointer;
}
.dp-continue-btn:hover { background: #1F59F0; }

/* =================================================================
   FINAL DEBUG RESULT PAGE (LOCAL ONLY, same as Phase 1 because
   this page is intentionally NOT shown to participants)
   ================================================================= */
.dp-result-phase {
  max-width: 1200px;
  margin: 0 auto 48px;
  padding: 20px 24px;
}
.dp-result-header {
  padding: 14px 18px;
  background: #ffffff;
  border: 1px solid #e5e7eb;
  border-radius: 10px;
  margin-bottom: 16px;
}
.dp-result-title {
  font-weight: 800;
  font-size: 17px;
  color: #1d4ed8;
}
.dp-result-sub {
  margin-top: 6px;
  color: #4b5563;
  font-size: 13px;
}
.dp-session-meta {
  margin-top: 10px;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 12px;
  color: #6b7280;
  background: #F3F4F6;
  padding: 8px 12px;
  border: 1px solid #E5E7EB;
  border-radius: 8px;
  white-space: pre-wrap;
  max-width: 100%;
  overflow-x: auto;
}

.dp-result-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 18px;
  margin-bottom: 18px;
}
@media (max-width: 720px) {
  .dp-result-grid { grid-template-columns: 1fr; }
}
.dp-period-result {
  background: #ffffff;
  border: 1px solid #e5e7eb;
  border-radius: 12px;
  padding: 16px;
}
.dp-period-result-title {
  font-weight: 700;
  color: #111827;
  margin-bottom: 10px;
}
.dp-period-result-table {
  width: 100%;
  border-collapse: collapse;
}
.dp-period-result-table td {
  padding: 6px 10px;
  border-bottom: 1px dashed #e5e7eb;
  font-size: 13px;
  vertical-align: top;
}
.dp-k {
  width: 42%;
  color: #6b7280;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
.dp-v {
  color: #111827;
  word-break: break-all;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
.dp-session-result {
  background: #ffffff;
  border: 1px solid #e5e7eb;
  border-radius: 12px;
  padding: 16px;
  margin-bottom: 18px;
}
.dp-session-result-title {
  font-weight: 700;
  margin-bottom: 10px;
  color: #111827;
}
.dp-event-log-box {
  background: #0f172a;
  color: #e5e7eb;
  border-radius: 12px;
  padding: 16px;
  margin-bottom: 18px;
}
.dp-event-log-title {
  font-weight: 700;
  color: #fbbf24;
  margin-bottom: 10px;
}
.dp-event-log {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 12px;
  line-height: 1.7;
  max-height: 360px;
  overflow: auto;
  white-space: pre-wrap;
}
.dp-event-row { white-space: nowrap; }

.dp-actions-row {
  display: flex;
  justify-content: flex-end;
}
.dp-secondary-btn {
  border: 1px solid #d1d5db;
  border-radius: 10px;
  padding: 10px 16px;
  background: #ffffff;
  color: #111827;
  font-weight: 600;
  cursor: pointer;
}
.dp-secondary-btn:hover { background: #f3f4f6; }

/* =================================================================
   Phase 1.10 Layered — Summary-only compact shells (§V / §XI).
   The goal is to truly reclaim vertical/horizontal space that the
   full shells occupy; hidden detail metrics must NOT keep equal-size
   placeholder blanks (visibility:hidden equivalent is forbidden).
   ================================================================= */
/* Nutrition summary-only modifier:
   Full shell uses 3 equal columns for 热量|脂肪|钠.  Here we collapse
   the grid to a SINGLE column (fit-content so no trailing blank cells
   for fat / sodium are retained) and slightly reduce inner padding to
   form a genuinely compact calories-only chip.  Typography, dot, cell
   stacks remain identical so users see the same 热量 visual language
   they'd recognise from the full Both shell. */
.dp-nutrition-expand-summary {
  grid-template-columns: minmax(0, auto) !important;
  padding: 8px 10px !important;
  display: inline-grid !important;
  width: auto;
  gap: 3px 10px;
  /* Phase 1.11.2 §III: allow the summary to grow to fill the Layered
     wrapper's left half but never force the CTA button outside the
     card (flex-shrink keeps the CTA's nowrap intact). */
  flex: 1 1 auto;
  min-width: 0;
  max-width: 72%;
  box-sizing: border-box;
}
/* Carbon summary-only modifier:
   Full shell is a row flex with justify-content:space-between so the
   level/等级 sits on the left and the exact kg CO₂e value sits on
   the right.  In Layered summary mode we render ONLY the left half
   (the level dot + 低/中等/高 text) in the DOM tree; this override
   collapses the wrapper width to fit-content, flips space-between to
   flex-start (redundant with 1 child, but explicit guard), and uses
   inline-flex so the panel truly shrinks instead of keeping the full
   card-width background.  No equal-width blank placeholder remains
   where .dp-carbon-right would have been (§XI explicit requirement). */
.dp-carbon-expand-summary {
  justify-content: flex-start !important;
  display: inline-flex !important;
  width: auto !important;
  padding: 8px 10px !important;
  /* Phase 1.11.2 §III: mirror the nutrition summary fix — let the
     summary take the left side of the Layered wrapper flex host,
     never push the CTA button outside the product card. */
  flex: 1 1 auto;
  min-width: 0;
  max-width: 72%;
  box-sizing: border-box;
}

/* =================================================================
   Phase 1.10c — Layered "summary + more-info exists" integrated
   visual module wrappers.

   Research intent (§II / §V): Layered must clearly read as "the
   summary/core is exposed by default AND more detailed information
   is freely available on demand" — not "the platform only shows
   calories / level and hides everything else".

   Structural rule: same neutral pale-blue frame (matching the
   Both/Space full-shell family) so the summary chip and the
   "查看更多XX信息" CTA visually belong to one single info
   container.  The wrapper still stays visibly more compact than
   Both's full 3-metric / 2-value shell because:
     - Nutrition: no fat / sodium grid cells are in the DOM
     - Carbon:    no exact kg CO₂e right-hand cell is in the DOM
     - Inner padding slightly reduced vs the full expand shell.

   Zero impact on other regimes (§X):
     - .dp-layered-nutrition-module  only exists inside layeredMode
     - .dp-layered-carbon-module     only exists inside layeredMode
     - .dp-od-inline-slot            modifier on the inline button
       (not used by Free / Low / High / Space on-demand entries).
   ================================================================= */

/* (1) Wrapper: single visual frame for summary + CTA.
       Same background/border as dp-nutrition-expand / dp-carbon-expand
       for visual family consistency; slightly smaller padding to
       keep the collapsed module tighter than the Both full shell. */
.dp-layered-nutrition-module,
.dp-layered-carbon-module {
  margin-top: 8px;
  padding: 9px 12px;
  border-radius: 12px;
  background: #F4F8FF;
  border: 1px solid #DCE5FF;
  display: flex;
  /* Phase 1.11.3 §4: CTA MUST NOT depend on horizontal space.
     Replace the old space-between + nowrap anchor with a wrap-
     enabled flow that lets the CTA fall to its own row whenever
     the card body is too narrow.  align-items:flex-start means
     the summary keeps its baseline alignment on the top row,
     and the CTA aligns naturally below when wrapped. */
  align-items: flex-start;
  justify-content: flex-start;
  flex-wrap: wrap;
  gap: 8px 12px;
  width: 100%;
  box-sizing: border-box;
  /* Phase 1.11.2 §III: never let the inline summary + CTA pair escape
     the product card (CTA white-space:nowrap can previously push
     content 14-20px outside the card's right border, visually merge
     into the neighbouring card). */
  overflow: hidden;
  max-width: 100%;
}

/* (2) Nested summary chip — strip its independent frame because the
       outer wrapper now provides the single visual frame.
       This avoids a "frame inside a frame" double-border look and
       keeps the default module genuinely compact (§II / §V / §XI). */
.dp-layered-nutrition-module > .dp-nutrition-expand-summary,
.dp-layered-carbon-module   > .dp-carbon-expand-summary {
  margin-top: 0 !important;
  padding: 0 !important;
  background: transparent !important;
  border: none !important;
  border-radius: 0 !important;
  /* Retain summary chip's native grid/flex layout so values, dots
     and label stacks look identical to what users recognise from
     the Both full shell — just without the extra metrics. */
  box-shadow: none !important;
  /* Phase 1.11.3 §4: allow the summary to grow on its row so it
     anchors LEFT, and the CTA button sits RIGHT on the same row
     when there IS space; when there isn't, flex-wrap:wrap on the
     host + the chip's flex-basis:160px ensures it takes enough
     width for "1350毫克 ●高" before the CTA "naturally" moves to
     its own line (no calc() hacks, no overflow:hidden-drift). */
  flex: 1 1 160px;
  min-width: 0;
  max-width: 100%;
}

/* (3) Inline "查看更多XX信息 ›" button slot.
       Reuses the family base class .dp-on-demand-text-btn (so same
       typography / colour / chevron / hitbox semantics) but strips
       the independent background padding so the click target lives
       cleanly inside the wrapper frame (no secondary box shadow).
       Hover keeps a very subtle tint — same colour family as 1.9c
       base, just lower alpha to avoid competing with the 加入 CTA. */
.dp-on-demand-text-btn.dp-od-inline-slot {
  /* Phase 1.11.4 §2: reduce CTA's intrinsic horizontal footprint
     so the button fits on one row with a wider range of narrow
     summary chips (e.g. Layered 1-row 热量-only summary on a
     small-portioned drink card).  Shrink only inline padding and
     font-size 0.5px; click hitbox is still generous (14–34px × 22+).
     ALLOWED per Phase 1.11.4's parameter list:
       padding / font-size / line-height / flex-shrink / max-width. */
  padding: 4px 8px 5px;
  /* Phase 1.11.4 §2: font-size 12.5 → 12.0px.  For the inline CTA
     "查看更多营养信息 ›" this reduces intrinsic width by ~4–5px,
     which is exactly the margin needed to coexist on the same row
     with a 170px summary chip (≈ drinks cards) before flex-wrap
     pushes the CTA to its own row. */
  font-size: 12px;
  line-height: 1.38;
  background: transparent !important;
  border: none !important;
  /* Phase 1.11.3 §4: CTA is anchored to the RIGHT of its row on
     wide cards but wraps fully to its OWN line on narrow cards.
     - margin-left:auto: on same row → pushes button to far R
     - flex-shrink: 1 lets the button give up 3–5px of horizontal
       space as a LAST RESORT before flex-wrap kicks in.
     - flex-basis: auto keeps intrinsic button width.
     - flex-grow is intentionally 0 so it does NOT push the summary
       off-screen when both are narrow enough to share ONE row. */
  margin-left: auto;
  flex: 0 1 auto;
  min-width: max-content;       /* Phase 1.11.4 §2: NEVER clip Chinese "查看更多…" glyphs. */
  max-width: 100%;
  overflow: visible;
  /* Keep hitbox generous (§1.9c frozen hitbox rule); inline-slot
     grows cursor priority on hover but never visually louder than
     the wrapper. */
  box-sizing: border-box;
}
/* Phase 1.11.4 §2: After wrap → the CTA becomes the ONLY flex item
   on the wrapped row.  Use :last-of-type (CTA always rendered after
   the summary in DOM) + a simple max-width trigger combined with
   100% wrapper logic: in wrapped position, flex-grow: 0 is OK, but
   we explicitly let min-width relax to max-content (already set)
   while keeping the button pinned to the RIGHT via margin-left:auto.
   No additional selector override needed. */

.dp-on-demand-text-btn.dp-od-inline-slot:hover {
  background: rgba(34, 68, 153, 0.05) !important;
  border-radius: 6px;
}
.dp-on-demand-text-btn.dp-od-inline-slot:active {
  background: rgba(34, 68, 153, 0.10) !important;
}

/* =================================================================
   Phase 1.11 — Domain Intro + Comprehension UI shell (§VIII).
   Frozen principle: do NOT invent a new visual style — reuse the
   prototype's existing family:
     - Neutral blue-grey palette (exactly the same as dp-nutrition-expand
       / dp-carbon-expand / dp-order-summary — #F4F8FF / #DCE5FF borders,
       12px rounded cards, 13-15px body size).
     - Primary action buttons = .dp-continue-btn (frozen Transition phase
       button family) so Intro Continue and Comprehension Submit visually
       match the existing 加入 / Confirm 权重.
     - Strictly NO: green "eco" tint, red "warning" tint, green "healthy"
       tint.  All feedback pills are the SAME neutral blue family as the
       panels themselves (§VIII explicit requirement).
   ================================================================= */

/* (1) Phase container — same overall width/centering grid as dp-menu-phase
       so participants don't experience a "page jump" between Intro → Menu. */
.dp-domain-intro-phase {
  padding: 40px 48px 80px;
  box-sizing: border-box;
}
/* Round chip that mirrors the menu-phase chip — same position + style. */
.dp-domain-intro-round-chip {
  margin: 0 auto 24px;
  max-width: 1040px;
}

/* (2) Generic inner slot — holds the per-domain Intro card or the
       Comprehension 2-question card list. */
.dp-domain-intro-slot {
  max-width: 900px;
  margin: 0 auto;
}

/* (3) Shared container wrapper (Intro + Comprehension use this so the
       page frame is 1:1 visually between the two stages). */
.dp-di-container {
  background: #FFFFFF;
  border: 1px solid #E0E6F2;
  border-radius: 14px;
  padding: 32px 40px;
  box-sizing: border-box;
}
.dp-di-title-block {
  margin-bottom: 24px;
}
.dp-di-title {
  margin: 0 0 14px;
  font-size: 22px;
  font-weight: 600;
  color: #2C3550;
  letter-spacing: 0;
}
.dp-di-body {
  margin: 0 0 8px;
  font-size: 14px;
  line-height: 1.65;
  color: #455172;
}
.dp-di-body:last-child { margin-bottom: 0; }

/* (4) Example Card (§III / §V): visually matches the product-card's
       info-shell family (same pale blue background + 1px blue border)
       so the example reads as "what you will see later inside the real
       product cards", not as a standalone ad-hoc panel. */
.dp-di-example-card {
  margin: 4px 0 28px;
  padding: 18px 22px;
  border-radius: 12px;
  background: #F7FAFF;
  border: 1px solid #DFE6F6;
}
.dp-di-example-title {
  font-size: 15px;
  font-weight: 600;
  color: #37415F;
  margin-bottom: 6px;
}
.dp-di-example-subtitle {
  font-size: 13px;
  color: #697698;
  margin-bottom: 14px;
}
/* Nested expand shells inside the example card.  They inherit the base
   dp-nutrition-expand / dp-carbon-expand grid and flex layouts but we
   strip margin-top (because the example card provides outer spacing)
   and slightly tone down the background (example sits on top of an
   already pale wrapper — a second #F4F8FF layer would read as "double
   emphasis" and cause visual drift from the neutral rule). */
.dp-di-example-nutr {
  margin-top: 0 !important;
  background: transparent !important;
  border: none !important;
  padding: 0 0 6px !important;
}
.dp-di-example-carb {
  margin-top: 0 !important;
  background: transparent !important;
  border: none !important;
  padding: 2px 0 6px !important;
}
/* TEMP-only NRV + level-tag columns added to the Intro example so the
   spec §III 4-piece format (value|unit|%NRV|●level) renders.  The
   in-menu 3-column nutrition stack NEVER carries these (they are
   explicitly TEMP-Intro-only markers; the suffix "-temp" in class name
   is deliberate so future grep can safely delete when NRV spec frozen). */
.dp-di-nutri-nrv-temp {
  margin-left: 10px;
  color: #6C7797;
  font-size: 12.5px;
  font-weight: 500;
}
.dp-di-nutri-level-temp {
  margin-left: 10px;
  color: #4D597B;
  font-size: 12.5px;
  font-weight: 600;
}
.dp-di-example-caption {
  margin-top: 10px;
  font-size: 12.5px;
  color: #626F90;
  line-height: 1.6;
}

/* (5) Action rows (Intro Continue / Comp Submit → Enter basket).
       Centered right-aligned so the primary button sits on the same
       visual "corner" as the frozen 确认本轮选择 button. */
.dp-di-actions-row {
  margin-top: 26px;
  display: flex;
  justify-content: flex-end;
}
.dp-di-continue-btn {
  /* Inherit EXACTLY the .dp-continue-btn frozen shape/colour so the
     transition-phase Continue and Intro/Comp Continue are one family. */
  min-width: 160px;
}

/* (6) Comprehension question cards (§IV, §VI).
       Each question is its own sub-card with the same neutral blue
       1px border + 12px radius as the example card.  Questions are
       stacked vertically with moderate whitespace between them. */
.dp-comp-question-card {
  background: #FAFCFF;
  border: 1px solid #E2E8F6;
  border-radius: 12px;
  padding: 18px 22px 16px;
  margin-bottom: 18px;
  box-sizing: border-box;
}
.dp-comp-qhead {
  display: flex;
  gap: 10px;
  align-items: baseline;
  margin-bottom: 14px;
}
.dp-comp-qnum {
  font-size: 13px;
  font-weight: 600;
  color: #5A6789;
  background: #EEF3FD;
  border-radius: 6px;
  padding: 2px 8px 3px;
  letter-spacing: 0;
  white-space: nowrap;
}
.dp-comp-qstem {
  font-size: 14.5px;
  font-weight: 500;
  color: #2C3550;
  line-height: 1.55;
}
/* Radio options layout: vertical list. */
.dp-comp-options {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin: 2px 0 0;
}
.dp-comp-option {
  display: inline-flex;
  align-items: flex-start;
  gap: 10px;
  padding: 9px 12px;
  border-radius: 8px;
  border: 1px solid transparent;
  cursor: pointer;
  font-size: 14px;
  line-height: 1.5;
  color: #3C4668;
  transition: background .15s ease, border-color .15s ease;
}
.dp-comp-option:hover {
  background: #F3F6FE;
  border-color: #D6DEF1;
}
.dp-comp-option input[type="radio"] {
  margin-top: 3px;
  accent-color: #3558B8;
}
.dp-comp-option-k {
  min-width: 18px;
  font-weight: 600;
  color: #3F4B68;
  user-select: none;
}
.dp-comp-option-v {
  color: inherit;
}
/* After the user submits, radios are frozen (disabled) → a "locked"
   look on the option row so the page reads as "this stage is over,
   move on", not "edit your answer". */
.dp-comp-option.is-locked {
  cursor: default;
  background: transparent;
  border-color: transparent;
}
.dp-comp-option.is-locked:hover {
  background: transparent;
  border-color: transparent;
}

/* (7) Feedback pill for wrong answers (§IV / §VI).
       STRICTLY neutral blue — no red/yellow/green — to avoid
       accidentally signalling "the nutrition/carbon domain is bad /
       unhealthy / dangerous / ecological" (§VIII explicit rule). */
.dp-comp-feedback {
  margin-top: 14px;
  padding: 10px 14px;
  border-radius: 8px;
  background: #EEF3FD;
  border-left: 3px solid #5C78CB;
  color: #344065;
  font-size: 13.5px;
  line-height: 1.6;
}
.dp-comp-feedback-head {
  display: inline-block;
  font-weight: 600;
  color: #3F4F82;
  margin-right: 6px;
}
.dp-comp-feedback-body {
  display: inline;
  color: #3B4667;
}

/* =================================================================
   Phase 1.11.1 — Unified Traffic-Light info shell (Nutrition + Carbon).
   Shared 4-column grid reading order: label | value-unit | %NRV | ●level
   The SAME class family is used for BOTH domains so the two info
   panels are visually homologous (§IV explicit: Carbon mirrors
   Nutrition's reading direction and column order).
   ================================================================= */

/* Outer-wrapper modifier — applied alongside legacy
   .dp-nutrition-expand (3-column grid host for old dp-nutri-stack
   cells).  The modifier overrides the outer layout so that the
   container becomes a VERTICAL stack of `.dp-unified-nutri-row`
   rows; each row then provides its OWN 4-column grid.  The legacy
   base class is kept intact so all 20 frozen Phase 1.10 headless
   probes that grep for `.dp-nutrition-expand` continue to match 1:1. */
.dp-nutrition-expand-unified {
  display: flex;
  flex-direction: column;
  gap: 6px;
  grid-template-columns: none;   /* disable the legacy 3-col grid (L395) */
}

/* Carbon outer-wrapper modifier — parallel to the nutrition one above.
   Legacy .dp-carbon-expand (L493) was a space-between flex host for
   dp-carbon-left (●level) + dp-carbon-right (value).  The modifier
   drops the old "left/right justify" flex so the single inner
   dp-unified-nutri-row can stretch full-width and render its own
   4-column label|value|%NRV-empty|●level grid. */
.dp-nutrition-expand-unified {
  /* Phase 1.11.5 §1: rebalance 4-column density WITHOUT widening the
     level column (per explicit instruction).  Return right padding to
     the symmetrical 12px (same as left); the breathing room for the
     level cell now comes from:
       - tighter column-gap (12 → 8px),
       - smaller value 15 → 14px,
       - smaller NRV 12.5 → 12px,
       - smaller level-text 12.5 → 12.0px + level-cell padding-right 4→3
     All of which are in the Phase 1.11.5 explicit allow-list
     (font-size / gap / padding).  Grid structure (4 columns, order)
     is untouched. */
  padding: 11px 12px;
  display: block;
  justify-content: normal;
  align-items: stretch;
}

/* Phase 1.19 §C: compact basis label row (每100g / 每100ml).
   Small, muted gray text near the top-right of the nutrition panel;
   does not materially increase card height. */
.dp-unified-nutri-basis-row {
  display: flex;
  justify-content: flex-end;
  margin: 0 0 4px;
}
.dp-unified-nutri-basis-label {
  font-size: 11.5px;
  font-weight: 400;
  color: #7A86A5;
  letter-spacing: 0.1px;
}

/* Carbon outer-wrapper modifier — mirror nutrition-unified padding. */
.dp-carbon-expand-unified {
  padding: 11px 12px;
  display: block;
  justify-content: normal;
  align-items: stretch;
}

/* =================================================================
   Core unified 4-column row (PRODUCT CARD default).
   Goal (§1): on ANY product card, 4 columns render clearly:
     指标 | 数值+单位 | %NRV | ●等级
   NEVER collapse into "720千卡36.4%NRV" (value + NRV visually fused).
   Strategy:
     - label/value-unit/%NRV/●level all have MIN column widths so the
       grid cannot squeeze any column to zero.
     - column-gap ≥ 10px (physical whitespace between every cell) is
       the PRIMARY defence against visual fusion of value-unit + %NRV.
     - level column (●中) is fixed on the far right (§II explicit:
       等级放最右侧) — never compressed, value-unit/%NRV overflow
       cannot push level off-card.
   ================================================================= */
.dp-unified-nutri-row {
  display: grid;
  grid-template-columns:
    minmax(48px, 54px)               /* col1 — metric label ("热量"/"脂肪"/"钠"/"碳足迹") */
    minmax(56px, auto)               /* col2 — value + unit (auto grows, min protects) */
    minmax(62px, 70px)               /* col3 — %NRV (右对齐, 62px容纳"34.0%NRV") */
    minmax(54px, 60px);              /* col4 — ●level (Phase 1.11.5: DO NOT widen; keep original 54/60) */
  /* Phase 1.11.5 §1: column-gap COMPRESSED from 12 → 8px to reclaim
     horizontal room for the 4 cells together, instead of stealing it
     from the level column or pushing padding wider.  8px is still
     ≥ value-unit gap (4px) so value + NRV never visually fuse. */
  column-gap: 8px;
  row-gap: 6px;
  align-items: baseline;
  min-width: 0;
  /* 商品卡: 100% 宽度, 让 level 保持在最右侧 (§2 explicit: 等级放最右侧) */
  width: 100%;
  max-width: 100%;
  box-sizing: border-box;
  /* Phase 1.11.5 §1: row base font 13 → 12.5px; individual value/NRV
     cells shrink further below to free space for the 4-column tuple
     without expanding any container. */
  font-size: 12.5px;
  line-height: 1.45;
}

/* --- col 1: metric label --- */
.dp-unified-nutri-label {
  color: #5B6A8A;
  font-weight: 500;
  font-size: 12.5px;
  white-space: nowrap;
}

/* --- col 2: value + unit (aligned together so there's no wrap) --- */
.dp-unified-nutri-valunit {
  display: inline-flex;
  align-items: baseline;
  /* Phase 1.11.5 §1: gap 4→3px (value ↔ unit).  Tighter, but still
     readable.  ALLOWED list (padding/gap only). */
  gap: 3px;
  min-width: 0;
  max-width: 100%;
  justify-content: flex-start;
}
.dp-unified-nutri-value {
  /* Phase 1.11.5 §1: SHRINK value font 15 → 14px.  This reduces
     intrinsic col2 width by ~3–6px per digit (for typical 3-digit
     values like "720" the reduction is ~8–10px), all reclaimed to
     keep the level cell on-screen without widening it. */
  font-size: 14px;
  font-weight: 700;
  color: #1F2937;
}
.dp-unified-nutri-unit {
  /* Phase 1.11.5 §1: SHRINK unit font 12.5 → 12.0px (minor). */
  font-size: 12px;
  font-weight: 500;
  color: #5B6A8A;
  white-space: nowrap;
}

/* --- col 3: %NRV (Nutrition) / empty placeholder (Carbon) --- */
.dp-unified-nutri-nrv {
  /* Phase 1.11.5 §1: SHRINK NRV font 12.5 → 11.5px.  Combined with
     col3's minmax reduced (68/76 → 62/70), this reclaims ~6–7px of
     horizontal space directly in the 4-column tuple so the level
     cell never gets clipped even on tablet 2-col narrow cards. */
  font-size: 11.5px;
  font-weight: 500;
  color: #6C7797;
  text-align: right;
  white-space: nowrap;
}

/* --- col 4: circular level dot + Chinese level text (最右侧, §II) --- */
.dp-unified-nutri-level {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
  justify-content: flex-end;
  /* Phase 1.11.5 §1: level cell's internal right padding 4 → 3px,
     but the COLUMN definition itself stays at original 54/60 (we
     explicitly DO NOT widen the level column).  All room comes from
     the 3 sibling columns shrinking above. */
  padding-right: 3px;
  box-sizing: border-box;
  flex: 0 0 auto;
  font-size: 12px;
}
.dp-unified-level-dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  flex-shrink: 0;
  background: #98A3C0;
}
/* Level classes are directly attached to the dot <span> by the
   unified row builder.  Names match the legacy `dp-nutri-level-LOW /
   MED / HIGH` palette defined at L471-L473 so we don't fork colours. */
.dp-unified-level-dot.dp-nutri-level-LOW  { background: #22A06B; }
.dp-unified-level-dot.dp-nutri-level-MED  { background: #D97706; }
.dp-unified-level-dot.dp-nutri-level-HIGH { background: #B91C1C; }
.dp-unified-level-text {
  /* Phase 1.11.5 §1: SHRINK level-text font 12.5 → 12.0px so the
     Chinese 低/中/高 glyphs require 1–2px less width inside the
     fixed (not widened) 54/60 column. */
  font-size: 12px;
  font-weight: 600;
  color: #4D597B;
  white-space: nowrap;
}

/* --- Empty column placeholder (Carbon's %NRV slot, or SUMMARY-mode
   Carbon value slot).  Uses visibility:hidden so the 4-column grid
   remains perfectly aligned between Nutrition and Carbon rows; the
   column width is controlled by the grid-template-columns definition
   on .dp-unified-nutri-row — NOT by the cell content. */
.dp-unified-empty {
  visibility: hidden;
  pointer-events: none;
  width: 100%;
  height: 100%;
}

/* =================================================================
   Intro example card variant (§4 轻微优化紧凑性).
   The Intro wrapper is WIDER than product cards, so the default
   `col2 = minmax(60, auto)` stretches value-unit to fill 1fr,
   creating a HUGE blank between value-unit and %NRV.  Fix:
     - shrink all column minima / maxima to "fit content" (not auto)
     - reduce column gap from 10 → 8
     - DON'T force row to 100% width → keep left-aligned, which
       eliminates the pointless right-hand whitespace (§4: "减少
       无意义空白, 提高阅读紧凑性")
   Still keep the 4-column logical order: label | value | %NRV | ●level
   (§4 explicit: 保持四列逻辑).
   ================================================================= */
.dp-di-example-nutr .dp-unified-nutri-row,
.dp-di-example-carb .dp-unified-nutri-row {
  grid-template-columns:
    minmax(44px, 50px)               /* col1: label — tighter */
    minmax(60px, max-content)        /* col2: value-unit — fit content, NO huge stretch */
    minmax(64px, max-content)        /* col3: %NRV — fit content */
    minmax(50px, 56px);              /* col4: ●level */
  column-gap: 8px;                   /* §4: 更紧凑的列间距 */
  row-gap: 4px;
  /* Intro 不强制 100% 宽度, 不引入右侧巨大空白 (§4) */
  width: auto;
  max-width: 100%;
  justify-content: start;
}

/* =================================================================
   Phase 1.11.3 — Responsive Downgrade Layouts (§2 Nutrition, §5 Carbon mirror).
   The SAME 4 logical cells (label / value-unit / nrv / ●level) are
   rendered in THREE different flows, based on the AVAILABLE CONTAINER
   WIDTH.  Breakpoints are set by viewport because the menu grid
   switches at 1100 (2-col → 1-col) and 680 (2-cards → 1-card), so:

     WIDE (default, no media):  ≥  821px viewport → 2-col menu + 2-card
           grid = 4 columns, one single per-metric row:
             [label]  [value+unit]  [%NRV]  [●level]

     TABLET (max-width: 820px):   ≤ 820px viewport → 1-col menu + 2-card
           grid = 2×2 per metric row:
             row 1:  [label]    [value+unit]
             row 2:  [%NRV]     [●level (far R of row)]

     MOBILE (max-width: 420px):  ≤ 420px viewport → 1-col menu + 1-card
           grid = 3 rows per metric (Carbon has no NRV cell, so 2 rows):
             row 1:  label
             row 2:  value+unit (L-aligned, bold)
             row 3:  [%NRV] — [●level] (2 col: NRV L | ●level R)

   NO NEW SELECTORS are introduced; all rules are ADD-ONS to the
   existing frozen .dp-unified-nutri-row family so Phase 1.10's 20
   frozen headless probes (which do NOT exercise responsive widths)
   still match 1:1.
   ================================================================= */

/* --- BREAKPOINT 1: TABLET (<= 820px) ----
   The menu drops to 1 column at ≤1100 but cards still stay 2-wide
   until ≤680; 820 is the sweet-spot where each card body (~210px)
   becomes too narrow to keep the full 4-col row readable without
   squeezing.  2×2 is the natural downgrade (readability first). */
@media (max-width: 820px) {
  .dp-unified-nutri-row {
    grid-template-columns:
      minmax(48px, 52px)                /* col A: label (row 1 col 1) */
      1fr;                               /* col B: value-unit (row 1 col 2, fills remainder) */
    /* 2 columns × 2 rows:
         label       value+unit
         %NRV        ●level (far R of this half) */
    grid-template-rows: auto auto;
    grid-auto-flow: row;
    column-gap: 10px;
    row-gap: 4px;
  }
  /* Cells that already live in their correct 2-col slots stay put;
     we re-home the 4-col orphans (NRV + ●level) down to row 2. */
  .dp-unified-nutri-row > .dp-unified-nutri-nrv   { grid-column: 1 / 2; grid-row: 2 / 3; text-align: left; }
  .dp-unified-nutri-row > .dp-unified-nutri-level { grid-column: 2 / 3; grid-row: 2 / 3; }
  .dp-unified-nutri-row > .dp-unified-empty {
    /* In tablet mode the 4th empty placeholder cell of Carbon rows
       no longer participates in flow — collapse it to invisible
       0-size so row 2 keeps just [NRV-left / ●level-right] pair. */
    display: none !important;
  }
}

/* --- BREAKPOINT 2: MOBILE (<= 420px) ----
   Menu section-grid drops to 1 card wide; each card body is ~210px
   × 86pic so horizontal space is at a premium.  We fully "stack"
   each metric into 3 rows with a final 2-col NRV+level pair.
   This matches the spec's §2 "mobile" reading order exactly. */
@media (max-width: 420px) {
  /* Phase 1.19 D1C1: true mobile viewport can now reach <=420px.
     Keep the summary / fee block shrinkable so Low/High fee rows do not
     expand the menu column beyond the real device width. */
  .dp-menu-phase {
    padding-left: 12px;
    padding-right: 12px;
  }
  .dp-page-header,
  .dp-menu-body {
    gap: 16px;
  }
  .dp-order-summary-wrap,
  .dp-order-summary,
  .dp-order-selected-box,
  .dp-order-price-rows,
  .dp-fee-details-list,
  .dp-outside-option-btn,
  .dp-submit-btn {
    width: 100%;
    max-width: 100%;
    min-width: 0;
  }
  .dp-fee-details-item {
    align-items: flex-start;
    flex-wrap: wrap;
  }
  .dp-fee-details-fee {
    margin-left: auto;
  }
  .dp-unified-nutri-row {
    /* Single column STACK. */
    grid-template-columns: 1fr;
    grid-template-rows: auto auto auto;
    column-gap: 0;
    row-gap: 3px;
  }
  .dp-unified-nutri-row > .dp-unified-nutri-label   { grid-column: 1 / -1; grid-row: 1 / 2; }
  .dp-unified-nutri-row > .dp-unified-nutri-valunit { grid-column: 1 / -1; grid-row: 2 / 3; }
  /* Row 3: [%NRV ------ far-left | ●level far-right] — reuse a
     2-col mini-grid inside the 1-col stack via a nested flex row
     (the two cells are direct siblings so flex on parent won't
     help; instead we promote row 3 to two sub-columns). */
  .dp-unified-nutri-row {
    /* Re-declare grid so row 3 = 2 cols (rows 1-2 still span full). */
    grid-template-columns: 1fr 1fr;
    grid-template-rows: auto auto auto;
    row-gap: 3px;
    column-gap: 8px;
  }
  .dp-unified-nutri-row > .dp-unified-nutri-label   { grid-column: 1 / -1; grid-row: 1 / 2; }
  .dp-unified-nutri-row > .dp-unified-nutri-valunit { grid-column: 1 / -1; grid-row: 2 / 3; }
  .dp-unified-nutri-row > .dp-unified-nutri-nrv     { grid-column: 1 / 2; grid-row: 3 / 4; text-align: left; }
  .dp-unified-nutri-row > .dp-unified-nutri-level   { grid-column: 2 / 3; grid-row: 3 / 4; }
  .dp-unified-nutri-row > .dp-unified-empty {
    /* Carbon NRV placeholder — kill in mobile (never render blank
       slot between valunit and the level row). */
    display: none !important;
  }
}

/* =================================================================
   Outer wrapper containment (§2 Free/Both level-dot escape guard).
   The Unified Shell wrapper hosts the 3 rows on a flex-column;
   even in overflow conditions we MUST guarantee that the ● level
   dot (and its adjacent 低/中/高) never paints outside the pale
   blue rounded rectangle, which itself must paint inside the
   product card (which already has overflow:visible by default, so
   we also clip on the info wrappers).
   ================================================================= */
.dp-nutrition-expand-unified,
.dp-carbon-expand-unified {
  /* Always clip content that would otherwise escape the rounded
     corners.  This is the SECONDARY defense for §2 / §5 (the PRIMARY
     defense being the responsive downgrade layouts above). */
  overflow: hidden;
  box-sizing: border-box;
}
/* Legacy base classes also need overflow clip so the 1.11.3
   containment applies equally to ANY regime that renders a
   nutrition/carbon disclosure. */
.dp-nutrition-expand,
.dp-carbon-expand {
  overflow: hidden;
}

/* ======================================================================
   Phase 1.19 — Layered Carbon CLOSED mobile ≤420px grade visibility fix
   ----------------------------------------------------------------------
   SCOPE (most-narrow selector, DO NOT leak outside Layered Carbon):
     .dp-layered-carbon-module (Layered only)
       :not(.is-open)           (CLOSED state only; expanded is untouched)
       .dp-carbon-expand-summary (CLOSED summary chip, not unified full)
       .dp-unified-nutri-row    (summary grid row inside the chip)

   PROBLEM (§2 ROOT CAUSE from audit 2026-09-02):
     In viewports ≤420px the shared responsive-downgrade MQs (L1808–L1874)
     reshape the generic 4-column unified row into a 3-row × 2-column stack
     AND simultaneously hide .dp-unified-empty valunit/NRV via
     display:none !important.  Because Layered Carbon CLOSED summary has
     BOTH valunit (col2) AND NRV (col3) permanently empty, the resulting
     grid collapses into 2 tracks with widths ~0px / 3px and the ●level
     node (9px dot + 6px gap + 12px 低/中/高 = 27px) gets completely
     truncated by the ancestor overflow:hidden chain (dp-carbon-expand →
     dp-carbon-expand-summary → dp-layered-carbon-module).  Carbon label
     "碳足迹" was simultaneously compressed from ~36px down to 11px.

   TREATMENT PRESERVED (§1 / §8 non-negotiable):
     - EMPTY valunit & empty NRV stay display:none (no resurrected blank
       slots between label and grade).
     - Exact carbon value stays HIDDEN in CLOSED (we only touch the
       summary row; full expanded unified shell keeps its 4-col grid).
     - Global .dp-unified-nutri-row and its shared 4-col default are
       UNCHANGED — this rule lives on the narrow parent chain above.

   LAYOUT STRATEGY:
     Establish a stable DEDICATED 2-column row on the Layered Carbon
     CLOSED summary row alone.  Col1 holds the label and uses
     max-content so "碳足迹" (3 characters at 12.5px ≈ 37.5px) renders
     in full.  Col2 holds the ●level with a min-width floor of 30px
     (≥ 27px required measured footprint + 3px breathing room) and
     grows with max-content (so 低/中/高 share identical width).
     column-gap 8px is kept for visual separation parity with the
     Free/Both full-disclosure 4-col rows.

   WHY NOT .dp-unified-nutri-level / .dp-unified-nutri-label overrides?
     We'd need to reset grid-column / grid-row for 4 orphan nodes placed
     by the shared auto-flow MQ.  Overriding the *entire row's*
     grid-template-columns forces the 4 existing children (label, valunit
     empty-display-none, nrv empty-display-none, level) onto a clean
     2-track auto-placement: since children 2 & 3 are display:none,
     the CSS grid auto-placement skips them and label / level flow
     naturally into track 1 / track 2 respectively.  No per-child
     grid-column / grid-row re-anchoring needed.

   CROSS-REGIME ISOLATION (§5 / §15 explicit checklist items):
     - .dp-layered-carbon-module is NOT present in Control / Free / Low /
       High / Both / Space → zero impact on those regimes.
     - :not(.is-open) means the EXPANDED (is-open) unified shell, which
       uses .dp-carbon-expand-unified, keeps its shared 4-col layout.
     - @media (max-width: 420px) scope means tablets ≥768 / desktops
       ≥1024 keep the original responsive downgrade (already PASS per
       earlier 4-col / 2-col tablet downgrades that rendered grade OK).
   ====================================================================== */
@media (max-width: 420px) {
  .dp-layered-carbon-module:not(.is-open)
    .dp-carbon-expand-summary
    .dp-unified-nutri-row {
    /* Dedicated 2-track grid for Carbon CLOSED summary only.
       minmax(, max-content) on both columns guarantees that a 3-char
       label and the ●level compound chip are never compressed by the
       shared responsive MQ's orphan 0px / 3px tracks. */
    grid-template-columns: max-content minmax(30px, max-content);
    /* Keep the same 8px gap as the unified 4-col default for visual
       spacing parity with adjacent regime rows (Free/Both disclosure
       buttons already use column-gap 8px between label + value). */
    column-gap: 8px;
    /* Override the shared responsive MQ's min-height.  Carbon CLOSED
       only has ONE logical row, so the 3-row × 60+ px tablet/mobile
       stacked minimum is pure waste. */
    grid-auto-rows: min-content;
    row-gap: 0;
  }

  /* Coerce label & level into stable auto-flow on the 2 dedicated tracks.
     The shared responsive MQs have assigned orphan :nth-child placements
     from the 3-row stack (e.g. level to grid-column:2 / grid-row:3); we
     unset those here so the implicit auto-flow picks tracks 1 / 2 in
     order after skipping the 2 display:none empty siblings. */
  .dp-layered-carbon-module:not(.is-open)
    .dp-carbon-expand-summary
    .dp-unified-nutri-row
    > .dp-unified-nutri-label {
    grid-column: auto;
    grid-row: auto;
  }
  .dp-layered-carbon-module:not(.is-open)
    .dp-carbon-expand-summary
    .dp-unified-nutri-row
    > .dp-unified-nutri-level {
    grid-column: auto;
    grid-row: auto;
    /* Explicitly keep the level row visible; the shared responsive MQ
       does not hide it but a defensive visibility:visible assertion is
       harmless because display:none empty siblings already handle the
       valunit/NRV slots. */
    visibility: visible;
    display: inline-flex;
    align-items: baseline;
  }

  /* Give the summary chip enough horizontal room on mobile.
     The default dp-carbon-expand-summary min-width / max-width may
     otherwise keep the 2-col grid under-sized; width:auto plus a
     100% max lets the 2 tracks grow to ~37.5 + 8 + 35 = 80.5px
     without being clipped by the triple overflow:hidden chain. */
  .dp-layered-carbon-module:not(.is-open) .dp-carbon-expand-summary {
    width: auto;
    max-width: 100%;
    /* Preserve the existing containment box model (never leak outside
       the pale rounded rectangle).  overflow:visible is EXPLICITLY
       rejected per §6 ("不要简单用overflow:visible绕过根因"). */
    overflow: hidden;
  }
}

/* ======================================================================
   Phase 1.19 — Layered CLOSED inline-slot CTA font-size 12px → 14px
   ----------------------------------------------------------------------
   SCOPE (most-narrow selector per §4 / §5 checklist — NO shared CTA
   rules are touched):
     Anchored to the two Layered-specific wrappers:
       .dp-layered-nutrition-module → "查看更多营养信息 ›" (CLOSED only)
       .dp-layered-carbon-module    → "查看更多碳足迹信息 ›" (CLOSED only)
     Combined with :not(.is-open) on the module wrapper to EXCLUDE the
     secondary "收起营养信息 ‹" / "收起碳足迹信息 ‹" collapse buttons
     which live in the EXPANDED (is-open) module variant.
     Combined with .dp-od-inline-slot to EXCLUDE any other CTA shapes
     that may share .dp-on-demand-text-btn elsewhere.

   This rule CANNOT match:
     - Control / Free / Low / High / Both / Space — regimes have NO
       .dp-layered-*-module wrapper on their disclosure buttons.
     - Collapse ("收起…") CTAs — rendered in is-open modules, excluded
       by the :not(.is-open) suffix.
     - Layered EXPANDED unified CTAs — same :not(.is-open) guard.

   PRESERVED (§4 explicit list):
     font-weight stays 500  (inherited from shared base, not overridden).
     color stays #1F2937  (inherited, not overridden; equivalent to
                            rgb(31,41,55) per §12 post-condition).
     font-family stays the prototype's system font stack (inherited).
     line-height stays 1.38 (inherited from dp-od-inline-slot base
                            rule L1259; we do NOT re-declare so any
                            future shared change propagates cleanly).
   ====================================================================== */
.dp-layered-nutrition-module:not(.is-open) .dp-on-demand-text-btn.dp-od-inline-slot,
.dp-layered-carbon-module:not(.is-open) .dp-on-demand-text-btn.dp-od-inline-slot {
  font-size: 14px;
  /* All other CTA metrics (padding 4px 8px 5px, margin-left:auto,
     flex 0 1 auto, min-width:max-content, color, font-weight,
     line-height 1.38) are inherited unchanged from the shared
     dp-on-demand-text-btn.dp-od-inline-slot base at L1244–L1279 so the
     inline/wrap behaviour stays identical; only the visual prominence
     (§4 12→14 upgrade) is bumped. */
}
