---
phase: 20.1.1.1
plan: "02"
type: execute
wave: 1
depends_on: []
files_modified:
  - crates/app/ui/recipient-detail.slint
autonomous: true
requirements: [D-08, D-09, D-10]
gap_closure: true
must_haves:
  truths:
    - "The recipient-detail sidebar has no visible X close button."
    - "The sidebar header shows a colored pill (not a labeled field) directly under the recipient name."
    - "Clicking the pill enters inline-edit mode using the existing TextInput pattern."
    - "Discord username, Shopify email, and Shopify customer link are the first content block below the header + pill."
  artifacts:
    - path: "crates/app/ui/recipient-detail.slint"
      provides: "Sidebar with Purpose pill replacing labeled Purpose, no X close button, reordered field block"
      contains: "background: root.purpose-color"
  key_links:
    - from: "purpose-pill-touch TouchArea clicked"
      to: "root.editing-purpose = true"
      via: "inline-edit toggle"
      pattern: "editing-purpose = true"
    - from: "pill display Rectangle"
      to: "root.purpose-color"
      via: "background binding"
      pattern: "background: root.purpose-color"
---

<objective>
Three redesign fixes in the recipient-detail sidebar:
- (D-08) Remove the X close button and its TouchArea; dismissal is implicit via tab-switch or breadcrumb.
- (D-09) Replace the labeled "Purpose" field with a colored pill directly under the recipient name; pill background = root.purpose-color; click-to-inline-edit via the existing TextInput pattern.
- (D-10) Move Discord username, Shopify email, and Shopify customer link to the TOP of the sidebar content (immediately below header + pill, above Rx OD/OS/Copy Rx/GitHub link).

Purpose: Restore intended sidebar information hierarchy and reduce visual clutter. The X was redundant (tab-switch dismisses it); the labeled Purpose wastes space compared to a pill; and contact info belongs above prescription info.

Output: Updated recipient-detail.slint with the new header + pill + reordered content blocks.
</objective>

<execution_context>
@$HOME/.ccs/instances/bigscreen/get-shit-done/workflows/execute-plan.md
@$HOME/.ccs/instances/bigscreen/get-shit-done/templates/summary.md
</execution_context>

<context>
@.planning/STATE.md
@.planning/phases/20.1.1.1-phase-20-1-1-gap-closure-recipient-tab-sidebar-coexistence-n/20.1.1.1-CONTEXT.md
@.planning/phases/20.1.1.1-phase-20-1-1-gap-closure-recipient-tab-sidebar-coexistence-n/20.1.1.1-PATTERNS.md
@code_tips/SLINT_TIPS.md
@CLAUDE.md
@crates/app/ui/recipient-detail.slint
@crates/app/ui/tokens.slint
</context>

<tasks>

