:root {
  --bg: #000000;
  --bg2: #1a1a1a;
  --card: #111111;
  --card2: #1a1a1a;
  --border: #262626;
  --text: #e0e0e0;
  --muted: #8a8a8a;
  --accent: #7B68EE;
  --dot-empty: #262626;
  --radius: 16px;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  font-size: 15px;
  line-height: 1.5;
}

a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }

.wrap { max-width: 1200px; margin: 0 auto; padding: 14px; }
.wrap-narrow { max-width: 640px; margin: 0 auto; padding: 20px; }

/* Top bar */
.topbar {
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px; flex-wrap: wrap; margin-bottom: 20px;
}
.topbar h1 { margin: 0; font-size: 24px; }
.topbar h1 .logo { color: var(--accent); }
.navlinks { display: flex; gap: 14px; flex-wrap: wrap; font-size: 14px; }

/* Stat row */
.stat-row {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 14px; margin-bottom: 20px;
}
.stat {
  background: var(--card); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 16px;
}
.stat .num { font-size: 28px; font-weight: 700; }
.stat .lbl { color: var(--muted); font-size: 13px; text-transform: uppercase; letter-spacing: .04em; }

/* Search */
.search {
  width: 100%; padding: 12px 16px; border-radius: 12px;
  border: 1px solid var(--border); background: var(--card2); color: var(--text);
  font-size: 15px; margin-bottom: 20px;
}
.search::placeholder { color: var(--muted); }

/* Model grid */
.model-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 16px;
}
.model-card {
  background: var(--card); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 18px; cursor: pointer;
  transition: transform .12s ease, border-color .12s ease;
}
.model-card:hover { transform: translateY(-3px); border-color: var(--accent); }
.model-card .mc-top {
  display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px;
}
.model-card .mc-name { font-size: 18px; font-weight: 700; }
.streak { font-size: 14px; color: var(--muted); display: inline-flex; align-items: center; gap: 6px; }
.streak .emoji { font-size: 20px; }

