/**
 * site-cards.css — the "your things" CARD GRID.
 *
 * The card layout from My websites, as a component: a picture of the design,
 * a status pip, a name, a progress bar, and the one action that continues the
 * work. Opted into with `.st-grid` on a container.
 *
 * ── Why it moved out of launch-studio.css ───────────────────────────────
 * Alex, 2026-08-01, on the Courses list: "the layout of how each course is
 * sitting here should be similar to how the website is looking, so that in
 * little panels you can have the thumbnail of the actual design." And before
 * that, as a standing instruction: "You shouldn't be rebuilding anything new
 * really. The whole UI should match or almost be taken as components from the
 * website builder."
 *
 * Every rule here was scoped to `#page-launch-sites`, so a second surface
 * could only have them by growing its own copy. Two copies of a card is how
 * two products stop looking like one product, and it is the exact thing the
 * instruction above is against.
 *
 * ── Scoped to a class, not global ───────────────────────────────────────
 * `.st-grid` rather than bare `.st-card`, for the reason the wizard-shell
 * extraction found the hard way: an unscoped move hands these rules to any
 * page that happens to share a class name, and the surprises show up on
 * screens nobody edited. A consumer opts in; nothing is opted in by accident.
 *
 * The move trades an id for a class, which LOWERS specificity from (1,1,0) to
 * (0,2,0) — anything that used to lose to these rules can now win.
 * tests/browser/site-cards-css.browser.js renders the real card markup against
 * the stylesheets as they were before the move and as they are now, and diffs
 * every property that decides what a card looks like.
 *
 * NOT here: `#page-launch-sites .topbar` / `.crumbs`. That is the page's own
 * chrome rather than the card's, and it stays where it is.
 */

.st-grid .st-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 20px; margin-bottom: 22px; }
.st-grid .st-head h1 { font-family: "Bricolage Grotesque", sans-serif; font-weight: 700; font-size: 32px; margin: 0; letter-spacing: -0.02em; }
.st-grid .st-head .sub { color: var(--text-2); font-size: 14.5px; margin-top: 6px; }
.st-grid .st-head .sub b { color: var(--text); font-weight: 600; }
/* 48px, not 40. CODING-STANDARDS: "Minimum touch target: 48px. No exceptions."
   Measured at 40px on 2026-08-02 when this button moved into the courses
   control strip and the strip's own touch-target check caught it. It was the
   same 40px on My websites, where nothing was measuring — a primary call to
   action under the minimum on both products. Raised in the component, so both
   get it. */