<task type="auto">
  <name>Task 1: Remove X close button (D-08)</name>
  <read_first>
    - crates/app/ui/recipient-detail.slint (lines 74-92 — close-button HorizontalLayout block)
    - crates/app/ui/recipient-detail.slint (line 47 — `callback close-clicked()` declaration)
    - crates/app/ui/recipient-detail.slint (lines 53-67 — FocusScope Esc handler that calls root.close-clicked())
    - .planning/phases/20.1.1.1-.../20.1.1.1-PATTERNS.md (D-08 section)
  </read_first>
  <action>
    In crates/app/ui/recipient-detail.slint:

    1) Delete the entire HorizontalLayout block at lines 74-92 that renders the X close button:
       ```
       HorizontalLayout {
           alignment: end;
           Rectangle {
               width: 20px; height: 20px;
               Text { text: "\u{2715}"; ... }
               close-touch := TouchArea { ... clicked => { root.close-clicked(); } }
           }
       }
       ```

    2) KEEP the `callback close-clicked()` declaration at line 47 — the FocusScope Esc handler (lines 53-67) still calls it for Esc-based dismissal, and dashboard.slint forwards it to `sidebar-close()`. Removing the callback would break the forwarding chain in dashboard.slint:663 and the main.rs `on_sidebar_close` handler. Leaving the callback in place is the safest change (Claude's Discretion per CONTEXT.md — pick the "stubbed" option; the Esc dismissal path still works even though tab-switch is the primary dismissal per D-08).

    3) Do NOT remove the FocusScope block or its Esc handler — two-level Esc (cancel-edit then dismiss) is a parent-phase contract (verified in 20.1.1-VERIFICATION.md #6).

    4) Do NOT change any data properties or other callbacks.
  </action>
  <acceptance_criteria>
    - Grep `crates/app/ui/recipient-detail.slint` for `\\u\{2715\}` — returns 0 matches (X glyph removed).
    - Grep `crates/app/ui/recipient-detail.slint` for `close-touch :=` — returns 0 matches (TouchArea removed).
    - Grep `crates/app/ui/recipient-detail.slint` for `callback close-clicked()` — still returns 1 match (declaration retained for Esc path).
    - Grep `crates/app/ui/recipient-detail.slint` for `key-pressed(event)` — still returns at least 1 match (FocusScope Esc handler preserved).
    - `cargo check --features bugsweeper` exits 0.
  </acceptance_criteria>
  <verify>
    <automated>cargo check --features bugsweeper 2>&1 | tail -5</automated>
  </verify>
  <done>X close button HorizontalLayout removed; close-clicked callback retained for Esc dismissal; cargo check passes.</done>
</task>

