/* ═══════════════════════════════════════════════════════════════════════════
   css/dashboard.css — the artist's one page (pivot, 8 Sep 2026; restyled
   9 Sep). Square's structure, not Square's CSS: card barely lighter than the
   page, contrast in the text, hairlines not tones, label-left rows, inset
   fields (--inset), 6 / 12 / 16 radii. Tokens from tokens.css, re-pointed by
   saas-skin.css which loads last. Nothing here is imported from Square.
   ═══════════════════════════════════════════════════════════════════════════ */
/* the page: full viewport width on desktop (9 Sep, third pass — the 1320px
   cap below is gone). It existed to keep the cards from spanning an entire
   1440px+ screen, but it also capped .db-main at 720px regardless of how
   much room there was, which is what actually starved the request-answers
   grid down to an unreadable column (css/requests.css .rq-answers has the
   full account of that). Cards, grids and lists are meant to use the
   space now; only running prose gets its own measure, at the paragraph
   (max-width:68ch on .db-note etc.), not the page. */
.db{padding:28px clamp(20px,3vw,56px) 80px}
/* the side column's ceiling is deliberately modest: fit() already scales
   the phone/tablet mockup to whatever width this gives it, so growing
   past what a phone mockup plus its bezel needs doesn't make the preview
   more useful — it only takes width directly from .db-main, which is
   what was starving the request-answers grid even after this got its own
   full-width column (css/requests.css .rq-answers has the account). */
.db-cols{display:grid;grid-template-columns:minmax(0,1fr) minmax(320px,440px);gap:0 32px;align-items:start}
.db-main{min-width:0;order:1}
.db-side{order:2;position:sticky;top:20px;min-width:0}
/* a short window (a 768px laptop): the pane is not pinned, so fit() sizes
   the device by width alone and the page scrolls to its bottom — better a
   phone you can read than a phone that fits under the fold */
@media(max-height:900px){.db-side{position:static}}
.db-top{display:flex;align-items:center;justify-content:space-between;gap:16px;margin-bottom:24px;position:relative;z-index:50}
.db-brand{font:400 26px/1 'Anton','Helvetica Neue',Arial,sans-serif;text-decoration:none;color:inherit}
.db-brand b{color:var(--red)}
.db-top-right{display:flex;align-items:center;gap:10px}

/* ── the light/dark toggle: same sun/moon mechanism as builder.css, its own
   small icon button so it stays visible without opening the menu ── */
