/* Portal Forum — one stylesheet, no framework, no build step. */

:root {
  color-scheme: light dark;

  --bg: #f0f2f5;
  --surface: #ffffff;
  --surface-2: #f7f8fa;
  --border: #dfe3e8;
  --text: #16181d;
  --text-dim: #616a75;
  /* --brand is the base colour the admin sets in Settings; --accent is what
     the current theme actually paints with, derived from it. */
  --brand: #4f46e5;
  --accent: var(--brand);
  --brand-hover: color-mix(in srgb, var(--accent) 84%, #000);
  --brand-soft: color-mix(in srgb, var(--accent) 10%, #fff);
  --danger: #c1362c;
  --danger-soft: #fdeceb;
  --ok: #1a7f5a;
  --ok-soft: #e7f5ef;
  --warn-soft: #fff6e5;
  --warn-text: #8a5a00;
  --shadow: 0 1px 2px rgba(16, 18, 26, .08), 0 8px 24px rgba(16, 18, 26, .06);
  --radius: 12px;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #101216;
    --surface: #191c22;
    --surface-2: #21252d;
    --border: #2c313b;
    --text: #e8eaed;
    --text-dim: #98a1ad;
    /* Lifted off the base so a dark surface still has contrast. */
    --accent: color-mix(in srgb, var(--brand) 60%, #fff);
    --brand-hover: color-mix(in srgb, var(--accent) 82%, #fff);
    --brand-soft: color-mix(in srgb, var(--accent) 20%, var(--surface));
    --danger: #f0857c;
    --danger-soft: #2b1b1a;
    --ok: #5ecfa4;
    --ok-soft: #14261f;
    --warn-soft: #2a2317;
    --warn-text: #e5b969;
    --shadow: 0 1px 2px rgba(0, 0, 0, .4), 0 8px 24px rgba(0, 0, 0, .3);
  }
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font: 15px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
}

a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }
img { max-width: 100%; display: block; }

.boot { padding: 4rem; text-align: center; color: var(--text-dim); }

/* ---------- Landing ---------- */

.landing {
  min-height: 100vh;
  min-height: 100dvh;
  display: grid;
  place-items: center;
  padding: 2rem 1rem;
  background: var(--surface);
}

.landing-inner {
  width: min(1000px, 100%);
  display: grid;
  grid-template-columns: 1.1fr 1fr;
  gap: 3.5rem;
  align-items: center;
}

@media (max-width: 860px) {
  .landing-inner { grid-template-columns: 1fr; gap: 2rem; text-align: center; }

  /* Centre the list as a block but keep the items left-aligned to each other,
     or the dashes zig-zag down the page. */
  .hero-points { display: inline-block; text-align: left; }

  /* A sign-in form stretched across a tablet reads as broken; cap it and
     centre it once the two columns have collapsed into one. */
  .auth-card { width: 100%; max-width: 420px; margin-inline: auto; }
}

.hero h1 {
  font-size: clamp(2.5rem, 6vw, 3.75rem);
  color: var(--accent);
  margin: 0 0 .5rem;
  letter-spacing: -.03em;
  /* The body's 1.5 is far too loose once a configured title wraps. */
  line-height: 1.05;
  overflow-wrap: break-word;
}

.hero p {
  font-size: clamp(1.125rem, 2.5vw, 1.5rem);
  line-height: 1.35;
  margin: 0 0 1.5rem;
  max-width: 32ch;
}

@media (max-width: 860px) { .hero p { max-width: none; } }

.hero-points { list-style: none; padding: 0; margin: 0; color: var(--text-dim); }
.hero-points li { padding: .3rem 0; }
.hero-points li::before { content: "—"; margin-right: .6rem; color: var(--accent); }

.auth-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 1.5rem;
}

.auth-card h2 { margin: 0 0 1rem; font-size: 1.25rem; }
.auth-divider { border: 0; border-top: 1px solid var(--border); margin: 1.25rem 0; }

/* ---------- Forms ---------- */

.field { margin-bottom: .85rem; }
.field label {
  display: block;
  font-size: .8125rem;
  font-weight: 600;
  color: var(--text-dim);
  margin-bottom: .3rem;
}

input, textarea, select {
  width: 100%;
  padding: .7rem .85rem;
  font: inherit;
  color: var(--text);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 8px;
}

input:focus, textarea:focus, select:focus {
  outline: 2px solid var(--accent);
  outline-offset: -1px;
  background: var(--surface);
}

textarea { resize: vertical; min-height: 90px; }

.hint { font-size: .75rem; color: var(--text-dim); margin-top: .3rem; }

button {
  font: inherit;
  font-weight: 600;
  padding: .7rem 1.1rem;
  border: 1px solid transparent;
  border-radius: 8px;
  background: var(--accent);
  color: #fff;
  cursor: pointer;
}
button:hover:not(:disabled) { background: var(--brand-hover); }
button:disabled { opacity: .55; cursor: not-allowed; }

button.block { width: 100%; }
button.secondary { background: var(--surface-2); color: var(--text); border-color: var(--border); }
button.secondary:hover:not(:disabled) { background: var(--border); }
button.ok { background: var(--ok); }
button.danger { background: var(--danger); }
button.link {
  background: none; color: var(--accent); padding: .25rem .4rem;
  border: 0; font-weight: 500;
}
button.link:hover:not(:disabled) { background: none; text-decoration: underline; }
button.small { padding: .35rem .6rem; font-size: .8125rem; }

.msg { padding: .7rem .85rem; border-radius: 8px; font-size: .875rem; margin-bottom: 1rem; }
.msg.error { background: var(--danger-soft); color: var(--danger); }
.msg.ok { background: var(--ok-soft); color: var(--ok); }
.msg.info { background: var(--warn-soft); color: var(--warn-text); }

/* ---------- Chrome ---------- */

.nav {
  position: sticky; top: 0; z-index: 10;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  padding: .6rem 1rem;
  display: flex; align-items: center; gap: 1rem;
}

.nav-brand { font-weight: 800; color: var(--accent); font-size: 1.2rem; }
.nav-links { display: flex; gap: .25rem; flex: 1; flex-wrap: wrap; }

.nav-links a {
  padding: .45rem .8rem; border-radius: 8px;
  color: var(--text-dim); font-weight: 600; font-size: .9375rem;
}
.nav-links a:hover { background: var(--surface-2); text-decoration: none; }
.nav-links a.active { color: var(--accent); background: var(--brand-soft); }

.nav-user { display: flex; align-items: center; gap: .6rem; }

.page { max-width: 720px; margin: 0 auto; padding: 1.25rem 1rem 4rem; }
.page.wide { max-width: 1000px; }
.page h1 { font-size: 1.5rem; margin: 0 0 .25rem; }
.page-sub { color: var(--text-dim); margin: 0 0 1.25rem; }

.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 1.1rem;
  margin-bottom: 1rem;
}

