/*
 * Old School Gamers — site overrides for infodancer/ui.
 *
 * Loaded last (open-props.css -> tokens.css -> base.css -> here), so these
 * :root redeclarations win the cascade. We override only the --app-* role
 * tokens; the scales come from Open Props via infodancer/ui.
 *
 * OSG runs a single LIGHT theme (clean, mjh-adjacent) — base-ui.gohtml
 * forces data-theme="light". The old-school identity comes from a parchment
 * "scroll" framing the campaign sidebar, not from a dark palette.
 */

/* --- Light palette ---------------------------------------------------- */
:root {
  --app-color-bg:           #f5f3ee; /* warm light page */
  --app-color-bg-raised:    #ffffff;
  --app-color-fg:           #1f2733; /* dark slate ink */
  --app-color-fg-muted:     #5c6673;
  --app-color-border:       #e3ddd1;
  --app-color-accent:       #1d4ed8; /* deep blue: links, actions */
  --app-color-accent-hover: #1e40af;
  --app-color-accent-on:    #ffffff;
  --app-color-prose-fg:     #232b36;

  /* Bookish serif for display type. */
  --app-font-display: "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, var(--font-serif);
}

/* --- Top nav: dark navy bar, contents aligned to the page column ------- */
/* The bar background spans full width; the padding-inline trick centers its
   contents within the same 80rem column as .app-container, so the brand and
   sign-in line up with the page content below. */
.app-nav {
  background: #1f2a37;
  border-block-end: 1px solid #14202c;
  padding-inline: max((100% - var(--app-max-width-page)) / 2, var(--app-space));
}
.app-nav-brand,
.app-nav-brand:hover {
  color: #ffffff;
}
.app-nav-links a,
.app-nav-auth a {
  color: #ccd4de;
}
.app-nav-links a:hover,
.app-nav-auth a:hover {
  color: #ffffff;
}

/* Breathing room between the nav bar and content (container is
   padding-inline only). */
.app-container {
  padding-block: var(--app-space-lg);
}

/* --- Layout: structure from infodancer/ui, skin from here -------------- */
/* The shared .app-sidebar-layout grid (open-props/base.css) lays out the
   content column and up to two asides. OSG skins the content column as a
   raised white card on the warm page; the right aside is repainted as a
   parchment scroll below. */
.app-sidebar-main {
  background: var(--app-color-bg-raised);
  border: 1px solid var(--app-color-border);
  border-radius: var(--app-radius);
  padding: var(--app-space-lg);
}
.app-sidebar-main > :first-child {
  margin-block-start: 0;
}

/* --- Parchment scroll: OSG's skin for the right discovery sidebar -------- */
/* infodancer/ui ships a clean bordered panel; OSG repaints the RIGHT aside as
   a rolled parchment scroll. The layout, the <details> collapse mechanics, and
   the feed list all come from the shared .app-sidebar* classes — only the look
   lives here, scoped to .app-sidebar-right so the clean default survives on any
   other (e.g. left) aside. */
.app-sidebar-right {
  position: relative;
  margin-block: 1.2rem;
  padding: calc(var(--app-space-lg) + 0.4rem) var(--app-space);
  color: #4a3b22; /* ink on parchment */
  border: none;
  border-radius: 3px;
  background-color: #efe3c6;
  background-image:
    linear-gradient(180deg, rgba(255, 255, 255, 0.35), rgba(255, 255, 255, 0) 9%),
    radial-gradient(130% 120% at 50% 0%, rgba(120, 90, 40, 0.04), rgba(120, 90, 40, 0.11));
  box-shadow:
    0 1px 2px rgba(0, 0, 0, 0.18),
    inset 0 0 55px rgba(120, 85, 35, 0.12);
}

/* The rolled top and bottom edges. Horizontal "cylinders" sticking out
   slightly past the paper, with a highlight band to read as round. */
