/* CubeWP client portal — LAYOUT ONLY.
 *
 * Badges, cards, buttons, tables, inputs, skeletons and empty states are the
 * platform's components (console.css). This file positions them and nothing
 * else. A `cl-` rule that restyles a `cw-` component is the bug this file was
 * once rewritten to remove: the old .cl-site set its own card chrome, which
 * beat .cw-card on source order and meant the portal's cards were never the
 * platform's cards at all.
 *
 * ===========================================================================
 * LAPTOP-FIRST DENSITY
 *
 * The portal is used from ordinary laptops (1366×768 is the common case), so
 * the shell is deliberately compact: a 224px sidebar, a 56px topbar, and a
 * content column capped at 1040px. At that size the header, the page title,
 * the stat row AND the first site rows all fit above the fold — the test this
 * layout was sized against.
 */

* { box-sizing: border-box; }

/* Body canvas, type and colour come from .dash-body in dashboard.css — the
   same surface /dashboard uses. A second opinion here is what made them
   differ. */
.cl-body { -webkit-font-smoothing: antialiased; }

/* !important is load-bearing: this is declared before .cl-app and .cl-gate,
   which set display at the same specificity, so source order would otherwise
   show something meant to be hidden. */
.hidden { display: none !important; }

/* ══ Boot + gate ═══════════════════════════════════════════════════════════ */

.cl-boot, .cl-gate {
  min-height: 100vh; display: flex; align-items: center; justify-content: center;
  padding: var(--cw-s6);
}
.cl-boot-spinner {
  width: 22px; height: 22px; border-radius: 50%;
  border: 2px solid var(--cw-border); border-top-color: var(--cw-accent);
  animation: cl-spin .8s linear infinite;
}
@keyframes cl-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .cl-boot-spinner { animation-duration: 3s; } }

/* THE CARD ITSELF IS dashboard.css's .auth-card — the same one /signin uses.
   What is left here is only what is genuinely the portal's: the agency's name
   in place of our logo. The wrapper, the inner card, the body text and the
   button spacing all went, because each was a second version of something
   .auth-card already does. */
.cl-gate-brand {
  display: flex; flex-direction: column; align-items: center;
  gap: 2px; margin-bottom: var(--cw-s5); text-align: center;
}
.cl-gate-agency { font: var(--cw-title); color: var(--cw-ink); overflow-wrap: anywhere; }
.cl-gate-eyebrow {
  font: var(--cw-micro); color: var(--cw-text-soft);
  text-transform: uppercase; letter-spacing: .07em;
}
/* THE CARD IS A FLEX ITEM HERE, so it shrank to its content (386px) while
   /signin's block-centred one filled its 400px max-width. Same rule, two
   different widths, purely because of what encloses it. */
.cl-gate .auth-card { width: 100%; }

/* THE SAME 20px/700 AS .auth-card #auth-title, and deliberately NOT the
   "font:" shorthand: both titles are <h2>, whose family comes from signup.css's
   h1,h2,h3 { font-family: var(--font-display) }. The shorthand resets family,
   which quietly set this heading in Inter Tight while /signin's stayed in
   Bricolage Grotesque — the same size, in a different typeface. Line-height is
   left alone for the same reason: /signin does not set one. */
.cl-gate-title {
  font-size: 20px; font-weight: 700; color: var(--cw-ink); margin: 0 0 8px;
}
/* The secondary way out sits under the primary button, not beside it. */
.cl-gate-alt   { display: block; width: 100%; margin-top: var(--cw-s3); }
.cl-gate-error { margin-top: var(--cw-s3); }

/* The site cards are .sc-card (console.css). Only the GRID is the portal's:
   one column on a phone, filling out as the column widens, with the same
   minimum a card needs to stay readable. */
.cl-cards {
  display: grid; gap: var(--cw-s4);
  grid-template-columns: repeat(auto-fill, minmax(min(300px, 100%), 1fr));
}



/* ══ Support ═══════════════════════════════════════════════════════════════
   A conversation is ONE object — who it is with, what was said, and the reply.
   Splitting those into three stacked cards read as three thin boxes floating
   on a page rather than something you are reading.
   ══════════════════════════════════════════════════════════════════════════ */
.cl-threads { list-style: none; margin: 0; padding: 0; }
.cl-thread + .cl-thread { border-top: 1px solid var(--cw-surface-2); }
/* The whole row is the control; the avatar and unread dot are fixed rails so
   rows do not shuffle sideways as they are read. */
