/* ==========================================================================
   Self-Hosted Apps — live directory board.
   Studio theme (tokens.css): indigo --accent, teal --signal, Space Grotesk /
   Inter / JetBrains Mono. Everything scoped under .sha-page / .sha-board.
   ========================================================================== */

.sha-page{
  --sha-ok:#0f8f74;    --sha-ok-soft:rgba(77,184,168,.15);
  --sha-warn:#9a6a11;  --sha-warn-soft:rgba(245,215,110,.28);
  --sha-bad:#c0392b;   --sha-bad-soft:rgba(255,107,107,.14);
  --sha-line-2:color-mix(in srgb, var(--ink) 22%, transparent);
  --sha-cream:var(--surface-2);
}

/* ---------- freshness ticker ---------- */
.sha-ticker{border:1px solid var(--line); border-radius:var(--radius);
  background:var(--sha-cream); overflow:hidden; display:flex; align-items:stretch; margin-bottom:18px}
.sha-ticker__tag{flex:none; display:flex; align-items:center; gap:8px; padding:0 15px;
  font-family:var(--font-mono); font-size:11px; letter-spacing:.08em; text-transform:uppercase;
  color:color-mix(in srgb, var(--accent) 78%, var(--ink)); background:var(--surface);
  border-right:1px solid var(--line); white-space:nowrap}
.sha-ticker__dot{width:8px; height:8px; border-radius:50%; background:var(--signal); animation:sha-pulse 2.2s infinite}
@keyframes sha-pulse{0%{box-shadow:0 0 0 0 var(--sha-ok-soft)}70%{box-shadow:0 0 0 7px transparent}100%{box-shadow:0 0 0 0 transparent}}
.sha-ticker__track{overflow:hidden; flex:1; display:flex; align-items:center}
.sha-ticker__move{display:inline-flex; gap:26px; padding:11px 0 11px 26px; white-space:nowrap;
  font-family:var(--font-mono); font-size:12.5px; align-items:center; animation:sha-scroll 46s linear infinite}
.sha-ticker__track:hover .sha-ticker__move{animation-play-state:paused}
@keyframes sha-scroll{from{transform:translateX(0)}to{transform:translateX(-50%)}}
.sha-tk{color:var(--muted)} .sha-tk b{color:var(--ink); font-weight:600}
.sha-tk__sep{color:var(--muted); opacity:.5}

/* ---------- top block ---------- */
.sha-top{display:grid; grid-template-columns:minmax(0,1fr) minmax(360px,.7fr); gap:28px; align-items:center; margin-bottom:8px}
.sha-hero h1{font-family:var(--font-display); font-size:clamp(28px,3.6vw,42px); line-height:1.05;
  letter-spacing:-.02em; margin:0 0 10px; color:var(--ink); text-wrap:balance; font-weight:700}
.sha-hero--hub{margin:6px 0 18px}
.sha-lede{max-width:56ch; color:var(--muted); font-size:15px; line-height:1.55; margin:0}
.sha-lede b{color:var(--ink); font-weight:600}

.sha-tiles{display:grid; grid-template-columns:repeat(3,1fr); gap:8px; margin:0}
.sha-tile{position:relative; overflow:hidden; background:var(--surface); border:1px solid var(--line);
  border-radius:var(--radius-sm); padding:10px 12px; box-shadow:var(--shadow-sm); min-width:0}
.sha-tile::before{content:""; position:absolute; left:0; top:0; bottom:0; width:2px; background:var(--accent); opacity:.6}
.sha-tile .k{font-family:var(--font-mono); font-size:9px; letter-spacing:.07em; text-transform:uppercase; color:var(--muted); white-space:nowrap}
.sha-tile .v{font-family:var(--font-display); font-size:19px; font-weight:700; margin-top:3px;
  letter-spacing:-.01em; font-variant-numeric:tabular-nums; color:var(--ink); line-height:1.15}
.sha-tile .sub{font-size:10px; color:var(--muted); margin-top:1px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis}