.app-sidebar-right::before,
.app-sidebar-right::after {
  content: "";
  position: absolute;
  left: -8px;
  right: -8px;
  height: 1.7rem;
  background:
    linear-gradient(180deg, #efe0b8 0%, #d8c391 38%, #c0a875 70%, #a98f5f 100%);
  border-radius: 0.85rem;
  box-shadow:
    0 2px 5px rgba(0, 0, 0, 0.3),
    inset 0 1px 0 rgba(255, 255, 255, 0.4);
}
.app-sidebar-right::before {
  top: -0.85rem;
}
.app-sidebar-right::after {
  bottom: -0.85rem;
}

/* Section labels: small uppercase ink, no divider (the parchment look). */
.app-sidebar-right .app-sidebar-section {
  margin-block-start: var(--app-space-lg);
}
.app-sidebar-right .app-sidebar-section > summary {
  border-block-end: none;
  padding-block-end: 0;
}
.app-sidebar-right .app-sidebar-section > summary > * {
  font-size: 0.8rem;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: #6b552c;
}
.app-sidebar-right .app-sidebar-section > summary:hover > *,
.app-sidebar-right .app-sidebar-section > summary:focus-visible > * {
  color: #4a3b22;
}
.app-sidebar-right .app-sidebar-section > summary::after {
  border-color: #8a7340; /* chevron */
}
.app-sidebar-right .app-sidebar-section > summary:focus-visible {
  outline-color: #8a7340;
}

/* Feed: ink links, brown dividers and meta. */
.app-sidebar-right .app-sidebar-feed li {
  border-block-start-color: rgba(120, 85, 35, 0.18);
}
.app-sidebar-right .app-sidebar-feed a {
  color: #5a3d12;
}
.app-sidebar-right .app-sidebar-meta {
  color: #7a6845;
  font-size: 0.76rem;
}

/* --- Notes count in the main-column tabs (on white) -------------------- */
.osg-count {
  display: inline-block;
  min-width: 1.4em;
  padding: 0 var(--app-space-xs);
  text-align: center;
  font-size: 0.72rem;
  font-weight: 700;
  border-radius: var(--app-radius-pill);
  background: #eceef1;
  color: var(--app-color-fg-muted);
}
.app-tab.is-active .osg-count {
  background: var(--app-color-accent);
  color: var(--app-color-accent-on);
}

/* --- Main-column typography ------------------------------------------- */
.app-page-header h1 {
  font-size: 2.4rem;
  font-weight: 700;
  margin: 0;
}

/* --- Owner affordances in the content column -------------------------- */
/* base.css already styles bare input/textarea/select/button via tokens; OSG
   only adds vertical form rhythm and a ghost variant for the inline × remove
   controls — the bare <button> rule fills them accent, wrong for a small
   dismiss glyph. */
.app-form {
  display: flex;
  flex-direction: column;
  gap: var(--app-space-sm);
  max-width: 32rem;
  margin-block-start: var(--app-space);
}
.app-form label {
  font-weight: 600;
}

/* base.css styles every <input> as a full-width bordered text field, which
   stretches checkboxes and radios into broken boxes. Reset them to their
   natural inline size. (Attribute selector outranks base.css's element rule;
   site.css loads after.) */
input[type="checkbox"],
input[type="radio"] {
  width: auto;
  padding: 0;
  margin: 0;
}

/* In the flex .app-search-form, base.css's width:100% on inputs makes the
   numeric "within (mi)" filter claim most of the row, leaving the search box
   (flex:1, basis 0) only scraps. Pin the number field to a few-digit width so
   the search box takes the rest. */
.app-search-form input[type="number"] {
  flex: 0 0 auto;
  width: 5rem;
}

/* Profile editor: a touch wider than the 32rem default so the clustered
   one-line fields and the Markdown editor have room. */
.osg-profile-form {
  max-width: 46rem;
}
/* Cluster the short, one-line fields into a responsive row at the top. */
.osg-field-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
  gap: var(--app-space);
}
/* Inline checkbox + label row (the listing toggle). The label is a control
   row here, not a field caption, so it isn't bolded. */