/* ---------- Avatars & photos ---------- */

.avatar {
  width: 40px; height: 40px; border-radius: 50%;
  object-fit: cover; background: var(--brand-soft);
  display: grid; place-items: center;
  color: var(--accent); font-weight: 700; font-size: .875rem;
  flex: 0 0 auto; overflow: hidden;
}
.avatar.lg { width: 84px; height: 84px; font-size: 1.75rem; }

.post-head { display: flex; gap: .75rem; align-items: center; margin-bottom: .75rem; }
.post-meta { flex: 1; min-width: 0; }
.post-author { font-weight: 600; }
.post-time { font-size: .8125rem; color: var(--text-dim); }
.post-title { font-size: 1.125rem; font-weight: 700; margin: 0 0 .4rem; }
.post-body { white-space: pre-wrap; overflow-wrap: anywhere; margin: 0 0 .75rem; }

.photo-grid {
  display: grid; gap: .4rem;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
}
.photo-grid img {
  width: 100%; aspect-ratio: 1; object-fit: cover;
  border-radius: 8px; background: var(--surface-2);
}
.photo-tile { position: relative; }
.photo-tile .remove {
  position: absolute; top: .3rem; right: .3rem;
  width: 26px; height: 26px; padding: 0; line-height: 1;
  border-radius: 50%; background: rgba(0, 0, 0, .65); color: #fff;
}

.post-actions {
  display: flex; gap: .25rem; align-items: center;
  border-top: 1px solid var(--border); margin-top: .75rem; padding-top: .5rem;
}

.comment { display: flex; gap: .6rem; padding: .5rem 0; }
.comment .bubble {
  background: var(--surface-2); border-radius: 12px;
  padding: .5rem .75rem; flex: 1; min-width: 0;
}
.comment .bubble p { margin: .15rem 0 0; white-space: pre-wrap; overflow-wrap: anywhere; }

/* ---------- Reactions ---------- */

/* `position: relative` is load-bearing: the picker below is absolutely
   positioned against this row, so it opens under the button that summoned it
   rather than under the card. */
.reactions {
  position: relative;
  display: flex; align-items: center; gap: .3rem; flex-wrap: wrap;
  margin-top: .5rem;
}
.reaction-chips { display: contents; }