.st-grid .st-add { background: var(--accent); color: #fff; border: none; border-radius: 11px; padding: 0 20px; min-height: 48px; font-size: 14px; font-weight: 600; display: inline-flex; align-items: center; gap: 8px; box-shadow: 0 10px 24px -10px rgba(106,76,241,0.6); white-space: nowrap; cursor: pointer; }
.st-grid .st-add:hover { background: var(--accent-deep); }
.st-grid .st-add svg { width: 15px; height: 15px; }
.st-grid .st-sites { display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: 16px; }
.st-grid .st-card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-lg); overflow: hidden; display: flex; flex-direction: column; transition: border-color .15s, box-shadow .15s, transform .15s; }
.st-grid .st-card:hover { border-color: var(--accent-2, var(--accent)); box-shadow: 0 26px 56px -40px rgba(106,76,241,0.45); transform: translateY(-2px); }
.st-grid .st-shot { aspect-ratio: 16/9; position: relative; background: var(--surface-3); overflow: hidden; }
.st-grid .st-shot img { width: 100%; height: 100%; object-fit: cover; object-position: top center; display: block; }
.st-grid .st-shot .ph.st-plain { font-size: 17px; padding: 0 22px; text-align: center; line-height: 1.3; color: var(--text-3); }
.st-grid .st-shot .ph { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; color: var(--text-4); font-family: "Bricolage Grotesque", sans-serif; font-weight: 700; font-size: 22px; background: linear-gradient(135deg, var(--surface-2), var(--surface-3)); }
.st-grid .st-shot .status { position: absolute; top: 12px; left: 12px; font-family: "Inter", sans-serif; font-size: 11px; font-weight: 600; padding: 4px 11px; border-radius: 999px; display: inline-flex; align-items: center; gap: 6px; z-index: 2; }
/* The course card's second pill — Live/Test payments — sits top-right so it never covers Published/Draft. */
.st-grid .st-shot .status[data-pay-mode] { left: auto; right: 12px; }
.st-grid .st-shot .status .d { width: 7px; height: 7px; border-radius: 50%; }
.st-grid .st-shot .status.live { background: #dcefe2; color: #1c7a4a; } .st-grid .st-shot .status.live .d { background: #1c7a4a; }
.st-grid .st-shot .status.prog { background: var(--accent-soft); color: var(--accent-deep); } .st-grid .st-shot .status.prog .d { background: var(--accent); }
.st-grid .st-shot .st-del { position: absolute; top: 10px; right: 10px; z-index: 3; width: 30px; height: 30px; border-radius: 8px; border: none; background: rgba(17,16,34,0.55); color: #fff; display: inline-flex; align-items: center; justify-content: center; cursor: pointer; opacity: 0; transition: opacity .15s ease, background .15s ease; }
.st-grid .st-card:hover .st-del, .st-grid .st-del:focus-visible { opacity: 1; }
.st-grid .st-shot .st-del:hover { background: #c0392b; }
.st-grid .st-shot .st-del svg { width: 15px; height: 15px; }
@media (hover: none) { .st-grid .st-shot .st-del { opacity: 1; } }
/* The ••• menu on a card's picture (cb-actions.js, edit/delete standard 2026-10-08): always shown, never on hover. */
.st-grid .st-shot .st-more { position: absolute; top: 8px; right: 8px; z-index: 3; }
.st-grid .st-shot .st-more .cba-dots { margin: 0; background: rgba(255,255,255,0.92); color: var(--text, #15172b); box-shadow: 0 1px 3px rgba(17,16,34,0.18); }
.st-grid .st-shot .st-more .cba-dots:hover, .st-grid .st-shot .st-more .cba-dots[aria-expanded="true"] { background: #fff; }
.st-grid .st-shot .st-refresh { position: absolute; top: 10px; right: 46px; z-index: 3; width: 30px; height: 30px; border-radius: 8px; border: none; background: rgba(17,16,34,0.55); color: #fff; display: inline-flex; align-items: center; justify-content: center; cursor: pointer; }
.st-grid .st-shot .st-refresh svg { width: 15px; height: 15px; }
.st-grid .st-shot .st-refresh.spin svg { animation: st-spin 0.9s linear infinite; }
@keyframes st-spin { to { transform: rotate(360deg); } }
/* "Delete this website" never sits beside "Show my site as it is now"
   (website round 9, F13, Patricia: two 30px buttons 6px apart, the
   destructive one at a thumb's slip from the everyday one). On a website
   card (the one with the refresh) the bin goes to the other corner, a row
   away, and on a phone or touch screen both are 44px targets. Funnel and
   course cards keep their bin where it was. */
.st-grid .st-shot .st-refresh { right: 10px; }
.st-grid .st-shot .st-refresh ~ .st-del { top: auto; bottom: 10px; }
@media (max-width: 760px), (pointer: coarse) {
  .st-grid .st-shot .st-del, .st-grid .st-shot .st-refresh { width: 44px; height: 44px; border-radius: 10px; }
  .st-grid .st-shot .st-del svg, .st-grid .st-shot .st-refresh svg { width: 18px; height: 18px; }
}
.st-grid .st-shot .st-sample { position: absolute; left: 10px; bottom: 10px; z-index: 2; max-width: calc(100% - 74px); font-size: 11px; font-weight: 600; padding: 3px 8px; border-radius: 999px; background: rgba(17,16,34,0.6); color: #fff; }
.st-grid .st-cbody { padding: 16px 18px 18px; flex: 1; display: flex; flex-direction: column; }
.st-grid .st-name { font-family: "Bricolage Grotesque", sans-serif; font-weight: 700; font-size: 17px; letter-spacing: -0.01em; }
.st-grid .st-url { font-family: "JetBrains Mono", monospace; font-size: 11.5px; color: var(--text-3); margin-top: 3px; }
.st-grid .st-prog { margin-top: 12px; }
.st-grid .st-prog .l { font-size: 12px; color: var(--text-3); display: flex; justify-content: space-between; margin-bottom: 5px; }
.st-grid .st-prog .l b { color: var(--accent-deep); font-weight: 600; }
.st-grid .st-prog .bar { height: 6px; border-radius: 3px; background: var(--surface-3); overflow: hidden; }
.st-grid .st-prog .bar i { display: block; height: 100%; background: var(--accent); border-radius: 3px; transition: width .4s; }
/* §COMMUNITY-TIDY.6 — his words: the Manage / Continue setup buttons "should
   always be aligned. It shouldn't be wonky." The card body is a flex column,
   so the actions row pins to the FOOT: every card's button lines up across
   the row however much text sits above it. */
.st-grid .st-acts { display: flex; gap: 8px; margin-top: auto; padding-top: 16px; }
.st-grid .st-acts button, .st-grid .st-acts a { border-radius: 9px; padding: 10px 14px; font-size: 13px; font-weight: 600; display: inline-flex; align-items: center; justify-content: center; gap: 7px; cursor: pointer; border: none; text-decoration: none; }
.st-grid .st-acts .primary { background: var(--accent); color: #fff; flex: 1; }
.st-grid .st-acts .primary:hover { background: var(--accent-deep); }
.st-grid .st-acts .primary svg { width: 13px; height: 13px; }
.st-grid .st-acts .ghost { background: var(--surface); color: var(--text-2); border: 1px solid var(--border); }
.st-grid .st-acts .ghost:hover { background: var(--surface-2); color: var(--text); }
.st-grid .st-acts .ghost svg { width: 14px; height: 14px; }
/* A quiet secondary action beside the primary (courses: "Delete this draft" on a
   course that was never built). Text, not a button shape, so the primary stays
   the obvious next step. */
.st-grid .st-acts .quiet { background: none; color: var(--text-3); font-weight: 500; padding: 10px 4px; }
.st-grid .st-acts .quiet:hover { color: #c0392b; text-decoration: underline; }
.st-grid .st-acts .quiet[disabled] { opacity: .5; cursor: default; }
.st-grid .st-addcard { border: 1.5px dashed var(--border-strong); border-radius: var(--radius-lg); background: var(--surface-2); display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; padding: 28px; min-height: 280px; color: var(--text-2); transition: border-color .15s, background .15s; cursor: pointer; }
.st-grid .st-addcard:hover { border-color: var(--accent-2, var(--accent)); background: var(--accent-softer, var(--accent-soft)); }
.st-grid .st-addcard .pl { width: 50px; height: 50px; border-radius: 14px; background: var(--surface); border: 1px solid var(--border); color: var(--accent); display: flex; align-items: center; justify-content: center; margin-bottom: 14px; }
.st-grid .st-addcard .pl svg { width: 24px; height: 24px; }
.st-grid .st-addcard .t { font-family: "Bricolage Grotesque", sans-serif; font-weight: 700; font-size: 16px; color: var(--text); }
.st-grid .st-addcard .d { font-size: 13px; margin-top: 5px; max-width: 200px; line-height: 1.45; }
.st-grid .st-addcard .go { margin-top: 14px; font-size: 13px; font-weight: 600; color: var(--accent); display: inline-flex; align-items: center; gap: 6px; }
.st-grid .st-addcard .go svg { width: 14px; height: 14px; }
.st-grid .st-empty { text-align: center; padding: 60px 24px; }
.st-grid .st-empty .ic { width: 76px; height: 76px; border-radius: 20px; background: var(--accent-soft); color: var(--accent-deep); display: inline-flex; align-items: center; justify-content: center; margin-bottom: 22px; }
.st-grid .st-empty .ic svg { width: 38px; height: 38px; }
.st-grid .st-empty h2 { font-family: "Bricolage Grotesque", sans-serif; font-weight: 800; font-size: 28px; margin: 0 0 10px; letter-spacing: -0.02em; }
.st-grid .st-empty p { color: var(--text-2); font-size: 15.5px; margin: 0 auto 24px; max-width: 480px; line-height: 1.55; }
.st-grid .st-empty p b { color: var(--text); font-weight: 600; }
.st-grid .st-empty .big { background: var(--accent); color: #fff; border: none; border-radius: 13px; padding: 15px 28px; font-size: 15.5px; font-weight: 700; display: inline-flex; align-items: center; gap: 10px; box-shadow: 0 14px 30px -12px rgba(106,76,241,0.6); cursor: pointer; }
.st-grid .st-empty .big:hover { background: var(--accent-deep); }
.st-grid .st-empty .big svg { width: 17px; height: 17px; }
.st-grid .st-empty .note { margin-top: 16px; font-size: 13px; color: var(--text-3); }
@media (max-width: 680px) { .st-grid .st-head { flex-direction: column; align-items: flex-start; } .st-grid .st-head h1 { font-size: 26px; } }

/* ══════════════════════════════════════════════════════════════════════
   ORDER AND SHAPE — the toolbar above the grid (2026-08-02)

   Alex: "in the courses area you should be able to sort by alphabet up or
   down, age, like most recent, and also you should be able to flip between
   rows or tiles."

   ⚠️ Honest note, because the standing instruction is to repurpose rather than
   rebuild: THIS DID NOT EXIST ANYWHERE. My websites has no sort and no view
   switch either — it renders whatever order the API returned, as tiles, full
   stop. So there was nothing to take. It is built HERE, in the shared card
   component, rather than privately in the Courses list, so My websites can
   have it by rendering one more element — which is the difference between
   this and the next lookalike.

   Rows are the same cards, turned on their side: the picture becomes a
   thumbnail at a fixed width and the body runs beside it. No second card
   markup, so nothing can drift between the two views.
   ══════════════════════════════════════════════════════════════════════ */

/* One right-aligned strip. `margin-left: auto` on the first child pushes the
   whole cluster right rather than each control finding its own edge — which is
   what the old `.sp` spacer did, and why Sort and the view switch ended up at
   opposite ends of the page with a gulf between them. */
.st-grid .st-tools {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  justify-content: flex-end; margin: 0 0 16px;
}
.st-grid .st-tools .st-add { margin-left: 4px; }

/* QUIET by default. Alex: "it doesn't need to be so dominant on the page."
   A sort control is a secondary thing — it carries no border until you go near
   it, and its type is the muted grey the rest of the page uses for metadata. */
.st-grid .st-sort {
  font: inherit; font-size: 13px; color: var(--text-2); background: transparent;
  border: 1px solid transparent; border-radius: 10px; padding: 0 30px 0 10px;
  /* 48px, the house minimum for anything a thumb has to hit — CODING-STANDARDS
     "Minimum touch target: 48px. No exceptions." The view switch beside it is
     built to the same height so the pair reads as one control strip. */
  height: 48px; cursor: pointer; appearance: none;
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%237c7a8f' stroke-width='2.4'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 9px center; background-size: 13px;
  transition: border-color .12s, background-color .12s, color .12s;
}
.st-grid .st-sort:hover { border-color: var(--border); background-color: var(--surface); color: var(--text); }
.st-grid .st-sort:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

.st-grid .st-view {
  display: inline-flex; background: transparent; border: 1px solid var(--border);
  border-radius: 10px; overflow: hidden;
}
.st-grid .st-view button {
  border: none; background: transparent; color: var(--text-3); cursor: pointer;
  width: 48px; height: 48px;
  display: inline-flex; align-items: center; justify-content: center;
}
.st-grid .st-view button + button { border-left: 1px solid var(--border); }
.st-grid .st-view button svg { width: 17px; height: 17px; }
.st-grid .st-view button:hover { color: var(--text); }
.st-grid .st-view button.on { background: var(--surface); color: var(--accent-deep); box-shadow: 0 1px 3px rgba(17,16,34,0.10); }

/* ── Rows: the same card, on its side ─────────────────────────────────── */
.st-grid .st-sites.is-rows { grid-template-columns: 1fr; gap: 10px; }
.st-grid .st-sites.is-rows .st-card { flex-direction: row; align-items: stretch; }
.st-grid .st-sites.is-rows .st-card:hover { transform: none; }
/* The picture keeps its 16/9, so every row is the same height. Letting it size
   to the body instead gave a ragged list — a course with no lessons ended up
   two thirds the height of one mid-build. */
.st-grid .st-sites.is-rows .st-shot { width: 180px; flex: none; }
/* 180px wide the picture is 101px tall, and the status pill (top 12px, ~22px
   tall) met the centred initials: "Unpublished" sat on "SB" (round 6). In a
   row the initials are centred in the space BELOW the pills, and a pill never
   runs wider than the picture. */
.st-grid .st-sites.is-rows .st-shot .ph { padding-top: 30px; }
.st-grid .st-sites.is-rows .st-shot .status { max-width: calc(100% - 24px); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.st-grid .st-sites.is-rows .st-cbody { flex-direction: row; align-items: center; gap: 20px; padding: 14px 18px; }
.st-grid .st-sites.is-rows .st-cbody > .st-name { flex: 1 1 auto; min-width: 0; }
/* The mono sub-line moves BESIDE the name rather than being hidden. It carries
   the design slug or the lesson count, which is most of what tells one row
   from another once the pictures are small. */
.st-grid .st-sites.is-rows .st-url { flex: none; margin-top: 0; }
.st-grid .st-sites.is-rows .st-prog { margin-top: 0; width: 180px; flex: none; }
.st-grid .st-sites.is-rows .st-acts { margin-top: 0; flex: none; }
.st-grid .st-sites.is-rows .st-acts .primary { flex: none; }
/* The add-card is a tile-shaped invitation; as a row it is just a thin strip. */
.st-grid .st-sites.is-rows .st-addcard { min-height: 0; padding: 18px; flex-direction: row; gap: 14px; text-align: left; }
.st-grid .st-sites.is-rows .st-addcard .pl { margin-bottom: 0; width: 40px; height: 40px; }
.st-grid .st-sites.is-rows .st-addcard .d { display: none; }
.st-grid .st-sites.is-rows .st-addcard .go { margin-top: 0; margin-left: auto; }

/* A phone is one column wide either way, so rows collapse back to the card
   shape rather than squeezing four things onto a 375px line. */
@media (max-width: 700px) {
  .st-grid .st-sites.is-rows .st-card { flex-direction: column; }
  .st-grid .st-sites.is-rows .st-shot { width: auto; aspect-ratio: 16/9; }
  .st-grid .st-sites.is-rows .st-shot .ph { padding-top: 0; }
  .st-grid .st-sites.is-rows .st-cbody { flex-direction: column; align-items: stretch; gap: 0; padding: 16px 18px 18px; }
  .st-grid .st-sites.is-rows .st-url { position: static; }
  .st-grid .st-sites.is-rows .st-prog { width: auto; margin-top: 12px; }
  .st-grid .st-sites.is-rows .st-acts { margin-top: 16px; }
  .st-grid .st-sites.is-rows .st-acts .primary { flex: 1; }
  /* The strip stays one line on a phone: three controls, right-aligned,
     wrapping only if the New course label needs it. */
  .st-grid .st-tools { gap: 6px; }
}

/* ══════════════════════════════════════════════════════════════════════
   "NEEDS SETUP" — the marker and the banner (L19)

   Alex, 2026-08-03: "a marker on each course tile to say that this one has got
   missing things in it and maybe a banner saying, 'You need to set these things
   up to make them work within' across the course page where all the tiles are"
   — and, in the same breath, "Not a banner that goes across the entire
   dashboard but a banner that sits within the course area."

   Both are ADVISORY. They use the warn tone, never the danger tone: nothing
   here blocks anything, and a red badge on a course that is live and selling
   would be a lie about its state.
   ══════════════════════════════════════════════════════════════════════ */
.st-grid .st-setup {
  position: absolute; left: 10px; bottom: 10px; z-index: 2;
  display: inline-flex; align-items: center; gap: 5px;
  padding: 4px 9px; border-radius: 999px;
  background: rgba(24,20,10,.82); color: #fdf0d5;
  font-size: 10.5px; font-weight: 650; letter-spacing: .01em;
  backdrop-filter: blur(3px);
}
/* ⚠️ The [hidden] guard, for the FIFTH time today. An author display beats the
   UA rule, and without this every tile would carry the badge before the answer
   arrives — the exact false alarm the fired-not-awaited design avoids. */
.st-grid .st-setup[hidden] { display: none; }

.st-grid .st-setup-banner {
  margin: 0 0 14px; padding: 12px 15px; border-radius: 12px;
  background: var(--warn-soft, rgba(214,158,46,.12));
  border: 1px solid var(--warn-border, rgba(214,158,46,.32));
  color: var(--text); font-size: 13px; line-height: 1.5;
}
.st-grid .st-setup-banner[hidden] { display: none; }
.st-grid .st-setup-banner b { font-weight: 700; }

/* (The 150px under the Courses grid is gone, round 5. It kept the floating
   Help launcher off the last row of cards; Help is now in the side menu and
   the app bar, and the room it left pushed the "make a course yourself" form
   a screen away from the link that opens it.) */

/* A course card's title opens the course (subpages.js). Looks like the title,
   behaves like a link. */
.st-grid .st-name .st-name-open { all: unset; cursor: pointer; font: inherit; color: inherit; }
.st-grid .st-name .st-name-open:hover { text-decoration: underline; }
.st-grid .st-name .st-name-open:focus-visible { outline: 2px solid var(--accent, #4f46e5); outline-offset: 2px; border-radius: 3px; }