.osg-check {
  display: flex;
  align-items: center;
  gap: var(--app-space-sm);
  font-weight: 400;
}

.app-tag-remove {
  margin-inline-start: var(--app-space-xs);
  padding: 0;
  background: none;
  border: none;
  color: var(--app-color-fg-muted);
  font-size: 0.95em;
  line-height: 1;
  cursor: pointer;
}
.app-tag-remove:hover {
  background: none;
  color: var(--app-color-accent);
}

/* Recognized (canonical) tags read a touch stronger than freeform ones. */
.app-tag-known {
  border-color: var(--app-color-accent);
  color: var(--app-color-accent);
}

.app-link-list {
  list-style: none;
  padding: 0;
  margin-block: var(--app-space-sm);
  display: flex;
  flex-direction: column;
  gap: var(--app-space-xs);
}
.app-link-list li {
  display: flex;
  align-items: center;
  gap: var(--app-space-sm);
}

/* --- Cross-group skins (shared by ≥2 Phase 4 page groups) -------------- */
/* Kept here, not in a single feature unit, so parallel conversions don't each
   redefine them. All token-bound / markup-agnostic: a unit applies the class to
   whatever element it emits. */

/* Flash banners — listings, manage, calendar. */
.osg-alert {
  padding: var(--app-space-sm) var(--app-space);
  border: 1px solid var(--app-color-border);
  border-radius: var(--app-radius-sm);
  margin-block: var(--app-space);
}
.osg-alert-success { border-color: #198754; background: #e8f5ee; color: #0f5132; }
.osg-alert-error   { border-color: #dc3545; background: #fdeaec; color: #842029; }
.osg-alert-info    { border-color: var(--app-color-accent); background: #e8eefc; color: var(--app-color-accent-hover); }

/* Semantic color variants for .app-badge (ui ships the shape; color belongs to
   the consuming module). Used for RSVP status and session status across the
   Sessions and Account-calendar groups. Apply alongside .app-badge. */
.osg-badge-success { background: #e8f5ee; color: #0f5132; }
.osg-badge-warning { background: #fcf3e3; color: #7a5b1e; }
.osg-badge-danger  { background: #fdeaec; color: #842029; }
.osg-badge-muted   { background: #eceef1; color: var(--app-color-fg-muted); }
.osg-badge-accent  { background: #e8eefc; color: var(--app-color-accent-hover); }

/* RSVP control: a row of yes/maybe/no actions (styled with .app-btn /
   .app-btn-secondary). Layout only — button states are the unit's to wire. */
.osg-rsvp {
  display: flex;
  flex-wrap: wrap;
  gap: var(--app-space-xs);
  margin-block-start: var(--app-space-sm);
}

/* --- Campaign management group (Phase 4) ------------------------------ */
/* Manage tab: each pending applicant card carries an approve form and a
   deny form (reason + button) side by side. The deny form keeps its input
   and button on one row; the two forms wrap together on narrow viewports. */
.osg-manage-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: var(--app-space-sm);
  margin-block-start: var(--app-space);
}
.osg-deny-form {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--app-space-sm);
}

/* --- Account calendar (Phase 4 account unit) -------------------------- */
/* Layout for the subscribe panel's controls and the upcoming-session rows.
   Owned by the account unit; appended here per the conversion recipe so the
   slice/CSS edits stay one mergeable block per page group. */
.osg-calendar-subscribe {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--app-space-sm);
  margin-block-start: var(--app-space-sm);
}
.osg-calendar-subscribe input[type="text"] {
  flex: 1 1 16rem;
  min-width: 0;
  font-family: var(--app-font-mono, monospace);
  font-size: 0.8rem;
}
.osg-calendar-list {
  list-style: none;
  padding: 0;
  margin-block: var(--app-space);
  display: flex;
  flex-direction: column;
  gap: var(--app-space-sm);
}
.osg-calendar-row {
  padding: var(--app-space);
  border: 1px solid var(--app-color-border);
  border-radius: var(--app-radius-sm);
}
.osg-calendar-row h2 {
  font-size: 1.15rem;
  margin: 0;
}

/* --- Notes group (Phase 4) -------------------------------------------- */
/* A horizontal button row: note-form submit/cancel and the note-detail
   edit/delete affordances. The inline <form> for delete is a flex item so
   its button lines up with the sibling edit link. */
.osg-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--app-space-sm);
  margin-block-start: var(--app-space);
}
.osg-actions form {
  margin: 0;
}

/* Notes-feed cards: a clickable row with the byline character's portrait on
   the left, and the author/badges line above a two-line excerpt on the right.
   The whole card is one link; the excerpt is plain text (never the note's
   first image) clamped to two lines for a consistent height. */
.osg-note-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: var(--app-space-sm);
}
.osg-note-link {
  display: flex;
  gap: var(--app-space);
  align-items: flex-start;
  padding: var(--app-space);
  border: 1px solid var(--app-color-border);
  border-radius: var(--app-radius);
  background: var(--app-color-bg-raised);
  color: inherit;
  text-decoration: none;
  transition: border-color 0.15s, box-shadow 0.15s;
}
.osg-note-link:hover,
.osg-note-link:focus-visible {
  border-color: var(--app-color-accent);
  box-shadow: var(--app-shadow, 0 1px 3px rgba(0, 0, 0, 0.2));
}
.osg-note-portrait {
  flex: none;
  width: 64px;
  height: 64px;
  border-radius: 8px;
  object-fit: cover;
  object-position: top;
}
.osg-note-initials {
  display: flex;
  align-items: center;
  justify-content: center;
  background: #e9e4d8;
  color: #6b552c;
  font-family: var(--app-font-display);
  font-size: 1.6rem;
  font-weight: 700;
  text-transform: uppercase;
}
/* min-width:0 lets the body shrink inside the flex row so the excerpt can
   line-clamp instead of forcing the card wider. */
.osg-note-body {
  flex: 1;
  min-width: 0;
}
.osg-note-byline {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--app-space-sm);
  margin-block-end: 0.25rem;
}
.osg-note-author {
  font-weight: 700;
  color: var(--app-color-fg);
}
.osg-note-excerpt {
  margin: 0;
  color: var(--app-color-fg-muted);
  font-size: 0.92rem;
  line-height: 1.4;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
}
.osg-note-tombstone {
  margin: 0;
  padding: var(--app-space);
  border: 1px dashed var(--app-color-border);
  border-radius: var(--app-radius);
}

/* --- Directory listings (Phase 4) ------------------------------------- */
/* Profile result cards carry a name, a meta line, and a bio paragraph —
   the ui .app-card-grid default (minmax(12rem, 1fr)) packs them too tight
   for prose. Widen the track here rather than touching ui. Apply alongside
   .app-card-grid on the directory index/search grids. */
.osg-profile-grid {
  grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr));
}