.reaction, .reaction-add {
  display: inline-flex; align-items: center; gap: .3rem;
  padding: .2rem .55rem;
  font-size: .8125rem; font-weight: 600; line-height: 1.5;
  border: 1px solid var(--border); border-radius: 999px;
  background: var(--surface-2); color: var(--text-dim);
}
.reaction:hover:not(:disabled), .reaction-add:hover:not(:disabled) {
  background: var(--border); color: var(--text);
}

/* The member's own reaction reads as pressed, not merely hovered — the count
   alone does not say whether one of them is yours. */
.reaction.on {
  background: var(--brand-soft);
  border-color: var(--accent);
  color: var(--accent);
}
.reaction.on:hover:not(:disabled) { background: var(--brand-soft); }

.reaction-emoji { font-size: .9375rem; line-height: 1; }
.reaction-count { font-variant-numeric: tabular-nums; }

.reaction-add { gap: .15rem; padding: .2rem .5rem; }
.reaction-plus { font-weight: 700; }

.reaction-picker {
  position: absolute; top: calc(100% + .3rem); left: 0; z-index: 20;
  /* A fixed column count, not flex-wrap: emoji advance widths differ from
     font to font, so wrapping would put a different number on each row per
     platform — and, at some of them, one lonely glyph on the last row. */
  display: grid; grid-template-columns: repeat(8, 1fr); gap: .15rem;
  /* The 7rem covers the deepest inset a bar can sit at — a comment bubble,
     behind the avatar — so the popover stays on screen at phone widths
     instead of pushing the page into a sideways scroll. */
  width: min(22rem, calc(100vw - 7rem));
  padding: .35rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: var(--shadow);
}

/* `display: flex` above outranks the UA stylesheet's `[hidden] { display: none }`,
   so the closed state has to be spelled out or every picker renders open. */
.reaction-picker[hidden] { display: none; }

.reaction-choice {
  display: inline-flex; align-items: center; justify-content: center;
  padding: .3rem .4rem; font-size: 1.25rem; line-height: 1.1;
  background: none; border: 1px solid transparent; border-radius: 8px;
}
.reaction-choice:hover:not(:disabled) { background: var(--surface-2); }
.reaction-choice.on { background: var(--brand-soft); border-color: var(--accent); }

.comment .bubble .reactions { margin-top: .35rem; }
.announcement .reactions { margin-top: .7rem; }

/* ---------- Admin ---------- */

.table { width: 100%; border-collapse: collapse; font-size: .9375rem; }
.table th, .table td {
  text-align: left; padding: .6rem .5rem;
  border-bottom: 1px solid var(--border); vertical-align: middle;
}
.table th { font-size: .75rem; text-transform: uppercase; color: var(--text-dim); letter-spacing: .04em; }
.table-scroll { overflow-x: auto; }

.badge {
  display: inline-block; padding: .15rem .5rem; border-radius: 999px;
  font-size: .75rem; font-weight: 700;
}
.badge.pending { background: var(--warn-soft); color: var(--warn-text); }
.badge.approved { background: var(--ok-soft); color: var(--ok); }
.badge.rejected, .badge.suspended { background: var(--danger-soft); color: var(--danger); }
.badge.admin { background: var(--brand-soft); color: var(--accent); }

.row-actions { display: flex; gap: .4rem; flex-wrap: wrap; }

.empty { text-align: center; color: var(--text-dim); padding: 2.5rem 1rem; }

.tabs { display: flex; gap: .25rem; margin-bottom: 1rem; flex-wrap: wrap; }
.tabs button { background: var(--surface); color: var(--text-dim); border-color: var(--border); }
.tabs button.active { background: var(--brand-soft); color: var(--accent); border-color: var(--accent); }

/* ---------- Live indicator & toast ---------- */

.live {
  display: inline-flex; align-items: center; gap: .4rem;
  font-size: .75rem; color: var(--text-dim);
}
.live::before {
  content: ""; width: 8px; height: 8px; border-radius: 50%;
  background: var(--text-dim);
}
.live.on::before { background: var(--ok); }

.toast {
  position: fixed; left: 50%; bottom: 1.5rem; transform: translateX(-50%);
  background: var(--text); color: var(--bg);
  padding: .7rem 1.1rem; border-radius: 999px; font-size: .875rem;
  box-shadow: var(--shadow); z-index: 100; max-width: 90vw;
}

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}


/* ---------- Layout utilities ----------
   These replace inline style attributes. Our CSP omits 'unsafe-inline' from
   style-src, so a style="" attribute is parsed and then ignored by the
   browser — layout has to come from real rules. */

