/* ============================================================================
   18 · `gp-*` — SETTINGS PANEL SYSTEM

   A feature-card grid where each card opens a modal built from `.gp-row`s.
   Page-agnostic by design — a layout system, not a theme.

   Part of the dashboard stylesheet, split out of the former single style.css.
   LOAD ORDER IS LOAD-BEARING (later parts intentionally override earlier
   ones) — the canonical order is dashboard/views/partials/_app_styles.ejs.
   ========================================================================== */

/* =============================================================================
   `gp-*` — SETTINGS PANEL SYSTEM  (Ga Panel)
   A "feature card grid + settings row" register: a page shows one card per area
   (icon, title, one-line description, status badge, Settings button) and each card
   opens a modal built from `.gp-row`s. Introduced for the Leveling page redesign.

   It is a LAYOUT system, not a theme — every colour, radius, font and easing comes
   from the existing site variables, so a `gp-` panel sits inside `.ga-panel`'s glass
   shell and reads as the same product. Namespaced `gp-` so nothing here collides
   with the site-wide `.ga-*` component library (note `.ga-panel-head` already
   exists and means something else).

   RULE: keep this generic. Anything page-specific belongs in that page's own
   markup — a second page adopting this register should need no edit here.
============================================================================= */

/* ── Section heading above a card grid ──────────────────────────────────────── */
.gp-section-title { font-family:var(--font-display); font-size:1.05rem; font-weight:700; color:var(--text);
  margin:1.75rem 0 0.25rem; display:flex; align-items:center; gap:0.5rem; }
.gp-section-title:first-child { margin-top:0; }
.gp-section-title ion-icon { color:var(--crimson-glow); font-size:1.15rem; }
.gp-section-sub { font-size:0.825rem; color:var(--text-secondary); margin:0 0 1rem; line-height:1.55; }

/* ── Panel shell: head (icon + title/desc + badge/actions) then body ────────── */
.gp-panel { display:flex; flex-direction:column; }
.gp-panel-head { display:flex; align-items:flex-start; justify-content:space-between; gap:1rem;
  padding-bottom:1.15rem; margin-bottom:1.15rem; border-bottom:1px solid var(--border); flex-wrap:wrap; }
.gp-panel-head-left { display:flex; align-items:flex-start; gap:1rem; min-width:0; }
.gp-panel-icon { width:2.75rem; height:2.75rem; border-radius:15px; display:flex; align-items:center;
  justify-content:center; font-size:1.3rem; flex-shrink:0;
  background:var(--gp-accent-bg, rgba(220,38,38,.14)); color:var(--gp-accent, var(--crimson-glow));
  box-shadow:inset 0 0 0 1px var(--gp-accent-bd, rgba(220,38,38,.32)),
             0 6px 18px -8px var(--gp-accent, rgba(220,38,38,.4));
  transition:transform .35s var(--spring), box-shadow .35s var(--ease); }
.gp-panel-icon ion-icon { font-size:1.35rem; }
.gp-panel-title { font-family:var(--font-display); font-size:1.1rem; font-weight:700; letter-spacing:-.01em;
  color:var(--text-primary); line-height:1.3; margin:0; }
.gp-panel-desc { font-size:0.825rem; color:var(--text-secondary); margin:0.3rem 0 0; line-height:1.55; max-width:46ch; }
.gp-panel-actions { display:flex; align-items:center; gap:0.625rem; flex-shrink:0; padding-top:0.2rem; }
.gp-panel-body { display:flex; flex-direction:column; }

/* Internal scroll region — the panel/modal stops growing and only this scrolls, so a
   long list never pushes the header or footer off screen. `--gp-scroll-max` lets each
   panel tune the cap to its own natural height, so a short list never gets a scrollbar. */
.gp-panel-body--scroll { max-height:var(--gp-scroll-max, 24rem); overflow-y:auto; overflow-x:hidden;
  padding-right:0.6rem; margin-right:-0.6rem;
  scrollbar-width:thin; scrollbar-color:rgba(220,38,38,.4) transparent; }
.gp-panel-body--scroll::-webkit-scrollbar { width:8px; }
.gp-panel-body--scroll::-webkit-scrollbar-track { background:transparent; }
.gp-panel-body--scroll::-webkit-scrollbar-thumb { border-radius:999px; border:2px solid transparent;
  background-clip:padding-box; background-color:rgba(220,38,38,.38);
  background-image:linear-gradient(180deg, rgba(220,38,38,.55), rgba(147,197,114,.5)); }
.gp-panel-body--scroll::-webkit-scrollbar-thumb:hover {
  background-image:linear-gradient(180deg, rgba(220,38,38,.8), rgba(147,197,114,.72)); }