/* --- Venue group (Phase 4) -------------------------------------------- */
/* .osg-choice is an inline radio/checkbox row: the ui base.css input rule
   stretches every input to width:100%, which is wrong for a radio or a
   checkbox. This re-sizes the control to its intrinsic width and lays the
   label text beside it. Used by the venue create/edit form (status radios,
   "listed" checkbox). */
.osg-choice {
  display: flex;
  align-items: baseline;
  gap: var(--app-space-sm);
  font-weight: normal;
}
.osg-choice input[type="radio"],
.osg-choice input[type="checkbox"] {
  width: auto;
  flex: none;
}

/* ── Session chronicles ──────────────────────────────────────────────────────
   The single-chronicle hero: the byline-character portrait beside a
   title-forward heading, with a quiet one-line byline (author · date) and a
   rule separating the hero from the prose. justify-content is pinned to
   flex-start because .app-page-header defaults to space-between — which would
   otherwise shove the heading to the far edge, away from the portrait. */
.osg-chronicle-header {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: 1.25rem;
  padding-block-end: var(--app-space);
  border-block-end: 1px solid var(--app-color-border);
}
.osg-chronicle-portrait {
  width: 112px;
  height: 112px;
  border-radius: 8px;
  object-fit: cover;
  flex: none;
  box-shadow: var(--app-shadow, 0 1px 3px rgba(0, 0, 0, 0.2));
}
.osg-chronicle-heading h1 {
  line-height: 1.1;
}
.osg-chronicle-byline {
  font-size: 1.05rem;
}

