[object Object]

← back to Dw Launches

Design refinement: DW luxury editorial theme for social composer

b3d1a74bdf16b466094fa08ffd86ab829783225a · 2026-06-19 10:26:17 -0700 · Steve

- Wordmark: serif 22px with restrained tracking, gold dot, eyebrow label above
- Palette: eliminated neon green accent; all interactive states now use muted gold/gold-dim
- Channel chips: replaced full candy-fill avatar circles with 8px brand-color dots + subtle pill styling
- Section headers: replaced ALL-CAPS bureaucratic h3 gold labels with serif .sl-title + numeric step badge
- Topbar nav: lighter weight, bottom-border active indicator vs old box border
- Buttons: differentiated hierarchy — ghost (Save), gold-border (Submit), italic (Steve sign-off), solid gold (Publish), suppressed-panel (Publish/disabled)
- Preview panel: device-chrome wrapper with shadow; preview card uses clean white with DW-warm bg tone
- Spacing: consistent scale (--sp-* tokens), tighter card gap 14px, wrap padding 28px
- Preview column: position:sticky so it follows scroll
- Media items: remove button appears on hover only (cleaner resting state)
- Inputs/selects: gold focus ring, custom select arrow, uniform border-radius
- Badges: bordered style with status-tinted backgrounds replacing plain filled pills
- Toast: entrance animation, box-shadow elevation
- All JS IDs/classes, fetch calls, and behavioral logic unchanged

Files touched

Diff

commit b3d1a74bdf16b466094fa08ffd86ab829783225a
Author: Steve <steve@designerwallcoverings.com>
Date:   Fri Jun 19 10:26:17 2026 -0700

    Design refinement: DW luxury editorial theme for social composer
    
    - Wordmark: serif 22px with restrained tracking, gold dot, eyebrow label above
    - Palette: eliminated neon green accent; all interactive states now use muted gold/gold-dim
    - Channel chips: replaced full candy-fill avatar circles with 8px brand-color dots + subtle pill styling
    - Section headers: replaced ALL-CAPS bureaucratic h3 gold labels with serif .sl-title + numeric step badge
    - Topbar nav: lighter weight, bottom-border active indicator vs old box border
    - Buttons: differentiated hierarchy — ghost (Save), gold-border (Submit), italic (Steve sign-off), solid gold (Publish), suppressed-panel (Publish/disabled)
    - Preview panel: device-chrome wrapper with shadow; preview card uses clean white with DW-warm bg tone
    - Spacing: consistent scale (--sp-* tokens), tighter card gap 14px, wrap padding 28px
    - Preview column: position:sticky so it follows scroll
    - Media items: remove button appears on hover only (cleaner resting state)
    - Inputs/selects: gold focus ring, custom select arrow, uniform border-radius
    - Badges: bordered style with status-tinted backgrounds replacing plain filled pills
    - Toast: entrance animation, box-shadow elevation
    - All JS IDs/classes, fetch calls, and behavioral logic unchanged
---
 public/index.html | 803 ++++++++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 687 insertions(+), 116 deletions(-)

diff --git a/public/index.html b/public/index.html
index a232f61..48d15b6 100644
--- a/public/index.html
+++ b/public/index.html
@@ -5,95 +5,640 @@
 <meta name="viewport" content="width=device-width, initial-scale=1">
 <title>DW Launches — Social Composer</title>
 <style>
+  /* ─── Design tokens ─────────────────────────────────────────── */
   :root{
-    --bg:#0e0f12; --panel:#16181d; --panel2:#1d2027; --line:#2a2e37;
-    --ink:#e9e7e1; --muted:#9aa0ab; --gold:#c8a96a; --accent:#34f480;
-    --danger:#e0606e; --warn:#e0b35a; --radius:12px;
+    /* surfaces */
+    --bg:#0a0b0d;
+    --panel:#111318;
+    --panel2:#181b22;
+    --panel3:#1e222b;
+    --line:#252932;
+    --line-soft:#1e2129;
+
+    /* ink */
+    --ink:#e8e4dc;
+    --ink-2:#b0aaa0;
+    --muted:#6e7480;
+
+    /* brand palette */
+    --gold:#c2a064;
+    --gold-dim:#8a6e3e;
+    --gold-faint:rgba(194,160,100,.08);
+    --gold-faint2:rgba(194,160,100,.14);
+
+    /* status */
+    --danger:#c0505e;
+    --danger-faint:rgba(192,80,94,.12);
+    --warn:#b8923a;
+    --warn-faint:rgba(184,146,58,.12);
+    --ok:#3a8a60;
+    --ok-faint:rgba(58,138,96,.12);
+    --info:#3a6aa0;
+    --info-faint:rgba(58,106,160,.12);
+
+    /* interaction */
+    --focus:rgba(194,160,100,.35);
+
+    --radius:10px;
+    --radius-sm:6px;
+    --radius-lg:14px;
+
     --font:"Helvetica Neue",Helvetica,Arial,sans-serif;
     --serif:"Georgia","Times New Roman",serif;
+
+    /* spacing scale */
+    --sp-1:4px; --sp-2:8px; --sp-3:12px; --sp-4:16px; --sp-5:20px;
+    --sp-6:24px; --sp-7:28px; --sp-8:32px;
+  }
+
+  /* ─── Reset ─────────────────────────────────────────────────── */
+  *{box-sizing:border-box;margin:0;padding:0}
+  body{
+    background:var(--bg);
+    color:var(--ink);
+    font-family:var(--font);
+    font-size:13.5px;
+    line-height:1.5;
+    -webkit-font-smoothing:antialiased;
+  }
+
+  /* ─── Topbar ─────────────────────────────────────────────────── */
+  header.topbar{
+    display:flex;
+    align-items:center;
+    justify-content:space-between;
+    padding:0 28px;
+    height:56px;
+    border-bottom:1px solid var(--line);
+    background:var(--panel);
+    position:sticky;
+    top:0;
+    z-index:20;
+  }
+
+  /* Wordmark */
+  .brand{
+    display:flex;
+    flex-direction:column;
+    gap:0;
+    line-height:1;
+  }
+  .brand-eyebrow{
+    font-family:var(--font);
+    font-size:9.5px;
+    letter-spacing:3px;
+    text-transform:uppercase;
+    color:var(--muted);
+    margin-bottom:3px;
+  }
+  .brand-name{
+    font-family:var(--serif);
+    font-size:22px;
+    font-weight:400;
+    letter-spacing:.8px;
+    color:var(--ink);
+    line-height:1;
+  }
+  .brand-name .dot{color:var(--gold)}
+
+  /* Topbar nav */
+  nav.tabs{display:flex;gap:2px}
+  nav.tabs button{
+    background:transparent;
+    border:none;
+    color:var(--muted);
+    padding:8px 16px;
+    border-radius:var(--radius-sm);
+    cursor:pointer;
+    font-size:12.5px;
+    font-family:var(--font);
+    letter-spacing:.3px;
+    transition:color .15s, background .15s;
+  }
+  nav.tabs button:hover{color:var(--ink-2);background:var(--panel2)}
+  nav.tabs button.active{
+    color:var(--ink);
+    background:var(--panel2);
+    box-shadow:inset 0 -2px 0 var(--gold);
+  }
+
+  /* ─── Layout ─────────────────────────────────────────────────── */
+  .wrap{
+    display:flex;
+    gap:20px;
+    padding:20px 28px;
+    max-width:1520px;
+    margin:0 auto;
   }