.db-theme-toggle{width:38px;height:38px;flex:none;border:1px solid var(--line);border-radius:50%;background:var(--inset,#fff);
  cursor:pointer;display:grid;place-items:center;color:var(--dim);transition:border-color .15s,color .15s}
.db-theme-toggle:hover{border-color:var(--paper);color:var(--paper)}
.db-theme-toggle svg{width:18px;height:18px;fill:none;stroke:currentColor;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round}
.db-theme-toggle .ico-sun{display:none}
html[data-ui-theme="dark"] .db-theme-toggle .ico-moon{display:none}
html[data-ui-theme="dark"] .db-theme-toggle .ico-sun{display:block}

/* ── the bell: unread requests the way every social app's top corner does
   it — a red count on the icon, the icon itself red, a dropdown that says
   who. Fed by requests.js watchBadge(), the same count the tab title
   carries. 30 Sep 2026. ── */
.db-bell-wrap{position:relative;flex:none}
.db-bell{width:38px;height:38px;border:1px solid var(--line);border-radius:50%;background:var(--inset,#fff);cursor:pointer;
  display:grid;place-items:center;color:var(--dim);position:relative;padding:0;transition:border-color .15s,color .15s}
.db-bell svg{width:18px;height:18px;fill:none;stroke:currentColor;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round}
.db-bell:hover,.db-bell[aria-expanded="true"]{border-color:var(--paper);color:var(--paper)}
.db-bell.has{border-color:var(--red);color:var(--red)}
.db-bell.has svg{stroke-width:2}
.db-bell-n{position:absolute;top:-6px;right:-6px;min-width:20px;height:20px;padding:0 6px;border-radius:999px;background:var(--red);color:#fff;
  font:700 .68rem/20px var(--mn);font-style:normal;letter-spacing:0;text-align:center;box-shadow:0 0 0 2px var(--ink)}
.db-bell-n[hidden]{display:none}
html[data-ui-theme="dark"] .db-bell-n{color:#141210}
.db-bell-menu{position:absolute;top:calc(100% + 10px);right:0;width:320px;max-width:calc(100vw - 40px);background:var(--card,var(--ink2));
  border:1px solid var(--line);border-radius:var(--radius-lg,16px);box-shadow:var(--shadow-2,0 16px 44px rgba(20,18,16,.16));overflow:hidden;z-index:60}
.db-bell-menu[hidden]{display:none}
.db-bell-head{margin:0;padding:12px 14px;border-bottom:1px solid var(--line);font:700 .62rem/1 var(--mn);letter-spacing:.14em;text-transform:uppercase;color:var(--red)}
.db-bell-empty,.db-bell-more{margin:0;padding:14px;font-size:.8rem;line-height:1.5;color:var(--dim)}
.db-bell-more{border-top:1px solid var(--line);padding:10px 14px;font-size:.72rem}
.db-bell-row{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:2px 10px;align-items:baseline;width:100%;text-align:left;background:none;
  border:0;border-top:1px solid var(--line);padding:11px 14px 11px 26px;font:inherit;color:var(--paper);cursor:pointer;position:relative}
.db-bell-row::before{content:"";position:absolute;left:12px;top:17px;width:7px;height:7px;border-radius:50%;background:var(--red)}
.db-bell-head+.db-bell-row{border-top:0}
.db-bell-row:hover{background:var(--inset,#fff)}
.db-bell-row b{font-size:.85rem;font-weight:700;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.db-bell-row small{font-size:.68rem;color:var(--dim);white-space:nowrap}
.db-bell-row span{grid-column:1/-1;font-size:.74rem;color:var(--dim);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* ── the account menu: one avatar button, one dropdown, three views ──────
   main → settings → plans, each with a back arrow — the same outline↔
   inspector rhythm the site designer already uses, so the two tools feel
   like one product. */
.db-menu-trigger{width:38px;height:38px;flex:none;border-radius:50%;border:1px solid var(--line);background:var(--inset,#fff);
  cursor:pointer;overflow:hidden;padding:0;display:grid;place-items:center;color:var(--dim);
  font:700 13px/1 'Anton',sans-serif;transition:border-color .15s}
.db-menu-trigger:hover,.db-menu-trigger[aria-expanded="true"]{border-color:var(--paper)}
.db-menu-trigger img{width:100%;height:100%;object-fit:cover;display:block}

.db-menu{position:absolute;top:calc(100% + 10px);right:0;width:300px;max-width:calc(100vw - 40px);
  color:var(--paper);background:var(--card,var(--ink2));border:1px solid var(--line);border-radius:var(--radius-lg,16px);
  box-shadow:var(--shadow-2,0 16px 44px rgba(20,18,16,.16));overflow:hidden;z-index:60}
.db-menu[hidden]{display:none}
.db-menu-view{display:none}
.db-menu-view.active{display:block}

.db-menu-head{display:flex;align-items:center;gap:12px;padding:16px}
.db-menu-avatar{width:40px;height:40px;flex:none;border-radius:50%;overflow:hidden;background:var(--inset,#fff);
  border:2px solid var(--paper);display:grid;place-items:center;font:700 14px/1 'Anton',sans-serif;color:var(--dim)}
.db-menu-avatar img{width:100%;height:100%;object-fit:cover;display:block}
.db-menu-id{min-width:0}
.db-menu-id strong{display:block;font-size:.85rem;font-weight:700;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.db-menu-id small{display:block;font-size:.72rem;color:var(--dim);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;margin-top:2px}

.db-menu-nav{border-top:1px solid var(--line);padding:6px}
.db-menu-row{width:100%;display:flex;align-items:center;justify-content:space-between;gap:10px;background:none;border:0;
  border-radius:10px;padding:11px 10px;font:inherit;font-size:.85rem;color:var(--paper);cursor:pointer;text-align:left}
.db-menu-row:hover{background:var(--inset,#fff)}
.db-menu-chev{color:var(--dim);font-size:.9rem}
.db-menu-foot{border-top:1px solid var(--line);padding:6px}
.db-menu-foot .db-menu-row{color:var(--dim)}
.db-menu-foot .db-menu-row:hover{color:var(--red)}

/* a sub-view's own header: back arrow + title, same shape everywhere */
.db-menu-crumb{display:flex;align-items:center;gap:8px;padding:12px 14px;border-bottom:1px solid var(--line)}
.db-menu-back{width:28px;height:28px;flex:none;border-radius:8px;border:1px solid var(--line);background:var(--inset,#fff);
  color:var(--paper);cursor:pointer;font-size:1.1rem;line-height:1;padding:0 0 2px}
.db-menu-back:hover{border-color:var(--paper)}
.db-menu-crumb h3{font:700 .8rem/1 inherit;margin:0}
.db-menu-body{padding:14px}

/* settings, 6 Oct 2026: label OVER value. The page's .db-row puts the
   label in a 120px column, which in a 300px panel left ~130px for
   "link.tattoo/handle" and the email — that was the squash. Then the
   folds (Change email / Change password), each a <details> with the
   same chevron the main rows use, turning when open. */
.db-set{padding:2px 0 12px}
.db-set+.db-set{border-top:1px solid var(--line);padding-top:12px}
.db-set h4{margin:0 0 4px;font:700 .62rem/1 var(--mn);letter-spacing:.12em;text-transform:uppercase;color:var(--dim)}
.db-set-row{display:flex;flex-direction:column;gap:2px;padding:7px 0}
.db-set-row span,.db-set-label{font-size:.68rem;color:var(--dim)}
.db-set-row b{font-weight:600;font-size:.84rem;line-height:1.35;overflow-wrap:anywhere}
.db-set-note{margin:6px 0 0;font-size:.78rem;line-height:1.5;color:var(--dim)}
.db-set-fold summary{list-style:none;display:flex;align-items:center;justify-content:space-between;gap:10px;
  padding:10px 0;font-size:.84rem;color:var(--paper);cursor:pointer}
.db-set-fold summary::-webkit-details-marker{display:none}
.db-set-fold summary:hover{color:var(--red)}
.db-set-fold .db-menu-chev{display:inline-block;transition:transform .15s}
.db-set-fold[open]>summary .db-menu-chev{transform:rotate(90deg)}
.db-set-form{display:grid;gap:6px;padding:2px 0 12px}
.db-set-form label{font-size:.68rem;color:var(--dim);margin-top:4px}
.db-set-form .db-in,.db-menu-confirm .db-in{padding:10px 12px;font-size:.88rem}
.db-menu-confirm .db-set-label{display:block;margin:-6px 0 6px}
.db-menu-confirm .db-in{margin-bottom:12px}
.db-set-form .db-btn{margin-top:4px;padding:9px 12px;font-size:.72rem;text-align:center}
.db-set-msg{margin:0;font-size:.74rem;line-height:1.5;color:var(--dim)}
.db-set-msg:empty{display:none}
.db-set-msg.ok{color:var(--acid)}
.db-set-msg.err{color:var(--red)}
.db-menu-text-link{background:none;border:0;padding:4px 0 0;font:inherit;font-size:.72rem;color:var(--dim);cursor:pointer;
  text-decoration:underline;text-underline-offset:2px;justify-self:start}
.db-menu-text-link:hover{color:var(--paper)}
.db-menu-text-link:disabled{opacity:.6;cursor:default}

/* settings: delete tucked at the very bottom, small and muted on purpose —
   never a red button sitting where the eye lands first */
.db-menu-danger{margin-top:16px;padding-top:14px;border-top:1px solid var(--line)}
.db-menu-danger-link{background:none;border:0;padding:0;font:inherit;font-size:.76rem;color:var(--dim);cursor:pointer;text-decoration:underline;text-underline-offset:2px}
.db-menu-danger-link:hover{color:var(--red)}
.db-menu-confirm p{font-size:.8rem;line-height:1.55;color:var(--dim);margin:0 0 14px}
.db-menu-confirm-acts{display:flex;gap:8px}
.db-menu-confirm-acts .db-btn{flex:1;text-align:center;padding:9px 12px;font-size:.72rem}

/* plans: current tier as plain text, the switch (admin) or a nudge (everyone
   else) below it — same information architecture a real billing page has */
.db-plan-row{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:10px 0}
.db-plan-row strong{font-size:.85rem}
.db-plan-current{font-size:.72rem;color:var(--dim);text-transform:uppercase;letter-spacing:.08em;font-weight:700}

/* the backdrop is ONLY ever a drawer thing — display:none outside the
   1024px breakpoint below, full stop, regardless of its [hidden] state.
   Without this base rule a plain <div> defaults to display:block the
   moment js/dashboard.js clears [hidden] to open the menu, which on
   desktop would drop a full-screen scrim over an anchored dropdown that
   was never supposed to have one. */
.db-menu-backdrop{display:none}

/* ── THE DRAWER (below 1024px) ────────────────────────────────────────────
   1024px because that is already this page's own line between "desktop"
   and "everything else" — .db-cols folds the preview pane at the same
   width a little further down. One number for both means the moment the
   pane stops being a side-by-side thing, the account menu stops being an
   anchored dropdown too; the page reads as one layout mode, not two
   independent guesses at where mobile starts.

   Same #db-menu, same JS (openMenu/closeMenu/showView) — only the CSS
   presentation and the backdrop's visibility change. [hidden] still
   drives it: overriding its display here (to something other than the
   UA sheet's none) is what lets the closed→open transform actually
   transition instead of jumping, and js/dashboard.js sets aria-hidden
   itself in lock-step so a CSS override of [hidden]'s display can never
   leave the drawer's content exposed to assistive tech while "closed". */
@media(max-width:1023px){
  .db-menu-backdrop{display:block;position:fixed;inset:0;z-index:65;background:rgba(20,18,16,.5);
    opacity:0;transition:opacity .22s ease}
  .db-menu-backdrop[hidden]{display:none}
  .db-menu-backdrop:not([hidden]){opacity:1}

  .db-menu{display:flex!important;flex-direction:column;
    position:fixed;inset:0 0 0 auto;width:min(86vw,360px);max-width:none;height:100%;
    border-radius:0;border-width:0 0 0 1px;box-shadow:-14px 0 40px rgba(20,18,16,.22);
    transform:translateX(100%);transition:transform .28s cubic-bezier(.4,0,.2,1);
    z-index:70;overflow-y:auto}
  .db-menu:not([hidden]){transform:translateX(0)}
  .db-menu-view.active{display:flex;flex-direction:column;min-height:100%}
  .db-menu-body{flex:1}

  /* 44px minimum tap targets in the drawer; the compact desktop dropdown
     keeps its own tighter sizing outside this breakpoint */
  .db-theme-toggle,.db-menu-trigger,.db-bell{width:44px;height:44px}
  .db-menu-row{min-height:44px;padding:12px}
  .db-menu-back{width:44px;height:44px;border-radius:10px}
  .db-set-fold summary{min-height:44px}
}
@media(prefers-reduced-motion:reduce){
  .db-menu,.db-menu-backdrop{transition:none}
}

/* the sliding switch (Square's MarketToggle mechanism, this app's tokens):
   a pill track, a circular thumb, one checkbox driving both */
.db-switch{position:relative;display:inline-flex;flex:none;width:44px;height:26px;border-radius:999px;
  border:1px solid var(--line);background:var(--inset,#fff);cursor:pointer;transition:background .15s,border-color .15s}
.db-switch input{position:absolute;inset:0;opacity:0;margin:0;cursor:pointer}
.db-switch i{position:absolute;top:2px;left:2px;width:20px;height:20px;border-radius:50%;background:var(--dim);
  transition:translate .18s cubic-bezier(.4,0,.2,1),background .15s}
.db-switch:has(input:checked){background:var(--red);border-color:var(--red)}
.db-switch:has(input:checked) i{translate:18px 0;background:#fff}
.db-switch:has(input:focus-visible){outline:2px solid var(--acid);outline-offset:2px}
.db-switch:has(input:disabled){opacity:.55;cursor:default}

/* the card: 1.07 against the page, a hairline and a whisper of shadow */
.db-card{background:var(--card,var(--ink2));border:1px solid var(--line);border-radius:var(--radius-lg,16px);padding:20px;margin-bottom:16px;
  box-shadow:var(--shadow-card,0 1px 2px rgba(20,18,16,.05))}
.db-card h2{font:700 .72rem/1 var(--mn);letter-spacing:.14em;text-transform:uppercase;color:var(--dim);margin:0 0 14px;display:flex;align-items:center;gap:10px}
/* the one place a max-width still applies: running prose. A card can be
   900px wide now; a paragraph inside it still shouldn't be. */
.db-note{font-size:.8rem;line-height:1.55;color:var(--dim);margin:12px 0 0;max-width:68ch}
.db-note b{color:var(--paper)}

/* ── the live line ── */
.db-live{display:flex;align-items:center;gap:8px;margin:0 0 8px;font:700 .7rem/1 var(--mn);letter-spacing:.14em;text-transform:uppercase;color:var(--acid)}
.db-dot{width:9px;height:9px;border-radius:50%;background:var(--acid);box-shadow:0 0 0 3px color-mix(in srgb,var(--acid) 22%,transparent)}
.db-link{display:flex;flex-wrap:wrap;align-items:center;gap:10px 14px}
.db-url{font:400 clamp(17px,3.6vw,22px)/1.3 var(--mn);word-break:break-all;color:var(--paper);background:var(--inset,#fff);
  border:1px solid var(--line);border-radius:6px;padding:10px 14px;flex:1;min-width:0}
.db-acts{display:flex;flex-wrap:wrap;gap:10px;margin-top:12px}
.db-btn{background:var(--red);color:var(--ink);border:1px solid var(--red);border-radius:999px;font:inherit;font-size:.78rem;font-weight:700;
  letter-spacing:.08em;text-transform:uppercase;padding:10px 16px;cursor:pointer;text-decoration:none;display:inline-block}
.db-btn.quiet{background:var(--inset,#fff);color:var(--paper);border-color:var(--line)}
.db-btn:hover{filter:brightness(1.06)} .db-btn.quiet:hover{border-color:var(--paper)}
/* pressed and kept: the Studio card's button after its one click (30 Sep 2026) */
.db-btn:disabled{opacity:.65;cursor:default}
.db-btn:disabled:hover{filter:none}
/* the Studio card's one line */
.db-lede{font-size:1.05rem;font-weight:600;line-height:1.4;color:var(--paper);margin:0;max-width:40ch}

/* ── the face, the name, where ── */
.db-who{display:grid;grid-template-columns:88px minmax(0,1fr);gap:20px;align-items:start}
/* the ring: 3px of the text colour, like the old wall badge — a light face on
   a light card still reads as a disc */
.db-av{width:88px;height:88px;border-radius:50%;overflow:hidden;background:var(--inset,#fff);border:3px solid var(--paper);
  display:grid;place-items:center;font:400 28px/1 'Anton',sans-serif;color:var(--dim);position:relative;cursor:pointer}
.db-av img{width:100%;height:100%;object-fit:cover;display:block}
.db-av input{position:absolute;inset:0;opacity:0;cursor:pointer}
.db-av-hint{font-size:.7rem;color:var(--dim);margin-top:6px;text-align:center;width:88px}
.db-fields{display:grid;gap:0}
/* label-left rows, hairline between, the field on an inset */
.db-row{display:grid;grid-template-columns:120px minmax(0,1fr);gap:0 16px;align-items:start;padding:12px 0;border-top:1px solid var(--line)}
.db-row:first-child{border-top:0;padding-top:0}
.db-row > label{padding-top:14px;font:700 .62rem/1 var(--mn);letter-spacing:.12em;text-transform:uppercase;color:var(--dim)}
.db-row small{display:block;margin-top:8px;font-size:.72rem;line-height:1.5;color:var(--dim)}
.db-in{width:100%;background:var(--inset,#fff);border:1px solid var(--line);border-radius:6px;padding:14px 16px;font:inherit;font-size:.95rem;color:var(--paper)}
.db-in:focus{outline:2px solid var(--acid);outline-offset:2px;border-color:transparent}
.db-in::placeholder{color:var(--faintext,var(--dim))}
/* the only word autosave ever says: a failure, floated over the page so nothing below it moves (14 Oct 2026) */
.db-savefail{position:fixed;left:50%;bottom:24px;transform:translate(-50%,8px);z-index:900;margin:0;padding:10px 16px;border-radius:8px;
  background:var(--paper);color:var(--ink);font-size:.78rem;line-height:1.3;box-shadow:0 6px 24px rgba(0,0,0,.25);
  opacity:0;pointer-events:none;transition:opacity .18s,transform .18s}
.db-savefail.show{opacity:1;transform:translate(-50%,0)}
@media(max-width:640px){.db-who{grid-template-columns:1fr;justify-items:center}.db-fields{width:100%}.db-row{grid-template-columns:1fr}.db-row > label{padding-top:0;margin-bottom:4px}}

/* ── the look: swatches, two live, four locked ── */
.db-themes{display:grid;grid-template-columns:repeat(auto-fill,minmax(96px,1fr));gap:10px}
.db-theme{position:relative;display:grid;gap:8px;justify-items:center;padding:12px 8px 10px;background:var(--inset,#fff);border:1px solid var(--line);
  border-radius:12px;font:inherit;cursor:pointer;color:var(--paper)}
.db-theme[aria-pressed="true"]{border-color:var(--paper);box-shadow:0 0 0 1px var(--paper)}
.db-sw{width:56px;height:40px;border-radius:8px;background:var(--tb);border:1px solid rgba(20,18,16,.18);display:grid;place-items:center}
.db-sw i{display:block;width:26px;height:6px;border-radius:3px;background:var(--ta);box-shadow:0 10px 0 -2px var(--tf)}
.db-tn{font-size:.7rem;letter-spacing:.06em}
/* LOCKED: still readable — the swatch keeps its true colours behind a
   hairline veil, the name stays at full contrast, the badge says SOON (not
   a tier: none exists to name, 30 Sep 2026). Greyed does not mean
   unreadable, and contrast.py checks the badge. */
.db-theme.locked{cursor:not-allowed}
.db-theme.locked .db-sw{opacity:.7}
.db-theme.locked .db-tn{color:var(--dim)}
.db-lock{display:inline-block;font:700 .58rem/1 var(--mn);letter-spacing:.14em;text-transform:uppercase;color:#6b5412;
  border:1px solid #d9c48f;background:#f6ead0;border-radius:999px;padding:4px 8px}
.db-theme .db-lock{position:absolute;top:6px;right:6px}
.db-locked h2 .db-lock{margin-left:auto}

/* ── hours: a week on a grid, a calendar app shrunk down (12 Oct 2026).
   14 Oct: every block is a switch of its own; the day and time labels
   flip a whole column or row. ── */
.db-cal{display:grid;grid-template-columns:44px repeat(7,minmax(0,1fr));gap:3px;max-width:560px}
.db-cal-day,.db-cal-time{min-height:30px;padding:0;background:var(--inset,#fff);border:1px solid var(--line);border-radius:6px;
  font:700 .62rem/1 var(--mn);letter-spacing:.06em;text-transform:uppercase;color:var(--dim);cursor:pointer;
  transition:background .12s,border-color .12s,color .12s}
.db-cal-time{min-height:26px;letter-spacing:0}
.db-cal-day:hover,.db-cal-time:hover{border-color:var(--paper);color:var(--paper)}
.db-cal-day[aria-pressed="true"],.db-cal-time[aria-pressed="true"]{background:var(--paper);color:var(--ink);border-color:var(--paper)}
.db-cal-cell{display:block;min-height:26px;padding:0;border:0;border-radius:4px;background:var(--faint);cursor:pointer;
  -webkit-tap-highlight-color:transparent;touch-action:manipulation;transition:background .12s,box-shadow .12s}
.db-cal-cell:hover{box-shadow:inset 0 0 0 1px var(--paper)}
.db-cal-cell:focus-visible{outline:2px solid var(--paper);outline-offset:1px}
.db-cal-cell.on{background:var(--live,#1f8a4c)}
.db-cal-cell.on:hover{box-shadow:inset 0 0 0 1px var(--ink)}
@media(max-width:420px){.db-cal{grid-template-columns:36px repeat(7,minmax(0,1fr));gap:2px}.db-cal-day,.db-cal-time{font-size:.55rem}.db-cal-cell{min-height:30px}}
#db-requests{min-height:80px}
.db-gate{text-align:center;padding:80px 20px;color:var(--dim)}

/* ── the cropper: the old app.js treatment, on the dashboard's tokens ── */
.crop-overlay{position:fixed;inset:0;z-index:1000;background:rgba(20,20,18,.55);display:flex;align-items:center;justify-content:center;padding:20px}
.crop-card{background:var(--card,var(--ink2));border:1px solid var(--line);border-radius:var(--radius-lg,16px);padding:24px;width:min(340px,94vw);
  display:flex;flex-direction:column;align-items:center}
.crop-title{font:400 17px/1 'Anton','Helvetica Neue',Arial,sans-serif;letter-spacing:.03em;text-transform:uppercase;margin-bottom:6px}
.crop-sub{font-size:11px;color:var(--dim);margin-bottom:16px;text-align:center;line-height:1.5}
.crop-stage{position:relative;width:280px;height:280px;overflow:hidden;border-radius:12px;background:var(--inset,#fff);
  touch-action:none;cursor:grab;-webkit-user-select:none;user-select:none}
.crop-stage.grab{cursor:grabbing}
.crop-img{position:absolute;left:0;top:0;transform-origin:0 0;max-width:none;pointer-events:none;display:block}
/* the scrim with a circular hole: the hole IS the avatar */
.crop-mask{position:absolute;inset:0;pointer-events:none}
.crop-mask i{position:absolute;left:50%;top:50%;width:248px;height:248px;transform:translate(-50%,-50%);border-radius:50%;
  box-shadow:0 0 0 999px rgba(20,20,18,.52);border:3px solid var(--paper)}
.crop-zoom{width:248px;margin:16px 0 14px;accent-color:var(--red)}
.crop-acts{display:flex;gap:10px}

/* ── the preview pane ─────────────────────────────────────────────────────
   One outline (the tablet came off 30 Sep 2026), one iframe. The device is drawn at its real CSS size and
   scaled down with transform (dashboard.js fit()), so a 393px phone is a
   393px phone however narrow the column. Bezels are decoration, not tokens:
   a black outline reads as a device on bone and on ink alike. */
.pv-head{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:10px}
.pv-show{display:none}
.pv-stage{position:relative}   /* the scaled device never exceeds the stage; its shadow may */
.pv-device{position:absolute;left:0;top:0;transform-origin:0 0;background:#111;box-sizing:border-box;display:grid}
.pv-device.phone{border-radius:48px;padding:12px;box-shadow:0 0 0 2px #2c2c2c,0 18px 40px -20px rgba(0,0,0,.6)}
.pv-screen{overflow:hidden;background:#efe9dd;width:100%;height:100%}
.pv-device.phone .pv-screen{border-radius:36px}
#pv-frame{display:block;border:0;background:#efe9dd}
.pv-note{font-size:.72rem;line-height:1.55;color:var(--dim);margin:10px 0 0}
.pv-reload{background:none;border:0;padding:0;font:inherit;color:var(--paper);text-decoration:underline;cursor:pointer}
/* narrow: the pane folds to one button above the cards; the toggles show
   only once it is open */
@media(max-width:1023px){
  .db-cols{grid-template-columns:minmax(0,1fr)}
  .db-side{position:static;order:0;margin-bottom:16px}
  .pv-show{display:inline-block;background:var(--inset,#fff);border:1px solid var(--line);border-radius:999px;padding:10px 16px;
    font:inherit;font-size:.78rem;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:var(--paper);cursor:pointer}
  .db-side:not(.open) .pv-body{display:none}
  .db-side.open .pv-show{background:var(--paper);color:var(--ink);border-color:var(--paper)}
}

/* ── your brand: logo (same ring the avatar uses) + a background photo ──
   Pro-gated exactly like the theme swatches: visible and inert on Free,
   real controls on Studio. */
.db-brandshot{width:100%;aspect-ratio:16/9;border-radius:12px;overflow:hidden;background:var(--inset,#fff);
  border:1px solid var(--line);display:grid;place-items:center;color:var(--dim);font-size:.72rem;cursor:pointer;position:relative}
.db-brandshot img{width:100%;height:100%;object-fit:cover;display:block}
.db-brandshot input{position:absolute;inset:0;opacity:0;cursor:pointer}
.db-brand-row{display:flex;align-items:flex-start;gap:16px;flex-wrap:wrap}
.db-brand-col{flex:1;min-width:160px}
.db-brand-col+.db-brand-col{flex:2;min-width:220px}
.db-brand-label{display:block;font:700 .62rem/1 var(--mn);letter-spacing:.12em;text-transform:uppercase;color:var(--dim);margin-bottom:8px}
.db-brand-clear{margin-top:8px}
.db-toggle-row{display:flex;align-items:center;gap:10px;margin-top:10px;font-size:.8rem;color:var(--paper)}
.db-lock-note{display:flex;align-items:center;gap:10px;flex-wrap:wrap}

/* ═══ DARK MODE (dashboard only) ═══════════════════════════════════════════
   A manual toggle, not prefers-color-scheme — [data-ui-theme] on <html>,
   the same mechanism builder.css already uses. Scoped to this page only via
   the attribute (nothing else ever sets it), so login.html and the client
   form are untouched. Every component above reads these as var(--x), so
   redefining the tokens is the whole job; only the handful of literals below
   (the lock badge, the phone-preview fallback) need a line of their own.

   Derived by swapping ink↔paper and keeping the warm hue family (not a cold
   grey) so it reads as the same brand inverted, not a different app. Every
   pair below is checked in contrast.py (DASH_DARK) the same way the light
   tokens are. */
html[data-ui-theme="dark"] body:not(.view-home){
  --ink:#141210;   --card:#201d1b;  --ink2:#201d1b;
  --inset:#292724; --ink3:#302d2a; --ink4:#3b3833;
  --paper:#eae3d5;
  --dim:#8c877e;
  --faintext:#726e67;
  --line:rgba(234,227,213,.12);
  --faint:rgba(234,227,213,.07);
  --red:#fd5457; --accent:#fd5457;
  --acid:#29c46b; --live:#29c46b;
}
html[data-ui-theme="dark"] .db-lock{color:#e0bc6c;border-color:#554418;background:#372d14}
html[data-ui-theme="dark"] .pv-screen{background:#141210}
html[data-ui-theme="dark"] .crop-mask i{border-color:var(--paper)}
