/* Meal planner — the 5-day rolling view (#147 PR4).
 *
 * Ported from the converged sandbox prototype
 * (~/Developer/recipe-masonry/meal-plan-prototype-converged.html). The
 * prototype's lavender :root block is intentionally NOT carried over —
 * production tokens (tokens.css) supply the warm tomato palette under
 * the same --md-* names, so the port just consumes them.
 *
 * Prototype-token mapping (proto name -> production token):
 *   --md-outline-variant          -> --md-border-muted
 *   --md-surface-container-highest-> --md-surface-container-high
 *   --md-emphasized               -> --motion-spring-default-effects
 *   --md-duration-{short,medium}  -> --motion-spring-*-effects-duration
 *
 * PR4 ships the READ view only: no "+ Add a recipe" buttons, no Month
 * view / toggle (PR5), no entry mutation (PR6/PR7). Day cards are laid
 * out as flex columns so a later PR can bottom-anchor an add footer.
 */

@layer components {
  /* ---------------------------------------------------------- Page */
  /* The .plan root carries no own-rule styling: it takes the shared
     .page-shell utility in the template for centering + the --content-max
     tier (1280px = the prior hand-declared literal). */

  .plan__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-6);
    margin-bottom: var(--space-5);
  }

  .plan__title {
    margin: 0;
    font-family: var(--font-heading);
    font-size: var(--text-3xl);
    font-weight: 600;
    letter-spacing: -0.02em;
    line-height: 1.1;
  }

  .plan__head-actions {
    display: flex;
    align-items: center;
    /* flex-wrap so the two children (view toggle + Groceries button)
       drop onto a second row at narrow viewports (~390px) instead of
       clipping. The existing `gap` is honored as row-gap when wrapped
       (#195). */
    flex-wrap: wrap;
    gap: var(--space-3);
  }

  /* Groceries "Soon" affordance (spec D3 / D-AC4). Visible but
     non-interactive: aria-disabled, no click handler, no hover/active
     styling. The "Soon" pill makes the coming-soon status explicit.
     The control ships per the D3 override of the bible's default-to-
     omission rule — a future agent must not delete it. */
  .plan__groceries {
    appearance: none;
    background: transparent;
    border: 1px solid var(--md-border-muted);
    border-radius: var(--radius-pill);
    min-height: var(--control-h);
    padding: 0 var(--space-4);
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    font-family: var(--font-body);
    font-size: var(--text-sm);
    font-weight: 500;
    color: var(--md-on-surface-variant);
  }
  .plan__groceries[aria-disabled="true"] {
    cursor: default;
    opacity: 0.72;
  }
  .plan__groceries .icon {
    width: 18px;
    height: 18px;
  }
  .plan__soon-pill {
    background: var(--md-surface-container-high);
    color: var(--md-on-surface-variant);
    font-size: var(--text-xs);
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    /* 3px block padding is a sub-token micro-gap (allowlisted); inline snapped 9px -> --space-2. */
    padding: 3px var(--space-2);
    border-radius: var(--radius-pill);
    line-height: 1.3;
  }

  /* ----------------------------------------------------- Today hero */
  .plan-hero {
    background: var(--md-surface-container-low);
    border: 1px solid var(--md-border-muted);
    border-radius: var(--radius-xl);
    padding: var(--space-7) var(--space-7) var(--space-8);
    margin-bottom: var(--space-8);
  }

  .plan-hero__head {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    margin-bottom: var(--space-6);
  }

  .plan-hero__pill {
    background: var(--md-primary);
    color: var(--md-on-primary);
    font-size: var(--text-xs);
    font-weight: 700;
    letter-spacing: 0.1em;
    /* inline snapped 11px -> --space-3. */
    padding: var(--space-1) var(--space-3);
    border-radius: var(--radius-pill);
  }

  .plan-hero__date {
    margin: 0;
    font-family: var(--font-heading);
    font-size: var(--text-2xl);
    font-weight: 600;
    letter-spacing: -0.02em;
    line-height: 1.1;
  }

  /* Subtle count chip, e.g. "4 recipes" — tells the user how dense
     today's plan is at a glance. */
  .plan-hero__count {
    margin-left: auto;
    font-size: var(--text-xs);
    color: var(--md-on-surface-variant);
    letter-spacing: 0.02em;
  }

  /* meals-row columns: floor at 3 (so a single recipe doesn't sprawl
     full-width), ceil at 4. --plan-cols is set inline on the element
     by the handler-rendered template. More than 4 wraps via an
     implicit row. */
  .plan-hero__meals {
    display: grid;
    grid-template-columns: repeat(var(--plan-cols, 3), 1fr);
    gap: var(--space-4);
  }

  /* Empty Today hero — typography + icon only, no imagery (D-AC3). */
  .plan-hero__empty {
    grid-column: 1 / -1;
    background: var(--md-surface-container);
    border-radius: var(--radius-lg);
    padding: var(--space-9) var(--space-6);
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-3);
    color: var(--md-on-surface-variant);
    text-align: center;
  }
  .plan-hero__empty .icon {
    width: 36px;
    height: 36px;
  }
  .plan-hero__empty p {
    margin: 0;
    font-size: var(--text-sm);
  }
  .plan-empty-cta {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    min-height: var(--control-h);
    /* inline snapped 22px -> --space-6. */
    padding: 0 var(--space-6);
    border-radius: var(--radius-pill);
    background: var(--md-primary);
    color: var(--md-on-primary);
    font-family: var(--font-body);
    font-weight: 600;
    font-size: var(--text-sm);
    transition: filter 140ms ease;
  }
  .plan-empty-cta:hover {
    filter: brightness(1.06);
  }

  /* ------------------------------------------------- Hero meal card
     A real recipe card inside the Today hero. The prototype rendered
     skeleton bars; PR4 renders real recipe data (title + hero image).
     Each card links to its recipe-detail page. */
  /* No card-level overflow clip: the card paints no background or
     border, so it needs no rounded-corner clip of its own — the media
     (the one element with a visible box) clips itself. A card-level
     overflow:hidden instead clips the body text against the card edge,
     shaving the first glyph's left side-bearing (and re-clipping the
     title's -0.08em side-bearing margin on the peek <button> variant). */
  .plan-meal-card {
    display: flex;
    flex-direction: column;
    transition: transform 220ms var(--motion-spring-default-effects);
  }
  .plan-meal-card:hover {
    transform: translateY(-2px);
  }

  .plan-meal-card__tag {
    display: inline-flex;
    align-self: flex-start;
    align-items: center;
    background: var(--md-primary-container);
    color: var(--md-on-primary-container);
    /* 3px block padding is a sub-token micro-gap (allowlisted); inline snapped 10px -> --space-3. */
    padding: 3px var(--space-3);
    border-radius: var(--radius-pill);
    font-size: var(--text-xs);
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    margin-bottom: var(--space-3);
    height: 20px;
  }
  /* Spacer keeps tagged + untagged cards vertically aligned. */
  .plan-meal-card__tag-spacer {
    display: block;
    height: 20px;
    margin-bottom: var(--space-3);
  }

  .plan-meal-card__media {
    position: relative;
    width: 100%;
    aspect-ratio: 4 / 3;
    border-radius: var(--radius-md);
    overflow: hidden;
    background: var(--md-surface-container-high);
  }
  .plan-meal-card__image {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
  }
  /* Typographic fallback when a hero image is missing or fails to
     load — no stock imagery (AGENTS.md non-negotiable #3). */
  .plan-meal-card__fallback {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--md-surface-container-high);
    color: var(--md-on-surface-variant);
  }
  .plan-meal-card__fallback .icon {
    width: 28px;
    height: 28px;
    opacity: 0.5;
  }

  /* Card body: source line over title. min-width:0 lets the children
     shrink so their single-line ellipsis engages instead of the text
     pushing the card wider / clipping at the edge. */
  .plan-meal-card__body {
    margin-top: var(--space-3);
    min-width: 0;
  }
  /* Source/author line, ABOVE the title. Single-line ellipsis. */
  .plan-meal-card__source {
    /* 2px is a sub-token micro-gap (allowlisted). */
    margin: 0 0 2px;
    font-size: var(--text-xs);
    color: var(--md-on-surface-variant);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .plan-meal-card__title {
    margin: 0;
    font-family: var(--font-body);
    font-size: var(--text-sm);
    font-weight: 600;
    line-height: 1.35;
    color: var(--md-on-surface);
    /* Two-line clamp keeps cards even-height across mixed titles;
       clamp (not single-line) because the title is the primary line
       and a wrapped title reads better than a clipped one. */
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    /* overflow:hidden clips the first glyph's left side-bearing
       (wide-bearing capitals like P/B and digits like 1 lose a hair
       of stem). A small inline padding gives the clip box breathing
       room; the matching negative inline margin keeps the on-screen
       text position unchanged. 0.08em fully un-clips empirically. */
    padding-inline: 0.08em;
    margin-inline: -0.08em;
  }

  /* ------------------------------------------------- Coming up rows */
  .plan__section-label {
    display: block;
    font-size: var(--text-xs);
    font-weight: 700;
    letter-spacing: 0.12em;
    color: var(--md-on-surface-variant);
    text-transform: uppercase;
    margin-bottom: var(--space-5);
  }

  .plan-upcoming {
    display: grid;
    /* minmax(0, 1fr) — not the implicit minmax(auto, 1fr) — so the four
       columns can shrink below a day card's min-content width instead of
       flooring the grid at 4x that width. The card's min-content is the
       "+ Add a recipe" footer (~290px); without the 0 floor the row
       demands ~1168px, which the body grid's auto-min track then forces
       onto the whole page as horizontal overflow (the toggle row only
       made the head wider — this grid is the real overflow source).
       Same fix the calendar grid below already applies. */
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: var(--space-4);
  }

  /* Day card — flex column so a later PR can bottom-anchor an add
     footer (PR6). PR4 ships with no footer button. */
  .plan-day {
    display: flex;
    flex-direction: column;
    background: var(--md-surface-container-low);
    border: 1px solid var(--md-border-muted);
    border-radius: var(--radius-lg);
    padding: var(--space-4);
    transition:
      background 160ms ease,
      transform 240ms var(--motion-spring-default-effects),
      border-color 160ms ease;
  }
  .plan-day:hover {
    background: var(--md-surface-container);
    transform: translateY(-2px);
    border-color: var(--md-border);
  }

  .plan-day__name {
    margin: 0 0 var(--space-3);
    font-family: var(--font-heading);
    font-size: var(--text-base);
    font-weight: 600;
    letter-spacing: -0.01em;
    color: var(--md-on-surface);
  }

  .plan-day__entry {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    /* padding + negative margin are a matched pair — the inset claws the
       padding back so the hover background bleeds to the day-card edge.
       Both snapped 6px -> --space-2 together. */
    padding: var(--space-2);
    margin: 0 calc(-1 * var(--space-2));
    border-radius: var(--radius-sm);
    color: inherit;
    transition: background 120ms ease;
  }
  .plan-day__entry:hover {
    background: var(--md-surface-container-high);
  }

  /* Lead glyph: meal-tag letter when tagged, ordinal bullet when not.
     Same width either way so the entry text stays aligned across
     mixed-tag rows. */
  .plan-day__lead {
    flex: 0 0 auto;
    width: 14px;
    text-align: center;
    font-size: var(--text-xs);
    font-weight: 700;
    color: var(--md-on-surface-variant);
  }
  .plan-day__lead--ordinal {
    color: var(--md-border);
    font-size: var(--text-sm);
    line-height: 1;
  }

  .plan-day__thumb {
    width: 36px;
    height: 36px;
    flex: 0 0 auto;
    border-radius: var(--radius-sm);
    overflow: hidden;
    background: var(--md-surface-container-high);
    position: relative;
  }
  .plan-day__thumb img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
  }
  .plan-day__thumb-fallback {
    position: absolute;
    inset: 0;
  }

  /* Compact day row text column: source over title. flex:1 + min-width:0
     so both lines truncate cleanly within the row instead of widening
     it or clipping at the edge. */
  .plan-day__entry-text {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    /* 1px is a sub-token micro-gap (allowlisted). */
    gap: 1px;
  }
  .plan-day__entry-source {
    font-size: var(--text-xs);
    color: var(--md-on-surface-variant);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .plan-day__entry-title {
    font-size: var(--text-sm);
    font-weight: 500;
    line-height: 1.3;
    color: var(--md-on-surface);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    /* Same overflow:hidden first-glyph side-bearing clip as the hero
       meal-card title — pad the clip box and cancel it with a negative
       inline margin so the text position is unchanged. */
    padding-inline: 0.08em;
    margin-inline: -0.08em;
  }

  /* Day with zero planned recipes — small italic placeholder. */
  .plan-day__empty {
    font-size: var(--text-xs);
    font-style: italic;
    color: var(--md-on-surface-variant);
    padding: var(--space-4) 0;
    text-align: center;
  }

  /* ------------------------------------------------- Window paging */
  .plan__pager {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
    margin-top: var(--space-8);
  }
  /* Forward-only paging (#171 PR3, I-AC10): the default window renders
     just "Next 5 days" — no backward link. flex-end keeps that lone
     link pinned to the trailing edge where the Next link always sits. */
  .plan__pager--forward-only {
    justify-content: flex-end;
  }
  .plan__pager-link {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    min-height: var(--control-h);
    padding: 0 var(--space-4);
    border-radius: var(--radius-pill);
    border: 1px solid var(--md-border-muted);
    font-family: var(--font-body);
    font-size: var(--text-sm);
    font-weight: 500;
    color: var(--md-on-surface-variant);
    transition: background 140ms ease, color 140ms ease;
  }
  .plan__pager-link:hover {
    background: var(--md-surface-container);
    color: var(--md-on-surface);
  }

  /* ----------------------------------------------------- Read-only
     A non-Pro user with pre-existing entries (spec D6) sees the plan
     read-only. The banner explains why the add controls are absent. */
  .plan__readonly-banner {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    background: var(--md-primary-container);
    color: var(--md-on-primary-container);
    border-radius: var(--radius-lg);
    padding: var(--space-3) var(--space-4);
    margin-bottom: var(--space-5);
    font-size: var(--text-sm);
  }
  .plan__readonly-banner .icon {
    width: 20px;
    height: 20px;
    flex: 0 0 auto;
  }
  .plan__readonly-banner a {
    color: inherit;
    font-weight: 600;
    text-decoration: underline;
  }
  .plan__readonly-form {
    margin: 0;
  }
  .plan__readonly-action {
    appearance: none;
    border: 0;
    background: transparent;
    color: inherit;
    font: inherit;
    font-weight: 600;
    text-decoration: underline;
    cursor: pointer;
    padding: 0;
  }

  /* ----------------------------------------------------- Placement
     The recipe-detail "Add to meal plan" placement mode (#147 PR8,
     spec D4): a Pro user arrives at /plan?place=<slug>. The banner
     names the recipe and tells the user to tap a day; the day cards
     below become "Plan here" tap-targets. The banner reuses the
     readonly-banner's primary-container idiom so placement reads as a
     faithful extension of the plan page, not a new surface. */
  .plan__placement-banner {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    background: var(--md-primary-container);
    color: var(--md-on-primary-container);
    border-radius: var(--radius-lg);
    padding: var(--space-3) var(--space-4);
    margin-bottom: var(--space-5);
    font-size: var(--text-sm);
  }
  .plan__placement-banner .icon {
    width: 20px;
    height: 20px;
    flex: 0 0 auto;
  }
  .plan__placement-text {
    flex: 1 1 auto;
  }
  .plan__placement-cancel {
    flex: 0 0 auto;
    color: inherit;
    font-weight: 600;
    text-decoration: underline;
    min-height: var(--control-h);
    display: inline-flex;
    align-items: center;
  }

  /* The placement "Plan here" tap-target. In the Today hero it sits in
     the hero head (a compact pill); in an upcoming day card it is the
     bottom-anchored footer. One <form> wrapper, one submit button. */
  .plan-placement-form {
    margin: 0;
  }
  .plan-hero__head .plan-placement-form {
    margin-left: auto;
  }
  .plan-day .plan-placement-form {
    margin-top: auto;
  }
  .plan-placement-form__submit {
    appearance: none;
    width: 100%;
    min-height: var(--control-h);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    padding: 0 var(--space-4);
    border: none;
    border-radius: var(--radius-pill);
    background: var(--md-primary);
    color: var(--md-on-primary);
    font-family: var(--font-body);
    font-weight: 600;
    font-size: var(--text-sm);
    cursor: pointer;
    transition: filter 140ms ease;
  }
  .plan-hero__head .plan-placement-form__submit {
    width: auto;
  }
  .plan-placement-form__submit:hover {
    filter: brightness(1.06);
  }
  .plan-placement-form__submit:active {
    transform: scale(0.98);
  }
  .plan-placement-form__submit .icon {
    width: 18px;
    height: 18px;
  }
  /* In placement mode both the Today hero and the upcoming day cards
     read as live tap-targets: a primary-tinted border distinguishes
     them from their normal state. Both surfaces already carry a
     border, so only the colour shifts. */
  .plan-day--placement,
  .plan-hero--placement {
    border-color: var(--md-primary);
  }

  /* ------------------------------------------------------- Reflow
     Preserve the horizontal arrangement as long as it stays readable;
     collapse columns progressively below. */
  @media (max-width: 1000px) {
    .plan-upcoming {
      grid-template-columns: repeat(2, minmax(0, 1fr));
    }
  }
  @media (max-width: 560px) {
    .plan-upcoming {
      grid-template-columns: minmax(0, 1fr);
    }
    .plan-hero {
      padding: var(--space-6) var(--space-6) var(--space-7);
    }
  }
  @media (max-width: 480px) {
    .plan-hero__meals {
      grid-template-columns: 1fr;
      gap: var(--space-3);
    }
    .plan__head {
      flex-direction: column;
      align-items: stretch;
      gap: var(--space-3);
    }
    /* The hero head is a nowrap flex row of pill + date + count + "Open
       day"; at phone width its intrinsic width exceeds the viewport, so
       it wraps here. Without this the row's min-content floors .plan and
       — through the body grid's auto-min track — overflows the page. */
    .plan-hero__head {
      flex-wrap: wrap;
    }
  }

  /* =================================================================
     PR6 — the editing layer (#147): the "+ Add a recipe" affordances,
     the side-sheet day view, and the recipe picker. Ported from the
     converged prototype's .sheet / .add-popover idioms.
     ================================================================= */

  /* ------------------------------------------- Day-card add controls
     The day name doubles as a side-sheet trigger; the "+ Add a recipe"
     footer is bottom-anchored (the .plan-day flex column makes this a
     clean footer). margin-top:auto pushes it to the bottom regardless
     of how many entry rows the card holds. */
  .plan-day__name--btn {
    appearance: none;
    background: transparent;
    border: 0;
    cursor: pointer;
    text-align: left;
    width: calc(100% + 2 * var(--space-2));
    margin: calc(-1 * var(--space-2)) calc(-1 * var(--space-2)) var(--space-3);
    padding: var(--space-2);
    border-radius: var(--radius-sm);
    transition: background 120ms ease;
  }
  .plan-day__name--btn:hover {
    background: var(--md-surface-container-high);
  }

  .plan-day__add {
    appearance: none;
    border: 0;
    cursor: pointer;
    background: transparent;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    width: calc(100% + 2 * var(--space-4));
    /* margin-top:auto bottom-anchors the footer in the flex-column
       card, so the "+ Add a recipe" buttons line up in one horizontal
       row across the four day cards regardless of entry count (0, 1,
       or many). The negative inline/bottom margins bleed it to the
       card edges to seat the full-width divider. Matches the
       placement-form footer's margin-top:auto. */
    margin: auto calc(-1 * var(--space-4)) calc(-1 * var(--space-4));
    min-height: var(--control-h);
    padding: var(--space-2);
    border-top: 1px solid var(--md-border-muted);
    border-radius: 0 0 var(--radius-lg) var(--radius-lg);
    color: var(--md-on-surface-variant);
    font-family: var(--font-body);
    font-size: var(--text-xs);
    font-weight: 600;
    transition: background 140ms ease, color 140ms ease;
  }
  .plan-day__add .icon {
    width: 14px;
    height: 14px;
  }
  .plan-day__add:hover {
    background: var(--md-surface-container-high);
    color: var(--md-on-surface);
  }

  /* "Open day" affordance in the Today hero head. */
  .plan-hero__open {
    appearance: none;
    cursor: pointer;
    background: transparent;
    border: 1px solid var(--md-border-muted);
    border-radius: var(--radius-pill);
    min-height: var(--control-h);
    padding: 0 var(--space-4);
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    font-family: var(--font-body);
    font-size: var(--text-sm);
    font-weight: 500;
    color: var(--md-on-surface-variant);
    transition: background 140ms ease, color 140ms ease;
  }
  .plan-hero__open .icon {
    width: 18px;
    height: 18px;
  }
  .plan-hero__open:hover {
    background: var(--md-surface-container);
    color: var(--md-on-surface);
  }

  /* The empty-Today CTA is a <button> for a Pro user (it opens the
     sheet) and an <a> for a read-only user — .plan-empty-cta styles
     both; reset the button-specific defaults so they match. */
  button.plan-empty-cta {
    appearance: none;
    border: 0;
    cursor: pointer;
    font-family: var(--font-body);
  }
  .plan-empty-cta .icon {
    width: 16px;
    height: 16px;
  }

  /* ----------------------------------------------------- Side sheet
     A right-anchored panel that slides in over a dimming scrim. The
     whole .plan-sheet is fixed and covers the viewport so the scrim
     can catch outside clicks; the .plan-sheet__panel is the visible
     surface. Parked off-screen + pointer-events:none until
     .plan-sheet--open. */
  .plan-sheet {
    position: fixed;
    inset: 0;
    z-index: 60;
    pointer-events: none;
    /* Clip the parked .plan-sheet__panel (translateX(100%) when
       closed) so it doesn't extend document scrollWidth and trigger
       a viewport-wide horizontal scroll (#195). The panel still
       transitions in/out fine; clipping only suppresses the off-
       screen footprint. */
    overflow: hidden;
  }
  .plan-sheet__scrim {
    position: absolute;
    inset: 0;
    appearance: none;
    border: 0;
    padding: 0;
    background: rgba(29, 27, 32, 0.32);
    opacity: 0;
    cursor: pointer;
    transition: opacity var(--motion-spring-default-effects-duration, 350ms) ease;
  }
  .plan-sheet__panel {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    width: min(480px, 100vw);
    background: var(--md-surface);
    box-shadow: var(--shadow-xl);
    transform: translateX(100%);
    transition: transform var(--motion-spring-default-effects-duration, 350ms)
      var(--motion-spring-default-effects);
    display: flex;
    flex-direction: column;
    overflow: hidden;
  }
  .plan-sheet--open {
    pointer-events: auto;
  }
  .plan-sheet--open .plan-sheet__scrim {
    opacity: 1;
  }
  .plan-sheet--open .plan-sheet__panel {
    transform: translateX(0);
  }
  @media (prefers-reduced-motion: reduce) {
    .plan-sheet__panel,
    .plan-sheet__scrim {
      transition: none;
    }
  }

  .plan-sheet__actions {
    display: flex;
    justify-content: flex-end;
    padding: var(--space-3) var(--space-3) 0;
    flex: 0 0 auto;
  }
  .plan-sheet__close {
    appearance: none;
    border: 0;
    cursor: pointer;
    background: transparent;
    width: 40px;
    height: 40px;
    border-radius: var(--radius-pill);
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--md-on-surface);
    transition: background 120ms ease;
  }
  .plan-sheet__close:hover {
    background: var(--md-surface-container-high);
  }
  .plan-sheet__close .icon {
    width: 20px;
    height: 20px;
  }

  /* The sheet body is the htmx-swap target; it scrolls independently. */
  .plan-sheet__body {
    flex: 1 1 auto;
    overflow-y: auto;
    overscroll-behavior: contain;
  }

  .plan-sheet__head {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-6) var(--space-4);
    border-bottom: 1px solid var(--md-border-muted);
  }
  .plan-sheet__pill {
    background: var(--md-primary);
    color: var(--md-on-primary);
    font-size: var(--text-xs);
    font-weight: 700;
    letter-spacing: 0.1em;
    /* inline snapped 11px -> --space-3. */
    padding: var(--space-1) var(--space-3);
    border-radius: var(--radius-pill);
  }
  .plan-sheet__date {
    margin: 0;
    font-family: var(--font-heading);
    font-size: var(--text-2xl);
    font-weight: 600;
    letter-spacing: -0.02em;
    line-height: 1.1;
  }

  .plan-sheet__entries {
    padding: var(--space-4) var(--space-6);
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
  }

  /* One entry in the sheet: a recipe link plus a "More" kebab that
     opens an anchored action menu. */
  .plan-sheet__entry {
    display: flex;
    align-items: center;
    gap: var(--space-2);
  }
  .plan-sheet__entry-link {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-2);
    margin: calc(-1 * var(--space-2)) 0;
    border-radius: var(--radius-md);
    color: inherit;
    transition: background 120ms ease;
  }
  .plan-sheet__entry-link:hover {
    background: var(--md-surface-container);
  }
  .plan-sheet__entry-thumb {
    width: 56px;
    height: 56px;
    flex: 0 0 auto;
    border-radius: var(--radius-md);
    overflow: hidden;
    background: var(--md-surface-container-high);
    position: relative;
  }
  .plan-sheet__entry-thumb img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
  }
  .plan-sheet__entry-thumb-fallback {
    position: absolute;
    inset: 0;
  }
  .plan-sheet__entry-text {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    /* 2px is a sub-token micro-gap (allowlisted). */
    gap: 2px;
  }
  .plan-sheet__entry-tag {
    align-self: flex-start;
    background: var(--md-primary-container);
    color: var(--md-on-primary-container);
    /* 2px block padding is a sub-token micro-gap (allowlisted); inline snapped 9px -> --space-2. */
    padding: 2px var(--space-2);
    border-radius: var(--radius-pill);
    font-size: var(--text-xs);
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    /* 2px is a sub-token micro-gap (allowlisted). */
    margin-bottom: 2px;
  }
  .plan-sheet__entry-source {
    font-size: var(--text-xs);
    color: var(--md-on-surface-variant);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .plan-sheet__entry-title {
    font-size: var(--text-sm);
    font-weight: 600;
    line-height: 1.3;
    color: var(--md-on-surface);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  /* A per-entry note, shown under the title when the entry carries one. */
  .plan-sheet__entry-note {
    font-size: var(--text-xs);
    color: var(--md-on-surface-variant);
    line-height: 1.4;
    /* 2px is a sub-token micro-gap (allowlisted). */
    margin-top: 2px;
  }

  /* The "More" kebab: opens the entry's anchored action menu. */
  .plan-row-menu-wrap {
    position: relative;
    flex: 0 0 auto;
  }
  .plan-sheet__entry-more {
    appearance: none;
    border: 0;
    cursor: pointer;
    background: transparent;
    width: 40px;
    height: 40px;
    border-radius: var(--radius-pill);
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--md-on-surface-variant);
    transition: background 120ms ease, color 120ms ease;
  }
  .plan-sheet__entry-more:hover,
  .plan-sheet__entry-more[aria-expanded="true"] {
    background: var(--md-surface-container-high);
    color: var(--md-on-surface);
  }
  .plan-sheet__entry-more .icon {
    width: 18px;
    height: 18px;
  }

  /* ------------------------------------------------- Row action menu
     A small anchored popover off the kebab: Edit entry / Move up /
     Move down / Move to another day / Remove. Absolutely positioned
     within the entry's .plan-row-menu-wrap so it tracks the kebab
     without JS positioning; hidden until the kebab is tapped. */
  .plan-row-menu {
    position: absolute;
    top: calc(100% + 4px);
    right: 0;
    z-index: 5;
    width: 212px;
    background: var(--md-surface);
    border: 1px solid var(--md-border-muted);
    border-radius: var(--radius-md);
    box-shadow: 0 14px 32px rgba(29, 27, 32, 0.16),
                0 2px 6px rgba(29, 27, 32, 0.06);
    padding: var(--space-1);
  }
  .plan-row-menu[hidden] {
    display: none;
  }
  .plan-row-menu__item {
    appearance: none;
    border: 0;
    cursor: pointer;
    background: transparent;
    width: 100%;
    min-height: var(--control-h);
    padding: 0 var(--space-3);
    display: flex;
    align-items: center;
    gap: var(--space-3);
    border-radius: var(--radius-sm);
    font-family: var(--font-body);
    font-size: var(--text-sm);
    font-weight: 500;
    color: var(--md-on-surface);
    text-align: left;
    transition: background 110ms ease;
  }
  .plan-row-menu__item:hover {
    background: var(--md-surface-container);
  }
  .plan-row-menu__item .icon {
    width: 18px;
    height: 18px;
    flex: 0 0 auto;
    color: var(--md-on-surface-variant);
  }
  .plan-row-menu__sep {
    height: 1px;
    background: var(--md-border-muted);
    margin: var(--space-1) var(--space-2);
  }
  .plan-row-menu__item--danger,
  .plan-row-menu__item--danger .icon {
    color: var(--md-error);
  }
  .plan-row-menu__item--danger:hover {
    background: var(--md-error-soft);
  }

  /* ================================================ Edit sheet-view
     The dedicated per-entry edit view (plan_entry_edit). It swaps into
     the same #plan-day-sheet slot as the day view, so it owns the full
     sheet height and scrolls independently. */
  .plan-edit {
    display: flex;
    flex-direction: column;
  }
  .plan-edit__head {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-3) var(--space-6) var(--space-4);
    border-bottom: 1px solid var(--md-border-muted);
  }
  .plan-edit__back {
    appearance: none;
    border: 0;
    cursor: pointer;
    background: transparent;
    width: 40px;
    height: 40px;
    flex: 0 0 auto;
    border-radius: var(--radius-pill);
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--md-on-surface-variant);
    transition: background 120ms ease, color 120ms ease;
  }
  .plan-edit__back:hover {
    background: var(--md-surface-container-high);
    color: var(--md-on-surface);
  }
  .plan-edit__back .icon {
    width: 20px;
    height: 20px;
  }
  .plan-edit__title {
    margin: 0;
    font-family: var(--font-heading);
    font-size: var(--text-xl);
    font-weight: 600;
    letter-spacing: -0.01em;
  }

  /* Compact entry identity — which entry is being edited. */
  .plan-edit__entry {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    margin: var(--space-4) var(--space-6);
    padding-bottom: var(--space-4);
    border-bottom: 1px solid var(--md-border-muted);
  }
  .plan-edit__entry-thumb {
    width: 56px;
    height: 56px;
    flex: 0 0 auto;
    border-radius: var(--radius-md);
    overflow: hidden;
    background: var(--md-surface-container-high);
    position: relative;
  }
  .plan-edit__entry-thumb img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
  }
  .plan-edit__entry-thumb-fallback {
    position: absolute;
    inset: 0;
  }
  .plan-edit__entry-text {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    /* 2px is a sub-token micro-gap (allowlisted). */
    gap: 2px;
  }
  .plan-edit__entry-source {
    font-size: var(--text-xs);
    color: var(--md-on-surface-variant);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .plan-edit__entry-title {
    font-size: var(--text-sm);
    font-weight: 600;
    line-height: 1.3;
    color: var(--md-on-surface);
  }

  /* The content form + the move/remove affordances share the body's
     horizontal padding. */
  .plan-edit__form,
  .plan-move-wrap,
  .plan-edit__remove {
    margin-left: var(--space-6);
    margin-right: var(--space-6);
  }
  .plan-edit__field {
    margin-top: var(--space-5);
  }
  .plan-edit__field:first-child {
    margin-top: var(--space-2);
  }
  .plan-edit__label {
    display: block;
    font-size: var(--text-xs);
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--md-on-surface-variant);
    margin-bottom: var(--space-2);
  }

  /* Servings stepper — minus / value / plus. */
  .plan-stepper {
    display: inline-flex;
    align-items: center;
    border: 1px solid var(--md-border-muted);
    border-radius: var(--radius-pill);
    background: var(--md-surface-container-low);
  }
  .plan-stepper__btn {
    appearance: none;
    border: 0;
    cursor: pointer;
    background: transparent;
    width: 44px;
    height: 44px;
    border-radius: var(--radius-pill);
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--md-on-surface);
    transition: background 120ms ease;
  }
  .plan-stepper__btn:hover {
    background: var(--md-surface-container-high);
  }
  .plan-stepper__btn .icon {
    width: 18px;
    height: 18px;
  }
  .plan-stepper__value {
    min-width: 76px;
    text-align: center;
    font-size: var(--text-base);
    font-weight: 600;
    color: var(--md-on-surface);
  }
  .plan-stepper__default {
    display: block;
    font-size: var(--text-xs);
    font-weight: 500;
    color: var(--md-on-surface-variant);
  }

  /* Meal-tag chips — None / Breakfast / Lunch / Dinner. */
  .plan-tag-choices {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
  }
  .plan-tag-choice {
    appearance: none;
    cursor: pointer;
    border: 1px solid var(--md-border-muted);
    background: var(--md-surface-container-low);
    min-height: var(--control-h);
    padding: 0 var(--space-4);
    border-radius: var(--radius-pill);
    font-family: var(--font-body);
    font-size: var(--text-sm);
    font-weight: 500;
    color: var(--md-on-surface-variant);
    display: inline-flex;
    align-items: center;
    /* snapped 6px -> --space-2. */
    gap: var(--space-2);
    transition: background 130ms ease, border-color 130ms ease, color 130ms ease;
  }
  .plan-tag-choice .icon {
    width: 15px;
    height: 15px;
  }
  .plan-tag-choice:hover {
    background: var(--md-surface-container);
    color: var(--md-on-surface);
  }
  .plan-tag-choice[aria-pressed="true"] {
    background: var(--md-primary-container);
    border-color: var(--md-primary-container);
    color: var(--md-on-primary-container);
    font-weight: 600;
  }
  .plan-tag-choice:focus-visible {
    outline: 2px solid var(--md-primary);
    outline-offset: 2px;
  }

  /* Note textarea. */
  .plan-edit__note {
    width: 100%;
    box-sizing: border-box;
    min-height: 80px;
    resize: vertical;
    padding: var(--space-3);
    border: 1px solid var(--md-border-muted);
    border-radius: var(--radius-md);
    background: var(--md-surface-container-low);
    font-family: var(--font-body);
    font-size: var(--text-sm);
    line-height: 1.5;
    color: var(--md-on-surface);
  }
  .plan-edit__note:focus {
    outline: none;
    border-color: var(--md-primary);
  }

  /* Move-to-another-day — a secondary navigation row, not a CTA. */
  .plan-move-wrap {
    position: relative;
    margin-top: var(--space-5);
  }
  .plan-edit__move {
    appearance: none;
    cursor: pointer;
    width: 100%;
    min-height: 52px;
    padding: 0 var(--space-4);
    border: 1px solid var(--md-border-muted);
    border-radius: var(--radius-md);
    background: transparent;
    display: flex;
    align-items: center;
    gap: var(--space-3);
    font-family: var(--font-body);
    color: var(--md-on-surface);
    transition: background 130ms ease, border-color 130ms ease;
  }
  .plan-edit__move:hover {
    background: var(--md-surface-container);
    border-color: var(--md-outline);
  }
  .plan-edit__move > .icon {
    width: 20px;
    height: 20px;
    flex: 0 0 auto;
    color: var(--md-on-surface-variant);
  }
  .plan-edit__move-text {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
  }
  .plan-edit__move-title {
    font-size: var(--text-sm);
    font-weight: 600;
  }
  .plan-edit__move-sub {
    font-size: var(--text-xs);
    color: var(--md-on-surface-variant);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 100%;
  }

  /* Day-picker popover — the next two weeks, anchored under the move
     row. Hidden until the move row is tapped. */
  .plan-day-picker {
    position: absolute;
    top: calc(100% + 4px);
    left: 0;
    right: 0;
    z-index: 5;
    max-height: 320px;
    overflow-y: auto;
    overscroll-behavior: contain;
    background: var(--md-surface);
    border: 1px solid var(--md-border-muted);
    border-radius: var(--radius-md);
    box-shadow: 0 14px 32px rgba(29, 27, 32, 0.16),
                0 2px 6px rgba(29, 27, 32, 0.06);
    padding: var(--space-1);
  }
  .plan-day-picker[hidden] {
    display: none;
  }
  .plan-day-picker__item {
    margin: 0;
  }
  .plan-day-picker__btn {
    appearance: none;
    border: 0;
    cursor: pointer;
    background: transparent;
    width: 100%;
    min-height: var(--control-h);
    padding: var(--space-2) var(--space-3);
    display: flex;
    align-items: center;
    gap: var(--space-3);
    border-radius: var(--radius-sm);
    text-align: left;
    transition: background 110ms ease;
  }
  .plan-day-picker__btn:hover {
    background: var(--md-surface-container);
  }
  /* The current-day row is a non-interactive sibling of the picker's
     .plan-day-picker__btn controls; it tracks --control-h so the picker
     list keeps a uniform row rhythm. */
  .plan-day-picker__item--current {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-2) var(--space-3);
    min-height: var(--control-h);
  }
  .plan-day-picker__day {
    flex: 1 1 auto;
    min-width: 0;
    font-size: var(--text-sm);
    font-weight: 500;
    color: var(--md-on-surface);
  }
  .plan-day-picker__item--current .plan-day-picker__day {
    color: var(--md-on-surface-variant);
  }
  .plan-day-picker__rel {
    display: block;
    font-size: var(--text-xs);
    font-weight: 500;
    color: var(--md-on-surface-variant);
  }
  .plan-day-picker__count {
    flex: 0 0 auto;
    font-size: var(--text-xs);
    color: var(--md-on-surface-variant);
  }
  .plan-day-picker__here {
    flex: 0 0 auto;
    font-size: var(--text-xs);
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--md-primary);
  }

  /* Remove — destructive, subordinate. A plain red text button. */
  .plan-edit__remove {
    appearance: none;
    border: 0;
    cursor: pointer;
    background: transparent;
    min-height: var(--control-h);
    margin-top: var(--space-4);
    border-radius: var(--radius-sm);
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    font-family: var(--font-body);
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--md-error);
    transition: background 120ms ease;
  }
  .plan-edit__remove:hover {
    background: var(--md-error-soft);
  }
  .plan-edit__remove .icon {
    width: 17px;
    height: 17px;
  }

  /* Sticky action bar — the single Save primary, pinned to the sheet
     bottom so it is always reachable. */
  .plan-edit__actionbar {
    position: sticky;
    bottom: 0;
    margin-top: var(--space-6);
    padding: var(--space-4) var(--space-6)
             calc(var(--space-4) + env(safe-area-inset-bottom, 0px));
    background: var(--md-surface);
    border-top: 1px solid var(--md-border-muted);
  }
  .plan-edit__save {
    appearance: none;
    border: 0;
    cursor: pointer;
    width: 100%;
    min-height: 52px;
    border-radius: var(--radius-pill);
    background: var(--md-primary);
    color: var(--md-on-primary);
    font-family: var(--font-body);
    font-size: var(--text-base);
    font-weight: 600;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    transition: filter 130ms ease;
  }
  .plan-edit__save:hover {
    filter: brightness(1.06);
  }
  .plan-edit__save .icon {
    width: 18px;
    height: 18px;
  }

  /* Unplanned day in the sheet — typography + icon, no imagery. */
  .plan-sheet__empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-8) var(--space-4) var(--space-4);
    color: var(--md-on-surface-variant);
    text-align: center;
  }
  .plan-sheet__empty .icon {
    width: 36px;
    height: 36px;
  }
  .plan-sheet__empty p {
    margin: 0;
    font-size: var(--text-sm);
  }

  /* "+ Add a recipe" button at the bottom of the sheet day view. */
  .plan-sheet__add {
    appearance: none;
    cursor: pointer;
    background: transparent;
    border: 1.5px dashed var(--md-border-muted);
    width: calc(100% - 2 * var(--space-6));
    margin: 0 var(--space-6) var(--space-6);
    min-height: var(--control-h);
    padding: var(--space-3);
    border-radius: var(--radius-md);
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    color: var(--md-on-surface-variant);
    font-family: var(--font-body);
    font-size: var(--text-sm);
    font-weight: 600;
    transition: background 160ms ease, border-color 160ms ease, color 160ms ease;
  }
  .plan-sheet__add .icon {
    width: 18px;
    height: 18px;
  }
  .plan-sheet__add:hover {
    background: var(--md-surface-container);
    border-color: var(--md-primary);
    color: var(--md-primary);
  }

  /* ------------------------------------------------- Recipe picker
     Mounted inside the sheet (#plan-picker-slot) when "+ Add a recipe"
     is tapped. A bordered card: search field, Recent/Suggested sections
     of saved-box recipes, and a "Browse all recipes" footer link out
     to Explore. */
  .plan-picker-slot {
    padding: 0 var(--space-6) var(--space-6);
  }
  .plan-picker {
    border: 1px solid var(--md-border-muted);
    border-radius: var(--radius-lg);
    background: var(--md-surface);
    display: flex;
    flex-direction: column;
    overflow: hidden;
    max-height: 440px;
  }

  .plan-picker__search {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-3) var(--space-4);
    border-bottom: 1px solid var(--md-border-muted);
    flex: 0 0 auto;
  }
  .plan-picker__search .icon {
    width: 18px;
    height: 18px;
    color: var(--md-on-surface-variant);
    flex: 0 0 auto;
  }
  .plan-picker__search-input {
    appearance: none;
    border: 0;
    outline: none;
    background: transparent;
    flex: 1 1 auto;
    min-width: 0;
    /* 2px block padding is a sub-token micro-gap (allowlisted). */
    padding: 2px 0;
    font-family: var(--font-body);
    font-size: var(--text-sm);
    color: var(--md-on-surface);
  }
  .plan-picker__search-input::placeholder {
    color: var(--md-on-surface-variant);
  }

  .plan-picker__content {
    flex: 1 1 auto;
    overflow-y: auto;
    overscroll-behavior: contain;
    padding: var(--space-2) 0;
  }
  .plan-picker__label {
    display: block;
    font-size: var(--text-xs);
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--md-on-surface-variant);
    padding: var(--space-2) var(--space-4) var(--space-1);
  }

  .plan-picker__item {
    margin: 0;
  }
  .plan-picker__item-btn {
    appearance: none;
    border: 0;
    cursor: pointer;
    background: transparent;
    width: 100%;
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-2) var(--space-4);
    text-align: left;
    transition: background 120ms ease;
  }
  .plan-picker__item-btn:hover {
    background: var(--md-surface-container);
  }
  .plan-picker__item-thumb {
    width: 40px;
    height: 40px;
    flex: 0 0 auto;
    border-radius: var(--radius-sm);
    overflow: hidden;
    background: var(--md-surface-container-high);
    position: relative;
  }
  .plan-picker__item-thumb img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
  }
  .plan-picker__item-thumb-fallback {
    position: absolute;
    inset: 0;
  }
  .plan-picker__item-text {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    /* 1px is a sub-token micro-gap (allowlisted). */
    gap: 1px;
  }
  .plan-picker__item-source {
    font-size: var(--text-xs);
    color: var(--md-on-surface-variant);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .plan-picker__item-title {
    font-size: var(--text-sm);
    font-weight: 500;
    line-height: 1.3;
    color: var(--md-on-surface);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .plan-picker__empty {
    padding: var(--space-6) var(--space-4);
    text-align: center;
    color: var(--md-on-surface-variant);
  }
  .plan-picker__empty p {
    margin: 0;
    font-size: var(--text-sm);
  }

  .plan-picker__browse {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2);
    padding: var(--space-3) var(--space-4);
    min-height: var(--control-h);
    border-top: 1px solid var(--md-border-muted);
    color: var(--md-primary);
    font-family: var(--font-body);
    font-size: var(--text-sm);
    font-weight: 600;
    flex: 0 0 auto;
    transition: background 120ms ease;
  }
  .plan-picker__browse:hover {
    background: var(--md-surface-container);
  }
  .plan-picker__browse .icon {
    width: 16px;
    height: 16px;
  }

  /* =================================================================
     #171 meal-planning-polish PR1 — the recipe peek-panel.

     The recipe peek is a third .plan-sheet body-view (decision D2),
     alongside the day view and the edit view. It is a faithful port of
     the converged proto's .sv-recipe side-sheet
     (~/Developer/recipe-masonry/meal-plan-history-converged.html):
     a recipe-detail hero + content, two pinned footer actions. Tomato
     (--md-primary) is the single accent; geometry on the --space-*
     scale (D-AC2). The plan-specific peek partial does NOT touch
     Explore's .recipe-preview markup.
     ================================================================= */

  /* The peek body is a .plan-sheet__body flex column (the shared
     scroll container) plus a pinned footer; the content scrolls. */
  .plan-peek,
  .plan-peek-days {
    display: flex;
    flex-direction: column;
  }

  /* Peek header — only rendered when the peek was opened from inside a
     day sheet (it carries a back-to-day control). Mirrors the edit
     view's .plan-edit__head. */
  .plan-peek__head {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-3) var(--space-6) var(--space-4);
    border-bottom: 1px solid var(--md-border-muted);
    flex: 0 0 auto;
  }
  .plan-peek__back {
    appearance: none;
    border: 0;
    cursor: pointer;
    background: transparent;
    width: 40px;
    height: 40px;
    flex: 0 0 auto;
    border-radius: var(--radius-pill);
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--md-on-surface-variant);
    transition: background 120ms ease, color 120ms ease;
  }
  .plan-peek__back:hover {
    background: var(--md-surface-container-high);
    color: var(--md-on-surface);
  }
  .plan-peek__back .icon {
    width: 20px;
    height: 20px;
  }
  .plan-peek__head-title {
    margin: 0;
    font-family: var(--font-heading);
    font-size: var(--text-xl);
    font-weight: 600;
    letter-spacing: -0.01em;
  }

  /* Peek hero — a 4:3 recipe image, or a neutral icon fallback. */
  .plan-peek__hero {
    position: relative;
    width: 100%;
    aspect-ratio: 4 / 3;
    background: var(--md-surface-container-high);
    overflow: hidden;
    flex: 0 0 auto;
  }
  .plan-peek__hero-image {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
  }
  .plan-peek__hero-fallback {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--md-on-surface-variant);
  }
  .plan-peek__hero-fallback .icon {
    width: 40px;
    height: 40px;
  }

  /* Peek content — the recipe-detail body (title, source, signal
     pills, description, ingredient preview). Shares the sheet's
     horizontal padding. */
  .plan-peek__content {
    padding: var(--space-5) var(--space-6) var(--space-6);
  }
  .plan-peek__title-group {
    margin-bottom: var(--space-3);
  }
  .plan-peek__category {
    margin: 0 0 var(--space-1);
    font-size: var(--text-xs);
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--md-on-surface-variant);
  }
  .plan-peek__title {
    margin: 0;
    font-family: var(--font-heading);
    font-size: var(--text-2xl);
    font-weight: 600;
    letter-spacing: -0.02em;
    line-height: 1.15;
  }
  .plan-peek__source {
    margin: 0 0 var(--space-4);
    font-size: var(--text-sm);
    color: var(--md-on-surface-variant);
  }
  /* Per-person span inside a Person-tier byline (attribution-
     unification PR6). Stays inline alongside its label and comma
     separators; the verified rosette renders inline next to the
     name. */
  .plan-peek__byline-person {
    display: inline;
  }
  .plan-peek__verified {
    display: inline-flex;
    align-items: center;
    color: var(--md-primary);
    vertical-align: -0.15em;
  }
  .plan-peek__verified .icon {
    width: 1em;
    height: 1em;
  }

  /* Signal pills — total time, servings, ingredient count, dietary
     flags. The same compact pill idiom the Explore preview uses. */
  .plan-peek__signals {
    list-style: none;
    margin: 0 0 var(--space-4);
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
  }
  .plan-peek__signal {
    display: inline-flex;
    align-items: baseline;
    gap: var(--space-1);
    padding: var(--space-1) var(--space-3);
    border-radius: var(--radius-pill);
    background: var(--md-surface-container);
    font-size: var(--text-xs);
    color: var(--md-on-surface-variant);
  }
  .plan-peek__signal strong {
    font-weight: 700;
    color: var(--md-on-surface);
  }
  .plan-peek__signal--flag {
    background: var(--md-tag-neutral);
    color: var(--md-tag-neutral-foreground);
    font-weight: 600;
  }
  .plan-peek__desc {
    margin: 0 0 var(--space-5);
    font-size: var(--text-sm);
    line-height: 1.5;
    color: var(--md-on-surface-variant);
  }
  .plan-peek__section-title {
    margin: 0 0 var(--space-2);
    font-size: var(--text-xs);
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--md-on-surface-variant);
  }
  .plan-peek__ingredients {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
  }
  .plan-peek__ingredient {
    font-size: var(--text-sm);
    line-height: 1.4;
    color: var(--md-on-surface);
    padding-left: var(--space-3);
    position: relative;
  }
  .plan-peek__ingredient::before {
    content: '';
    position: absolute;
    left: 0;
    top: 0.6em;
    width: 4px;
    height: 4px;
    border-radius: var(--radius-pill);
    background: var(--md-primary);
  }
  .plan-peek__more {
    margin: var(--space-3) 0 0;
    font-size: var(--text-xs);
    color: var(--md-on-surface-variant);
  }

  /* Peek footer — the two pinned actions. "Add to meal plan" is a
     tomato-outlined tonal; "View full recipe" is the filled tomato
     primary. Both on the single accent (converged proto BLOCKER 1
     fix). Pinned to the sheet bottom so they are always reachable. */
  .plan-peek__footer {
    position: sticky;
    bottom: 0;
    margin-top: auto;
    display: flex;
    gap: var(--space-3);
    padding: var(--space-4) var(--space-6)
             calc(var(--space-4) + env(safe-area-inset-bottom, 0px));
    background: var(--md-surface);
    border-top: 1px solid var(--md-border-muted);
  }
  .plan-peek__action {
    appearance: none;
    cursor: pointer;
    flex: 1 1 0;
    min-height: var(--control-h);
    border-radius: var(--radius-pill);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    font-family: var(--font-body);
    font-size: var(--text-sm);
    font-weight: 600;
    text-decoration: none;
    transition: background 140ms ease, border-color 140ms ease,
                filter 140ms ease;
  }
  .plan-peek__action .icon {
    width: 17px;
    height: 17px;
  }
  /* Primary — "View full recipe". Filled tomato. Hover is a brightness
     filter, the same on-token hover idiom .plan-edit__save uses — the
     hover-token pattern (--md-primary-hover) is reserved to
     save-heart.css per design-bible Decision 4. */
  .plan-peek__action--primary {
    border: 0;
    background: var(--md-primary);
    color: var(--md-on-primary);
  }
  .plan-peek__action--primary:hover {
    filter: brightness(1.06);
  }
  /* Secondary — "Add to meal plan". Tomato-outlined tonal, demoted
     relative to the filled primary but still on the single accent. */
  .plan-peek__action--tonal {
    border: 1.5px solid var(--md-primary);
    background: var(--md-surface);
    color: var(--md-primary);
  }
  .plan-peek__action--tonal:hover {
    background: var(--md-primary-container);
  }

  /* ---------------------------------- "Add to meal plan" day-picker
     The peek's day-picker body-view (decision D10). A list of the
     upcoming two weeks, each a tappable row. Pattern-matches the edit
     view's move-to-another-day picker rows. */
  .plan-peek-days__intro {
    padding: var(--space-4) var(--space-6) var(--space-2);
  }
  .plan-peek-days__lead {
    margin: 0;
    font-size: var(--text-sm);
    color: var(--md-on-surface-variant);
  }
  .plan-peek-days__lead strong {
    color: var(--md-on-surface);
    font-weight: 600;
  }
  .plan-peek-days__list {
    padding: var(--space-2) var(--space-6) var(--space-6);
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
  }
  .plan-peek-days__item {
    margin: 0;
  }
  .plan-peek-days__btn {
    appearance: none;
    border: 1px solid var(--md-border-muted);
    cursor: pointer;
    background: var(--md-surface);
    width: 100%;
    min-height: 52px;
    padding: var(--space-3) var(--space-4);
    border-radius: var(--radius-md);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    text-align: left;
    transition: background 120ms ease, border-color 120ms ease;
  }
  .plan-peek-days__btn:hover {
    background: var(--md-surface-container);
    border-color: var(--md-primary);
  }
  .plan-peek-days__day {
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--md-on-surface);
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
  }
  .plan-peek-days__rel {
    font-size: var(--text-xs);
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--md-primary);
  }
  .plan-peek-days__count {
    font-size: var(--text-xs);
    color: var(--md-on-surface-variant);
    flex: 0 0 auto;
  }

  /* A recipe tap on the editable plan is a peek trigger, not a
     navigation link — the meal card / day row / sheet entry become
     buttons. Reset the button chrome so they render exactly like the
     anchor variants they replace. The card/row/link base rules each
     set display:flex and live inside a flex column or grid, so the
     button stretches to full width without an explicit width (which
     would fight .plan-day__entry's negative bleed margins). */
  .plan-meal-card--peek,
  .plan-day__entry--peek,
  .plan-sheet__entry-link--peek {
    appearance: none;
    border: 0;
    background: transparent;
    font: inherit;
    text-align: left;
    cursor: pointer;
  }

  /* =================================================================
     PR2 (#171 meal-planning-polish) — cooked-state.

     A per-entry retrospective marker. Each entry on a today-or-past
     day carries a cook toggle; a cooked entry de-emphasizes. Two
     pieces, both on-token:

       1. The toggle (.plan-cook-toggle / .plan-cook-mark) — a hollow
          neutral ring when un-cooked, a filled tomato circle + white
          check when cooked. The filled-accent / on-accent pairing
          reads as accomplished. Ported from the converged proto's
          .cook-toggle / .cook-mark.
       2. The de-emphasis (.*--cooked) — the entry's media steps down
          to 0.7 opacity and its title to the muted on-surface-variant
          colour. Decision D-AC3: this is a DE-EMPHASIS — no
          line-through, no disabled greying, no pointer-events removal;
          the entry stays fully interactive and reads as "done", not
          "deleted".
     ================================================================= */

  /* The toggle — a real <button>, a sibling of the activatable entry
     region (never nested inside it). */
  .plan-cook-toggle {
    appearance: none;
    border: 0;
    background: transparent;
    cursor: pointer;
    flex: 0 0 auto;
    width: var(--space-7);
    height: var(--space-7);
    padding: 0;
    border-radius: var(--radius-pill);
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--md-on-surface-variant);
    transition: background 120ms ease;
  }
  .plan-cook-toggle:hover {
    background: var(--md-surface-container-high);
  }
  .plan-cook-toggle:focus-visible {
    outline: none;
    box-shadow: var(--focus-ring);
  }
  /* Not cooked: a hollow hairline ring, the check hidden. */
  .plan-cook-mark {
    width: 18px;
    height: 18px;
    border-radius: var(--radius-pill);
    border: 1.5px solid var(--md-border);
    display: flex;
    align-items: center;
    justify-content: center;
    transition: background 160ms ease, border-color 160ms ease;
  }
  .plan-cook-mark .icon {
    width: 12px;
    height: 12px;
    color: var(--md-on-primary);
    opacity: 0;
    transition: opacity 160ms ease;
  }
  /* Cooked: a filled tomato circle, the white check shown. */
  .plan-cook-toggle--cooked .plan-cook-mark {
    background: var(--md-primary);
    border-color: var(--md-primary);
  }
  .plan-cook-toggle--cooked .plan-cook-mark .icon {
    opacity: 1;
  }

  /* ----- Hero meal card: the toggle overlays the media top-right.
     .plan-meal-card-wrap is the grid item; the card fills it and the
     toggle floats over the media corner. */
  .plan-meal-card-wrap {
    position: relative;
    display: flex;
    flex-direction: column;
    min-width: 0;
  }
  .plan-meal-card-wrap .plan-meal-card {
    flex: 1 1 auto;
  }
  .plan-meal-card-wrap .plan-cook-toggle {
    position: absolute;
    /* Inset into the MEDIA's top-right corner. The toggle is a sibling
       of the card (no button-in-button), so it is positioned from the
       wrap top -- which begins at the tag row, not the media. Clear
       that row first: .plan-meal-card__tag / __tag-spacer are 20px
       tall with a var(--space-3) margin-bottom; then var(--space-2)
       insets into the media corner. */
    top: calc(20px + var(--space-3) + var(--space-2));
    right: var(--space-2);
    background: var(--md-surface);
    box-shadow: var(--shadow-sm);
  }
  .plan-meal-card-wrap .plan-cook-toggle:hover {
    background: var(--md-surface-container-high);
  }
  /* Cooked hero card: media + title step down. */
  .plan-meal-card-wrap--cooked .plan-meal-card__media {
    opacity: 0.7;
  }
  .plan-meal-card-wrap--cooked .plan-meal-card__title {
    color: var(--md-on-surface-variant);
  }

  /* ----- Day-row entry: the toggle is a trailing sibling in the row.
     .plan-day__entry-wrap is the flex row; the entry takes the
     remaining width, the toggle sits at the end. */
  .plan-day__entry-wrap {
    display: flex;
    align-items: center;
    gap: var(--space-1);
  }
  .plan-day__entry-wrap .plan-day__entry {
    flex: 1 1 auto;
    min-width: 0;
  }
  /* Cooked day row: thumb + title step down. */
  .plan-day__entry-wrap--cooked .plan-day__thumb {
    opacity: 0.7;
  }
  .plan-day__entry-wrap--cooked .plan-day__entry-title {
    color: var(--md-on-surface-variant);
  }

  /* ----- Day-sheet entry: the toggle is the leading sibling.
     .plan-sheet__entry is already a flex row (toggle, entry-link,
     kebab). Cooked: thumb + title step down. */
  .plan-sheet__entry--cooked .plan-sheet__entry-thumb {
    opacity: 0.7;
  }
  .plan-sheet__entry--cooked .plan-sheet__entry-title {
    color: var(--md-on-surface-variant);
  }

  /* =================================================================
     PR5 — the Month view + the 5 days / Month toggle (#147). Ported
     from the converged prototype's .segmented control and .calendar-
     card / .cal-grid Month view. The prototype's lavender :root block
     is not carried over — production tokens supply the palette.
     ================================================================= */

  /* ---------------------------------------------- Page-head title block
     The title block consolidates the page title with the prev/next
     month nav (Month view only — the 5-day view renders just the
     title). Keeping nav here, not inside the calendar card, avoids a
     duplicated month-heading row. */
  .plan__head-title {
    display: flex;
    align-items: center;
    gap: var(--space-2);
  }

  /* Prev / next month nav — circular icon buttons flanking the month
     heading. 44px touch target. Month view only. */
  .plan__month-nav {
    width: 44px;
    height: 44px;
    flex: 0 0 auto;
    border-radius: var(--radius-pill);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--md-on-surface-variant);
    transition: background 140ms ease, color 140ms ease;
  }
  .plan__month-nav:hover {
    background: var(--md-surface-container);
    color: var(--md-on-surface);
  }
  .plan__month-nav .icon {
    width: 22px;
    height: 22px;
  }

  /* ------------------------------- History / 5 days / Month toggle
     A segmented control of three anchor links. The sliding tomato pill
     (::before) translates between positions via the data-active
     attribute. All three segments share equal width so the indicator
     stays aligned: the pill is one-third of the inner track and
     translates 0 / 100% / 200% of its own width to land on each stop
     (History · 5 days · Month, in DOM order — see
     partials/plan_view_toggle.html). Grew from two segments to three
     in #171 meal-planning-polish PR3. */
  .plan-toggle {
    position: relative;
    display: inline-flex;
    background: var(--md-surface-container);
    border-radius: var(--radius-pill);
    padding: var(--space-1);
  }
  .plan-toggle::before {
    content: '';
    position: absolute;
    top: 4px;
    bottom: 4px;
    left: 4px;
    width: calc((100% - var(--space-2)) / 3);
    background: var(--md-primary);
    border-radius: var(--radius-pill);
    transition: transform 350ms var(--motion-spring-default-effects);
    z-index: 0;
  }
  /* data-active="history" is the first segment — pill at translateX(0),
     the default left position, so no rule is needed. */
  .plan-toggle[data-active="five"]::before {
    transform: translateX(100%);
  }
  .plan-toggle[data-active="month"]::before {
    transform: translateX(200%);
  }
  .plan-toggle__seg {
    position: relative;
    z-index: 1;
    min-height: var(--control-h);
    min-width: 92px;
    padding: 0 var(--space-5);
    border-radius: var(--radius-pill);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--md-on-surface);
    font-family: var(--font-body);
    font-size: var(--text-sm);
    font-weight: 500;
    white-space: nowrap;
    transition: color 200ms var(--motion-spring-default-effects);
  }
  .plan-toggle__seg[aria-current="page"] {
    color: var(--md-on-primary);
  }

  /* ----------------------------------------------------- Calendar */
  .plan-cal {
    background: var(--md-surface-container-low);
    border: 1px solid var(--md-border-muted);
    border-radius: var(--radius-xl);
    padding: var(--space-3) var(--space-5) var(--space-4);
  }
  .plan-cal__weekdays {
    display: grid;
    grid-template-columns: repeat(7, minmax(0, 1fr));
    gap: var(--space-1);
    /* 2px is a sub-token micro-gap (allowlisted). */
    margin-bottom: 2px;
  }
  .plan-cal__weekdays span {
    text-align: center;
    font-size: var(--text-xs);
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--md-on-surface-variant);
    padding: var(--space-2) 0;
  }
  .plan-cal__grid {
    display: grid;
    /* minmax(0, 1fr) — not the implicit minmax(auto, 1fr) — so the 7
       columns shrink below their min-content width on a narrow phone
       rather than forcing horizontal overflow. */
    grid-template-columns: repeat(7, minmax(0, 1fr));
    gap: var(--space-1);
  }

  /* A calendar cell. A real day is a link (whole cell tappable);
     a filler cell (a day from an adjacent month) is an inert div. */
  .plan-cal__cell {
    aspect-ratio: 1.5 / 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    /* snapped 5px -> --space-1. */
    gap: var(--space-1);
    padding: var(--space-2) 0 var(--space-1);
    border-radius: var(--radius-md);
    color: inherit;
    transition:
      background 120ms ease,
      transform 200ms var(--motion-spring-default-effects);
  }
  a.plan-cal__cell:hover {
    background: var(--md-surface-container);
  }
  a.plan-cal__cell:active {
    transform: scale(0.97);
  }
  .plan-cal__cell--filler {
    pointer-events: none;
  }
  .plan-cal__num {
    font-size: var(--text-sm);
    color: var(--md-on-surface);
    line-height: 1;
  }
  /* Today: a filled lavender chip behind the day number. */
  .plan-cal__cell--today .plan-cal__num {
    background: var(--md-primary);
    color: var(--md-on-primary);
    width: 24px;
    height: 24px;
    border-radius: var(--radius-pill);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-weight: 600;
  }
  /* Count-based dot row. Every dot is the same lavender; the dot count
     (capped at 4) signals how many recipes are planned that day.
     --space-1 (4px) keeps the dots clearly separated even at 390px
     (carry-forward from the Stage 4a "Month-view dot spacing" critique). */
  .plan-cal__dots {
    display: flex;
    gap: var(--space-1);
    min-height: 5px;
  }
  .plan-cal__dot {
    width: 5px;
    height: 5px;
    border-radius: 50%;
    background: var(--md-primary);
    opacity: 0.85;
  }

  /* Month-view reflow. The calendar grid stays 7 columns at every
     width; below the 5-day view's breakpoints the cells just shrink.
     At phone widths the cell aspect ratio tightens so the grid is not
     excessively tall, and the calendar-card padding contracts. */
  @media (max-width: 560px) {
    .plan-cal__cell {
      aspect-ratio: 1.15 / 1;
    }
    .plan-cal {
      padding: var(--space-3) var(--space-3) var(--space-3);
    }
    /* 3px is a sub-token micro-gap (allowlisted) — the deliberate
       phone-width compression of the calendar grid's --space-1 gap. */
    .plan-cal__grid {
      gap: 3px;
    }
    .plan-cal__weekdays {
      gap: 3px;
    }
    .plan-cal__weekdays span {
      font-size: 10px;
      letter-spacing: 0.02em;
    }
  }
  @media (max-width: 480px) {
    /* The head stacks (5-day view rule already does this); the toggle
       and month-nav stay usable in the stacked layout. */
    .plan__head-title {
      justify-content: space-between;
    }
    .plan-toggle {
      flex: 1 1 auto;
    }
    .plan-toggle__seg {
      flex: 1 1 auto;
      min-width: 0;
      padding: 0 var(--space-3);
    }
  }

  /* =================================================================
     PR3 (#171 meal-planning-polish) — the history view.

     A reverse-chronological, month-grouped timeline of the user's
     strictly-past planned days. Ported from the converged Stage 4a
     proto (~/Developer/recipe-masonry/meal-plan-history-converged
     .html): a left-gutter rail spine the day nodes hang off, sticky
     month headers, cooked-day rail dots, empty days as a quiet dashed
     ring. Tomato is the single accent (D-AC1); every geometry literal
     resolves to the --space-* / --radius-* scale (hairline strokes and
     glyph-sized control measures are inline-justified, matching the
     proto's BLOCKER-2 fix).
     ================================================================= */

  /* ----- Timeline intro: a label + the summary line. */
  .plan-history__intro {
    display: flex;
    align-items: baseline;
    gap: var(--space-3);
    margin-bottom: var(--space-2);
  }
  .plan-history__intro-label {
    display: block;
    font-size: var(--text-xs);
    font-weight: 700;
    letter-spacing: 0.12em;
    color: var(--md-on-surface-variant);
    text-transform: uppercase;
  }
  .plan-history__intro-sub {
    font-size: var(--text-sm);
    color: var(--md-on-surface-variant);
  }

  /* ----- The timeline is a single reading column — a deliberate
     contrast with the full-width 5-day / Month grids (the ~720px
     measure was reviewed and kept at the converged-review touchpoint). */
  .plan-history__timeline {
    max-width: 720px;
  }

  /* Sticky month header. A soft gradient scrim — opaque at the top edge
     so the label stays legible, fading to transparent at the bottom so
     a row scrolling under is not hard-clipped. */
  .plan-history__month {
    position: sticky;
    top: 0;
    z-index: 5;
    padding: var(--space-4) 0 var(--space-2);
    display: flex;
    align-items: center;
    gap: var(--space-3);
    background: linear-gradient(
      to bottom,
      var(--md-surface-container-low) 0%,
      var(--md-surface-container-low) 58%,
      color-mix(in srgb, var(--md-surface-container-low) 55%, transparent) 88%,
      transparent 100%);
  }
  .plan-history__month-label {
    display: inline-flex;
    align-items: baseline;
    gap: var(--space-2);
    flex: 0 0 auto;
  }
  .plan-history__month-name {
    font-size: var(--text-xs);
    font-weight: 700;
    letter-spacing: 0.12em;
    color: var(--md-on-surface);
    text-transform: uppercase;
  }
  .plan-history__month-meta {
    font-size: var(--text-xs);
    color: var(--md-on-surface-variant);
  }
  /* A hairline trailing the label — a divider marking where the rail
     spine begins for this month. */
  .plan-history__month-rule {
    flex: 1 1 auto;
    height: 1px; /* hairline stroke, not a spacing step */
    background: var(--md-border-muted);
  }

  /* Each month's day nodes sit in a track carrying the rail spine.
     border-inline-start IS the rail; the inline-start margin opens the
     gutter the nodes + content live in. */
  .plan-history__track {
    border-inline-start: 1.5px solid var(--md-border); /* hairline spine */
    margin-inline-start: var(--space-6);
    position: relative;
  }
  /* A cap where the spine meets the month header. */
  .plan-history__track::before {
    content: '';
    position: absolute;
    left: 0;
    top: -1px;
    width: var(--space-2);
    height: var(--space-2);
    border-radius: var(--radius-pill);
    background: var(--md-border);
    transform: translateX(-50%);
  }

  /* A day node. position:relative anchors the dot onto the spine. */
  .plan-history__day {
    position: relative;
    padding: var(--space-4) 0 var(--space-4) var(--space-7);
  }
  /* The dot — absolutely positioned, straddling the spine. */
  .plan-history__dot {
    position: absolute;
    left: 0;
    top: var(--space-5);
    width: var(--space-3);
    height: var(--space-3);
    border-radius: var(--radius-pill);
    background: var(--md-surface-container-low);
    border: 1.5px solid var(--md-border-strong); /* hairline ring */
    transform: translateX(-50%);
    transition:
      background 200ms var(--motion-spring-default-effects),
      border-color 200ms var(--motion-spring-default-effects);
  }
  /* The dot goes tomato when ANY entry that day was cooked — the spine
     becomes a scannable cooked record. */
  .plan-history__day--cooked .plan-history__dot {
    background: var(--md-primary);
    border-color: var(--md-primary);
    box-shadow: 0 0 0 var(--space-1) var(--md-primary-container);
  }
  /* The empty-day node — a deliberate quiet gap: a small dashed hollow
     ring, not a dropped dot. */
  .plan-history__day--empty .plan-history__dot {
    width: var(--space-2);
    height: var(--space-2);
    background: var(--md-surface-container-low);
    border: 1.5px dashed var(--md-border);
    top: calc(var(--space-5) + 2px);
    box-shadow: none;
  }

  /* Day label row above the entries. */
  .plan-history__day-head {
    display: flex;
    align-items: baseline;
    gap: var(--space-3);
    margin-bottom: var(--space-2);
  }
  .plan-history__date {
    font-family: var(--font-heading);
    font-size: var(--text-base);
    font-weight: 600;
    letter-spacing: -0.01em;
    color: var(--md-on-surface);
  }
  .plan-history__day-count {
    margin-left: auto;
    font-size: var(--text-xs);
    color: var(--md-on-surface-variant);
  }
  .plan-history__day--empty .plan-history__date {
    color: var(--md-on-surface-variant);
  }

  /* Empty day — a single quiet italic line, no card. */
  .plan-history__empty-note {
    font-size: var(--text-xs);
    font-style: italic;
    color: var(--md-on-surface-variant);
  }

  /* The day's entries — a small read-oriented list right of the spine. */
  .plan-history__entries {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
  }

  /* Each entry row holds TWO siblings — the cooked toggle and the
     activatable peek control. No button nested inside a button. */
  .plan-history__entry-wrap {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-2);
    margin: 0 calc(-1 * var(--space-2));
    border-radius: var(--radius-md);
    transition: background 120ms ease;
  }
  .plan-history__entry-wrap:hover {
    background: var(--md-surface-container);
  }

  /* The read-only cooked mark — a static stand-in for the toggle when
     the entry is not cookable (non-Pro read-only plan, I-AC6). Same
     glyph-sized ring as the cooked toggle's .plan-cook-mark. */
  .plan-history__cook-mark {
    flex: 0 0 auto;
    width: 18px; /* glyph-sized control, matches .plan-cook-mark */
    height: 18px;
    border-radius: var(--radius-pill);
    border: 1.5px solid var(--md-border); /* hairline ring */
    display: flex;
    align-items: center;
    justify-content: center;
  }
  .plan-history__cook-mark .icon {
    width: 12px;
    height: 12px;
    color: var(--md-on-primary);
    opacity: 0;
  }
  .plan-history__cook-mark--cooked {
    background: var(--md-primary);
    border-color: var(--md-primary);
  }
  .plan-history__cook-mark--cooked .icon {
    opacity: 1;
  }

  /* The activatable region — opens the recipe peek. A real <button>. */
  .plan-history__entry {
    appearance: none;
    border: 0;
    background: transparent;
    cursor: pointer;
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: 0;
    border-radius: var(--radius-sm);
    color: inherit;
    text-align: left;
  }
  .plan-history__entry:focus-visible {
    outline: none;
    box-shadow: var(--focus-ring);
  }
  .plan-history__entry-thumb {
    width: var(--space-8);
    height: var(--space-8);
    flex: 0 0 auto;
    border-radius: var(--radius-sm);
    overflow: hidden;
    background: var(--md-surface-container-high);
    position: relative;
  }
  .plan-history__entry-thumb img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
  }
  .plan-history__entry-thumb-fallback {
    position: absolute;
    inset: 0;
  }
  .plan-history__entry-text {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    /* 1px is a sub-token micro-gap (allowlisted). */
    gap: 1px;
  }
  .plan-history__entry-top {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    min-width: 0;
  }
  .plan-history__entry-title {
    font-size: var(--text-sm);
    font-weight: 500;
    line-height: 1.3;
    color: var(--md-on-surface);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    /* Same first-glyph side-bearing clip fix the 5-day titles use. */
    padding-inline: 0.08em;
    margin-inline: -0.08em;
  }
  .plan-history__entry-source {
    font-size: var(--text-xs);
    color: var(--md-on-surface-variant);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  /* Meal-type tag chip — a neutral muted treatment (not an accent
     moment; tomato stays reserved for the cooked state). */
  .plan-history__entry-tag {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    background: var(--md-tag-neutral);
    color: var(--md-tag-neutral-foreground);
    /* 2px block padding is a sub-token micro-gap (allowlisted). */
    padding: 2px var(--space-2);
    border-radius: var(--radius-pill);
    font-size: var(--text-xs);
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
  }

  /* Cooked de-emphasis (decision D-AC1 / D-AC3): the entry's media +
     title step down one notch. A DE-EMPHASIS, never a deletion — no
     line-through, no disabled greying, the row stays interactive. */
  .plan-history__entry-wrap--cooked .plan-history__entry-thumb {
    opacity: 0.7;
  }
  .plan-history__entry-wrap--cooked .plan-history__entry-title {
    color: var(--md-on-surface-variant);
  }

  /* End-of-rail cap node + label. */
  .plan-history__end {
    position: relative;
    padding: var(--space-5) 0 var(--space-2) var(--space-7);
    margin-inline-start: var(--space-6);
  }
  .plan-history__end-cap {
    position: absolute;
    left: 0;
    top: 0;
    width: 9px; /* cap node, glyph-sized */
    height: 9px;
    border-radius: var(--radius-pill);
    background: var(--md-surface-container-high);
    border: 1.5px solid var(--md-border); /* hairline ring */
    transform: translateX(-50%);
  }
  .plan-history__end-label {
    font-size: var(--text-xs);
    color: var(--md-on-surface-variant);
    letter-spacing: 0.04em;
  }

  /* ----- History empty state — typographic, no imagery (design bible). */
  .plan-history__empty {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-3);
    max-width: 720px;
    padding: var(--space-8) 0;
  }
  .plan-history__empty-title {
    margin: 0;
    font-family: var(--font-heading);
    font-size: var(--text-xl);
    font-weight: 600;
    color: var(--md-on-surface);
  }
  .plan-history__empty-sub {
    margin: 0;
    font-size: var(--text-sm);
    color: var(--md-on-surface-variant);
  }

  /* ----- History reflow at phone widths. The timeline drops its
     reading-column cap and tightens the rail gutter so entry content
     keeps width at 390px. */
  @media (max-width: 768px) {
    .plan-history__timeline,
    .plan-history__empty {
      max-width: none;
    }
    .plan-history__track {
      margin-inline-start: var(--space-4);
    }
    .plan-history__day,
    .plan-history__end {
      padding-left: var(--space-5);
    }
    .plan-history__end {
      margin-inline-start: var(--space-4);
    }
  }
}