/* Inline dice-mechanics annotation (the `roll` directive). Ported from the
   Blowfish-side extend-head.html so the Go-rendered chronicles style it
   identically: a die glyph with the mechanics in a hover/focus tooltip. */
.roll-annotated {
  position: relative;
  display: inline-block;
  vertical-align: baseline;
}
.roll-indicator {
  font-size: 1.1em;
  opacity: 0.8;
  cursor: help;
  user-select: none;
}
[data-theme="dark"] .roll-indicator {
  opacity: 0.7;
}
.roll-tooltip {
  display: none;
  position: absolute;
  left: 0;
  top: -0.5em;
  transform: translateY(-100%);
  background: #1a1a2e;
  color: #e0e0e0;
  padding: 0.5em 0.75em;
  border-radius: 6px;
  font-size: 0.8em;
  font-family: monospace;
  /* The mechanics is a single short sentence; keep it on one line. Without
     nowrap the tooltip shrink-to-fits the narrow inline-block anchor and wraps
     to one word per line. */
  white-space: nowrap;
  z-index: 100;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
  pointer-events: none;
}
.roll-annotated:hover .roll-tooltip,
.roll-annotated:focus .roll-tooltip {
  display: block;
}

/* ── Sessions table ──────────────────────────────────────────────────────────
   The Sessions tab listing: session title, GM, player tally, start time. */
.osg-session-table {
  width: 100%;
  border-collapse: collapse;
}
.osg-session-table th,
.osg-session-table td {
  text-align: left;
  padding: 0.5rem 0.75rem;
  border-bottom: 1px solid var(--app-color-border, #e5e7eb);
  vertical-align: baseline;
}
.osg-session-table thead th {
  font-size: 0.85em;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--app-color-text-muted, #6b7280);
  border-bottom-width: 2px;
}
.osg-session-table .osg-num {
  text-align: right;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

/* Sessions tab controls + group headings. */
.osg-session-controls {
  display: flex;
  align-items: center;
  gap: 1rem;
  flex-wrap: wrap;
  margin-block: var(--app-space, 1rem);
}
.osg-cancelled-toggle {
  flex: 0 0 auto;
}
.osg-cancelled-toggle label {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.9em;
  color: var(--app-color-text-muted, #6b7280);
  white-space: nowrap;
}
.osg-session-group {
  margin-top: var(--app-space-lg, 1.5rem);
}

/* Campaign card thumbnail + post count — used by the shared campaign_cards
   partial on the home page and the /campaign/ directory. 3:2 cover crop. */
.app-card-thumb {
  width: 100%;
  aspect-ratio: 3 / 2;
  object-fit: cover;
  object-position: top;
  border-radius: var(--app-radius, 0.5rem);
  margin-block-end: var(--app-space-sm, 0.5rem);
}
.app-card-posts {
  margin: 0;
  color: var(--app-color-fg-muted);
  font-size: 0.95rem;
}

/* Campaign card grid: more, narrower columns than the ui default (12rem) so a
   full row of featured games fits on the home page, with a compact title that
   doesn't wrap to three lines. Scoped to campaign cards — venue/FAQ cards keep
   the default. */
.osg-campaign-cards {
  grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));
}
.osg-campaign-cards .app-card {
  padding: var(--app-space-sm, 0.5rem);
}
.osg-campaign-cards .app-card h2 {
  font-size: 1.05rem;
  line-height: 1.2;
  margin-block: 0.2rem;
}
