/* ============================================================
   Pagelove Design System — primitives

   The parts every Pagelove surface is built from: labels, fields,
   buttons, tables, dividers, panels. Values come from tokens.css and
   the shapes come from pagelove.com.

   Load order on every page: tokens.css, fonts.css, primitives.css,
   then the page's own stylesheet, then any sub-app's.

   A page or sub-app stylesheet CONSUMES these. It should not restate a
   font stack, a type size, a radius, a border colour or a button; if it
   needs one, it needs a class from here. What belongs in a page or
   sub-app stylesheet is its own layout — where things sit, how big the
   column is, what reveals on hover.

   Element-level primitives are wrapped in :where() so their specificity
   is zero and any page rule wins without reaching for !important.
   ============================================================ */

/* ── Small labels ─────────────────────────────────────────────
   The site's own label voice (.code-inline on pagelove.com): Fira Code
   at 14px, sentence case, never uppercased and never tracked open. Used
   for field labels, eyebrows, column headings, legends. */
.pl-label,
:where(dl.pl-fields > dt, fieldset > legend) {
  font-family: var(--font-mono);
  font-size: var(--fs-caption-primary, 14px);
  font-weight: 450;
  letter-spacing: -0.6px;
  line-height: var(--lh-caption-primary, 22px);
  color: var(--text-subtle);
}

/* The eyebrow variant carries the brand gradient, as the site's section
   eyebrows do. */
.pl-label--brand {
  background: var(--gradient-main);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

/* ── Text fields ──────────────────────────────────────────────
   A value being typed is usually a technical string on these surfaces,
   so fields are set in mono. */
:where(
  input[type="text"],
  input[type="email"],
  input[type="search"],
  input[type="password"],
  input[type="url"],
  textarea,
  select
) {
  box-sizing: border-box;
  padding: 9px 14px;
  font-family: var(--font-mono);
  font-size: 15px;
  color: var(--text-body);
  background: var(--surface-card);
  border: var(--border-width, 1px) solid var(--border-subtle);
  border-radius: var(--radius-md, 12px);
  transition: border-color 0.15s ease, box-shadow 0.25s ease;
}

:where(
  input[type="text"],
  input[type="email"],
  input[type="search"],
  input[type="password"],
  input[type="url"],
  textarea,
  select
):focus-visible {
  outline: none;
  border-color: var(--colours-brand-lilac);
  box-shadow: var(--glow-soft);
}

:where(input, textarea)::placeholder {
  color: var(--text-subtle);
}

/* A field whose content is prose rather than a value. */
.pl-field--prose {
  font-family: var(--font-sans);
  font-size: var(--fs-body, 16px);
}

/* ── Buttons ──────────────────────────────────────────────────
   Four variants, and no others. All four are pills with an Inter 500
   label in sentence case, because that is the only button shape the site
   has. On hover the face holds still and the gradient glow arrives
   underneath — never a colour change. */
.btn-primary,
.btn-secondary,
.btn-danger,
.btn-quiet {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  appearance: none;
  padding: 8px 20px;
  font-family: var(--font-sans);
  font-size: var(--fs-label-secondary, 14px);
  font-weight: var(--weight-medium, 500);
  line-height: var(--lh-label-secondary, 22px);
  letter-spacing: -0.4px;
  border-radius: var(--radius-full, 999px);
  cursor: pointer;
  transition: color 0.15s ease, background 0.15s ease,
              border-color 0.15s ease, box-shadow 0.25s ease,
              transform 0.08s ease;
}

/* Primary — the site's slate face. */
.btn-primary {
  color: var(--btn-primary-fg);
  background: var(--btn-primary-bg);
  border: 1px solid var(--btn-primary-bg);
}
.btn-primary:hover,
.btn-primary:focus-visible {
  outline: none;
  box-shadow: var(--glow);
}

/* Secondary — white face, the site's lilac hairline. The site clips the
   brand gradient onto this label; at 14px that fails the 4.5:1 contrast
   floor, so the label stays solid slate. */
.btn-secondary {
  color: var(--text-muted);
  background: var(--surface-card);
  border: 1px solid var(--colours-brand-lilac);
}
.btn-secondary:hover,
.btn-secondary:focus-visible {
  outline: none;
  color: var(--text-body);
  box-shadow: var(--glow-soft);
}

/* Quiet — a secondary at a smaller footprint, for the many small actions
   inside a card, a tree, a table or a panel. */
.btn-quiet {
  padding: 6px 16px;
  color: var(--text-muted);
  background: var(--surface-card);
  border: 1px solid var(--colours-brand-lilac);
}
.btn-quiet:hover,
.btn-quiet:focus-visible {
  outline: none;
  color: var(--text-body);
  box-shadow: var(--glow-soft);
}

/* Danger — rose. The site has no destructive variant to follow, and the
   colour carries meaning, so it keeps a halo of its own rather than the
   brand glow. */
.btn-danger {
  color: var(--colours-white);
  background: linear-gradient(180deg, rgb(244, 63, 94) 0%, rgb(225, 29, 72) 100%);
  border: 1px solid color-mix(in srgb, var(--danger) 70%, transparent);
  box-shadow: 0 2px 8px color-mix(in srgb, var(--danger) 25%, transparent);
}
.btn-danger:hover,
.btn-danger:focus-visible {
  outline: none;
  box-shadow: 0 4px 16px color-mix(in srgb, var(--danger) 40%, transparent);
  filter: brightness(1.06);
}

/* An outlined destructive action, for places where a filled rose button
   would shout: a per-row delete, a danger zone inside a panel. */
.btn-danger--quiet {
  padding: 6px 16px;
  color: var(--danger);
  background: var(--surface-card);
  border-color: color-mix(in srgb, var(--danger) 45%, transparent);
  box-shadow: none;
  filter: none;
}
.btn-danger--quiet:hover,
.btn-danger--quiet:focus-visible {
  border-color: var(--danger);
  box-shadow: none;
  filter: none;
}

.btn-primary:active,
.btn-secondary:active,
.btn-quiet:active,
.btn-danger:active {
  transform: translateY(1px);
}

.btn-primary:disabled,
.btn-secondary:disabled,
.btn-quiet:disabled,
.btn-danger:disabled {
  opacity: 0.6;
  cursor: not-allowed;
  box-shadow: none;
}

/* An icon-only control: a close ×, a per-row delete. Round, quiet until
   hovered. */
.btn-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  padding: 0;
  appearance: none;
  font-size: 18px;
  line-height: 1;
  color: var(--text-subtle);
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--radius-full, 999px);
  cursor: pointer;
  transition: color 0.15s ease, background 0.15s ease, border-color 0.15s ease;
}
.btn-icon:hover,
.btn-icon:focus-visible {
  outline: none;
  color: var(--text-body);
  background: var(--accent-wash);
}
.btn-icon--danger:hover,
.btn-icon--danger:focus-visible {
  color: var(--danger);
  background: var(--danger-tint);
}