.row { display: flex; align-items: center; gap: .6rem; }
.row-between {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: 1rem; gap: .75rem; flex-wrap: wrap;
}
.row-between.tight { margin-bottom: .75rem; }
.row-end { display: flex; justify-content: flex-end; margin-top: .75rem; }
.grow { flex: 1; min-width: 0; }
.section-title { margin: 0; font-size: 1.125rem; }

.comment-form { display: flex; gap: .5rem; margin-top: .5rem; }

.profile-head { display: flex; gap: 1rem; align-items: center; flex-wrap: wrap; }
.profile-ident { flex: 1; min-width: 200px; }
.profile-edit { margin-top: 1rem; }

.member-row { display: flex; gap: .75rem; align-items: center; cursor: pointer; }
.member-row:hover { border-color: var(--accent); }

/* ---------- Announcements ---------- */

.announcement {
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 4px solid var(--accent);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 1.1rem;
  margin-bottom: 1rem;
}

.announcement-label {
  display: inline-flex; align-items: center; gap: .4rem;
  font-size: .6875rem; font-weight: 800; letter-spacing: .08em;
  text-transform: uppercase; color: var(--accent);
  margin-bottom: .5rem;
}

.announcement-title { font-size: 1.125rem; font-weight: 700; margin: 0 0 .35rem; }
.announcement-body { margin: 0; white-space: pre-wrap; overflow-wrap: anywhere; }
.announcement-meta {
  margin-top: .6rem; font-size: .8125rem; color: var(--text-dim);
  display: flex; align-items: center; gap: .5rem; flex-wrap: wrap;
}

.announcement-row {
  border-bottom: 1px solid var(--border);
  padding: .85rem 0;
}
.announcement-row:last-child { border-bottom: 0; }

/* ---------- Settings form ---------- */

.settings-grid {
  display: grid; gap: 1rem;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
}

/* Qualified with `label` so it outranks `.field label`, which would otherwise
   force display:block and collapse the row. */
label.switch {
  display: flex; align-items: center; gap: .6rem;
  padding: .7rem .85rem;
  margin-bottom: 0;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 8px;
  cursor: pointer;
}
label.switch input {
  width: auto; height: 1.15rem; flex: 0 0 auto;
  margin: 0; accent-color: var(--accent); cursor: pointer;
}
label.switch span {
  font-weight: 600; font-size: .9375rem; color: var(--text);
}

input[type="color"] {
  height: 44px; padding: .25rem; cursor: pointer;
}

.color-field { display: flex; gap: .5rem; align-items: center; }
.color-field input[type="color"] { width: 64px; flex: 0 0 auto; }

/* ---------- Admin-set page background ----------
   Content lives on cards, which keep their theme surface colour, so only the
   text that sits directly on the background needs contrast handling. */

body.has-custom-bg { background: var(--bg-custom, var(--bg)); }

/* Painted by a pinned pseudo-element rather than background-attachment: fixed,
   which iOS Safari renders zoomed and jitters while scrolling. */
body.has-bg-image { background: none; }

body.has-bg-image::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  /* The scrim is what makes arbitrary photos safe to put text on. */
  background-image:
    linear-gradient(rgba(8, 10, 14, .62), rgba(8, 10, 14, .62)),
    var(--bg-image);
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}

/* The landing page paints its own full-bleed surface by default; step aside
   so a configured background is actually visible behind the hero. */
body.has-custom-bg .landing { background: transparent; }

:root[data-bg-contrast="light"] {
  --on-bg: #f4f6fa;
  --on-bg-dim: rgba(244, 246, 250, .78);
}
:root[data-bg-contrast="dark"] {
  --on-bg: #14161b;
  --on-bg-dim: rgba(20, 22, 27, .72);
}

.has-custom-bg .hero h1,
.has-custom-bg .hero p,
.has-custom-bg .page h1 { color: var(--on-bg); }

.has-custom-bg .hero-points,
.has-custom-bg .page-sub,
.has-custom-bg .live { color: var(--on-bg-dim); }

.has-custom-bg .hero-points li::before { color: var(--on-bg); }

.bg-preview {
  width: 100%; height: 120px; object-fit: cover;
  border-radius: 8px; border: 1px solid var(--border);
  background: var(--surface-2);
}

/* ---------- @mentions ---------- */

.mention {
  color: var(--accent);
  font-weight: 600;
  background: var(--brand-soft);
  padding: 0 .2rem;
  border-radius: 4px;
  text-decoration: none;
}
.mention:hover { text-decoration: underline; }

.mention-menu {
  position: absolute;
  z-index: 200;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
  box-shadow: var(--shadow);
  max-height: 240px;
  overflow-y: auto;
  overflow-x: hidden;
}