.cl-thread-btn {
  display: grid; grid-template-columns: 36px minmax(0, 1fr) auto 8px;
  align-items: center; gap: var(--cw-s4);
  width: 100%; text-align: left; font: inherit; cursor: pointer;
  background: none; border: 0; padding: var(--cw-s4) var(--cw-s5);
  transition: background var(--cw-t-micro);
}
.cl-thread-btn:hover { background: var(--cw-bg); }
.cl-thread-btn:focus-visible { outline: 2px solid var(--cw-accent); outline-offset: -2px; }
.cl-thread-av {
  width: 36px; height: 36px; border-radius: var(--cw-r-md); flex: none;
  display: grid; place-items: center;
  background: var(--cw-surface-2); color: var(--cw-text-soft);
  font: 600 12px/1 var(--cw-font);
}
.cl-thread.is-unread .cl-thread-av { background: var(--cw-accent-subtle); color: var(--cw-accent); }
.cl-thread-main { min-width: 0; display: grid; gap: 3px; }
.cl-thread-top { display: flex; align-items: center; gap: var(--cw-s2); min-width: 0; }
.cl-thread-subject {
  font: var(--cw-body); font-weight: 600; color: var(--cw-ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.cl-thread.is-unread .cl-thread-subject { font-weight: 700; }
.cl-thread.is-closed .cl-thread-btn { opacity: .62; }
.cl-thread-tag {
  flex: none; font: var(--cw-micro); font-weight: 600; letter-spacing: .04em;
  text-transform: uppercase; padding: 1px 6px; border-radius: var(--cw-r-sm);
  background: var(--cw-surface-2); color: var(--cw-text-faint);
}
/* "You" as a quiet chip, not a prefix that reads as part of the message. */
.cl-thread-you { color: var(--cw-text-faint); font-weight: 600; }
.cl-thread-you::after { content: ' · '; font-weight: 400; }

/* Unread count on the Support nav item — visible from any screen, or the
   client only discovers a reply by happening to open the tab. */
.cl-nav-badge {
  margin-left: auto; flex: none;
  min-width: 18px; height: 18px; padding: 0 5px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--cw-r-full);
  background: var(--cw-accent); color: var(--cw-accent-ink);
  font: 700 11px/1 var(--cw-font); font-variant-numeric: tabular-nums;
}
.cl-thread-preview {
  font: var(--cw-small); color: var(--cw-text-soft);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.cl-thread-when { font: var(--cw-micro); color: var(--cw-text-faint); }
.cl-thread-dot {
  width: 8px; height: 8px; border-radius: 50%; flex: none; background: var(--cw-accent);
}
.cl-thread-dot.is-empty { background: transparent; }

/* ── the conversation ──────────────────────────────────────────────────── */
.cl-conv { overflow: hidden; }
.cl-conv-head {
  display: flex; align-items: center; gap: var(--cw-s3);
  padding: var(--cw-s4) var(--cw-s5);
  border-bottom: 1px solid var(--cw-border);
}
.cl-conv-av {
  width: 38px; height: 38px; border-radius: var(--cw-r-md); flex: none;
  display: grid; place-items: center;
  background: var(--cw-accent-subtle); color: var(--cw-accent);
  font: 600 13px/1 var(--cw-font);
}
.cl-conv-id { flex: 1; min-width: 0; display: grid; gap: 2px; }
.cl-conv-subject {
  font: var(--cw-heading); color: var(--cw-ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.cl-conv-who { font: var(--cw-small); color: var(--cw-text-soft); }
.cl-conv-state { font-weight: 600; color: var(--cw-text-faint); }

.cl-msgs {
  display: flex; flex-direction: column; gap: var(--cw-s4);
  padding: var(--cw-s5);
  /* A long thread scrolls inside the card so the reply box stays reachable. */
  max-height: 52vh; overflow-y: auto;
}
.cl-msg { max-width: 76%; }
/* Alignment carries who spoke; neither side needs colour to be legible. */
.cl-msg.is-mine { margin-left: auto; }
.cl-msg-who {
  font: var(--cw-micro); font-weight: 600; color: var(--cw-text-soft); margin-bottom: 4px;
}
.cl-msg-at { font-weight: 400; color: var(--cw-text-faint); }
.cl-msg.is-mine .cl-msg-who { text-align: right; }
.cl-msg-body {
  font: var(--cw-body); color: var(--cw-ink);
  background: var(--cw-surface-2);
  border-radius: var(--cw-r-lg) var(--cw-r-lg) var(--cw-r-lg) var(--cw-r-sm);
  padding: var(--cw-s3) var(--cw-s4);
  /* Typed by a person: keep the line breaks, break a pasted URL. */
  white-space: pre-wrap; overflow-wrap: anywhere;
}
.cl-msg.is-mine .cl-msg-body {
  background: var(--cw-accent-subtle);
  border-radius: var(--cw-r-lg) var(--cw-r-lg) var(--cw-r-sm) var(--cw-r-lg);
}

/* ── composer ──────────────────────────────────────────────────────────── */
.cl-composer { border-top: 1px solid var(--cw-border); padding: var(--cw-s4) var(--cw-s5); }
.cl-label { display: block; font: var(--cw-small); font-weight: 600;
            color: var(--cw-ink); margin-bottom: var(--cw-s2); }
.cl-textarea {
  min-height: 76px; padding: var(--cw-s3) var(--cw-s4); resize: vertical;
  line-height: 1.5; font-family: inherit;
}
.cl-composer-foot {
  display: flex; align-items: center; gap: var(--cw-s3); margin-top: var(--cw-s3);
}
/* Holds its place empty so an error does not shove Send sideways. */
.cl-composer-hint { flex: 1; min-width: 0; font: var(--cw-small); color: transparent; }
.cl-composer-hint.is-error { color: var(--cw-danger); }

@media (max-width: 600px) {
  .cl-thread-btn { grid-template-columns: 32px minmax(0, 1fr) 8px; row-gap: 2px; }
  .cl-thread-when { grid-column: 2; }
  .cl-msg { max-width: 90%; }
  .cl-msgs { max-height: none; }
}

/* ══ Shell ═════════════════════════════════════════════════════════════════ */

/* ══════════════════════════════════════════════════════════════════════════
   THE SHELL LIVES IN dashboard.css NOW.

   This file used to re-implement it — .cl-app, .cl-sidebar, .cl-nav,
   .cl-topbar, .cl-main, .cl-view — a THIRD copy of chrome that already existed
   in /dashboard and /agency. Three copies of one idea drift in three
   directions, which is why the portal looked like older software.

   The markup now renders .dash-shell / .dash-sidebar / .dash-sidenav-item /
   .cw-header / .dash-content. What remains below is portal-specific only: the
   agency's brand block, the drawer (the dashboard sidebar has no off-canvas
   mode), and the client views themselves.
   ══════════════════════════════════════════════════════════════════════════ */


/* THE CONTENT COLUMN HAS TO CLAIM THE ROW.
 *
 * .dash-shell is a flex row and dashboard.css leaves .dash-content at the
 * default `flex: 0 1 auto`, so it is sized by its CONTENTS: a narrow tab
 * collapses well short of the viewport, and `.dash-tab-panel`'s
 * `max-width: 960px; margin: 0 auto` then centres nothing, because the parent
 * is already narrower than the cap. The portal has the narrowest content of the
 * three consoles, so it collapsed the furthest.
 *
 * Kept out of the shared sheet on purpose — see the matching note in
 * agency/assets/css/app.css.
 */
.dash-content { flex: 1; min-width: 0; }

/* ══ Sidebar brand ═════════════════════════════════════════════════════════
   THIS BLOCK HAD NO CSS AT ALL — not overridden, never written. Two bare
   spans rendered inline at the body's default size, tight against the corner,
   which is why the sidebar read "Client portal Wooster" as one run of text
   instead of a brand.

   It is the slot /dashboard and /agency fill with the CubeWP logo, and on a
   client's portal that space belongs to whoever they hired. Same padding and
   the same 28px gap down to the nav as .dash-sidebar .logo, so all three
   consoles start their navigation on the same line.                          */
.cl-brand {
  display: flex; flex-direction: column; gap: 1px;
  padding: 0 8px; margin-bottom: 28px; min-width: 0;
}
/* 17px/700 is the logo's own weight and size in that slot. */
.cl-brand-name {
  font: 700 17px/1.25 var(--cw-font); color: var(--cw-ink);
  /* An agency name is user data: it can be long, and a sidebar is narrow. */
  overflow-wrap: anywhere;
}
.cl-brand-eyebrow {
  font: var(--cw-micro); color: var(--cw-text-soft);
  text-transform: uppercase; letter-spacing: .07em;
}

.cl-menu-btn { display: none; }
.cl-scrim { position: fixed; inset: 0; background: rgba(0, 0, 0, .38); z-index: 40; }

/* ══ Overview ══════════════════════════════════════════════════════════════ */



.cl-card-title { font: var(--cw-heading); color: var(--cw-ink); margin: 0 0 var(--cw-s2); }

/* ══ Site rows ═════════════════════════════════════════════════════════════ */

.cl-row:first-child { padding-top: 0; }

.cl-row-host { font: var(--cw-micro); color: var(--cw-text-soft); text-decoration: none;
               overflow-wrap: anywhere; }
a.cl-row-host:hover { color: var(--cw-accent); text-decoration: underline; }

/* The status dot inside a badge — colour comes from the badge's own text
   colour so the pair can never disagree. */
.cl-dot {
  width: 6px; height: 6px; border-radius: 50%;
  display: inline-block; margin-right: 5px; vertical-align: 1px;
  background: currentColor;
}

.cl-toolbar { margin-bottom: var(--cw-s3); max-width: 340px; }

/* ══ Site detail ═══════════════════════════════════════════════════════════ */

.cl-crumb { margin-bottom: var(--cw-s2); }
.cl-crumb-back {
  appearance: none; border: 0; background: transparent; padding: 2px 0; cursor: pointer;
  font: var(--cw-micro); color: var(--cw-text-soft);
}
.cl-crumb-back:hover { color: var(--cw-accent); }
.cl-crumb-back:focus-visible { outline: 2px solid var(--cw-accent); outline-offset: 2px; border-radius: 2px; }

.cl-detail-head {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: var(--cw-s4); margin-bottom: var(--cw-s5); flex-wrap: wrap;
}
.cl-detail-id { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.cl-detail-title { font: var(--cw-title); color: var(--cw-ink); margin: 0; overflow-wrap: anywhere; }

.cl-block { margin-bottom: var(--cw-s4); }
.cl-btn-row { display: flex; gap: var(--cw-s2); flex-wrap: wrap; }

.cl-kv { table-layout: fixed; }
.cl-kv th, .cl-kv td { overflow-wrap: anywhere; }
.cl-kv th { text-align: left; font: var(--cw-small); color: var(--cw-text-soft);
            font-weight: 450; width: 34%; }
.cl-kv-note { display: block; font: var(--cw-micro); color: var(--cw-text-soft); margin-top: 2px; }

/* ══ Utilities ═════════════════════════════════════════════════════════════ */

.cl-muted  { color: var(--cw-text-soft); font: var(--cw-small); margin: 0; }
.cl-spaced { margin-top: var(--cw-s3); }
/* Pulls a card subtitle up toward its title. -4px against the title's 8px
   bottom margin leaves a 4px gap; the full -8px closed it to zero and the
   pair read as one crowded line. */
.cl-tight  { margin: -4px 0 var(--cw-s4); }
.cl-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }

/* ══ Fallback toast (only when console.js is absent) ════════════════════════ */

.cl-toast {
  position: fixed; left: 50%; bottom: var(--cw-s6); transform: translateX(-50%);
  background: var(--cw-ink); color: var(--cw-surface);
  padding: var(--cw-s3) var(--cw-s5); border-radius: var(--cw-r-md);
  font: var(--cw-small); max-width: min(520px, 92vw); z-index: 50;
}
.cl-toast-error { background: var(--cw-danger); }

/* ══ Drawer ════════════════════════════════════════════════════════════════ */

@media (max-width: 900px) {
  .dash-shell { display: block; }
  /* The SAME sidebar becomes an off-canvas drawer — one navigation moved, not a
     second mobile menu to keep in sync with the first. */
  .cl-app .dash-sidebar {
    position: fixed; inset: 0 auto 0 0; width: min(280px, 84vw); z-index: 50;
    transform: translateX(-100%); transition: transform var(--cw-t-base);
    padding: var(--cw-s6) var(--cw-s4);
  }
  .cl-app .dash-sidebar.open { transform: translateX(0); }
  .cl-menu-btn { display: inline-flex; }
  .cl-topbar { padding: var(--cw-s2) var(--cw-s4); }
  .cl-view   { padding: var(--cw-s4); }
  .cl-account-who, .cl-chevron { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .cl-sidebar { transition: none; }
}

@media (max-width: 560px) {
  .cl-view { padding: var(--cw-s3); }
  /* Rows become stacked cards: name+host on top, badge and actions below.
     Shrinking the desktop row squeezes the buttons into uselessness. */
  .cl-row { flex-wrap: wrap; }
  .cl-row .cw-badge { order: 2; }
  .cl-detail-head .cl-btn-row { width: 100%; }
  .cl-detail-head .cw-btn { flex: 1 1 auto; }
  .cl-toolbar { max-width: none; }
}

/* Light branding: the agency's logo in the slot its name already fills. */
/* .cl-brand is a flex COLUMN, whose default is to stretch every item to the
   full width — for an image that meant a 160px box holding a 132px-wide SVG,
   which centres itself inside its box (xMidYMid) and so painted ~14px to the
   right of the eyebrow under it (WPVender, 2026-09-09). align-self keeps the
   box at the image's own width; object-position is the belt for browsers that
   still hand it a wider box. */
.cl-brand-logo { display: block; align-self: flex-start; max-height: 28px; max-width: 160px; width: auto; height: auto; margin-bottom: 2px; object-fit: contain; object-position: left center; }
.cl-brand-logo[hidden] { display: none; }
/* When a logo is shown the name is hidden — it is the logo's alt instead. */
.cl-brand-name[hidden], .cl-gate-agency[hidden] { display: none; }
.cl-gate-logo { display: block; max-height: 44px; max-width: 220px; width: auto; height: auto; margin: 0 auto 8px; }
.cl-help a { color: inherit; text-decoration: underline; }