/* ---------- breadcrumb (hub pages) ---------- */
.sha-crumbs{font-family:var(--font-mono); font-size:12px; color:var(--muted); margin:0 0 14px; display:flex; gap:8px; flex-wrap:wrap}
.sha-crumbs a{color:var(--accent); text-decoration:none}
.sha-crumbs a:hover{text-decoration:underline}

/* ---------- controls ---------- */
.sha-controls{display:flex; flex-wrap:wrap; align-items:center; gap:10px; margin:18px 0 10px}
.sha-search{flex:1 1 240px; min-width:200px}
.sha-search input{width:100%; font-family:var(--font-body); font-size:13.5px; color:var(--ink);
  border:1px solid var(--line); background:var(--surface); border-radius:999px; padding:9px 16px; outline:none; transition:.13s}
.sha-search input:focus{border-color:color-mix(in srgb, var(--accent) 45%, transparent);
  box-shadow:0 0 0 3px color-mix(in srgb, var(--accent) 12%, transparent)}
.sha-chips{display:flex; flex-wrap:wrap; gap:7px}
.sha-controls__right{display:flex; align-items:center; gap:9px; margin-left:auto}
.sha-chip{font-family:var(--font-mono); font-size:12px; color:var(--muted); cursor:pointer;
  border:1px solid var(--line); background:var(--surface); padding:7px 12px; border-radius:999px;
  display:inline-flex; align-items:center; gap:7px; transition:.13s; user-select:none}
.sha-chip:hover{border-color:var(--sha-line-2); color:var(--ink)}
.sha-chip[aria-pressed="true"]{background:color-mix(in srgb, var(--accent) 10%, transparent);
  border-color:color-mix(in srgb, var(--accent) 45%, transparent); color:var(--accent-strong)}
.sha-chip .n{font-size:10.5px; opacity:.6}
.sha-chip--toggle .dot{width:6px; height:6px; border-radius:50%; background:var(--sha-ok)}
.sha-sort select{font-family:var(--font-mono); font-size:12px; color:var(--ink); border:1px solid var(--line);
  background:var(--surface); border-radius:999px; padding:7px 30px 7px 13px; cursor:pointer; outline:none;
  appearance:none; background-image:linear-gradient(45deg,transparent 50%,var(--muted) 50%),linear-gradient(135deg,var(--muted) 50%,transparent 50%);
  background-position:calc(100% - 15px) 50%,calc(100% - 11px) 50%; background-size:4px 4px,4px 4px; background-repeat:no-repeat}
.sha-countbar{font-family:var(--font-mono); font-size:12px; color:var(--muted); margin:2px 0 14px}
.sha-countbar b{color:var(--ink)}

/* ---------- card grid ---------- */
.sha-grid{display:grid; grid-template-columns:repeat(auto-fill,minmax(300px,1fr)); gap:14px}
.sha-card{display:flex; flex-direction:column; gap:10px; text-decoration:none; background:var(--surface);
  border:1px solid var(--line); border-radius:var(--radius); padding:16px 16px 14px; box-shadow:var(--shadow-sm);
  transition:transform .13s, box-shadow .13s, border-color .13s; min-width:0}
.sha-card:hover{transform:translateY(-2px); box-shadow:var(--shadow-md,0 8px 24px rgba(0,0,0,.08));
  border-color:var(--sha-line-2)}
.sha-card__head{display:flex; align-items:center; gap:11px}
.sha-logo{width:42px; height:42px; border-radius:10px; flex:none; background:#fff; border:1px solid var(--line);
  display:grid; place-items:center; overflow:hidden; box-shadow:var(--shadow-sm)}
.sha-logo img{max-width:80%; max-height:80%; object-fit:contain; display:block}
.sha-logo .fb{font-family:var(--font-display); font-weight:700; font-size:17px; color:var(--muted)}
.sha-card__title{flex:1; min-width:0}
.sha-name{display:block; font-family:var(--font-display); font-weight:600; font-size:16px; color:var(--ink); line-height:1.2}
.sha-card:hover .sha-name{color:var(--accent)}
.sha-cat{display:block; font-family:var(--font-mono); font-size:10.5px; color:var(--muted); margin-top:2px; text-transform:uppercase; letter-spacing:.04em}