<task type="auto">
  <name>Task 2: Replace labeled Purpose field with colored pill (D-09)</name>
  <read_first>
    - crates/app/ui/recipient-detail.slint (lines 94-130 — avatar+name header block)
    - crates/app/ui/recipient-detail.slint (lines 132-194 — existing labeled Purpose VerticalLayout with editing branches)
    - crates/app/ui/recipient-detail.slint (lines 343-407 — Discord inline-edit as analog template)
    - .planning/phases/20.1.1.1-.../20.1.1.1-PATTERNS.md (D-09 section — exact pill structure)
    - code_tips/SLINT_TIPS.md (Rectangle-wrapper rule for TouchArea + parent.width — avoid binding loops)
  </read_first>
  <action>
    In crates/app/ui/recipient-detail.slint:

    Replace the labeled Purpose VerticalLayout (lines 132-194, starting with `Text { text: "Purpose"; ... }`) with a colored pill. The pill sits immediately below the header HorizontalLayout (the avatar+name block ending around line 130), above the first content block.

    Concrete pill values:
    - Display mode: filled Rectangle, `height: 24px`, `border-radius: 12px`, `background: root.purpose-color`, padding: inner text has horizontal padding of 10px (implicit via width), no border. Text inside: `font-size: Typography.size-xs`, `font-weight: 600`, `color: #ffffff`, horizontal-alignment: center, vertical-alignment: center.
    - Pill width: sized to content (use explicit `width: purpose-pill-text.preferred-width + 20px` with a minimum of 70px via ternary: `root.purpose-draft != "" ? purpose-pill-text.preferred-width + 20px : 70px`). Placed in a HorizontalLayout with `alignment: start` so the pill hugs the left side rather than stretching.
    - Empty-state text: if `root.purpose` is empty, show "Purpose" as placeholder text.
    - Edit mode: same pill Rectangle shape (`border-radius: 13px`, `height: 26px`, 1px accent border) containing a TextInput. Reuse the accepted+key-pressed pattern from the existing Purpose edit block (lines 165-193): accepted saves via `root.save-purpose(root.purpose-draft)` and exits edit mode; Escape cancels.

    Concrete Slint structure:

    ```slint
    HorizontalLayout {
        alignment: start;
        padding-left: 12px;
        padding-right: 12px;
        padding-top: 4px;
        padding-bottom: 8px;

        if !root.editing-purpose : Rectangle {
            height: 24px;
            width: root.purpose-draft != "" ? purpose-pill-text.preferred-width + 20px : 70px;
            border-radius: 12px;
            background: root.purpose-color;

            purpose-pill-touch := TouchArea {
                mouse-cursor: pointer;
                clicked => {
                    root.purpose-draft = root.purpose;
                    root.editing-purpose = true;
                }
            }

            purpose-pill-text := Text {
                text: root.purpose != "" ? root.purpose : "Purpose";
                font-size: Typography.size-xs;
                font-weight: 600;
                color: #ffffff;
                horizontal-alignment: center;
                vertical-alignment: center;
                width: parent.width;
                height: parent.height;
            }
        }

        if root.editing-purpose : Rectangle {
            height: 26px;
            width: 180px;                       // fixed edit-mode width for consistent TextInput space
            border-radius: 13px;
            background: root.purpose-color;
            border-width: 1px;
            border-color: Colors.accent;

            purpose-pill-input := TextInput {
                x: 10px;
                y: 4px;
                width: parent.width - 20px;
                height: 18px;
                text <=> root.purpose-draft;
                font-size: Typography.size-xs;
                color: #ffffff;
                single-line: true;
                accepted => {
                    root.editing-purpose = false;
                    if (root.purpose-draft != root.purpose) {
                        root.save-purpose(root.purpose-draft);
                    }
                    sidebar-focus.focus();
                }
                key-pressed(event) => {
                    if (event.text == Key.Escape) {
                        root.editing-purpose = false;
                        root.purpose-draft = root.purpose;
                        sidebar-focus.focus();
                        return accept;
                    }
                    return reject;
                }
            }
        }
    }
    ```

    Notes:
    - `root.purpose-color` is already an `in property <brush>` on RecipientDetailPanel — no new property.
    - `root.purpose`, `root.purpose-draft`, `root.editing-purpose`, and `root.save-purpose(...)` already exist — reuse unchanged.
    - Do NOT delete the `editing-purpose`, `purpose-draft`, `save-purpose` declarations — they are still in use.
    - Do NOT wrap TouchArea in HorizontalLayout — use Rectangle wrapper (SLINT_TIPS and Phase 20.1.1 D-16.1-03 finding: TouchArea inside HorizontalLayout can cause binding loops with parent.width).
    - `#ffffff` literal is acceptable here — tokens.slint does not expose `text-on-accent` (parent phase documented this at STATE.md "Colors.text-on-accent absent from tokens.slint"). Add a `// #ffffff substitutes for Colors.text-on-accent (absent from tokens.slint)` comment above the first use.
  </action>
  <acceptance_criteria>
    - Grep `crates/app/ui/recipient-detail.slint` for `Text { text: "Purpose"` — returns 0 matches (labeled field gone).
    - Grep `crates/app/ui/recipient-detail.slint` for `purpose-pill-touch :=` — returns exactly 1 match.
    - Grep `crates/app/ui/recipient-detail.slint` for `purpose-pill-input :=` — returns exactly 1 match.
    - Grep `crates/app/ui/recipient-detail.slint` for `background: root.purpose-color` — returns at least 2 matches (display + edit pill rectangles; avatar ring may also match).
    - Grep `crates/app/ui/recipient-detail.slint` for `border-radius: 12px` — returns at least 1 match for the display pill.
    - Grep `crates/app/ui/recipient-detail.slint` for `root.save-purpose` — still returns at least 1 match (callback retained).
    - Grep `crates/app/ui/recipient-detail.slint` for `editing-purpose` — still returns at least 2 matches (draft + branches).
    - `cargo check --features bugsweeper` exits 0.
  </acceptance_criteria>
  <verify>
    <automated>cargo check --features bugsweeper 2>&1 | tail -5</automated>
  </verify>
  <done>Purpose renders as a colored pill (24px tall, 12px radius) beneath the header, clickable to enter TextInput edit mode in the same pill shape; build passes.</done>
</task>