/* ── Links ────────────────────────────────────────────────────
   The site underlines its links and firms the underline on hover. Slate
   alone does not read as a link. */
.pl-link {
  color: var(--text-body);
  font-weight: var(--weight-medium, 500);
  text-decoration: underline;
  text-decoration-color: var(--accent-line);
  text-underline-offset: 3px;
  transition: text-decoration-color 0.15s ease, color 0.15s ease;
}
.pl-link:hover {
  text-decoration-color: var(--accent);
}

/* ── Tables ───────────────────────────────────────────────────
   Hairline rows, no fills, mono sentence-case column headings. */
.pl-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--fs-body, 16px);
}
.pl-table th {
  text-align: left;
  padding: 0 16px 12px 0;
  border-bottom: 1px solid var(--border-subtle);
  font-family: var(--font-mono);
  font-weight: 450;
  font-size: var(--fs-caption-primary, 14px);
  letter-spacing: -0.6px;
  color: var(--text-subtle);
}
.pl-table td {
  padding: 16px 16px 16px 0;
  border-bottom: 1px solid var(--border-subtle);
  color: var(--text-body);
  vertical-align: baseline;
}
.pl-table tbody tr {
  transition: background 0.12s ease;
}
.pl-table tbody tr:hover {
  background: var(--accent-wash);
}

/* ── Dividers ─────────────────────────────────────────────────
   The site's hairline dissolves at both ends. border-image paints it on
   whichever edge has a width, so one class covers a rule above or below. */
.pl-divider-top {
  border-top: 1px solid var(--border-subtle);
  border-image: var(--gradient-divider) 1;
}
.pl-divider-bottom {
  border-bottom: 1px solid var(--border-subtle);
  border-image: var(--gradient-divider) 1;
}
hr.pl-divider {
  height: 1px;
  width: 100%;
  border: none;
  margin: 0;
  background: var(--gradient-divider);
}

/* ── Panels ───────────────────────────────────────────────────
   A floating surface: a dialog, a tile, a notice. White, a hairline, and
   a soft lift. Flat sections of a page do not need this — a hairline and
   whitespace are how the site separates those. */
.pl-panel {
  background: var(--surface-card);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg, 16px);
  box-shadow: var(--shadow-panel);
}
.pl-panel--tile {
  border-radius: var(--radius-md, 12px);
  box-shadow: var(--shadow-tile);
}

/* A frosted bar over content: a sticky header, a floating toolbar. */
.pl-mask {
  background: var(--colours-background-mask);
  backdrop-filter: blur(var(--blur-strong, 24px));
  -webkit-backdrop-filter: blur(var(--blur-strong, 24px));
}