/* ── Status badge ───────────────────────────────────────────────────────────── */
.gp-badge { display:inline-flex; align-items:center; gap:0.3rem; padding:0.3rem 0.7rem; border-radius:999px;
  font-size:0.7rem; font-weight:700; letter-spacing:.03em; text-transform:uppercase; white-space:nowrap;
  background:rgba(255,255,255,.05); border:1px solid var(--border-strong); color:var(--text-secondary);
  transition:background .3s, border-color .3s, color .3s; }
.gp-badge--info { background:rgba(220,38,38,.12); border-color:rgba(220,38,38,.32); color:var(--crimson-glow); }
.gp-badge--on   { background:rgba(147,197,114,.14); border-color:rgba(147,197,114,.4); color:var(--pistachio-light); }
.gp-badge--off  { background:rgba(255,255,255,.04); border-color:var(--border-strong); color:var(--text-muted); }

/* ── Feature card grid — one card per settings area, each opening a modal ───── */
.gp-feature-grid { display:grid; grid-template-columns:repeat(auto-fill, minmax(300px, 1fr)); gap:1.25rem; }
.gp-feature-card { padding:1.5rem; display:flex; flex-direction:column; gap:1.1rem; }
.gp-feature-card-head { display:flex; align-items:flex-start; gap:1rem; }
.gp-feature-card-text { flex:1 1 auto; min-width:0; }
.gp-feature-card:hover .gp-panel-icon { transform:scale(1.06) rotate(-4deg);
  box-shadow:inset 0 0 0 1px var(--gp-accent-bd, rgba(220,38,38,.4)),
             0 10px 26px -8px var(--gp-accent, rgba(220,38,38,.55)); }
.gp-feature-card-footer { display:flex; align-items:center; justify-content:space-between; gap:0.75rem;
  margin-top:auto; padding-top:1.05rem; border-top:1px solid var(--border); }
.gp-feature-settings-btn { display:inline-flex; align-items:center; gap:0.4rem; flex-shrink:0; }
.gp-feature-settings-btn ion-icon { font-size:1rem; }

/* ── Group labels + dividers — hierarchy inside a long modal body ───────────── */
.gp-group-label { font-size:0.68rem; font-weight:700; text-transform:uppercase; letter-spacing:.1em;
  color:var(--text-muted); opacity:.75; margin:1.1rem 0 0.5rem; }
.gp-group-label:first-child { margin-top:0; }
.gp-divider { height:1px; margin:1.1rem 0;
  background:linear-gradient(90deg, transparent, var(--border-strong) 15%, var(--border-strong) 85%, transparent); }

/* ── Settings row: icon / title+desc / control on one baseline ──────────────── */
.gp-row-list { display:flex; flex-direction:column; }
.gp-row { position:relative; display:flex; align-items:center; gap:0.9rem; padding:0.8rem 0.75rem;
  border-radius:14px; transition:background .3s var(--ease), transform .25s var(--ease), box-shadow .3s var(--ease); }
.gp-row-list > .gp-row:not(:last-child) { border-bottom:1px solid var(--border); }
.gp-row:hover { background:rgba(255,255,255,.035); transform:translateX(3px);
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.05); }
.gp-row--top { align-items:flex-start; }
/* The control drops to its own full-width line under the description — for textareas,
   expressions and any control too wide to dock on the right. */
.gp-row--stacked { flex-wrap:wrap; row-gap:0.55rem; }
.gp-row--stacked .gp-row-text { flex-basis:calc(100% - 3.15rem); }
/* 3.15rem is the icon (2.25rem) plus the row gap (0.9rem) — the indent that lines the
   control up under the title. It has to come OUT of the basis as well as going into the
   margin: `flex-basis:100%` + a left margin is 100% + 3.15rem wide, and overflows the
   row by exactly that margin. Basis + margin must total 100%, which also still forces
   the control onto its own line. */
.gp-row--stacked .gp-row-control { flex-basis:calc(100% - 3.15rem); margin-left:3.15rem; padding-left:0;
  justify-content:flex-start; flex-wrap:wrap; row-gap:0.5rem; }
.gp-row-icon { width:2.25rem; height:2.25rem; border-radius:11px; flex-shrink:0; display:flex;
  align-items:center; justify-content:center; font-size:0.72rem; font-weight:800; letter-spacing:-.01em;
  background:var(--gp-row-accent-bg, rgba(255,255,255,.05)); color:var(--gp-row-accent, var(--text-secondary));
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.06);
  transition:transform .3s var(--spring), color .25s, box-shadow .3s; }