.mention-option {
  display: flex; gap: .5rem; align-items: baseline;
  padding: .5rem .7rem;
  cursor: pointer;
}
.mention-option.active { background: var(--brand-soft); }
.mention-option strong { color: var(--accent); }
.mention-name {
  color: var(--text-dim); font-size: .8125rem;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}


/* ==========================================================================
   Responsive: phone, tablet, desktop
   Breakpoints follow the content, not device names — each is the width where
   a particular layout actually stops working.
   ========================================================================== */

/* --- Touch devices, at any width ---------------------------------------- */
@media (pointer: coarse) {
  /* iOS Safari zooms the page when a focused field is under 16px. Bumping the
     field text is the fix; nothing else about the layout changes. */
  input, textarea, select { font-size: 16px; }

  /* Comfortable hit targets. */
  button { min-height: 44px; }
  button.small, button.link { min-height: 38px; }
  .reaction, .reaction-add { min-height: 34px; padding-inline: .7rem; }
  .reaction-choice { min-height: 44px; }
  .nav-links a { min-height: 40px; display: flex; align-items: center; }
  .photo-tile .remove { width: 34px; height: 34px; font-size: 1.1rem; }
  .mention-option { padding: .7rem; }
}

/* --- Narrow enough that the reaction picker runs out of room ------------- */
/* Below roughly this width the picker is no longer 22rem but whatever the
   viewport clamp leaves it, and eight columns inside that put each emoji
   under the 44px touch target. Trading columns for rows keeps them tappable. */
@media (max-width: 520px) {
  .reaction-picker { grid-template-columns: repeat(5, 1fr); }
}

/* --- Tablet and below ---------------------------------------------------- */
@media (max-width: 900px) {
  .page.wide { max-width: 100%; }
  .settings-grid { gap: .75rem; }
}

/* --- Phone --------------------------------------------------------------- */
@media (max-width: 640px) {
  .page { padding: 1rem .75rem 3rem; }
  .card, .announcement { padding: .9rem; border-radius: 10px; }
  .auth-card { padding: 1.1rem; }
  .landing { padding: 1.5rem .75rem; }

  /* Brand and account on the first row; navigation gets its own full-width
     row that scrolls sideways rather than wrapping into a ragged block. */
  .nav {
    flex-wrap: wrap;
    padding: .5rem .75rem;
    gap: .5rem .75rem;
  }
  .nav-brand { flex: 1; font-size: 1.05rem; }
  .nav-user { order: 2; }
  .nav-links {
    order: 3;
    flex: 1 0 100%;
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
  }
  .nav-links::-webkit-scrollbar { display: none; }
  .nav-links a { white-space: nowrap; padding: .4rem .65rem; }

  /* Same treatment for the admin tab strip — seven tabs would otherwise wrap
     into three rows. */
  .tabs {
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
    padding-bottom: .25rem;
  }
  .tabs::-webkit-scrollbar { display: none; }
  .tabs button { white-space: nowrap; flex: 0 0 auto; }

  .comment-form input { min-width: 0; }
  .comment-form button { flex: 0 0 auto; }

  .avatar.lg { width: 64px; height: 64px; font-size: 1.35rem; }
  .photo-grid { grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); }

  /* A five-column table cannot be read on a phone, so each row becomes a
     card and the header labels move onto the cells themselves. */
  .table thead { display: none; }
  .table, .table tbody, .table tr, .table td { display: block; width: 100%; }
  .table tr {
    border: 1px solid var(--border);
    border-radius: 10px;
    padding: .75rem;
    margin-bottom: .75rem;
  }
  .table td {
    border: 0;
    padding: .3rem 0;
    display: flex;
    gap: .5rem;
    align-items: center;
    /* Label pinned left by its auto margin, everything else grouped right —
       space-between would scatter multiple badges across the row. */
    justify-content: flex-end;
  }
  .table td[data-label]::before {
    content: attr(data-label);
    font-size: .75rem;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--text-dim);
    flex: 0 0 auto;
    margin-right: auto;
  }
  /* A labelled row with nothing in it reads as a bug; drop it entirely. */
  .table td.is-empty { display: none; }
  /* The member cell carries its own avatar block; no label, full width. */
  .table td:first-child { display: block; }
  .table-scroll { overflow-x: visible; }
  .row-actions { width: 100%; }
  .row-actions button { flex: 1; }
}

/* --- Very narrow (small phones, split view) ------------------------------ */
@media (max-width: 380px) {
  .page { padding: .75rem .5rem 3rem; }
  .nav-brand { font-size: 1rem; }
  .photo-grid { grid-template-columns: repeat(auto-fill, minmax(100px, 1fr)); }
}