<task type="auto">
  <name>Task 3: Reorder sidebar fields — Discord, Shopify email, Shopify customer TOP (D-10)</name>
  <read_first>
    - crates/app/ui/recipient-detail.slint (full file, especially blocks for Rx OD lines 196-258, Rx OS lines 260-322, Copy Rx lines 324-341, Discord lines 343-407, Shopify email lines 409-418, Shopify customer link lines 420-443, ww-recipient link lines 445-463)
    - .planning/phases/20.1.1.1-.../20.1.1.1-PATTERNS.md (D-10 section — exact target order)
    - .planning/phases/20.1.1.1-.../20.1.1.1-CONTEXT.md (D-10: Discord → Shopify email → Shopify customer; directly under header + pill)
  </read_first>
  <action>
    In crates/app/ui/recipient-detail.slint, inside the main content VerticalLayout (the one containing all sections below the header + Purpose pill from Task 2):

    Reorder blocks to this exact sequence:

    1. Header: avatar + name HorizontalLayout (unchanged — above this section)
    2. Purpose pill (from Task 2 — unchanged)
    3. **Discord username block** (current lines ~343-407) — move to TOP of content
    4. **Shopify email block** (current lines ~409-418) — move to TOP of content
    5. **Shopify customer link block** (current lines ~420-443) — move to TOP of content
    6. Rx OD block (current lines ~196-258)
    7. Rx OS block (current lines ~260-322)
    8. Copy Rx button (current lines ~324-341)
    9. GitHub / ww-recipient link block (current lines ~445-463)

    This is a pure cut-and-paste reorder. Do NOT modify the internals of any block — keep all TouchAreas, TextInputs, callbacks, properties, labels, conditional guards (e.g. `if root.recipient-issue-url != ""`) exactly as they are.

    After reorder, verify the outer VerticalLayout's `spacing` and `padding` still produce sensible visual rhythm; if the old implicit visual ordering had label texts like "Discord" / "Email" / "Shopify customer", those labels stay with their blocks (they are inside the blocks being moved, not standalone siblings).
  </action>
  <acceptance_criteria>
    - Read the file; between the header + pill and the Rx OD block, the order of sibling VerticalLayout / Rectangle blocks MUST be: Discord block → Shopify email block → Shopify customer link block.
    - Grep `crates/app/ui/recipient-detail.slint` for `Text { text: "Rx OD"` OR the analogous label — still present (block itself unchanged).
    - Grep `crates/app/ui/recipient-detail.slint` for `save-discord-username` — still returns at least 1 match (Discord block's callback preserved after move).
    - Grep `crates/app/ui/recipient-detail.slint` for `recipient-issue-url != ""` — still returns 1 match (conditional guard preserved).
    - Line-number audit: `grep -n "save-discord-username\|Rx OD\|save-rx-od" crates/app/ui/recipient-detail.slint` — the Discord callback line number MUST be less than the Rx OD label line number (structural proof of reorder).
    - `cargo check --features bugsweeper` exits 0.
  </acceptance_criteria>
  <verify>
    <automated>cargo check --features bugsweeper 2>&1 | tail -5 && grep -n "save-discord-username\|save-rx-od" crates/app/ui/recipient-detail.slint | head -5</automated>
  </verify>
  <done>Discord → Shopify email → Shopify customer blocks appear before Rx OD; internals of each block unchanged; cargo check passes.</done>
</task>

</tasks>

<verification>
- cargo check --features bugsweeper exits 0
- Visual verification (pill color, field order, no X button) deferred to Plan 06 via BUGSWEEPER + screen-timelapse.
</verification>

<success_criteria>
- Sidebar has no X close button.
- Purpose is a colored pill that matches the recipient's ring color.
- Discord/Shopify fields appear above Rx fields.
- Esc dismissal path still compiles (close-clicked callback retained).
</success_criteria>

<output>
After completion, create `.planning/phases/20.1.1.1-phase-20-1-1-gap-closure-recipient-tab-sidebar-coexistence-n/20.1.1.1-02-SUMMARY.md`
</output>