.pill {
  display: inline-block; padding: 4px 12px; border-radius: 999px;
  font-weight: 700; font-size: 14px; color: #111;
}
.pill.na { color: #fff; }

/* mini dot grid on dashboard */
.mini-grid { display: flex; flex-wrap: wrap; gap: 3px; margin-top: 14px; }
.mini-dot {
  width: 9px; height: 9px; border-radius: 50%; background: var(--dot-empty);
}
.mini-dot.complete { background: #4CAF50; }
.mini-dot.partial  { background: #FFC107; }
.mini-dot.miss     { background: #F44336; }
.mini-dot.exception{ background: #555; opacity: .5; }
.mini-dot.none     { background: transparent; box-shadow: inset 0 0 0 1px var(--border); }
.mini-dot.today    { box-shadow: 0 0 0 2px var(--accent); }

/* Detail header */
.detail-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px; flex-wrap: wrap; margin-bottom: 20px;
}
.detail-head .name { font-size: 26px; font-weight: 800; }
.detail-head .meta { display: flex; align-items: center; gap: 18px; flex-wrap: wrap; }
.big-streak { font-size: 18px; display: inline-flex; align-items: center; gap: 8px; }
.big-streak .emoji { font-size: 30px; }

/* Category dot cards */
.cat-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: 16px; margin-bottom: 24px; }
.cat-card {
  background: var(--card); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 18px;
}
.cat-card .ch { display: flex; align-items: center; gap: 10px; margin-bottom: 14px; }
.cat-card .ch .icon { font-size: 22px; }
.cat-card .ch .nm { font-weight: 700; font-size: 16px; }
.cat-card .ch .qty { margin-left: auto; color: var(--muted); font-size: 13px; }

.dot-grid { display: grid; grid-template-columns: repeat(15, 1fr); gap: 6px; }
.dot {
  aspect-ratio: 1; border-radius: 50%; background: var(--dot-empty);
  display: flex; align-items: center; justify-content: center;
  font-size: 9px; color: transparent; position: relative;
}
.dot.clickable { cursor: pointer; }
.dot.clickable:hover { outline: 2px solid var(--accent); }
.dot.done     { /* color set inline per category */ }
.dot.missed   { background: var(--dot-empty); }
.dot.future   { background: #202038; }
.dot.none     { background: transparent; box-shadow: inset 0 0 0 1px #23233c; }
.dot.exception{
  background: repeating-linear-gradient(45deg, #444, #444 2px, #2a2a4a 2px, #2a2a4a 4px);
}
.dot.today { box-shadow: 0 0 0 2px #fff; }
.dot .num { position: absolute; font-size: 8px; color: var(--muted); pointer-events: none; }

/* Sections */
.section { margin-bottom: 14px; }
.section h2 { font-size: 18px; margin: 0 0 10px; }

/* Today's tasks */
.task-list { display: flex; flex-direction: column; gap: 10px; }
.task-row {
  display: flex; align-items: center; gap: 12px; background: var(--card);
  border: 1px solid var(--border); border-radius: 12px; padding: 12px 16px;
}
.task-row .ticon { font-size: 20px; }
.task-row .tname { font-weight: 600; }
.task-row .treq { color: var(--muted); font-size: 13px; margin-left: 4px; }
.task-row .spacer { flex: 1; }
.task-row input[type=checkbox] { width: 22px; height: 22px; accent-color: var(--accent); cursor: pointer; }
.task-row.done { border-color: #4CAF50; }
.badge-done { color: #4CAF50; font-weight: 700; }
.badge-todo { color: var(--muted); }

/* Tables */
table { width: 100%; border-collapse: collapse; background: var(--card); border-radius: var(--radius); overflow: hidden; }
th, td { text-align: left; padding: 12px 14px; border-bottom: 1px solid var(--border); }
th { color: var(--muted); font-size: 12px; text-transform: uppercase; letter-spacing: .04em; }
tr:last-child td { border-bottom: none; }

/* Buttons & forms */
.btn {
  display: inline-block; padding: 9px 16px; border-radius: 10px; border: none;
  background: var(--accent); color: #fff; font-weight: 600; cursor: pointer; font-size: 14px;
}
.btn:hover { opacity: .9; text-decoration: none; }
.btn.secondary { background: var(--card2); border: 1px solid var(--border); color: var(--text); }
.btn.danger { background: #F44336; }
.btn.small { padding: 5px 10px; font-size: 13px; }

input[type=text], input[type=number], input[type=date], input[type=password], select, textarea {
  padding: 10px 12px; border-radius: 10px; border: 1px solid var(--border);
  background: var(--card2); color: var(--text); font-size: 14px;
}
label { font-size: 14px; color: var(--muted); display: block; margin-bottom: 4px; }
.form-grid { display: grid; gap: 14px; }
.card-box { background: var(--card); border: 1px solid var(--border); border-radius: var(--radius); padding: 20px; margin-bottom: 20px; }

/* Day toggle buttons */
.day-toggles { display: flex; gap: 8px; flex-wrap: wrap; }
.day-toggle {
  padding: 8px 12px; border-radius: 10px; border: 1px solid var(--border);
  background: var(--card2); color: var(--muted); cursor: pointer; font-size: 13px; user-select: none;
}
.day-toggle.on { background: var(--accent); color: #fff; border-color: var(--accent); }

.flash { background: #F44336; color: #fff; padding: 10px 16px; border-radius: 10px; margin-bottom: 16px; }
.summary-text { color: var(--muted); font-size: 14px; margin-top: 10px; }

.legend { display: flex; gap: 16px; flex-wrap: wrap; color: var(--muted); font-size: 13px; margin-top: 12px; }
.legend .item { display: inline-flex; align-items: center; gap: 6px; }
.legend .swatch { width: 12px; height: 12px; border-radius: 50%; display: inline-block; }

.muted { color: var(--muted); }
.row-inline { display: flex; gap: 10px; align-items: end; flex-wrap: wrap; }
.center { text-align: center; }
.mt { margin-top: 16px; }

/* Login */
.login-box { max-width: 360px; margin: 12vh auto; }

/* ============================================================= */
/* ADMIN DASHBOARD (TickTick-style)                              */
/* ============================================================= */
.dash-wrap { max-width: 1200px; }

/* Top bar: toggle + date nav + search */
.dash-topbar {
  display: flex; align-items: center; justify-content: center;
  gap: 18px; flex-wrap: wrap; margin-bottom: 12px;
}
.dash-toggle {
  display: inline-flex; background: #111; border: 1px solid var(--border);
  border-radius: 999px; padding: 3px; gap: 2px;
}
.dash-toggle-btn {
  padding: 5px 18px; border-radius: 999px; font-size: 13px; font-weight: 600;
  color: var(--muted); text-decoration: none;
}
.dash-toggle-btn:hover { text-decoration: none; color: var(--text); }
.dash-toggle-btn.active { background: var(--accent); color: #fff; }
.dash-datenav { display: inline-flex; align-items: center; gap: 8px; }
.dash-range { font-size: 14px; font-weight: 700; min-width: 150px; text-align: center; }
.dash-arrow {
  display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; border-radius: 8px; border: 1px solid var(--border);
  background: #111; color: var(--text); font-size: 16px; text-decoration: none; line-height: 1;
}
.dash-arrow:hover { border-color: var(--accent); text-decoration: none; }
.dash-search {
  padding: 6px 12px; border-radius: 999px; border: 1px solid var(--border);
  background: #111; color: var(--text); font-size: 13px; width: 180px;
}
.dash-search::placeholder { color: var(--muted); }

/* Quick stats bar */
.dash-stats {
  display: flex; align-items: center; justify-content: center; gap: 10px;
  flex-wrap: wrap; font-size: 13px; color: var(--muted); margin-bottom: 14px;
}
.dash-stats b { color: var(--text); font-weight: 700; }
.ds-sep { opacity: .4; }

/* Model sections: flat on black, divider between */
.dash-body { overflow-x: auto; }
.model-section { padding: 16px 0; border-bottom: 1px solid var(--border); }
.model-section:last-child { border-bottom: none; }

.ms-header {
  display: flex; align-items: center; gap: 8px; margin-bottom: 8px;
}
.ms-pfp {
  width: 28px; height: 28px; border-radius: 50%; object-fit: cover; flex: 0 0 auto;
}
.ms-pfp-letter {
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 13px; font-weight: 700; color: #fff;
  background: linear-gradient(135deg, var(--accent), #E85D75);
}
.ms-name { font-size: 14px; font-weight: 700; color: var(--text); }
.ms-name:hover { color: var(--accent); text-decoration: none; }
.ms-emoji { font-size: 18px; line-height: 1; }
.ms-streak { font-size: 12px; color: var(--muted); }
.ms-mtd {
  display: inline-block; padding: 1px 8px; border-radius: 999px;
  font-size: 12px; font-weight: 700; color: #111;
}
.ms-mtd.na { color: #fff; }

/* Category rows + square grid */
.dash-row { display: flex; align-items: center; gap: 10px; margin-bottom: 4px; }
.dash-row:last-child { margin-bottom: 0; }
.dash-label {
  width: 120px; flex: 0 0 120px; display: flex; align-items: center; gap: 6px;
  font-size: 12px; color: var(--text); overflow: hidden; white-space: nowrap;
}
.dash-label .dl-icon { font-size: 13px; }
.dash-label .dl-name { overflow: hidden; text-overflow: ellipsis; }
.dash-squares { display: flex; gap: 3px; }

.dash-dayhead-row { margin-bottom: 6px; }
.dash-dayhead {
  width: 28px; text-align: center; font-size: 10px; color: var(--muted);
  font-weight: 600; flex: 0 0 auto;
}
.dash-dayhead.today { color: #fff; }

.sq {
  width: 28px; height: 28px; flex: 0 0 auto; border-radius: 4px;
  background: #1a1a1a; border: 1px solid #262626;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 12px; line-height: 1; user-select: none;
}
.sq-complete { background: #2d5a2d; border-color: #4CAF50; }
.sq-missed   { background: #5a2d2d; border-color: #F44336; }
.sq-future, .sq-exception { background: #1a1a1a; border-color: #262626; }
/* Past day, scheduled, but admin hasn't reviewed it yet (no completion row).
   Amber "?" waiting state -- deliberately loud so it can't be mistaken for
   green (done), red (missed), or gray (future). */
.sq-pending  {
  background: #1a1a0a !important;
  border: 2px solid #8B8000 !important;
  color: #8B8000; font-size: 10px;
  display: flex; align-items: center; justify-content: center;
}
.sq-pending::after { content: "?"; opacity: 0.6; }
/* Month view squares are tiny (16px) -- shrink the "?" to fit */
.dash-month .sq-pending { font-size: 8px; }

/* Reusable diagonal hatch: category NOT scheduled on this day.
   Distinct from "scheduled but future" (dark solid) and from exception
   days (which keep their 🙏/🚨 emoji, never hatching). Deliberately
   whisper-subtle. (No border-radius here — each square keeps its own.) */
.sq-off {
  background: repeating-linear-gradient(
    -45deg,
    transparent,
    transparent 3px,
    rgba(255, 255, 255, 0.04) 3px,
    rgba(255, 255, 255, 0.04) 4px
  );
  background-color: #0d0d0d;
  border: 1px solid #161616;
}
.sq.today { border: 2px solid #fff; }
.sq.clickable { cursor: pointer; }
.sq.clickable:hover { outline: 2px solid var(--accent); outline-offset: -1px; }

/* Month view: smaller squares so ~31 fit */
.dash-month .sq { width: 16px; height: 16px; border-radius: 3px; font-size: 9px; }
.dash-month .dash-dayhead { width: 16px; font-size: 8px; }
.dash-month .dash-squares { gap: 3px; }

/* ---------------- Streak hero (compact centered stack, no box) ---------------- */
.streak-hero {
  display: flex; flex-direction: column; align-items: center; gap: 5px;
  padding: 6px 16px 10px; margin-bottom: 6px;
  /* no background / border / box-shadow -- sits on the black page */
}
.sh-logo { height: 30px; width: auto; margin-bottom: 2px; }
.sh-pfp {
  width: 56px; height: 56px; border-radius: 50%; object-fit: cover;
  display: inline-flex; align-items: center; justify-content: center; flex: 0 0 auto;
}
.sh-pfp-letter {
  font-size: 24px; font-weight: 700; color: #fff;
  background: linear-gradient(135deg, var(--accent), #E85D75);
}
.sh-name {
  font-size: 18px; font-weight: 700; color: #fff; text-align: center; line-height: 1.1;
}
.streak-badge {
  width: 50px; height: 50px; border-radius: 50%; flex: 0 0 auto;
  display: flex; align-items: center; justify-content: center;
  background: radial-gradient(circle at 50% 38%,
              color-mix(in srgb, var(--tier) 32%, transparent),
              color-mix(in srgb, var(--tier) 6%, transparent) 72%);
  border: 2px solid color-mix(in srgb, var(--tier) 50%, transparent);
  box-shadow: 0 0 20px color-mix(in srgb, var(--tier) 28%, transparent);
}
.sh-emoji { font-size: 26px; line-height: 1; margin: 0; }
.sh-stats {
  display: flex; align-items: center; justify-content: space-between;
  gap: 24px; width: 100%; max-width: 300px; margin-top: 2px;
}
.sh-streak-txt { color: #fff; font-size: 16px; font-weight: 600; }
.sh-mtd-block { display: flex; flex-direction: column; align-items: flex-end; line-height: 1.1; }
.sh-mtd-num { font-size: 18px; font-weight: 800; }
.sh-mtd-label { font-size: 12px; color: #fff; }

/* ---------------- Calendar view ---------------- */
.cal-head {
  display: flex; align-items: center; justify-content: center; gap: 14px; margin-bottom: 8px;
}
.cal-title { font-size: 16px; font-weight: 700; min-width: 130px; text-align: center; }
.cal-nav {
  display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; border-radius: 8px; border: 1px solid var(--border);
  background: var(--card); color: var(--text); font-size: 18px; text-decoration: none;
}
.cal-nav:hover { border-color: var(--accent); text-decoration: none; }

.cal-grid {
  display: grid; gap: 5px; align-items: stretch;
  background: var(--card); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 10px;
  max-width: 700px; margin: 0 auto;
}
.cal-corner { }
.cal-colhead {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  font-size: 10px; color: var(--muted); font-weight: 600; padding: 2px 0;
}
.cal-colhead .rng { font-size: 9px; font-weight: 400; opacity: .8; }
.cal-rowhead {
  display: flex; align-items: center; justify-content: flex-end; padding-right: 6px;
  font-size: 11px; color: var(--muted); font-weight: 600;
}
.cal-cell {
  background: #0d0d0d; border: 1px solid var(--border); border-radius: 9px;
  min-height: 70px; padding: 3px 3px 4px; position: relative;
  display: flex; flex-direction: column; overflow: hidden;
}
.cal-cell.empty { background: transparent; border: none; }
.cal-cell.is-future { background: #080808; }
/* Overall-status cell tint + colored left border (past = always green or red).
   Brighter fills so the tint is clearly visible on mobile screens too. */
.cal-cell.cell-complete { background: #14521a; border-left: 3px solid #4CAF50; }
.cal-cell.cell-miss { background: #5c1414; border-left: 3px solid #F44336; }
/* Past day awaiting admin review: neutral bg, dashed border (no red/green) */
.cal-cell.cell-pending { background: #101010; border: 1px dashed #333; }
.cal-cell.is-today { border: 2px solid #fff; }
.cal-cell.is-today.cell-complete { border-left: 3px solid #4CAF50; }
.cal-cell.is-today.cell-miss { border-left: 3px solid #F44336; }
/* Exception day: neutral cell with a centered indicator emoji (no green/red) */
.cal-cell.is-exception { background: #0d0d0d; }
.cal-cell .cal-day { font-size: 10px; color: var(--muted); line-height: 1; margin-bottom: 2px; text-align: left; padding-left: 2px; }
.cal-cell.is-today .cal-day { color: #fff; font-weight: 700; }
.cal-exc-tag { font-size: 22px; line-height: 1; margin: auto; text-align: center; }

.cal-chips {
  display: flex; flex-direction: column; gap: 1px;
  align-items: center; justify-content: center; flex: 1;
}
.cal-chip {
  font-size: 19px; line-height: 1.1; filter: grayscale(1); opacity: .3;
  border-bottom: 2px solid transparent; user-select: none;
}
.cal-chip.completed { filter: none; opacity: 1; }
.cal-chip.clickable { cursor: pointer; }
.cal-chip.clickable:hover { opacity: .85; }

.cal-legend { display: flex; gap: 16px; flex-wrap: wrap; color: var(--muted); font-size: 13px; margin-top: 12px; justify-content: center; }
.cal-legend .item { display: inline-flex; align-items: center; gap: 6px; }

/* Mini calendar on dashboard cards */
.mini-cal { display: grid; gap: 2px; margin-top: 14px; }
.mini-cell {
  aspect-ratio: 1; border-radius: 2px; background: var(--dot-empty); min-width: 0;
}
.mini-cell.blank { background: transparent; }
.mini-cell.complete { background: #4CAF50; }
.mini-cell.partial  { background: #FFC107; }
.mini-cell.miss     { background: #F44336; }
.mini-cell.exception{ background: #444; }
.mini-cell.none     { background: #1c1c1c; }
.mini-cell.today    { box-shadow: 0 0 0 1.5px #fff; }

/* ============================================================= */
/* MODEL VIEW (/m/<token>) -- S16 TickTick redesign.              */
/* Categories are ROWS, days are COLUMNS, each cell one colored   */
/* square. Completed squares glow in the category's own color;    */
/* gray squares recede. No boxes, no containers -- squares float  */
/* on black with generous spacing. One viewport, zero scroll.     */
/* Scoped to body.model-view; admin views unaffected.             */
/* ============================================================= */
body.model-view {
  /* min-height (not fixed height) + overflow-y:auto: legibility first --
     allow a small scroll rather than crushing the content. */
  min-height: 100vh; min-height: 100dvh; overflow-y: auto; overflow-x: hidden; margin: 0;
  padding: 24px 24px 16px; background: #000;
  display: flex; flex-direction: column; box-sizing: border-box;
  font-family: -apple-system, BlinkMacSystemFont, sans-serif;
  color: #e8e8e8;
}
/* Dissolve the shared .wrap so body's flex column manages the page */
body.model-view .wrap { display: contents; }

/* ---------------- HERO: centered stack (~90px) ---------------- */
/* Same centering contract as .pl-top: flex column + text-align + width 100%,
   so nothing can drift left/right on a narrow screen. */
body.model-view .mv-hero {
  flex: 0 0 auto; position: relative;   /* anchor for the level-up text */
  display: flex; flex-direction: column; align-items: center;
  width: 100%; text-align: center;
}
/* The id row keeps PFP and name side by side; the ROW is what gets centered. */
body.model-view .mv-id {
  display: flex; align-items: center; justify-content: center;
  gap: 8px; margin: 0 auto; max-width: 100%;
}
body.model-view .mv-pfp {
  width: 36px; height: 36px; border-radius: 50%; object-fit: cover;
  border: 1.5px solid rgba(255, 255, 255, 0.12); box-sizing: border-box;
  flex: 0 0 auto; float: none; position: static;
}
body.model-view .mv-pfp-letter {
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 15px; font-weight: 700; color: #fff;
  background: linear-gradient(135deg, #7B68EE, #E85D75);
}
body.model-view .mv-name {
  font-size: 17px; font-weight: 700; color: #fff;
  max-width: 70vw; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  text-align: center; line-height: 1.2;
}
/* Streak row: 🔥 6  daily plan streak -- flame LEFT of the number, one line */
body.model-view .mv-streak-row {
  display: flex; align-items: center; justify-content: center; margin-top: 6px;
}
body.model-view .mv-flame-box {
  display: flex; align-items: center; justify-content: center; min-height: 14px;
}
body.model-view .mv-streak-num {
  font-size: 24px; font-weight: 700; color: #fff; line-height: 1.1; margin-left: 6px;
}
body.model-view .mv-streak-lbl { font-size: 11px; color: #888; line-height: 1.3; margin-left: 8px; }
body.model-view .mv-cons {
  display: flex; align-items: baseline; gap: 5px;
  font-size: 12px; color: #666; margin-top: 3px;
}
body.model-view .mv-cons > span:first-child { font-size: 13px; font-weight: 700; }

/* Exception-day notice (rare): one tight line */
body.model-view .center.muted { flex-shrink: 0; margin: 0 !important; font-size: 11px; }

/* ---------------- CELEBRATIONS ---------------- */
/* Confetti particles (created + removed by JS on tier level-up) */
body.model-view .confetti {
  position: fixed; width: 6px; height: 6px; z-index: 999; pointer-events: none;
  animation: mv-confetti-burst 1.5s ease-out forwards;
}
@keyframes mv-confetti-burst {
  0%   { transform: translate(0, 0) rotate(0deg) scale(1); opacity: 1; }
  100% { transform: translate(var(--dx), var(--dy)) rotate(var(--rot)) scale(.5); opacity: 0; }
}
/* Flame pulse with a brief golden glow (wrapper, so it doesn't fight the
   flame's own flicker transform) */
body.model-view .mv-flame-box.pulse { animation: mv-emoji-pulse .6s ease; }
@keyframes mv-emoji-pulse {
  0%   { transform: scale(1);   filter: none; }
  50%  { transform: scale(1.4); filter: drop-shadow(0 0 10px rgba(255, 215, 0, .75)); }
  100% { transform: scale(1);   filter: none; }
}
/* Floating "New streak!" text below the streak line */
body.model-view .mv-levelup {
  position: absolute; top: 100%; left: 50%; transform: translateX(-50%);
  margin-top: 2px; font-size: 13px; color: #FFD700; white-space: nowrap;
  opacity: 0; transition: opacity .4s ease; pointer-events: none;
}
body.model-view .mv-levelup.show { opacity: 1; }
/* Daily-completion sparkle: one shine sweep across today's completed
   squares, only when ALL of today's tasks are done (.all-done set by the
   template from the same data as the Today card) */
body.model-view .tt-week.all-done .tt-sq.tt-complete.today { position: relative; overflow: hidden; }
body.model-view .tt-week.all-done .tt-sq.tt-complete.today::after {
  content: ""; position: absolute; top: 0; left: -75%; width: 50%; height: 100%;
  background: linear-gradient(105deg, transparent, rgba(255, 255, 255, .4), transparent);
  transform: skewX(-20deg);
  animation: mv-shine-sweep 1s ease-out .4s 1 both;
}
@keyframes mv-shine-sweep { to { left: 125%; } }
/* Respect users who opt out of motion */
@media (prefers-reduced-motion: reduce) {
  body.model-view .confetti,
  body.model-view .mv-flame-box.pulse,
  body.model-view .tt-week.all-done .tt-sq.tt-complete.today::after,
  .flame, .ldr-flame-wrap, .ldr-spark {
    animation: none !important;
  }
}

/* ---------------- RANGE HEADER ---------------- */
body.model-view .tt-range {
  flex: 0 0 auto; text-align: center; font-size: 12px; color: #555; margin: 16px 0 8px;
}

/* ---------------- WEEK VIEW ---------------- */
body.model-view .tt-week {
  flex: 0 1 auto; min-height: 0; overflow: hidden;
  width: fit-content; max-width: 700px; margin: 0 auto;
}
body.model-view .tt-row { display: flex; align-items: center; }
body.model-view .tt-label {
  width: 160px; flex: 0 0 160px; display: flex; align-items: center; gap: 8px;
  overflow: hidden; white-space: nowrap;
}
body.model-view .tt-icon { font-size: 22px; line-height: 1; }
body.model-view .tt-name { font-size: 15px; color: #fff; overflow: hidden; text-overflow: ellipsis; }
body.model-view .tt-squares { display: flex; }

/* Day headers aligned over the squares (same 48+3+3 rhythm) */
body.model-view .tt-dayhead-row { margin-bottom: 4px; }
body.model-view .tt-dayhead {
  width: 48px; margin: 0 3px; text-align: center;
  font-size: 12px; color: #444; font-weight: 600;
}

/* The squares (3px margins = 6px gap between neighbors) */
body.model-view .tt-sq {
  width: 48px; height: 48px; border-radius: 10px; margin: 3px;
  box-sizing: border-box; flex: 0 0 auto;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 14px; line-height: 1;
}
/* COMPLETE: category's own color via inline style (beats everything);
   slight brightness lift for the glow feel */
body.model-view .tt-sq.tt-complete { filter: brightness(1.12) saturate(1.05); }
/* State backgrounds !important per spec (mobile-proof). Complete is NOT
   listed here on purpose: an !important rule would override the inline
   category color. Today's border wins via higher specificity below. */
body.model-view .tt-sq.tt-missed { background: #1e1e1e !important; border: 1px solid #2a2a2a; }
/* FUTURE: near-invisible outline only (transparent fill, whisper border) */
body.model-view .tt-sq.tt-future { background: transparent !important; border: 1px solid #1a1a1a; }
/* NOT SCHEDULED: no square at all -- transparent slot preserves grid
   alignment while showing only black space (TickTick-style). */
body.model-view .tt-sq.tt-not_scheduled { background: transparent !important; border: none; }
/* EXCEPTION: 🙏/🚨 emoji centered in empty space, no square background */
body.model-view .tt-sq.tt-exception { background: transparent !important; border: none; }
/* Awaiting admin review: loud amber "?" waiting state (mobile-proof
   !important; today's white border re-wins via its own !important below) */
body.model-view .tt-sq.sq-pending {
  background: #1a1a0a !important;
  border: 2px solid #8B8000 !important;
  color: #8B8000;
}
body.model-view .tt-sq.sq-pending::after { content: "?"; font-size: 14px; opacity: 0.6; }
body.model-view .tt-sq.today { border: 1.5px solid #fff !important; }

/* Daily Plan aggregate row: slight separation + bolder label */
body.model-view .tt-agg-row { margin-bottom: 6px; }
body.model-view .tt-agg-row .tt-name { font-weight: 700; }
/* Daily Plan is binary: complete=green (inline), any incomplete=RED. The red
   must clearly read as "missed day" (per-category rows keep their gray). */
body.model-view .tt-agg-row .tt-sq.tt-missed {
  background: #e05268 !important; border: 1px solid #e05268;
}

/* Clickable category label (week grid) when the category has a Drive link */
body.model-view .tt-label-link {
  display: flex; align-items: center; gap: 8px; min-width: 0;
  color: inherit; text-decoration: none;
}
body.model-view .tt-label-link:hover .tt-name { text-decoration: underline; }

body.model-view .tt-empty { text-align: center; color: #555; font-size: 13px; }

/* ---------------- TODAY'S CARD ---------------- */
body.model-view .td-card {
  flex: 0 0 auto; width: 100%; max-width: 700px; margin: 14px auto 0;
  background: #111; border-radius: 10px; padding: 14px 20px; box-sizing: border-box;
}
body.model-view .td-head {
  font-size: 12px; color: #555; text-transform: uppercase;
  letter-spacing: 1px; margin-bottom: 6px;
}
body.model-view .td-row { display: flex; align-items: center; height: 26px; gap: 8px; }
body.model-view .td-icon { font-size: 16px; line-height: 1; }
body.model-view .td-name { font-size: 14px; color: #fff; }
body.model-view .td-qty { font-size: 14px; color: #666; }
/* Spacer pushes the drive link + status to the right edge of the row */
body.model-view .td-spacer { flex: 1; }
/* Drive link: small, subtle; brightens to white on hover/tap */
body.model-view .td-drive {
  font-size: 14px; line-height: 1; color: #888; text-decoration: none;
  opacity: .8; transition: color .12s ease, opacity .12s ease;
}
body.model-view .td-drive:hover, body.model-view .td-drive:active { color: #fff; opacity: 1; text-decoration: none; }
body.model-view .td-status { font-size: 16px; color: #555; line-height: 1; }
body.model-view .td-status.done { color: #6ec49a; }
body.model-view .td-none { font-size: 12px; color: #555; text-align: center; padding: 4px 0; }

/* ---------------- MINI MONTH: one dot-grid per category ---------------- */
body.model-view .mm-wrap { flex: 0 0 auto; width: 100%; max-width: 700px; margin: 14px auto 0; }
body.model-view .mm-title {
  text-align: center; font-size: 12px; color: #444;
  text-transform: uppercase; letter-spacing: 1px; margin-bottom: 6px;
}
body.model-view .mm-cats { display: flex; gap: 24px; justify-content: center; }
body.model-view .mm-cat { display: flex; flex-direction: column; align-items: center; }
body.model-view .mm-head { display: flex; align-items: center; gap: 4px; margin-bottom: 4px; }
body.model-view .mm-icon { font-size: 16px; line-height: 1; }
body.model-view .mm-name { font-size: 11px; color: #666; }
body.model-view .mm-grid { display: grid; grid-template-columns: repeat(7, 18px); gap: 3px; }
body.model-view .mm-sq {
  width: 18px; height: 18px; border-radius: 4px; background: transparent;
  box-sizing: border-box;
}
body.model-view .mm-sq.mm-missed { background: #1e1e1e !important; }
/* FUTURE: whisper outline only. NOT SCHEDULED: nothing (transparent slot). */
body.model-view .mm-sq.mm-future { background: transparent !important; border: 1px solid #1a1a1a; }
body.model-view .mm-sq.mm-not_scheduled { background: transparent !important; border: none; }
/* EXCEPTION: emoji centered in empty space, no square background */
body.model-view .mm-sq.mm-exception {
  background: transparent !important; border: none;
  display: flex; align-items: center; justify-content: center;
  font-size: 10px; line-height: 1;
}
body.model-view .mm-sq.sq-pending {
  background: #1a1a0a !important;
  border: 2px solid #8B8000;
  color: #8B8000;
  display: flex; align-items: center; justify-content: center;
}
body.model-view .mm-sq.sq-pending::after { content: "?"; font-size: 8px; opacity: 0.6; }
body.model-view .mm-sq.mm-blank { background: transparent; }
body.model-view .mm-sq.today { border: 1px solid #fff; }
/* Month Daily Plan aggregate block: binary green/red (complete green is inline) */
body.model-view .mm-agg .mm-sq.mm-missed { background: #e05268 !important; }

/* ---------------- ANIMATED FLAME (loading screen + hero) ---------------- */
/* Real 🔥 emoji, sized by streak tier via --fs, scaled down for the hero by
   .flame-sm (--k). Guaranteed upright in every browser. The flicker sways it
   gently left-right (small scale + small rotation, NOT a 90° spin); the glow
   is a tier-colored drop-shadow pulse. */
.flame {
  --fs: 48px;
  --k: 1;
  --glow: rgba(255, 160, 60, .55);
  display: inline-block;
  font-size: calc(var(--fs) * var(--k));
  line-height: 1;
  transform-origin: 50% 90%;   /* pivot at the base so it sways like a candle */
  animation: fl-flicker 1.5s ease-in-out infinite,
             fl-glow 2s ease-in-out infinite;
}
.flame-sm { --k: .55; }
/* 0 days: no flame -- just a dim placeholder circle */
.f-dim {
  display: inline-block; width: calc(var(--fs) * var(--k));
  height: calc(var(--fs) * var(--k)); border-radius: 50%;
  background: #1a1a1a; border: 1px solid #2a2a2a;
}

@keyframes fl-flicker {
  0%, 100% { transform: scale(1)   rotate(-2deg); }
  30%      { transform: scale(.97) rotate(1deg); }
  60%      { transform: scale(1.03) rotate(2deg); }
}
@keyframes fl-glow {
  0%, 100% { filter: drop-shadow(0 0 6px  var(--glow)); }
  50%      { filter: drop-shadow(0 0 16px var(--glow)); }
}

/* Tier scaling & glow color (thresholds match STREAK_TIERS) */
.flame-t0  { --fs: 24px; animation: none; }
/* 1-2: tiny, muted, very subtle flicker */
.flame-t1  { --fs: 24px; --glow: rgba(220, 130, 60, .4); opacity: .85;
  animation-duration: 2.4s, 3s; }
/* 3-6: small, warm orange */
.flame-t3  { --fs: 36px; --glow: rgba(255, 150, 60, .5); animation-duration: 1.9s, 2.4s; }
/* 7-13: medium, bright gold/orange */
.flame-t7  { --fs: 48px; --glow: rgba(255, 195, 70, .6); }
/* 14-29: large, deep orange with red edges */
.flame-t14 { --fs: 60px; --glow: rgba(255, 95, 40, .65); }
/* 30-89: intense blue-white glow */
.flame-t30 { --fs: 72px; --glow: rgba(150, 195, 255, .7); }
/* 90-179: purple/blue glow */
.flame-t90 { --fs: 80px; --glow: rgba(170, 125, 255, .75); }
/* 180+: maximum white glow */
.flame-t180 { --fs: 90px; --glow: rgba(255, 255, 255, .85); }

/* ---------------- LOADING SPLASH (Duolingo-style) ---------------- */
#mv-loader {
  position: fixed; inset: 0; z-index: 9999; background: #000;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 16px; transition: opacity .4s ease;
}
#mv-loader.ldr-out { opacity: 0; pointer-events: none; }
/* (.ldr-brand removed in S39 with the "ekko" wordmark on the splash screen.) */
.ldr-flame-wrap {
  position: relative; display: flex; align-items: flex-end; justify-content: center;
  animation: ldr-fadein .3s ease both;
}
.ldr-num { font-size: 48px; font-weight: 700; color: #fff; line-height: 1; }
.ldr-lbl { font-size: 14px; color: #999; }
@keyframes ldr-fadein { from { opacity: 0; } to { opacity: 1; } }
/* Sparkle particles drifting around the flame during the count-up */
.ldr-spark {
  position: absolute; width: 4px; height: 4px; border-radius: 50%;
  background: #ffca7a; opacity: 0; pointer-events: none;
  animation: ldr-spark 1.7s ease-out infinite;
}
.ldr-spark.s1 { left: -12px; bottom: 30%; --sx: -14px; --sy: -30px; animation-delay: .25s; }
.ldr-spark.s2 { right: -10px; bottom: 45%; --sx: 12px; --sy: -26px; animation-delay: .55s; }
.ldr-spark.s3 { left: -18px; bottom: 60%; --sx: -8px; --sy: -34px; animation-delay: .85s; width: 3px; height: 3px; }
.ldr-spark.s4 { right: -16px; bottom: 20%; --sx: 16px; --sy: -24px; animation-delay: .4s; width: 3px; height: 3px; }
.ldr-spark.s5 { left: 50%; top: -8px; --sx: 5px; --sy: -22px; animation-delay: .7s; }
@keyframes ldr-spark {
  0%   { transform: translate(0, 0) scale(1); opacity: 0; }
  25%  { opacity: .95; }
  100% { transform: translate(var(--sx), var(--sy)) scale(.4); opacity: 0; }
}
/* While booting, dashboard children are invisible; removing .mv-boot fades
   them in (.3s). The loader (opaque, on top) is excluded via :not(). */
body.model-view .wrap > * { transition: opacity .3s ease; }
body.model-view.mv-boot .wrap > *:not(#mv-loader) { opacity: 0; }

/* ---------------- MOBILE (<=560px) ---------------- */
@media (max-width: 560px) {
  body.model-view { padding: 14px 12px 8px; }

  body.model-view .mv-pfp { width: 28px; height: 28px; }
  body.model-view .mv-pfp-letter { font-size: 12px; }
  body.model-view .mv-name { font-size: 14px; }
  body.model-view .mv-flame-box { margin-top: 4px; }
  body.model-view .mv-flame-box .flame { --k: .4; }
  body.model-view .mv-streak-num { font-size: 20px; margin-top: 3px; }
  body.model-view .mv-streak-lbl { font-size: 10px; }
  body.model-view .mv-cons { font-size: 11px; margin-top: 2px; }
  body.model-view .mv-cons > span:first-child { font-size: 12px; }
  .ldr-num { font-size: 40px; }
  .ldr-lbl { font-size: 12px; }

  body.model-view .tt-range { margin: 8px 0 4px; }
  body.model-view .tt-week { margin-top: 4px; }

  /* Week view: 28px squares, 100px labels */
  body.model-view .tt-label { width: 100px; flex-basis: 100px; gap: 6px; }
  body.model-view .tt-icon { font-size: 16px; }
  body.model-view .tt-name { font-size: 12px; }
  body.model-view .tt-sq { width: 28px; height: 28px; border-radius: 6px; margin: 2px; font-size: 10px; }
  body.model-view .tt-dayhead { width: 28px; margin: 0 2px; font-size: 9px; }

  /* Today's card */
  body.model-view .td-card { padding: 8px 12px; margin-top: 12px; }
  body.model-view .td-head { font-size: 11px; }
  body.model-view .td-row { height: 20px; }
  body.model-view .td-icon { font-size: 12px; }
  body.model-view .td-name { font-size: 11px; }
  body.model-view .td-qty { font-size: 11px; }
  body.model-view .td-status { font-size: 12px; }

  /* Mini month: stays side by side, just smaller squares */
  body.model-view .mm-wrap { margin-top: 12px; }
  body.model-view .mm-title { font-size: 11px; }
  body.model-view .mm-cats { gap: 12px; }
  body.model-view .mm-icon { font-size: 14px; }
  body.model-view .mm-name { font-size: 9px; }
  body.model-view .mm-grid { grid-template-columns: repeat(7, 10px); gap: 1.5px; }
  body.model-view .mm-sq { width: 10px; height: 10px; }
}

/* Very narrow screens only: stack the 3 month grids vertically */
@media (max-width: 360px) {
  body.model-view .mm-cats { flex-direction: column; gap: 10px; align-items: center; }
}

/* ============================================================= */
/* PRE-LAUNCH PHASE SYSTEM (S25)                                  */
/* ============================================================= */

/* ---- Model-facing pre-launch checklist (/m/<token>) ---- */
body.pre-launch {
  margin: 0; min-height: 100vh; min-height: 100dvh;
  background: #000; color: #e8e8e8;
  padding: 28px 20px 24px;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
}
body.pre-launch .wrap { display: contents; }
.pl-wrap { max-width: 500px; margin: 0 auto; }

/* Hero: every child is its own centered block -- no reliance on flex
   alignment, so the logo/pfp/name can never drift off-center. */
/* Hero stack: BOTH a flex column AND text-align/auto-margins, so the logo,
   PFP, name and badge stay centered no matter which mechanism a browser
   honours first. Nothing here may use float / position:absolute / a one-sided
   offset -- that is what pushed the logo off-centre on mobile. */
.pl-top {
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 100%;
}
/* (.pl-logo / .pl-logo-wrap removed in S38 along with the logo itself --
   the model pages now start at the PFP. The ADMIN hero keeps its .sh-logo.) */
.pl-pfp {
  width: 56px; height: 56px; border-radius: 50%; object-fit: cover;
  display: flex; align-items: center; justify-content: center;
  margin: 0 auto; flex: 0 0 auto;
  float: none; position: static;
}
.pl-pfp-letter {
  font-size: 24px; font-weight: 700; color: #fff;
  background: linear-gradient(135deg, var(--accent), #E85D75);
}
.pl-name {
  font-size: 18px; font-weight: 700; color: #fff;
  text-align: center; width: 100%; margin-top: 6px;
}
.pl-top .pl-badge { margin: 6px auto 0; }
.pl-badge {
  display: inline-block; font-size: 10px; text-transform: uppercase;
  letter-spacing: 2px; color: #E88D67; border: 1px solid #E88D67;
  border-radius: 999px; padding: 3px 12px;
}

.pl-progress { margin-top: 20px; text-align: center; }
.pl-progress-title { font-size: 14px; font-weight: 700; color: #fff; margin-bottom: 10px; }
.pl-bar {
  width: 100%; max-width: 500px; height: 8px; border-radius: 4px;
  background: #1e1e1e; margin: 0 auto; overflow: hidden;
}
/* Animated fill: grows 0% -> --bar-pct on load, then one shimmer sweep.
   The width lives in the --bar-pct custom property (set inline by the
   template) so the animation's `forwards` fill and the base width always
   agree -- and so JS can move the bar later by updating the variable. */
.pl-bar-fill {
  height: 100%; border-radius: 4px;
  position: relative;
  width: var(--bar-pct, 0%);
  background: linear-gradient(90deg, #E88D67, #FFD700);
  transition: width .4s ease;
  animation: bar-fill 1.2s ease-out forwards;
}
@keyframes bar-fill {
  from { width: 0%; }
  to   { width: var(--bar-pct, 0%); }
}
/* Highlight sweep, once, starting as the fill lands. Parked off-screen left
   until the delay elapses (otherwise the band would sit visible at the left
   edge for the first 1.2s), and left off-screen right by `forwards`. */
.pl-bar-fill::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 4px;
  pointer-events: none;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.15), transparent);
  background-size: 200px 100%;
  background-repeat: no-repeat;
  background-position: -200px 0;
  animation: bar-shimmer 1s ease 1.2s forwards;
}
@keyframes bar-shimmer {
  0%   { background-position: -200px 0; }
  100% { background-position: 200px 0; }
}
.pl-progress-text { font-size: 11px; color: #888; margin-top: 6px; }
/* Instruction line: deliberately loud -- this is the one thing she must read. */
.pl-subtitle {
  font-size: 13px; color: #e05268; font-weight: 600;
  text-align: center; margin-top: 8px;
}
/* Target launch date is important info -- bold white, not muted gray. */
.pl-target { font-size: 14px; font-weight: 700; color: #fff; margin-top: 8px; }

/* ---- Checklist cards: [status + item] [guide] [upload here] ---- */
.pl-list { max-width: 500px; margin: 16px auto 0; }
.pl-item {
  display: flex; align-items: center; gap: 10px;
  background: #111; border-radius: 10px; padding: 14px 16px; margin-bottom: 8px;
  border-left: 3px solid transparent;
}
/* Approved items get a green left border on the card */
.pl-item.pl-complete { border-left: 3px solid #2d8a4e; }

/* COLUMN 1 -- status icon + task text (takes the slack) */
.pl-col-main { flex: 1 1 auto; min-width: 0; }
.pl-main-row { display: flex; align-items: center; gap: 12px; }
.pl-status { flex: 0 0 auto; display: inline-flex; align-items: center; }

/* complete: green filled circle + white check.
   NOTE: still used by the ONBOARDING page (onboarding.html). The pre-launch
   page uses .task-circle.state-complete instead -- see below. */
.pl-check {
  width: 28px; height: 28px; border-radius: 50%; flex: 0 0 auto;
  display: inline-flex; align-items: center; justify-content: center;
  background: #2d8a4e; border: none; color: #fff; font-size: 15px; font-weight: 700;
}

/* ===================================================================== */
/* THE SINGLE TASK CIRCLE (S35)                                          */
/* Exactly ONE .task-circle per pre-launch task row. Always 28px, always  */
/* in the same slot to the left of the task name. It MORPHS between five  */
/* states -- there is deliberately no second checkbox, ring or spinner    */
/* anywhere on the row, so the circle never shifts position.             */
/* ===================================================================== */
.task-circle {
  width: 28px; height: 28px; border-radius: 50%;
  flex: 0 0 auto; padding: 0; box-sizing: border-box;
  display: inline-flex; align-items: center; justify-content: center;
  background: transparent; border: 2px solid transparent;
  /* The morph between states */
  transition: all 0.3s ease;
}

/* STATE 1 -- EMPTY: outline only, tappable */
.task-circle.state-empty {
  border: 2px solid #444;
  background: transparent;
  cursor: pointer;
}
.task-circle.state-empty:hover, .task-circle.state-empty:focus-visible {
  border-color: #E88D67; box-shadow: 0 0 0 3px rgba(232, 141, 103, .15); outline: none;
}

/* STATE 2 -- IN PROGRESS: the circle IS the SVG ring, tappable */
.task-circle.state-progress {
  border-color: transparent;
  cursor: pointer;
}
.task-circle.state-progress:hover, .task-circle.state-progress:focus-visible {
  box-shadow: 0 0 0 3px rgba(76, 175, 80, .18); outline: none;
}
.tc-ring { display: block; width: 28px; height: 28px; }
.tc-ring-track { fill: none; stroke: #333; stroke-width: 2.5; }
.tc-ring-fill {
  fill: none; stroke: #4CAF50; stroke-width: 2.5; stroke-linecap: round;
  /* dashoffset counts DOWN from the circumference as the ring fills */
  transition: stroke-dashoffset .3s ease;
}

/* STATE 3 -- PENDING REVIEW: the circle IS the coral spinner. Still tappable
   since S42 -- the tap opens the undo confirmation. */
.task-circle.state-pending { border-color: transparent; cursor: pointer; }
.task-circle.state-pending:hover, .task-circle.state-pending:focus-visible {
  box-shadow: 0 0 0 3px rgba(232, 141, 103, .18); outline: none;
}

/* STATE 4 -- COMPLETE: solid green circle + white check, inert */
.task-circle.state-complete {
  background: #2d8a4e; border-color: #2d8a4e; cursor: default;
}
.tc-check { color: #fff; font-size: 14px; font-weight: 700; line-height: 1; }

/* STATE 5 -- LOCKED: sequential unlock, inert. (Not one of the four content
   states -- it simply replaces them until the previous task is submitted.) */
.task-circle.state-locked { border-color: transparent; cursor: default; }
.tc-lock { font-size: 16px; line-height: 1; }

@media (prefers-reduced-motion: reduce) {
  .task-circle, .tc-ring-fill { transition: none; }
}

/* Task text -- long names wrap inside column 1, never truncate */
.pl-task-wrap {
  display: flex; align-items: center; gap: 8px; min-width: 0; flex-wrap: wrap;
}
.pl-task {
  font-size: 14px; color: #fff; min-width: 0;
  word-wrap: break-word; overflow-wrap: break-word; word-break: break-word;
}
/* Task names are printed verbatim -- the quantity is part of the name itself
   ("4x Sexting Content"), so nothing is ever prefixed. The old struck-prefix
   rules (.pl-qty-orig / .pl-qty-left) are gone with the markup that used them.
   Only a fully approved item gets struck through. */
.pl-task .pl-struck { color: #666; text-decoration: line-through; }
/* Sub-line under the name: "2/4 complete · Pending review" */
.pl-pending-note { font-size: 10px; color: #888; margin-top: 3px; padding-left: 40px; }

/* (The progress ring lives on .task-circle.state-progress -- see above.) */

/* ---- Task cards: 3-column grid [item | guide | upload here] ----
   Scoped to .pl-task-item so the onboarding rows (single column) keep the
   plain flex layout. The column widths here MUST match .pl-head-row. */
.pl-item.pl-task-item {
  display: grid;
  /* Guide/upload tracks are sized to the WIDEST label ("📋 Coming soon" /
     "📁 Link pending") at the button's padding, so nothing ever overflows. */
  grid-template-columns: 1fr 108px 118px;
  align-items: center;
  gap: 8px;
}
/* Column headers -- rendered once, above the first card only. */
.pl-head-row {
  display: grid;
  grid-template-columns: 1fr 108px 118px;
  gap: 8px;
  max-width: 500px;
  margin: 16px auto 4px;
  padding: 0 16px 0 19px;      /* 16px card padding + 3px left border */
  font-size: 10px; color: #fff; font-weight: 700;
  text-transform: uppercase; letter-spacing: .5px;
}
.pl-head-guide  { text-align: center; }
.pl-head-upload { text-align: right; }

/* COLUMN 2 -- guide.  COLUMN 3 -- upload here.
   Both render as real, tappable-looking buttons. The ACTIVE (link is set) state
   is green-tinted so it reads as "go here next"; the INACTIVE state keeps the
   same button silhouette in near-black, so the column never looks empty and the
   two states line up pixel-for-pixel. */
.pl-col-guide  { text-align: center; min-width: 0; }
.pl-col-upload { text-align: right;  min-width: 0; }
.pl-btn-link {
  background: #1a2a1a;
  border: 1.5px solid #3d7a4a;
  border-radius: 8px;
  padding: 8px 12px;
  color: #8eca8e;
  font-weight: 600;
  font-size: 12px;
  cursor: pointer;
  transition: all 0.15s ease;
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  /* Never let a button spill out of its fixed grid track. */
  white-space: nowrap; box-sizing: border-box; max-width: 100%;
}
.pl-btn-link:hover, .pl-btn-link:focus-visible {
  background: #243824;
  border-color: #5aad5a;
  color: #a8e8a8;
  text-decoration: none;
}
.pl-dim {
  background: #141414;
  border: 1.5px solid #2a2a2a;
  border-radius: 8px;
  padding: 8px 12px;
  color: #444;
  font-size: 11px;
  cursor: default;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  white-space: nowrap; box-sizing: border-box; max-width: 100%;
  user-select: none;
}
/* Safety net: the tracks above are sized off estimated text widths, so if a
   device font runs wider the label ellipsises inside its own button instead of
   bleeding across into the neighbouring column. */
.pl-btn-link .pl-btn-txt, .pl-dim .pl-btn-txt {
  min-width: 0; overflow: hidden; text-overflow: ellipsis;
}

/* ---- Pending-review indicator ----
   Eight rounded coral bars (3x10px, radius 2) set 45 degrees apart around a
   28px box, fading clockwise 1.0 -> .15. Drawn as an inline SVG background so
   a bare <span class="spinner-review"></span> still works with no children --
   the existing markup (and the JS that re-injects it) is untouched.
   .spinner-review ROTATES continuously; .spinner-static is the same graphic
   held still (kept as an alias -- no template currently uses it). */
.spinner-review,
.spinner-static {
  width: 28px;
  height: 28px;
  position: relative;
  display: inline-block;
  flex: 0 0 auto;
  background-repeat: no-repeat;
  background-position: center;
  background-size: 28px 28px;
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 28 28'%3E%3Cg fill='%23E88D67'%3E%3Crect x='12.5' y='1.5' width='3' height='10' rx='1.5' opacity='1'/%3E%3Crect x='12.5' y='1.5' width='3' height='10' rx='1.5' opacity='.85' transform='rotate(45 14 14)'/%3E%3Crect x='12.5' y='1.5' width='3' height='10' rx='1.5' opacity='.7' transform='rotate(90 14 14)'/%3E%3Crect x='12.5' y='1.5' width='3' height='10' rx='1.5' opacity='.55' transform='rotate(135 14 14)'/%3E%3Crect x='12.5' y='1.5' width='3' height='10' rx='1.5' opacity='.4' transform='rotate(180 14 14)'/%3E%3Crect x='12.5' y='1.5' width='3' height='10' rx='1.5' opacity='.3' transform='rotate(225 14 14)'/%3E%3Crect x='12.5' y='1.5' width='3' height='10' rx='1.5' opacity='.2' transform='rotate(270 14 14)'/%3E%3Crect x='12.5' y='1.5' width='3' height='10' rx='1.5' opacity='.15' transform='rotate(315 14 14)'/%3E%3C/g%3E%3C/svg%3E");
}
/* Kill the old animated ring pseudo-element wherever it may still match. */
.spinner-review::before,
.spinner-static::before { content: none; }

/* Continuous rotation of the coral dashes (the graphic itself is unchanged). */
@keyframes spin {
  to { transform: rotate(360deg); }
}
.spinner-review { animation: spin 3s linear infinite; }
.spinner-static { animation: none; }

/* ---- Self-report modal (S36) ----
   A centered, full-viewport overlay -- replaces the cramped in-card popup.
   One modal for the page; the JS fills in the task name and input cap on open. */
.tc-modal {
  position: fixed; inset: 0; z-index: 9999;
  background: rgba(0, 0, 0, 0.85);
  display: flex; align-items: center; justify-content: center;
  padding: 20px;
  /* Keep touch scrolling from leaking to the page behind the overlay. The
     picker re-enables vertical panning for itself via touch-action: pan-y. */
  overscroll-behavior: contain;
  touch-action: none;
}
.tc-modal[hidden] { display: none; }
.tc-modal-box {
  background: #1a1a1a;
  border: 1px solid #333;
  border-radius: 16px;
  padding: 28px 32px;
  max-width: 320px;
  width: 90vw;
  text-align: center;
  animation: tc-modal-in .18s ease both;
}
@keyframes tc-modal-in {
  from { opacity: 0; transform: scale(.96); }
  to   { opacity: 1; transform: scale(1); }
}
.tc-modal-task {
  font-size: 15px; font-weight: 700; color: #fff; margin-bottom: 16px;
  word-wrap: break-word; overflow-wrap: break-word;
}
.tc-modal-q { font-size: 13px; color: #999; margin-bottom: 14px; }
/* Vertical scroll picker (iOS / TickTick style) -- replaces the +/- stepper.
   No input element, so a phone never raises a keyboard; the value is read back
   from scroll position by getPickerValue(). */
.picker-wrap {
  position: relative;
  height: 150px;
  width: 80px;
  margin: 8px auto 20px auto;
  overflow: hidden;
}
/* The fixed selection frame the numbers scroll through. */
.picker-window {
  position: absolute;
  top: 50%;
  left: 0;
  right: 0;
  height: 48px;
  transform: translateY(-50%);
  border-top: 1.5px solid #444;
  border-bottom: 1.5px solid #444;
  pointer-events: none;
  z-index: 2;
}
.picker-scroll {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  overflow-y: scroll;
  height: 100%;
  /* `proximity`, not `mandatory`: mandatory fights every small drag and makes
     the wheel feel stiff. Proximity lets it coast and only snaps near a row. */
  scroll-snap-type: y proximity;
  scroll-behavior: smooth;
  overscroll-behavior: contain;
  /* Overrides the overlay's touch-action:none so the wheel still pans. */
  touch-action: pan-y;
  -webkit-overflow-scrolling: touch;
  /* (150 - 48) / 2 -- lets row 1 and the last row both reach dead centre.
     MUST stay in step with PICKER_PAD in pre_launch.html. */
  padding: 51px 0;
  scrollbar-width: none;
}
.picker-scroll::-webkit-scrollbar { display: none; }

.picker-item {
  height: 48px;
  min-height: 48px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 28px;
  font-weight: 700;
  color: #333;
  scroll-snap-align: center;
  transition: color 0.15s, transform 0.15s;
  user-select: none;
  cursor: pointer;
}
.picker-item.active {
  color: #fff;
  transform: scale(1.1);
}
@media (prefers-reduced-motion: reduce) {
  .picker-item { transition: none; }
  .picker-scroll { scroll-behavior: auto; }
}
/* Sits between the input and the button; display:none when hidden, so it
   costs no vertical space in the normal (no-error) layout. */
.tc-modal-err { font-size: 12px; color: #e05268; margin: -6px 0 14px; }
.tc-modal-err[hidden] { display: none; }
.tc-modal-submit {
  width: 100%; padding: 14px;
  background: linear-gradient(135deg, #0d9b4a, #2ecc71);
  border: none; border-radius: 10px;
  color: #fff; font-size: 15px; font-weight: 600;
  cursor: pointer; font-family: inherit;
  transition: all 0.15s ease;
}
.tc-modal-submit:hover {
  background: linear-gradient(135deg, #10b856, #3ddb85);
}
.tc-modal-submit:disabled { opacity: .6; cursor: default; }
.tc-modal-cancel {
  display: block; margin: 10px auto 0;
  background: none; border: none; padding: 0;
  font-size: 12px; color: #666; cursor: pointer; font-family: inherit;
  transition: color 0.15s ease;
}
.tc-modal-cancel:hover { color: #999; }

/* ---- Undo confirmation (S42), mode B of the same overlay ---- */
.tc-undo-text { font-size: 14px; color: #999; margin-bottom: 18px; }
/* Only shown for a PARTIALLY submitted task, where "add more" is still a
   sensible action -- see the handoff note. */
.tc-undo-more {
  display: block; width: 100%; margin: 0 auto 14px;
  padding: 11px 16px; border-radius: 10px;
  background: #111; border: 1px solid #333; color: #aaa;
  font-size: 13px; font-weight: 600; cursor: pointer; font-family: inherit;
  transition: all 0.15s ease;
}
.tc-undo-more:hover { border-color: #3d7a4a; color: #8eca8e; }
.tc-undo-actions {
  display: flex; gap: 10px; align-items: center; justify-content: center;
}
.tc-undo-btn, .tc-keep-btn {
  flex: 1 1 0; padding: 12px 24px; border-radius: 10px;
  font-size: 14px; font-weight: 600; cursor: pointer; font-family: inherit;
  transition: all 0.15s ease;
}
.tc-undo-btn { background: #3d1424; border: 1px solid #7d2a4a; color: #e88; }
.tc-undo-btn:hover { background: #4d1a2e; border-color: #9d3a5e; }
.tc-undo-btn:disabled { opacity: .6; cursor: default; }
.tc-keep-btn { background: #1a2a1a; border: 1px solid #3d7a4a; color: #8eca8e; }
.tc-keep-btn:hover { background: #243824; border-color: #5aad5a; }
#tc-undo-err { margin: 14px 0 0; }

@media (prefers-reduced-motion: reduce) { .tc-modal-box { animation: none; } }

/* Phones: keep all three columns, tighten them, and drop the button labels
   down to just the emoji so nothing wraps or overflows at 375px. */
@media (max-width: 560px) {
  .pl-item { gap: 6px; padding: 12px 12px; }
  .pl-item.pl-task-item { grid-template-columns: 1fr 92px 100px; gap: 6px; }
  .pl-head-row {
    grid-template-columns: 1fr 92px 100px; gap: 6px;
    padding: 0 12px 0 15px; font-size: 9px;
  }
  .pl-main-row { gap: 8px; }
  /* Keep most of the button height on phones -- it is the tap target. */
  .pl-btn-link { padding: 7px 9px; font-size: 10px; }
  .pl-dim { padding: 7px 9px; font-size: 9px; }
  .pl-pending-note, .pl-lock-note { padding-left: 36px; }
}
/* Very narrow phones: labels off, emoji only (the title attr keeps meaning). */
@media (max-width: 420px) {
  .pl-btn-txt { display: none; }
  .pl-btn-link, .pl-dim { gap: 0; }
  .pl-item.pl-task-item { grid-template-columns: 1fr 46px 52px; }
  .pl-head-row { grid-template-columns: 1fr 46px 52px; }
}

.pl-bottom { text-align: center; margin-top: 18px; }
.pl-ready { font-size: 16px; font-weight: 700; color: #FFD700; animation: pl-pulse 1.6s ease-in-out infinite; }
.pl-remaining { font-size: 13px; color: #888; }
.pl-remaining .pl-cash { font-weight: 700; color: #bbb; }
@keyframes pl-pulse { 0%, 100% { opacity: 1; } 50% { opacity: .55; } }

/* ---- Launch button (locked / unlocked) ---- */
.launch-btn {
  width: 100%; max-width: 500px; padding: 16px; border-radius: 12px;
  margin: 20px auto; display: block; box-sizing: border-box; font-family: inherit;
  text-align: center; line-height: 1.2;
}
.launch-btn.locked {
  background: #1e1e1e; border: 1px solid #333; color: #666;
  cursor: not-allowed; font-size: 14px;
}
.launch-btn.unlocked {
  background: linear-gradient(135deg, #2d8a4e, #34a853); border: none; color: white;
  cursor: pointer; font-weight: bold; font-size: 16px;
  animation: pulse-glow 2s ease-in-out infinite;
}
.launch-btn.unlocked:hover { filter: brightness(1.1); }
@keyframes pulse-glow {
  0%, 100% { transform: scale(1);    box-shadow: 0 0 10px rgba(52, 168, 83, 0.3); }
  50%      { transform: scale(1.02); box-shadow: 0 0 20px rgba(52, 168, 83, 0.5); }
}

/* ---- Launch fireworks overlay (built inline by showFireworks()) ---- */
@keyframes scaleUp { from { transform: scale(0); } 50% { transform: scale(1.2); } to { transform: scale(1); } }
@keyframes fadeIn { to { opacity: 1; } }

@media (prefers-reduced-motion: reduce) {
  .pl-ready, .launch-btn.unlocked { animation: none !important; }
  /* Bar jumps straight to its real width (base `width: var(--bar-pct)`
     still applies) and the shimmer stays parked off-screen. */
  .pl-bar-fill, .pl-bar-fill::after { animation: none !important; }
}

/* ---- Admin: phase badges (models manage + dashboard) ---- */
.phase-badge {
  display: inline-block; font-size: 10px; text-transform: uppercase;
  letter-spacing: 1px; border-radius: 999px; padding: 2px 10px; font-weight: 700;
}
.phase-badge.prelaunch { color: #E88D67; border: 1px solid #E88D67; }
.phase-badge.launched { color: #6ec49a; border: 1px solid #1a6b40; background: #0d3320; }
.phase-count { font-size: 12px; color: var(--muted); margin-left: 6px; font-weight: 700; }
.ms-pre {
  font-size: 11px; font-weight: 700; letter-spacing: .5px;
  color: #E88D67; border: 1px solid #E88D67; border-radius: 999px; padding: 1px 8px;
}
.ms-pre:hover { text-decoration: none; background: rgba(232, 141, 103, .12); }

/* ---- Admin: pre-launch checklist management page ---- */
.pla-head { display: flex; align-items: center; gap: 12px; margin: 14px 0 18px; }
.pla-pfp {
  width: 48px; height: 48px; border-radius: 50%; object-fit: cover; flex: 0 0 auto;
  display: inline-flex; align-items: center; justify-content: center;
}
.pla-pfp-letter {
  font-size: 20px; font-weight: 700; color: #fff;
  background: linear-gradient(135deg, var(--accent), #E85D75);
}
.pla-name { font-size: 20px; font-weight: 800; color: #fff; }
.pla-badge {
  display: inline-block; font-size: 10px; text-transform: uppercase; letter-spacing: 1px;
  color: #E88D67; border: 1px solid #E88D67; border-radius: 999px; padding: 2px 10px;
}
.pla-progress { font-size: 13px; color: var(--muted); margin-left: 8px; }

.pla-list { display: flex; flex-direction: column; gap: 10px; }
.pla-item {
  display: flex; align-items: flex-start; gap: 14px;
  background: var(--card); border: 1px solid var(--border);
  border-radius: 12px; padding: 14px 16px; border-left: 3px solid transparent;
}
.pla-item.done, .pla-item.pla-complete { border-left: 3px solid #2d8a4e; }
.pla-item.pla-pending_review { border-left: 3px solid #E88D67; }
/* Partially submitted -- the model is still working through the quantity. */
.pla-item.pla-in_progress { border-left: 3px solid #4CAF50; }
.pla-state { flex: 0 0 auto; padding-top: 2px; display: inline-flex; }
.pla-icon-check {
  width: 28px; height: 28px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  background: #2d8a4e; color: #fff; font-size: 15px; font-weight: 700;
}
.pla-icon-empty {
  width: 28px; height: 28px; border-radius: 50%;
  display: inline-block; border: 2px solid #444;
}
.pla-body { flex: 1; min-width: 0; }
.pla-task {
  font-weight: 600; font-size: 15px; color: var(--text); margin-bottom: 8px;
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  word-wrap: break-word; overflow-wrap: break-word;
}
.pla-item.done .pla-task, .pla-item.pla-complete .pla-task { color: var(--muted); }
.pla-qty { font-weight: 400; font-size: 13px; color: var(--muted); }
.pla-review-badge {
  font-size: 10px; text-transform: uppercase; letter-spacing: 1px; font-weight: 700;
  color: #E88D67; border: 1px solid #E88D67; border-radius: 999px; padding: 1px 8px;
}
.pla-done-badge {
  font-size: 10px; text-transform: uppercase; letter-spacing: 1px; font-weight: 700;
  color: #6ec49a; border: 1px solid #1a6b40; background: #0d3320;
  border-radius: 999px; padding: 1px 8px;
}
.pla-progress-badge {
  font-size: 10px; text-transform: uppercase; letter-spacing: 1px; font-weight: 700;
  color: #8eca8e; border: 1px solid #3d7a4a; border-radius: 999px; padding: 1px 8px;
}
.pla-fields { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.pla-drive { flex: 1 1 220px; min-width: 160px; }
.pla-guide { flex: 1 1 180px; min-width: 140px; }
.pla-notes { flex: 1 1 180px; min-width: 140px; }
.pla-actions { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; margin-top: 10px; }
.btn.pla-approve { background: #2d8a4e; }
.pla-qty-set { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; color: var(--muted); margin: 0; }
.pla-qty-input { width: 64px; padding: 5px 8px; font-size: 13px; }

.pla-launch-row { display: flex; align-items: center; margin-top: 22px; flex-wrap: wrap; }
.btn.pla-launch { background: linear-gradient(135deg, #E88D67, #FFD700); color: #111; }
.btn.pla-launch:disabled { background: #222; color: #555; cursor: not-allowed; opacity: 1; }

/* ============================================================= */
/* THREE-PHASE MODEL SYSTEM (S31)                                 */
/* onboarding -> pre_launch -> launched                           */
/* ============================================================= */

/* ---- Model-facing onboarding page (reuses the .pl-* shell) ---- */
.pl-badge-onboarding { color: #4A90D9; border-color: #4A90D9; }
.ob-bar-fill { background: linear-gradient(90deg, #4A90D9, #7FC1FF); }
/* Read-only status marker: the model cannot tick these off herself. */
.ob-circle {
  width: 28px; height: 28px; border-radius: 50%; flex: 0 0 auto;
  display: inline-block; background: transparent; border: 2px solid #444;
}
.ob-item { cursor: default; }
/* Onboarding's "all done" button is a STATUS, not an action: the admin
   advances the phase, so it stays disabled and never pulses (unlike the
   pre-launch launch button, which the model herself clicks). */
body.onboarding .launch-btn.unlocked {
  background: #1a3d2a;
  border: 1px solid #2d8a4e;
  color: #6ec49a;
  font-size: 14px;
  font-weight: 700;
  cursor: default;
  animation: none;
  transform: none;
  box-shadow: none;
}
body.onboarding .launch-btn.unlocked:hover { filter: none; }

/* ---- Pre-launch: section headers + locked tasks + reference rows ---- */
.pl-section-head {
  max-width: 500px; margin: 22px auto 8px; font-size: 11px; color: #666;
  text-transform: uppercase; letter-spacing: 2px; font-weight: 700;
}
/* Locked = the previous task isn't approved yet. Dimmed, and the ITEM column
   is inert (nothing to tap). The guide/upload columns stay live on purpose --
   she should be able to read ahead even before the task opens up. */
.pl-item.pl-locked { opacity: .4; }
.pl-item.pl-locked .pl-col-main { pointer-events: none; }
/* (The padlock is .task-circle.state-locked -- see the task-circle block.) */
.pl-lock-note { font-size: 10px; color: #888; margin-top: 3px; padding-left: 40px; }

/* Guide / upload reference cards: one full-width tappable row each. */
.pl-item.pl-ref { gap: 10px; align-items: center; }
.pl-ref-icon { font-size: 15px; line-height: 1; flex: 0 0 auto; }
.pl-ref-name {
  font-size: 13px; color: #ddd; text-decoration: none; flex: 1 1 auto; min-width: 0;
  word-wrap: break-word; overflow-wrap: break-word;
}
a.pl-ref-name:hover { color: #fff; text-decoration: underline; }
a.pl-ref-name.pl-ref-btn {
  background: #1e1e1e; border: 1px solid #333; border-radius: 6px;
  padding: 7px 12px; flex: 0 1 auto; text-align: left;
}
a.pl-ref-name.pl-ref-btn:hover { text-decoration: none; filter: brightness(1.4); }
.pl-ref-off { color: #666; }
.pl-ref-note { flex: 0 0 auto; margin-left: auto; color: #555; }

/* ---- Launched view: persistent Resources block ---- */
body.model-view .rs-wrap {
  flex: 0 0 auto; width: 100%; max-width: 700px; margin: 18px auto 0;
  background: #0a0a0a; border-radius: 8px; padding: 10px; box-sizing: border-box;
}
body.model-view .rs-title {
  font-size: 11px; color: #555; text-transform: uppercase;
  letter-spacing: 1px; margin-bottom: 6px;
}
body.model-view .rs-cols { display: flex; gap: 24px; flex-wrap: wrap; }
body.model-view .rs-col { flex: 1 1 220px; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
body.model-view .rs-head { font-size: 10px; color: #444; text-transform: uppercase; letter-spacing: 1px; }
body.model-view .rs-link {
  font-size: 12px; color: #888; text-decoration: none;
  transition: color .12s ease; word-wrap: break-word; overflow-wrap: break-word;
}
body.model-view a.rs-link:hover { color: #fff; text-decoration: none; }
body.model-view .rs-link.rs-off { color: #3a3a3a; }
@media (max-width: 560px) {
  body.model-view .rs-wrap { margin-top: 12px; }
  body.model-view .rs-cols { gap: 10px; }
  body.model-view .rs-link { font-size: 11px; }
}

/* ---- Admin: phase tabs ---- */
.ph-tabs {
  display: flex; gap: 4px; flex-wrap: wrap; margin: 10px 0 16px;
  border-bottom: 1px solid var(--border); padding-bottom: 0;
}
.ph-tab {
  display: inline-block; padding: 7px 16px; font-size: 13px; font-weight: 600;
  color: var(--muted); text-decoration: none;
  border: 1px solid transparent; border-bottom: none;
  border-radius: 8px 8px 0 0; margin-bottom: -1px;
}
a.ph-tab:hover { color: var(--text); text-decoration: none; background: #111; }
.ph-tab.current {
  color: #fff; background: var(--card);
  border-color: var(--border); border-bottom: 1px solid var(--card);
}
.ph-tab.future { color: #3a3a3a; cursor: default; }

/* ---- Admin: onboarding page ---- */
.ob-head { font-size: 15px; margin: 22px 0 10px; color: var(--text); }
.ob-head-note { font-size: 12px; font-weight: 400; color: var(--muted); }
.ob-list { display: flex; flex-direction: column; gap: 6px; }
.ob-row {
  display: flex; align-items: center; gap: 12px; width: 100%; text-align: left;
  background: var(--card); border: 1px solid var(--border); border-radius: 10px;
  padding: 10px 14px; cursor: pointer; color: var(--text);
  font-size: 14px; font-family: inherit; border-left: 3px solid transparent;
}
.ob-row:hover { border-color: #3a3a3a; }
.ob-row.done { border-left: 3px solid #2d8a4e; }
.ob-row.done .ob-name { color: var(--muted); text-decoration: line-through; }
.ob-box {
  width: 22px; height: 22px; flex: 0 0 auto; border-radius: 6px;
  border: 2px solid #444; display: inline-flex; align-items: center;
  justify-content: center; font-size: 13px; font-weight: 700; color: #fff;
}
.ob-row.done .ob-box { background: #2d8a4e; border-color: #2d8a4e; }
.ob-name { flex: 1; min-width: 0; }

.ob-form { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 14px; }
.ob-form input[type=text], .ob-form select, .ob-form textarea { width: 100%; }
.ob-form-wide { grid-column: 1 / -1; }

.pla-badge-onboarding { color: #4A90D9; border-color: #4A90D9; }
.pla-badge-brand { color: #C77DFF; border-color: #C77DFF; margin-left: 6px; }

/* ---- Admin: locked task + global reference rows on the pre-launch page ---- */
.pla-item.pla-locked { opacity: .65; }
.pla-lock-badge {
  font-size: 10px; text-transform: uppercase; letter-spacing: 1px; font-weight: 700;
  color: #888; border: 1px solid #444; border-radius: 999px; padding: 1px 8px;
}
.pla-ref-icon { font-size: 18px; line-height: 1; width: 28px; text-align: center; }
.pla-ref-input { flex: 1 1 320px; min-width: 200px; }

/* ---- Admin: Generate App ---- */
.mc-box { max-width: 620px; }
.mc-form { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 14px; }
.mc-form input[type=text], .mc-form input[type=date], .mc-form select { width: 100%; }
.mc-req { color: #E85D75; }
.mc-actions { grid-column: 1 / -1; margin-top: 4px; }
.btn.mc-generate {
  background: linear-gradient(135deg, #2d8a4e, #34a853); color: #fff;
  font-size: 16px; font-weight: 700; padding: 14px 28px; border-radius: 12px;
}
.btn.mc-generate:hover { filter: brightness(1.1); text-decoration: none; }

.mc-done { max-width: 620px; text-align: center; }
.mc-done-icon { font-size: 42px; line-height: 1; }
.mc-done-title { font-size: 22px; font-weight: 800; color: #fff; margin-top: 8px; }
.mc-done-brand {
  display: inline-block; margin-top: 6px; font-size: 10px; font-weight: 700;
  text-transform: uppercase; letter-spacing: 2px; color: #C77DFF;
  border: 1px solid #C77DFF; border-radius: 999px; padding: 2px 10px;
}
.mc-url-label {
  font-size: 11px; color: var(--muted); text-transform: uppercase;
  letter-spacing: 1px; margin: 20px 0 6px;
}
.mc-url-row { display: flex; gap: 8px; align-items: center; justify-content: center; flex-wrap: wrap; }
.mc-url { flex: 1 1 320px; min-width: 220px; font-size: 13px; text-align: center; }
.mc-done-actions { display: flex; gap: 10px; justify-content: center; flex-wrap: wrap; margin-top: 22px; }

/* ---- Admin: dashboard + manage-page phase badges ---- */
.phase-badge.onboarding { color: #4A90D9; border: 1px solid #4A90D9; }
.ms-pre.ms-onb { color: #4A90D9; border-color: #4A90D9; }
.ms-pre.ms-onb:hover { background: rgba(74, 144, 217, .12); }
.ms-launched {
  font-size: 11px; font-weight: 700; letter-spacing: .5px;
  color: #6ec49a; border: 1px solid #1a6b40; background: #0d3320;
  border-radius: 999px; padding: 1px 8px;
}
