/* EZ Realm — the hub.
 *
 * Palette: the family's own. #1E2124 is the shared tile background every app icon
 * in this fleet sits on (standardised 2026-07-14), and #6FA3CF is the family blue
 * from the original roof mark. The umbrella wears the shared colours rather than
 * inventing a tenth accent — the point of a hub is that it looks like the parent
 * of everything it lists. Each app keeps its own accent on its own card.
 */

:root {
  --bg:        #15171A;
  --surface:   #1E2124;
  --surface-2: #24282C;
  --line:      #2E3338;
  --ink:       #E9ECEF;
  --ink-dim:   #A4ADB6;
  --ink-faint: #6E7A85;
  --brand:     #6FA3CF;
  --brand-dim: #4A7CA6;
  --radius: 14px;
  --pad: clamp(20px, 5vw, 64px);
  --maxw: 1120px;
}

*, *::before, *::after { box-sizing: border-box; }

html, body { margin: 0; padding: 0; }

body {
  background: var(--bg);
  color: var(--ink);
  font: 16px/1.65 -apple-system, BlinkMacSystemFont, 'Segoe UI', Inter, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

/* Scrollbars hidden everywhere — house rule. The page still scrolls by wheel,
   trackpad, swipe and keyboard; only the visible bar is gone. The one documented
   exception is a wide data table's horizontal bar, and there are none here. */
html { scrollbar-width: none; -ms-overflow-style: none; }
::-webkit-scrollbar { width: 0; height: 0; }

a { color: var(--brand); text-decoration: none; }
a:hover { text-decoration: underline; text-underline-offset: 3px; }

h1 { font-size: clamp(30px, 5vw, 46px); line-height: 1.12; letter-spacing: -0.02em; margin: 0 0 14px; }
h2 { font-size: clamp(21px, 2.6vw, 26px); letter-spacing: -0.01em; margin: 0 0 10px; }
h3 { font-size: 16px; margin: 0 0 6px; letter-spacing: -0.005em; }

.lede { color: var(--ink-dim); font-size: clamp(16px, 1.7vw, 18.5px); max-width: 62ch; margin: 0 0 22px; }

.skip {
  position: absolute; left: -9999px; top: 0; background: var(--surface);
  color: var(--ink); padding: 10px 14px; z-index: 50; border-radius: 0 0 8px 0;
}
.skip:focus { left: 0; }

/* ---------- splash (app-specific overrides on the shared structure) ---------- */
#splash { background: var(--bg); z-index: 60; }
.splash-inner { text-align: center; animation: splashIn .62s cubic-bezier(.2,.7,.3,1) both; }
.splash-mark svg { width: 108px; height: 108px; display: block; margin: 0 auto 18px; }
.splash-name { font-size: 30px; font-weight: 650; letter-spacing: -0.02em; }
.splash-by { color: var(--ink-faint); font-size: 13.5px; margin-top: 5px; letter-spacing: .01em; }

/* ---------- chrome ---------------------------------------------------------- */
.topbar {
  display: flex; align-items: center; justify-content: space-between; gap: 18px;
  padding: 16px var(--pad); border-bottom: 1px solid var(--line);
  position: sticky; top: 0; background: rgba(21,23,26,.86);
  backdrop-filter: saturate(160%) blur(12px); z-index: 20;
}
.brand { display: inline-flex; align-items: center; gap: 9px; color: var(--ink); font-weight: 640; letter-spacing: -0.01em; }
.brand:hover { text-decoration: none; }
.brand-mark { width: 26px; height: 26px; color: var(--brand); flex: none; }

.nav { display: flex; gap: 4px; flex-wrap: wrap; }
.nav a {
  color: var(--ink-dim); padding: 7px 13px; border-radius: 999px; font-size: 14.5px;
  border: 1px solid transparent;
}
.nav a:hover { color: var(--ink); background: var(--surface); text-decoration: none; }
.nav a.is-active { color: var(--ink); background: var(--surface); border-color: var(--line); }

main { flex: 1 0 auto; width: 100%; max-width: var(--maxw); margin: 0 auto; padding: 0 var(--pad); }

.sitefoot {
  display: flex; justify-content: space-between; gap: 12px; flex-wrap: wrap;
  max-width: var(--maxw); width: 100%; margin: 56px auto 0; padding: 20px var(--pad) 30px;
  border-top: 1px solid var(--line); color: var(--ink-faint); font-size: 13px;
}

/* ---------- sections -------------------------------------------------------- */
.hero { padding: clamp(48px, 9vw, 96px) 0 clamp(28px, 4vw, 44px); max-width: 74ch; }
.hero-actions { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 26px; }

.btn {
  display: inline-block; padding: 11px 19px; border-radius: 10px; font-size: 15px;
  font-weight: 560; background: var(--brand); color: #10161B; border: 1px solid var(--brand);
}
.btn:hover { background: #82B2DA; text-decoration: none; }
.btn--quiet { background: transparent; color: var(--ink); border-color: var(--line); }
.btn--quiet:hover { background: var(--surface); }

.pad { padding: clamp(26px, 4vw, 46px) 0; }
.sec-title { color: var(--ink); }
.sec-title + .grid, .sec-title + .prin { margin-top: 18px; }

/* ---------- cards ----------------------------------------------------------- */
.grid {
  display: grid; gap: 14px;
  grid-template-columns: repeat(auto-fill, minmax(288px, 1fr));
}
.grid--tight { grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); }

.card {
  display: flex; flex-direction: column; gap: 8px; position: relative;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 18px 18px 16px; color: var(--ink);
  transition: border-color .16s ease, transform .16s ease, background .16s ease;
}
a.card:hover { border-color: var(--brand-dim); background: var(--surface-2); transform: translateY(-2px); text-decoration: none; }
.card--flat { opacity: .93; }

/* The app's own accent, as a bar rather than a coloured tile — the family grey
   stays the background so nine accents in one grid still read as one family. */
.card-mark { display: block; width: 30px; height: 3px; border-radius: 2px; background: var(--mark, var(--brand)); }
.card-head { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.card-name { font-weight: 640; font-size: 17px; letter-spacing: -0.01em; }
.card-status { font-size: 11px; text-transform: uppercase; letter-spacing: .07em; color: var(--ink-faint); white-space: nowrap; }
.card-status--live { color: #74C79A; }
.card-status--soon, .card-status--beta { color: var(--brand); }
.card-tagline { color: var(--ink); font-size: 14.5px; }
.card-blurb { color: var(--ink-dim); font-size: 13.6px; line-height: 1.6; }

/* An app you can install rather than only visit. */
.card-download {
  display: inline-block; margin-top: 4px;
  font-size: 12.5px; font-weight: 600;
  color: var(--mark, currentColor);
}
.card-stack { display: flex; flex-wrap: wrap; gap: 5px; list-style: none; margin: 4px 0 0; padding: 0; }
.card-stack li {
  font-size: 11.5px; color: var(--ink-faint); border: 1px solid var(--line);
  border-radius: 999px; padding: 2px 8px;
}
.card-own { font-size: 11.5px; color: var(--ink-faint); font-style: italic; }
.card-go { margin-top: 6px; font-size: 13px; color: var(--brand); font-weight: 560; }

/* ---------- principles / list ----------------------------------------------- */
.prin { list-style: none; margin: 0; padding: 0; display: grid; gap: 14px;
        grid-template-columns: repeat(auto-fill, minmax(268px, 1fr)); }
.prin li { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); padding: 18px; }
.prin p { color: var(--ink-dim); font-size: 13.8px; margin: 0; line-height: 1.6; }

/* ---------- portfolio ------------------------------------------------------- */
.pf-head { padding-top: clamp(44px, 8vw, 84px); }
.pf-kicker { color: var(--brand); font-size: 12.5px; text-transform: uppercase; letter-spacing: .16em; margin: 0 0 10px; }
.pf-contact { border-top: 1px solid var(--line); margin-top: 12px; }

/* ---------- launcher -------------------------------------------------------- */
.page-launcher .card-blurb, .page-launcher .card-stack { display: none; }
/* The launcher used to strip the download line, on the reasoning that there he
   is opening apps that are already running. Magic Monitor broke that: it is
   launcher-only, and its card points at localhost:8195, which does nothing at
   all until the app has been installed. For an app you do not have yet, the
   fact that it CAN be installed is the most useful thing on the card, so the
   line stays. */
.page-launcher .card-download { display: inline-block; }
/* Stacked rather than baseline-aligned: a long name next to a long status ("EZ Realm
   Consulting" / "LAUNCHING SOON") wraps and drags the badge out of line. Vertical
   works at every name length instead of only the short ones. */
.page-launcher .card-head { flex-direction: column; align-items: flex-start; gap: 1px; }
.page-launcher .card-status { order: -1; }

@media (max-width: 560px) {
  .topbar { flex-direction: column; align-items: flex-start; gap: 12px; }
  .hero { padding-top: 40px; }
}

@media (prefers-reduced-motion: reduce) {
  * { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

/* ---------- Veri EZ explainer (/veri-ez) ------------------------------------
 * The hub itself wears the family blue, but this is one app's own page, and the
 * card convention already gives every app its own accent on its own surface.
 * Scoped to .page-veriez so nothing else on the site picks up the purple.
 */
.page-veriez { --accent: #7A6FCF; }
.vz-head { padding-top: clamp(44px, 8vw, 84px); padding-bottom: 6px; }
.vz-kicker {
  color: var(--accent); font-size: 12.5px; text-transform: uppercase;
  letter-spacing: .16em; margin: 0 0 10px;
}
.vz-chips { margin-top: 10px; }
.vz-prose { max-width: 68ch; color: var(--ink-dim); }
.vz-prose p { margin: 0 0 14px; font-size: 15.5px; line-height: 1.7; }
.vz-prose p:last-child { margin-bottom: 0; }

/* The "you got here by clicking a joke" panel — a left accent bar rather than a
   tinted background, so it reads as an aside without becoming a callout box. */
.vz-note {
  border: 1px solid var(--line); border-left: 3px solid var(--accent);
  border-radius: var(--radius); background: var(--surface);
  padding: 20px 22px; max-width: 72ch;
}
.vz-note h2 { font-size: clamp(19px, 2.2vw, 22px); margin-bottom: 8px; }
.vz-note p { color: var(--ink-dim); font-size: 15px; line-height: 1.7; margin: 0 0 12px; }
.vz-note p:last-child { margin-bottom: 0; }
.vz-note em { color: var(--ink); font-style: normal; }
.vz-note--quiet { border-left-color: var(--line); }
.vz-back { margin-top: 14px !important; }
.vz-back a { color: var(--accent); }

/* ===== Recent visits (launcher only) =====
   Who has been on the hub who is not him. It lives on the launcher because that
   page is already token-gated; a second private route would be a second gate to
   get wrong. A three-column list rather than a table: there are only ever thirty
   rows and a table would need the one horizontal scrollbar the house rule allows,
   for no gain. Plain text and a middle dot — no emoji, per the standing rule. */
.visits-lede { font-size: 15px; }
.visits {
  list-style: none; margin: 0; padding: 0;
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--surface); overflow: hidden;
}
.visits li {
  display: grid; gap: 2px 16px; padding: 11px 16px;
  grid-template-columns: 190px 150px 1fr; align-items: baseline;
  border-top: 1px solid var(--line); font-size: 14px;
}
.visits li:first-child { border-top: 0; }
.visits-when { color: var(--ink-faint); font-variant-numeric: tabular-nums; }
.visits-path { color: var(--ink); }
.visits-who  { color: var(--ink-dim); overflow-wrap: anywhere; }
.visits-empty, .visits-arm { color: var(--ink-dim); font-size: 14.5px; max-width: 68ch; }
.visits-arm { margin-top: 14px; }
.visits-arm a { color: var(--brand); }

@media (max-width: 720px) {
  .visits li { grid-template-columns: 1fr; }
  .visits-when { font-size: 13px; }
}