.gp-row-icon ion-icon { font-size:1.05rem; }
.gp-row:hover .gp-row-icon { transform:scale(1.12) rotate(-4deg); color:var(--crimson-glow);
  box-shadow:inset 0 0 0 1px rgba(220,38,38,.35), 0 0 14px -2px rgba(220,38,38,.4); }
.gp-row-text { flex:1 1 auto; min-width:0; }
.gp-row-title { font-size:0.875rem; font-weight:700; color:var(--text); display:flex; align-items:center;
  gap:0.4rem; line-height:1.35; }
.gp-row-desc { font-size:0.78rem; color:var(--text-muted); margin-top:0.2rem; line-height:1.5; }
.gp-row-control { flex-shrink:0; display:flex; align-items:center; gap:0.6rem; margin-left:auto; padding-left:0.75rem; }
.gp-row-control .input, .gp-row-control .cs-wrap { width:auto; }
/* A control that lives full width beneath its own description. */
.gp-row-wide { margin-top:0.65rem; width:100%; box-sizing:border-box; }

/* ── Compact inline fields (the XP / cooldown pairs on an activity row) ─────── */
.gp-field-inline { display:inline-flex; align-items:center; gap:0.35rem; font-size:0.72rem; font-weight:700;
  color:var(--text-muted); text-transform:uppercase; letter-spacing:.04em; }
.gp-field-label { display:block; font-size:0.7rem; font-weight:700; color:var(--text-muted); margin-bottom:0.3rem; }
.gp-input-sm { width:5.25rem !important; text-align:center; }
.gp-input-xs { width:3.9rem !important; text-align:center; }

/* ── Callouts — tips and warnings inside a modal body ───────────────────────── */
.gp-note { display:flex; gap:0.7rem; align-items:flex-start; padding:0.9rem 1rem; border-radius:14px;
  font-size:0.8125rem; line-height:1.6; color:var(--text-secondary); margin-top:1.1rem; }
.gp-note-icon { flex-shrink:0; width:1.55rem; height:1.55rem; border-radius:8px; display:flex;
  align-items:center; justify-content:center; font-size:0.8rem; font-weight:800; margin-top:0.05rem; }
.gp-note strong { color:var(--text-primary); }
.gp-note code { font-family:var(--font-mono); font-size:.85em; background:rgba(255,255,255,.08);
  border-radius:3px; padding:0 4px; }