/* status badge */
.sha-status{flex:none; display:inline-flex; align-items:center; gap:5px; font-family:var(--font-mono);
  font-size:10.5px; font-weight:600; padding:4px 9px; border-radius:999px; white-space:nowrap}
.sha-status .dot{width:6px; height:6px; border-radius:50%; background:currentColor}
.sha-status--maintained{color:var(--sha-ok); background:var(--sha-ok-soft)}
.sha-status--stale{color:var(--sha-warn); background:var(--sha-warn-soft)}
.sha-status--abandoned{color:var(--sha-bad); background:var(--sha-bad-soft)}
.sha-status--unknown{color:var(--muted); background:color-mix(in srgb, var(--ink) 8%, transparent)}

.sha-tagline{margin:0; color:var(--muted); font-size:13.5px; line-height:1.5;
  display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden}
.sha-replaces{margin:0; font-family:var(--font-mono); font-size:11.5px; color:color-mix(in srgb, var(--accent) 75%, var(--ink))}

.sha-meta{display:flex; flex-wrap:wrap; gap:12px; margin-top:auto; padding-top:4px}
.sha-stat{font-family:var(--font-mono); font-size:12px; color:var(--ink); font-variant-numeric:tabular-nums; display:inline-flex; gap:4px; align-items:center}
.sha-stat--dim{color:var(--muted)}

.sha-card__foot{display:flex; flex-wrap:wrap; gap:6px; padding-top:10px; border-top:1px solid var(--line)}
.sha-diff{font-family:var(--font-mono); font-size:10.5px; font-weight:600; padding:3px 8px; border-radius:6px}
.sha-diff--easy{color:var(--sha-ok); background:var(--sha-ok-soft)}
.sha-diff--medium{color:var(--sha-warn); background:var(--sha-warn-soft)}
.sha-diff--hard{color:var(--sha-bad); background:var(--sha-bad-soft)}
.sha-deploy{font-family:var(--font-mono); font-size:10.5px; color:var(--muted); padding:3px 8px;
  border:1px solid var(--line); border-radius:6px}

.sha-empty,.sha-noresults{grid-column:1/-1; text-align:center; color:var(--muted); font-family:var(--font-mono); font-size:13px; padding:30px 0}
.sha-noresults button{color:var(--accent); background:none; border:none; cursor:pointer; text-decoration:underline; font:inherit}

/* ---------- host-it CTA (internal funnel to VPS board) ---------- */
.sha-hostcta{display:flex; align-items:center; justify-content:space-between; gap:20px; flex-wrap:wrap;
  margin-top:26px; padding:22px 24px; border:1px solid var(--line); border-radius:var(--radius);
  background:linear-gradient(120deg, var(--sha-cream), var(--surface)); box-shadow:var(--shadow-sm)}
.sha-hostcta h2{font-family:var(--font-display); font-size:19px; font-weight:700; color:var(--ink); margin:0 0 4px}
.sha-hostcta p{margin:0; color:var(--muted); font-size:14px; max-width:60ch}
.sha-hostcta__btn{flex:none; font-family:var(--font-mono); font-size:13px; font-weight:600; text-decoration:none;
  color:#fff; background:var(--accent); padding:11px 18px; border-radius:999px; transition:.13s; white-space:nowrap}
.sha-hostcta__btn:hover{background:var(--accent-strong)}

/* Course variant of the same band. Violet instead of indigo so the two stacked
   CTAs read as different offers ("where to run it" vs "learn the whole stack")
   rather than the same one repeated. */
.sha-hostcta--course{margin-top:14px;
  background:linear-gradient(120deg, color-mix(in srgb, var(--accent-2) 10%, var(--surface)), var(--surface))}
.sha-hostcta--course .sha-hostcta__btn{background:var(--accent-2)}
.sha-hostcta--course .sha-hostcta__btn:hover{background:color-mix(in srgb, var(--accent-2) 82%, black)}

/* ---------- responsive ---------- */
@media (max-width:820px){
  .sha-top{grid-template-columns:1fr; gap:16px}
  .sha-controls__right{margin-left:0}
}
@media (max-width:520px){
  .sha-tiles{grid-template-columns:1fr 1fr}
  .sha-grid{grid-template-columns:1fr}
}