-  *{box-sizing:border-box}
-  body{margin:0;background:var(--bg);color:var(--ink);font-family:var(--font);font-size:14px}
-  header.topbar{display:flex;align-items:center;justify-content:space-between;padding:14px 22px;border-bottom:1px solid var(--line);background:var(--panel)}
-  .brand{font-family:var(--serif);font-size:20px;letter-spacing:.5px}
-  .brand .dot{color:var(--gold)}
-  .brand small{display:block;font-family:var(--font);font-size:11px;color:var(--muted);letter-spacing:2px;text-transform:uppercase}
-  nav.tabs{display:flex;gap:4px}
-  nav.tabs button{background:transparent;border:1px solid var(--line);color:var(--muted);padding:7px 16px;border-radius:8px;cursor:pointer;font-size:13px}
-  nav.tabs button.active{background:var(--panel2);color:var(--ink);border-color:var(--gold)}
-  .wrap{display:flex;gap:18px;padding:18px 22px;max-width:1500px;margin:0 auto}
   .col{flex:1;min-width:0}
-  .card{background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);padding:16px;margin-bottom:16px}
-  .card h3{margin:0 0 12px;font-size:12px;letter-spacing:1.5px;text-transform:uppercase;color:var(--gold)}
-  /* 1. channel rail */
-  .chanrail{display:flex;gap:10px;flex-wrap:wrap}
-  .chip{display:flex;align-items:center;gap:8px;padding:8px 12px;border:1px solid var(--line);border-radius:999px;cursor:pointer;user-select:none;background:var(--panel2)}
-  .chip .av{width:26px;height:26px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-weight:700;font-size:12px;color:#0e0f12}
-  .chip.sel{border-color:var(--accent);box-shadow:0 0 0 1px var(--accent) inset}
-  .chip.disabled{opacity:.42;cursor:not-allowed}
-  .chip .connect{font-size:10px;color:var(--warn);border:1px dashed var(--warn);border-radius:6px;padding:1px 5px}
-  textarea,input[type=text],input[type=datetime-local],select{width:100%;background:var(--panel2);border:1px solid var(--line);color:var(--ink);border-radius:8px;padding:10px;font-family:inherit;font-size:13px}
-  textarea{min-height:130px;resize:vertical;line-height:1.5}
-  label{display:block;font-size:11px;color:var(--muted);margin:10px 0 4px;letter-spacing:.5px}
-  .row{display:flex;gap:10px}.row>*{flex:1}
-  button.btn{background:var(--gold);color:#1a1408;border:none;border-radius:8px;padding:10px 16px;font-weight:600;cursor:pointer;font-size:13px}
-  button.ghost{background:transparent;border:1px solid var(--line);color:var(--ink)}
-  button.danger{background:var(--danger);color:#fff}
-  button:disabled{opacity:.4;cursor:not-allowed}
-  /* per-channel tabs */
-  .ctabs{display:flex;gap:4px;flex-wrap:wrap;margin-bottom:12px}
-  .ctabs button{padding:6px 12px;font-size:12px;border-radius:7px;border:1px solid var(--line);background:var(--panel2);color:var(--muted);cursor:pointer}
-  .ctabs button.active{color:var(--ink);border-color:var(--accent)}
-  /* media */
-  .media-drop{border:1.5px dashed var(--line);border-radius:10px;padding:16px;text-align:center;color:var(--muted);cursor:pointer}
-  .media-drop.over{border-color:var(--accent);color:var(--ink)}
+
+  /* ─── Cards ─────────────────────────────────────────────────── */
+  .card{
+    background:var(--panel);
+    border:1px solid var(--line);
+    border-radius:var(--radius-lg);
+    padding:20px;
+    margin-bottom:14px;
+  }
+
+  /* Section label — editorial, not bureaucratic */
+  .section-label{
+    display:flex;
+    align-items:baseline;
+    gap:10px;
+    margin-bottom:16px;
+    padding-bottom:12px;
+    border-bottom:1px solid var(--line-soft);
+  }
+  .section-label .sl-step{
+    font-family:var(--font);
+    font-size:10px;
+    font-weight:600;
+    letter-spacing:1.5px;
+    text-transform:uppercase;
+    color:var(--gold-dim);
+    min-width:16px;
+  }
+  .section-label .sl-title{
+    font-family:var(--serif);
+    font-size:14px;
+    font-weight:400;
+    letter-spacing:.3px;
+    color:var(--ink);
+  }
+  /* Legacy h3 inside .card — keep for any missed cards */
+  .card h3{
+    font-family:var(--font);
+    font-size:10px;
+    letter-spacing:1.5px;
+    text-transform:uppercase;
+    color:var(--gold-dim);
+    margin:0 0 14px;
+    font-weight:600;
+  }
+
+  /* ─── Channel rail ───────────────────────────────────────────── */
+  .chanrail{display:flex;gap:8px;flex-wrap:wrap}
+  .chip{
+    display:flex;
+    align-items:center;
+    gap:8px;
+    padding:7px 13px 7px 9px;
+    border:1px solid var(--line);
+    border-radius:999px;
+    cursor:pointer;
+    user-select:none;
+    background:var(--panel2);
+    color:var(--ink-2);
+    font-size:12.5px;
+    transition:border-color .15s, color .15s, background .15s;
+  }
+  .chip:hover:not(.disabled){
+    border-color:var(--gold-dim);
+    color:var(--ink);
+    background:var(--panel3);
+  }
+  /* Brand-color dot replaces full candy avatar */
+  .chip .av{
+    width:8px;
+    height:8px;
+    border-radius:50%;
+    flex-shrink:0;
+  }
+  .chip.sel{
+    border-color:var(--gold);
+    color:var(--ink);
+    background:var(--gold-faint2);
+  }
+  .chip.sel .av{
+    /* Slightly brightened dot on selected */
+    box-shadow:0 0 0 2px rgba(0,0,0,.4);
+  }
+  .chip.disabled{opacity:.35;cursor:not-allowed}
+  .chip .connect{
+    font-size:9.5px;
+    color:var(--warn);
+    border:1px solid var(--warn-faint);
+    border-radius:4px;
+    padding:1px 5px;
+    background:var(--warn-faint);
+  }
+
+  /* ─── Form elements ──────────────────────────────────────────── */
+  textarea,
+  input[type=text],
+  input[type=datetime-local],
+  select{
+    width:100%;
+    background:var(--panel2);
+    border:1px solid var(--line);
+    color:var(--ink);
+    border-radius:var(--radius-sm);
+    padding:9px 11px;
+    font-family:inherit;
+    font-size:13px;
+    line-height:1.5;
+    transition:border-color .15s, box-shadow .15s;
+    -webkit-appearance:none;
+    appearance:none;
+  }
+  textarea:focus,
+  input[type=text]:focus,
+  input[type=datetime-local]:focus,
+  select:focus{
+    outline:none;
+    border-color:var(--gold-dim);
+    box-shadow:0 0 0 3px var(--focus);
+  }
+  textarea{min-height:128px;resize:vertical;line-height:1.6}
+  select{cursor:pointer;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%236e7480'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 10px center;padding-right:28px}
+
+  label{
+    display:block;
+    font-size:11px;
+    color:var(--muted);
+    margin:12px 0 4px;
+    letter-spacing:.4px;
+    text-transform:uppercase;
+  }
+  label:first-child{margin-top:0}
+
+  .row{display:flex;gap:10px}
+  .row>*{flex:1}
+
+  /* ─── Buttons ────────────────────────────────────────────────── */
+  button.btn{
+    border:none;
+    border-radius:var(--radius-sm);
+    padding:9px 18px;
+    font-weight:500;
+    cursor:pointer;
+    font-size:13px;
+    font-family:inherit;
+    letter-spacing:.2px;
+    transition:opacity .15s, background .15s, box-shadow .15s;
+  }
+  /* Primary — gold CTA (Save draft) */
+  button.btn:not(.ghost):not(.danger):not(.btn-submit):not(.btn-approve):not(.btn-publish){
+    background:var(--gold-faint2);
+    color:var(--gold);
+    border:1px solid var(--gold-dim);
+  }
+  button.btn:not(.ghost):not(.danger):not(.btn-submit):not(.btn-approve):not(.btn-publish):hover{
+    background:rgba(194,160,100,.22);
+  }
+  /* Ghost */
+  button.ghost{
+    background:transparent;
+    border:1px solid var(--line);
+    color:var(--ink-2);
+  }
+  button.ghost:hover{border-color:var(--ink-2);color:var(--ink)}
+
+  /* Submit for approval */
+  button.btn-submit{
+    background:var(--panel2);
+    border:1px solid var(--gold-dim);
+    color:var(--gold);
+  }
+  button.btn-submit:hover{background:var(--gold-faint2)}
+
+  /* Steve sign-off */
+  button.btn-approve{
+    background:var(--panel2);
+    border:1px solid var(--line);
+    color:var(--ink-2);
+    font-style:italic;
+  }
+  button.btn-approve:hover{border-color:var(--gold-dim);color:var(--ink)}
+
+  /* Publish — solid gold when enabled, visually suppressed when gated */
+  button.btn-publish{
+    background:var(--gold);
+    color:#0d0b06;
+    font-weight:600;
+    letter-spacing:.3px;
+  }
+  button.btn-publish:hover:not(:disabled){
+    background:#d4b070;
+    box-shadow:0 2px 12px rgba(194,160,100,.25);
+  }
+  button.btn-publish:disabled{
+    background:var(--panel3);
+    border:1px solid var(--line);
+    color:var(--muted);
+    cursor:not-allowed;
+    font-weight:400;
+    letter-spacing:0;
+  }
+
+  button.danger{background:var(--danger);color:#fff;border:none}
+  button.danger:hover{opacity:.88}
+  button:disabled{cursor:not-allowed}
+
+  /* ─── Per-channel tabs ───────────────────────────────────────── */
+  .ctabs{
+    display:flex;
+    gap:3px;
+    flex-wrap:wrap;
+    margin-bottom:14px;
+    padding-bottom:12px;
+    border-bottom:1px solid var(--line-soft);
+  }
+  .ctabs button{
+    padding:5px 12px;
+    font-size:12px;
+    border-radius:var(--radius-sm);
+    border:1px solid transparent;
+    background:transparent;
+    color:var(--muted);
+    cursor:pointer;
+    font-family:inherit;
+    transition:color .15s, background .15s, border-color .15s;
+  }
+  .ctabs button:hover{color:var(--ink-2);background:var(--panel2)}
+  .ctabs button.active{
+    color:var(--ink);
+    background:var(--panel2);
+    border-color:var(--line);
+    box-shadow:inset 0 -2px 0 var(--gold);
+  }
+
+  /* ─── Media ──────────────────────────────────────────────────── */
+  .media-drop{
+    border:1px dashed var(--line);
+    border-radius:var(--radius);
+    padding:18px 14px;
+    text-align:center;
+    color:var(--muted);
+    font-size:12px;
+    cursor:pointer;
+    transition:border-color .15s, color .15s, background .15s;
+    margin-top:4px;
+  }
+  .media-drop:hover{border-color:var(--gold-dim);color:var(--ink-2);background:var(--gold-faint)}
+  .media-drop.over{border-color:var(--gold);color:var(--ink);background:var(--gold-faint2)}
   .media-list{display:flex;gap:8px;flex-wrap:wrap;margin-top:10px}
-  .media-item{position:relative;width:74px;height:74px;border-radius:8px;background:var(--panel2);border:1px solid var(--line);display:flex;align-items:center;justify-content:center;font-size:10px;color:var(--muted);overflow:hidden;text-align:center;padding:4px}
-  .media-item img{width:100%;height:100%;object-fit:cover}
-  .media-item .x{position:absolute;top:2px;right:3px;cursor:pointer;color:var(--danger);font-weight:700}
-  .media-item .tag{position:absolute;bottom:2px;left:3px;font-size:8px;background:#000a;padding:0 3px;border-radius:3px}
-  .counter{font-size:11px;color:var(--muted);text-align:right}
-  .counter.over{color:var(--danger);font-weight:700}
-  /* preview */
-  .pv{background:#fff;color:#111;border-radius:12px;overflow:hidden;border:1px solid var(--line)}
-  .pv .pvhead{display:flex;align-items:center;gap:8px;padding:10px 12px}
-  .pv .pvav{width:32px;height:32px;border-radius:50%;background:var(--gold)}
-  .pv .pvname{font-weight:700;font-size:13px}
-  .pv .pvsub{font-size:11px;color:#777}
-  .pv .pvbody{padding:0 12px 10px;font-size:13px;line-height:1.45;white-space:pre-wrap}
-  .pv .pvimg{width:100%;background:#e6e2da;display:flex;align-items:center;justify-content:center;color:#999;font-size:11px}
+  .media-item{
+    position:relative;
+    width:76px;
+    height:76px;
+    border-radius:var(--radius-sm);
+    background:var(--panel2);
+    border:1px solid var(--line);
+    display:flex;
+    align-items:center;
+    justify-content:center;
+    font-size:9.5px;
+    color:var(--muted);
+    overflow:hidden;
+    text-align:center;
+    padding:4px;
+    transition:border-color .15s;
+  }
+  .media-item:hover{border-color:var(--gold-dim)}
+  .media-item img{width:100%;height:100%;object-fit:cover;border-radius:3px}
+  .media-item .x{
+    position:absolute;
+    top:3px;right:4px;
+    cursor:pointer;
+    color:var(--danger);
+    font-weight:700;
+    font-size:13px;
+    line-height:1;
+    opacity:0;
+    transition:opacity .12s;
+  }
+  .media-item:hover .x{opacity:1}
+  .media-item .tag{
+    position:absolute;
+    bottom:3px;left:3px;
+    font-size:8px;
+    background:rgba(0,0,0,.65);
+    padding:1px 4px;
+    border-radius:3px;
+    letter-spacing:.3px;
+    text-transform:uppercase;
+  }
+
+  /* ─── Counters ───────────────────────────────────────────────── */
+  .counter{font-size:11px;color:var(--muted);text-align:right;margin-top:3px}
+  .counter.over{color:var(--danger);font-weight:600}
+
+  /* ─── Preview panel ──────────────────────────────────────────── */
+  /* Outer wrapper — device chrome feel */
+  .preview-device{
+    background:var(--panel2);
+    border:1px solid var(--line);
+    border-radius:var(--radius-lg);
+    padding:14px;
+    margin-top:0;
+  }
+  .pv{
+    background:#fff;
+    color:#111;
+    border-radius:10px;
+    overflow:hidden;
+    box-shadow:0 1px 4px rgba(0,0,0,.18);
+  }
+  .pv .pvhead{display:flex;align-items:center;gap:9px;padding:10px 13px}
+  .pv .pvav{width:34px;height:34px;border-radius:50%;flex-shrink:0}
+  .pv .pvname{font-weight:700;font-size:13px;color:#111;line-height:1.2}
+  .pv .pvsub{font-size:11px;color:#888;margin-top:1px}
+  .pv .pvbody{
+    padding:2px 13px 11px;
+    font-size:13px;
+    line-height:1.5;
+    white-space:pre-wrap;
+    color:#1a1a1a;
+  }
+  .pv .pvimg{
+    width:100%;
+    background:#edeae4;
+    display:flex;
+    align-items:center;
+    justify-content:center;
+    color:#bbb;
+    font-size:11px;
+    letter-spacing:.5px;
+    text-transform:uppercase;
+  }
   .pv.ig .pvimg{aspect-ratio:1/1}
   .pv.pinterest .pvimg{aspect-ratio:2/3}
   .pv.youtube .pvimg{aspect-ratio:16/9}
-  .pv .pvactions{display:flex;gap:18px;padding:8px 12px;color:#555;font-size:12px;border-top:1px solid #eee}
-  .pv .pvtitle{font-weight:700;font-size:14px;padding:8px 12px 2px}
-  .pv .thread .tw{border-bottom:1px solid #eee;padding:8px 0}
-  .badge{display:inline-block;font-size:10px;padding:2px 7px;border-radius:999px;letter-spacing:.5px;text-transform:uppercase}
-  .b-draft{background:#3a3a3a;color:#ccc}.b-pending{background:#5a4a1a;color:var(--warn)}
-  .b-approved{background:#1a4a2a;color:var(--accent)}.b-published{background:#1a3a5a;color:#7ec8ff}
-  .gatebar{background:var(--panel2);border:1px solid var(--line);border-radius:10px;padding:12px;margin-top:8px}
-  .gatebar.warn{border-color:var(--warn)}
+  .pv.facebook .pvimg{aspect-ratio:1.91/1}
+  .pv.linkedin .pvimg{aspect-ratio:1.91/1}
+  .pv .pvactions{
+    display:flex;
+    gap:18px;
+    padding:9px 13px;
+    color:#777;
+    font-size:12px;
+    border-top:1px solid #f0ede8;
+  }
+  .pv .pvtitle{font-weight:700;font-size:14px;padding:9px 13px 3px;color:#111}
+  .pv .thread .tw{border-bottom:1px solid #f0ede8;padding:8px 0}
+
+  /* ─── Badges ─────────────────────────────────────────────────── */
+  .badge{
+    display:inline-block;
+    font-size:9.5px;
+    padding:2px 8px;
+    border-radius:999px;
+    letter-spacing:.6px;
+    text-transform:uppercase;
+    font-weight:500;
+  }
+  .b-draft{background:#252830;color:#7a8090;border:1px solid #2e3240}
+  .b-pending{background:var(--warn-faint);color:var(--warn);border:1px solid rgba(184,146,58,.25)}
+  .b-approved{background:var(--ok-faint);color:#5ab880;border:1px solid rgba(58,138,96,.25)}
+  .b-published{background:var(--info-faint);color:#6aacda;border:1px solid rgba(58,106,160,.25)}
+
+  /* ─── Gate bar ───────────────────────────────────────────────── */
+  .gatebar{
+    background:var(--panel2);
+    border:1px solid var(--line);
+    border-radius:var(--radius);
+    padding:12px 14px;
+    margin-top:10px;
+    font-size:12.5px;
+  }
+  .gatebar.warn{border-color:rgba(184,146,58,.4);background:var(--warn-faint)}
+  .gatebar strong{font-size:12.5px;color:var(--ink-2)}
+  .gatebar .muted{margin-top:4px}
+
+  /* Approval row — stack buttons cleanly */
+  .approval-actions{display:flex;flex-direction:column;gap:8px;margin-top:14px}
+  .approval-actions .row{gap:8px}
+  .approval-actions .row>*{flex:1}
+
+  /* ─── Misc helpers ───────────────────────────────────────────── */
   .muted{color:var(--muted);font-size:12px}
-  /* calendar */
-  .cal{display:grid;grid-template-columns:repeat(7,1fr);gap:6px}
-  .cal .dh{font-size:11px;color:var(--muted);text-align:center;padding:4px}
-  .cal .cell{min-height:78px;background:var(--panel2);border:1px solid var(--line);border-radius:8px;padding:5px;font-size:11px}
-  .cal .cell .dn{color:var(--muted);font-size:10px}
-  .cal .ev{font-size:10px;margin-top:3px;padding:2px 4px;border-radius:5px;background:#222633;border-left:2px solid var(--gold);overflow:hidden;white-space:nowrap;text-overflow:ellipsis}
-  .launchcard{background:var(--panel2);border:1px solid var(--line);border-radius:10px;padding:12px;margin-bottom:10px;cursor:pointer}
-  .launchcard:hover{border-color:var(--gold)}
-  .launchcard .when{font-size:11px;color:var(--muted)}
-  .toast{position:fixed;bottom:18px;left:50%;transform:translateX(-50%);background:var(--panel2);border:1px solid var(--gold);padding:12px 18px;border-radius:10px;z-index:50;max-width:480px}
-  .toast.err{border-color:var(--danger)}
-  .hide{display:none}
-  .queueslots{display:flex;gap:6px;flex-wrap:wrap}
-  .queueslots button{font-size:11px;padding:5px 9px}
-  .field-block{border:1px solid var(--line);border-radius:8px;padding:10px;margin-top:8px;background:var(--panel2)}
+  .hide{display:none!important}
+  .divider{height:1px;background:var(--line-soft);margin:14px 0}
+
+  /* ─── Queue slots ────────────────────────────────────────────── */
+  .queueslots{display:flex;gap:6px;flex-wrap:wrap;margin-top:6px}
+  .queueslots button{
+    font-size:11px;
+    padding:4px 10px;
+    border-radius:var(--radius-sm);
+    background:var(--panel2);
+    border:1px solid var(--line);
+    color:var(--ink-2);
+    cursor:pointer;
+    font-family:inherit;
+    transition:border-color .12s, color .12s;
+  }
+  .queueslots button:hover{border-color:var(--gold-dim);color:var(--ink)}
+
+  /* ─── Field block (platform fields) ─────────────────────────── */
+  .field-block{
+    border:1px solid var(--line-soft);
+    border-radius:var(--radius-sm);
+    padding:12px;
+    margin-top:10px;
+    background:var(--panel2);
+  }
+
+  /* ─── Calendar ───────────────────────────────────────────────── */
+  .cal{display:grid;grid-template-columns:repeat(7,1fr);gap:5px}
+  .cal .dh{
+    font-size:10.5px;
+    color:var(--muted);
+    text-align:center;
+    padding:5px 2px;
+    letter-spacing:.5px;
+    text-transform:uppercase;
+  }
+  .cal .cell{
+    min-height:76px;
+    background:var(--panel2);
+    border:1px solid var(--line);
+    border-radius:var(--radius-sm);
+    padding:6px;
+    font-size:11px;
+  }
+  .cal .cell .dn{color:var(--muted);font-size:10px;margin-bottom:2px}
+  .cal .ev{
+    font-size:10px;
+    margin-top:3px;
+    padding:2px 5px;
+    border-radius:4px;
+    background:var(--panel3);
+    border-left:2px solid var(--gold);
+    overflow:hidden;
+    white-space:nowrap;
+    text-overflow:ellipsis;
+    color:var(--ink-2);
+  }
+  #cal-label{
+    text-align:center;
+    font-family:var(--serif);
+    font-size:17px;
+    color:var(--ink);
+    letter-spacing:.3px;
+  }
+
+  /* ─── Launch cards (Drafts view) ─────────────────────────────── */
+  .launchcard{
+    background:var(--panel2);
+    border:1px solid var(--line);
+    border-radius:var(--radius);
+    padding:13px 15px;
+    margin-bottom:8px;
+    cursor:pointer;
+    transition:border-color .15s, background .15s;
+  }
+  .launchcard:hover{border-color:var(--gold-dim);background:var(--panel3)}
+  .launchcard .when{
+    font-size:11px;
+    color:var(--muted);
+    margin-top:5px;
+    display:flex;
+    align-items:center;
+    gap:4px;
+  }
+
+  /* ─── Toast ──────────────────────────────────────────────────── */
+  .toast{
+    position:fixed;
+    bottom:20px;
+    left:50%;
+    transform:translateX(-50%);
+    background:var(--panel2);
+    border:1px solid var(--gold-dim);
+    padding:11px 18px;
+    border-radius:var(--radius);
+    z-index:50;
+    max-width:500px;
+    font-size:13px;
+    color:var(--ink-2);
+    box-shadow:0 4px 24px rgba(0,0,0,.4);
+    animation:toastin .18s ease;
+  }
+  .toast.err{border-color:var(--danger);color:var(--danger)}
+  @keyframes toastin{from{opacity:0;transform:translateX(-50%) translateY(8px)}to{opacity:1;transform:translateX(-50%) translateY(0)}}
+
+  /* ─── State line ─────────────────────────────────────────────── */
+  #state-line{margin-bottom:6px;display:flex;align-items:center;gap:8px}
+
+  /* ─── Preview sticky wrapper ─────────────────────────────────── */
+  .preview-col{
+    flex:1;
+    min-width:0;
+    position:sticky;
+    top:72px;
+    align-self:flex-start;
+  }
 </style>
 </head>
 <body>
 <header class="topbar">
-  <div class="brand">Designer Wallcoverings<span class="dot">.</span><small>Launches · Social Composer</small></div>
+  <div class="brand">
+    <div class="brand-eyebrow">Launches · Social Composer</div>
+    <div class="brand-name">Designer Wallcoverings<span class="dot">.</span></div>
+  </div>
   <nav class="tabs">
     <button id="nav-compose" class="active" onclick="showView('compose')">Compose</button>
     <button id="nav-calendar" onclick="showView('calendar')">Calendar</button>
@@ -105,20 +650,27 @@
 <div id="view-compose">
   <div class="wrap">
     <!-- LEFT: editor -->
-    <div class="col" style="flex:1.2">
+    <div class="col" style="flex:1.25">
+
       <!-- 1. Channel selector rail -->
       <div class="card">
-        <h3>1 · Channels</h3>
+        <div class="section-label">
+          <span class="sl-step">01</span>
+          <span class="sl-title">Channels</span>
+        </div>
         <div id="chanrail" class="chanrail"></div>
       </div>
 
       <!-- 2. Global editor -->
       <div class="card">
-        <h3>2 · Global post (master)</h3>
-        <label>Launch title (admin only)</label>
+        <div class="section-label">
+          <span class="sl-step">02</span>
+          <span class="sl-title">Global Post</span>
+        </div>
+        <label>Launch title <span class="muted" style="display:inline;text-transform:none;letter-spacing:0">(admin only)</span></label>
         <input type="text" id="launch-title" placeholder="e.g. Trending Wallcoverings Collection 2026 — Weekly Arrivals">
-        <label>Master body — selected channels inherit this by default</label>
-        <textarea id="global-body" placeholder="Write the master post… (the word &quot;Wallpaper&quot; is banned — use &quot;Wallcoverings&quot;)"></textarea>
+        <label>Master body <span class="muted" style="display:inline;text-transform:none;letter-spacing:0">— selected channels inherit this by default</span></label>
+        <textarea id="global-body" placeholder='Write the master post… (the word "Wallpaper" is banned — use "Wallcoverings")'></textarea>
         <div class="counter" id="global-counter"></div>
 
         <!-- 4. Media attach -->
@@ -130,14 +682,20 @@
 
       <!-- 3. Per-channel tabs + 6. platform fields -->
       <div class="card" id="perchan-card">
-        <h3>3 · Per-channel overrides</h3>
+        <div class="section-label">
+          <span class="sl-step">03</span>
+          <span class="sl-title">Per-channel Overrides</span>
+        </div>
         <div class="ctabs" id="ctabs"></div>
         <div id="perchan-editor" class="muted">Select 2+ channels to unlock per-channel overrides.</div>
       </div>
 
       <!-- 7. Scheduling -->
       <div class="card">
-        <h3>7 · Scheduling</h3>
+        <div class="section-label">
+          <span class="sl-step">07</span>
+          <span class="sl-title">Scheduling</span>
+        </div>
         <div class="row">
           <div>
             <label>Mode</label>
@@ -149,7 +707,7 @@
             </select>
           </div>
           <div id="sched-dt-wrap">
-            <label>Date &amp; time (applies to selected channels w/o their own)</label>
+            <label>Date &amp; time</label>
             <input type="datetime-local" id="sched-dt">
           </div>
         </div>
@@ -157,34 +715,44 @@
           <label>Preset queue slots (PT)</label>
           <div class="queueslots" id="queue-slots"></div>
         </div>
-        <p class="muted" style="margin-top:8px">Per-channel cadence (overrides above) is set inside each channel tab.</p>
+        <p class="muted" style="margin-top:10px">Per-channel cadence overrides global schedule — set inside each channel tab.</p>
       </div>
 
-      <!-- 9. Draft / approval -->
+      <!-- 9. State & approval -->
       <div class="card">
-        <h3>9 · State &amp; approval</h3>
+        <div class="section-label">
+          <span class="sl-step">09</span>
+          <span class="sl-title">State &amp; Approval</span>
+        </div>
         <div id="state-line"><span class="badge b-draft">draft</span></div>
         <div class="gatebar warn" id="gatebar">
           <strong>Publish is gated.</strong>
-          <div class="muted">Nothing goes live without explicit Steve sign-off. The publish button stays disabled behind the approval flag. This tool never calls a live social API.</div>
+          <div class="muted">Nothing goes live without explicit Steve sign-off. The publish button stays disabled until approval. This tool never calls a live social API.</div>
         </div>
-        <div class="row" style="margin-top:12px">
-          <button class="btn ghost" onclick="saveLaunch('draft')">Save draft</button>
-          <button class="btn ghost" onclick="submitApproval()">Submit for approval</button>
-        </div>
-        <div class="row" style="margin-top:8px">
-          <button class="btn ghost" id="btn-approve" onclick="approve()">Steve sign-off ✓</button>
-          <button class="btn" id="btn-publish" onclick="publish()" disabled>Publish (gated stub)</button>
+        <div class="approval-actions">
+          <div class="row">
+            <button class="btn ghost" onclick="saveLaunch('draft')">Save draft</button>
+            <button class="btn btn-submit" onclick="submitApproval()">Submit for approval</button>
+          </div>
+          <div class="row">
+            <button class="btn btn-approve" id="btn-approve" onclick="approve()">Steve sign-off ✓</button>
+            <button class="btn btn-publish" id="btn-publish" onclick="publish()" disabled>Publish (gated)</button>
+          </div>
         </div>
       </div>
     </div>
 
-    <!-- RIGHT: preview -->
-    <div class="col">
+    <!-- RIGHT: preview (sticky) -->
+    <div class="col preview-col">
       <div class="card">
-        <h3>5 · Live preview</h3>
+        <div class="section-label">
+          <span class="sl-step">05</span>
+          <span class="sl-title">Live Preview</span>
+        </div>
         <div class="ctabs" id="pv-tabs"></div>
-        <div id="preview"></div>
+        <div class="preview-device">
+          <div id="preview"></div>
+        </div>
       </div>
     </div>
   </div>
@@ -194,11 +762,11 @@
 <div id="view-calendar" class="hide">
   <div class="wrap"><div class="col">
     <div class="card">
-      <h3>8 · Calendar</h3>
-      <div class="row" style="align-items:center;margin-bottom:12px">
-        <button class="btn ghost" onclick="calShift(-1)">‹ Prev</button>
-        <div id="cal-label" style="text-align:center;font-family:var(--serif);font-size:16px"></div>
-        <button class="btn ghost" onclick="calShift(1)">Next ›</button>
+      <h3>Calendar</h3>
+      <div class="row" style="align-items:center;margin-bottom:16px">
+        <button class="btn ghost" onclick="calShift(-1)" style="flex:0 0 auto;padding:7px 14px">‹ Prev</button>
+        <div id="cal-label"></div>
+        <button class="btn ghost" onclick="calShift(1)" style="flex:0 0 auto;padding:7px 14px">Next ›</button>
       </div>
       <div class="cal" id="cal-grid"></div>
     </div>
@@ -209,7 +777,7 @@
 <div id="view-drafts" class="hide">
   <div class="wrap"><div class="col">
     <div class="card">
-      <h3>Drafts &amp; queue</h3>
+      <h3>Drafts &amp; Queue</h3>
       <div id="drafts-list"></div>
     </div>
   </div></div>
@@ -270,7 +838,8 @@ function renderChanRail(){
     const sel = state.channelsSelected.includes(c.id);
     const d=document.createElement('div');
     d.className='chip'+(sel?' sel':'')+(c.connected?'':' disabled');
-    d.innerHTML=`<span class="av" style="background:${COLORS[c.id]}">${c.name[0]}</span>${c.name}`
+    // refined: colored dot, not full candy avatar
+    d.innerHTML=`<span class="av" style="background:${COLORS[c.id]}"></span>${c.name}`
       + (c.connected?'':' <span class="connect">connect</span>');
     if(c.connected) d.onclick=()=>toggleChan(c.id);
     el.appendChild(d);
@@ -359,11 +928,11 @@ function renderPerChanEditor(){
   const limit=CHAR_LIMITS[id];
   const effBody = c.body || state.global.body || '';
   let html = `
-    <label>${chanName(id)} copy (overrides master; blank = inherit master)</label>
+    <label>${chanName(id)} copy <span class="muted" style="display:inline;text-transform:none;letter-spacing:0">(overrides master; blank = inherit master)</span></label>
     <textarea id="pc-body" placeholder="Inherit master, or override here…">${esc(c.body||'')}</textarea>
     <div class="counter" id="pc-counter"></div>
-    <label>${chanName(id)} media (blank = inherit master media)</label>
-    <div class="media-drop" id="pc-drop">Add ${chanName(id)} media (image / carousel / video)</div>
+    <label>${chanName(id)} media <span class="muted" style="display:inline;text-transform:none;letter-spacing:0">(blank = inherit master media)</span></label>
+    <div class="media-drop" id="pc-drop">Add ${chanName(id)} media</div>
     <input type="file" id="pc-file" class="hide" multiple accept="image/*,video/*">
     <div class="media-list" id="pc-media"></div>`;
   html += platformFields(id, c);
@@ -403,7 +972,7 @@ function platformFields(id,c){
   if(id==='instagram') return `<div class="field-block"><label>IG first comment</label><input type="text" id="f-firstComment" value="${fb(f.firstComment)}" placeholder="First comment (hashtags / link)"></div>`;
   if(id==='youtube') return `<div class="field-block"><label>YouTube title</label><input type="text" id="f-ytTitle" value="${fb(f.ytTitle)}"><label>Thumbnail ref</label><input type="text" id="f-ytThumbnail" value="${fb(f.ytThumbnail)}"></div>`;
   if(id==='pinterest') return `<div class="field-block"><label>Pin title</label><input type="text" id="f-pinTitle" value="${fb(f.pinTitle)}"><label>Board</label><input type="text" id="f-board" value="${fb(f.board)}"><label>Destination link</label><input type="text" id="f-destinationLink" value="${fb(f.destinationLink)}"></div>`;
-  if(id==='twitter') return `<div class="field-block"><label>Thread split (one tweet per line)</label><textarea id="f-thread" style="min-height:90px">${fb((f.thread||[]).join('\n'))}</textarea></div>`;
+  if(id==='twitter') return `<div class="field-block"><label>Thread split <span class="muted" style="display:inline;text-transform:none;letter-spacing:0">(one tweet per line)</span></label><textarea id="f-thread" style="min-height:90px">${fb((f.thread||[]).join('\n'))}</textarea></div>`;
   return '';
 }
 function wirePlatformFields(id,c){
@@ -422,7 +991,7 @@ function renderSchedule(){
   document.getElementById('queue-wrap').classList.toggle('hide', mode!=='queue');
   if(mode==='queue'){
     const q=document.getElementById('queue-slots'); q.innerHTML='';
-    QUEUE_SLOTS.forEach(t=>{const b=document.createElement('button');b.className='btn ghost';b.textContent=t+' PT';
+    QUEUE_SLOTS.forEach(t=>{const b=document.createElement('button');b.textContent=t+' PT';
       b.onclick=()=>{ applyQueueSlot(t); }; q.appendChild(b);});
   }
 }
@@ -480,8 +1049,10 @@ function renderPreview(){
 }
 function pvShell(id, name, inner, extra, label){
   return `<div class="pv ${id}">
-    <div class="pvhead"><div class="pvav" style="background:${COLORS[id]}"></div>
-      <div><div class="pvname">${name}</div><div class="pvsub">${label} preview</div></div></div>
+    <div class="pvhead">
+      <div class="pvav" style="background:${COLORS[id]}"></div>
+      <div><div class="pvname">${name}</div><div class="pvsub">${label} preview</div></div>
+    </div>
     ${inner}${extra}
     <div class="pvactions"><span>♥ Like</span><span>💬 Comment</span><span>↗ Share</span></div>
   </div>`;
@@ -560,7 +1131,7 @@ async function renderCalendar(){
     cell.innerHTML=`<div class="dn">${d}</div>`;
     events.filter(e=>{const dt=new Date(e.datetime);return dt.getFullYear()===y&&dt.getMonth()===mo&&dt.getDate()===d;})
       .forEach(e=>{const ev=document.createElement('div');ev.className='ev';
-        ev.style.borderLeftColor=COLORS[e.channel]||'#c8a96a';
+        ev.style.borderLeftColor=COLORS[e.channel]||'#c2a064';
         ev.title=`${e.title}\n${e.channel} · ${new Date(e.datetime).toISOString()}\nstatus: ${e.status}`;
         ev.textContent=`${new Date(e.datetime).toLocaleTimeString([], {hour:'numeric',minute:'2-digit'})} ${chanName(e.channel)}`;
         cell.appendChild(ev);});
@@ -577,10 +1148,10 @@ async function renderDrafts(){
     const created=l.created_at?new Date(l.created_at):null;
     const whenStr=created?created.toLocaleString(undefined,{year:'numeric',month:'short',day:'numeric',hour:'numeric',minute:'2-digit'}):'—';
     const m={draft:'b-draft',pending_approval:'b-pending',approved:'b-approved',published:'b-published'};
-    d.innerHTML=`<div style="display:flex;justify-content:space-between">
+    d.innerHTML=`<div style="display:flex;justify-content:space-between;align-items:flex-start">
         <strong>${esc(l.title)}</strong>
         <span class="badge ${m[l.status]||'b-draft'}">${(l.status||'draft').replace('_',' ')}</span></div>
-      <div class="muted">${(l.channelsSelected||[]).map(chanName).join(' · ')||'no channels'}</div>
+      <div class="muted" style="margin-top:4px">${(l.channelsSelected||[]).map(chanName).join(' · ')||'no channels'}</div>
       <div class="when" title="${l.created_at||''}">🕓 ${whenStr}</div>`;
     d.onclick=()=>{ state=l; activeChanTab=null; activePvTab=null; showView('compose'); hydrate(); toast('Loaded: '+l.title); };
     el.appendChild(d);

← 6df89ad add README with run instructions, component map, and stub li  ·  back to Dw Launches  ·  add modal-rig.js drop-in (vanilla drag/resize/maximize/persi 8db4dc5 →