.gp-note--tip { background:rgba(147,197,114,.07); border:1px solid rgba(147,197,114,.28); }
.gp-note--tip .gp-note-icon { background:rgba(147,197,114,.18); color:var(--pistachio-light); }
.gp-note--warning { background:rgba(239,68,68,.07); border:1px solid rgba(239,68,68,.28); }
.gp-note--warning .gp-note-icon { background:rgba(239,68,68,.18); color:#F87171; }

/* ── Subcards — a recessed "add new" form under a list ──────────────────────── */
.gp-subcard { background:rgba(255,255,255,.02); border:1px solid var(--border); border-radius:16px;
  padding:1rem 1.1rem; margin-top:1rem; transition:border-color .3s var(--ease), box-shadow .3s var(--ease); }
.gp-subcard:hover { border-color:var(--border-strong); box-shadow:0 12px 28px -18px rgba(0,0,0,.5); }
.gp-subcard-label { font-size:0.72rem; font-weight:700; text-transform:uppercase; letter-spacing:.08em;
  color:var(--text-muted); margin-bottom:0.65rem; }
.gp-add-row { display:grid; grid-template-columns:6rem 1fr auto; gap:0.6rem; align-items:end; }
.gp-error-text { color:var(--red); font-size:0.75rem; min-height:1rem; margin:0.45rem 0 0; }

/* ── Empty state for a dynamic list ─────────────────────────────────────────── */
.gp-empty { display:flex; flex-direction:column; align-items:center; text-align:center; gap:0.5rem;
  padding:1.5rem 1rem; border:1px dashed var(--border-strong); border-radius:14px; color:var(--text-muted); }
.gp-empty ion-icon { font-size:1.5rem; opacity:.5; }
.gp-empty-title { font-size:0.8125rem; font-weight:600; color:var(--text-secondary); }
.gp-empty-sub { font-size:0.75rem; }

/* ── Pager for a server-paginated list inside a gp- panel ───────────────────── */
.gp-pager { display:flex; align-items:center; justify-content:space-between; gap:1rem;
  margin-top:0.9rem; font-size:0.78rem; color:var(--text-muted); }
@media (max-width: 560px) {
  .gp-pager { flex-direction:column; gap:0.5rem; }
}

/* ── A settings modal built from the above ──────────────────────────────────── */
.gp-feature-modal { width:min(var(--gp-modal-w, 560px), 95vw); max-height:90vh; display:flex; flex-direction:column; }
.gp-feature-modal .modal-body { padding:1.25rem; }
/* `.modal-nocrop` unclips the body so a dropdown inside it isn't cut off — but these
   modals carry it only for its square-cornered header/footer, and their dropdowns are
   the enhanced kind, whose open menu is portaled to <body> and clipped by nothing. So
   a body that asked to scroll gets to: without this the list simply runs out through
   the footer and off the bottom of the modal. Specificity has to beat
   `.modal.modal-nocrop > .modal-body`, hence the long selector. */
.modal.modal-nocrop > .modal-body.gp-panel-body--scroll { overflow-y:auto; overflow-x:hidden; }
/* The gutter trick that pulls a panel's scrollbar out into its padding has nothing to
   sit in here — a modal body has its own padding, and `.modal-nocrop` leaves the modal
   unclipped, so the negative margin puts the scrollbar outside the rounded edge. */
.gp-feature-modal .modal-body.gp-panel-body--scroll { padding-right:0.65rem; margin-right:0; }
.gp-feature-modal .modal-header h3 { margin:0; font-size:1rem; color:var(--text); }
.gp-feature-modal .modal-header .gp-panel-icon { width:2.25rem; height:2.25rem; border-radius:12px; font-size:1.05rem; }
.gp-feature-modal .modal-header .gp-panel-icon ion-icon { font-size:1.1rem; }

/* A two-column settings/preview modal — the editor on the left, a live preview
   pinned beside it. Each column scrolls on its own so a long form never drags the
   preview out of view (which is the whole point of previewing while you edit). */
.gp-split-modal { --gp-modal-w:1180px; }
.gp-split-modal .modal-body { padding:0; }
.gp-split { display:grid; grid-template-columns:minmax(0, 1.05fr) minmax(0, 1fr); min-height:0; }
.gp-split-edit { padding:1.25rem; border-right:1px solid var(--border); min-width:0; }
.gp-split-side { padding:1.25rem; background:rgba(255,255,255,.015); min-width:0; }
.gp-split-edit, .gp-split-side { max-height:calc(90vh - 8.5rem); overflow-y:auto; overflow-x:hidden; }
/* Inside the modal the builder is already ONE column, so the shared `.wz-layout`
   two-column rail must not apply — the preview lives in the other half of the split. */
.gp-split .wz-layout { display:block; }
.gp-split .wz-builder { min-width:0; }
/* `.gp-split-side` is itself the scroll port, so the rail must not ALSO pin and cap
   itself to the viewport — that height is measured against the window, not the modal,
   and would push the mock past the modal's bottom edge. */
.gp-split .wz-preview { position:static; max-height:none; }
.gp-split .wz-preview-col { align-self:start; }
/* The image designer's canvas+properties split is sized for a full-width page. Half a
   modal is about the width its own stacked breakpoint targets, and that breakpoint is
   keyed to the VIEWPORT, so it never fires here however narrow this column gets —
   stack it explicitly instead. */
.gp-split .wd-editor { grid-template-columns:1fr; }
.gp-split .wd-props { order:2; max-height:none; }

@media (max-width: 900px) {
  .gp-split { grid-template-columns:1fr; }
  .gp-split-edit { border-right:none; border-bottom:1px solid var(--border); }
  .gp-split-edit, .gp-split-side { max-height:none; }
  .gp-split-modal .modal-body { max-height:calc(90vh - 8.5rem); overflow-y:auto; }
}
@media (max-width: 640px) {
  .gp-feature-grid { grid-template-columns:1fr; }
  .gp-add-row { grid-template-columns:1fr; }
  /* Every row becomes the `--stacked` shape: icon + title/description keep their line,
     the control drops beneath them indented under the title. The text needs an explicit
     basis or it wraps below the icon and spends a whole line on a 2.25rem tile. */
  .gp-row { flex-wrap:wrap; row-gap:0.55rem; }
  .gp-row-text { flex-basis:calc(100% - 3.15rem); }
  /* Basis + margin must total 100% — see the `--stacked` note above. */
  .gp-row-control { flex-basis:calc(100% - 3.15rem); margin-left:3.15rem; padding-left:0;
    flex-wrap:wrap; row-gap:0.5rem; }
  /* The XP/variance/cooldown trio is three labelled boxes on one line; let them wrap
     onto a second rather than run off the edge of a phone-width modal. */
  .gp-field-inline { flex-shrink:0; }
}
