/* Vendored from design-system/css/df.css.
   Re-vendor via scripts/sync_design_system.sh; import a new drop with --import.
   Do not hand-edit this file. */

/* =============================================================
   df.css — Downfield Forecast component classes
   For Jinja/HTMX/server-rendered HTML. Pairs with colors_and_type.css.
   Link order: colors_and_type.css FIRST, then df.css.
   ============================================================= */

/* ---------- BASE PAGE ---------- */
.df-page {
  background: var(--bg);
  color: var(--fg);
  font-family: var(--font-ui);
  font-size: var(--t-ui-lg);
  line-height: var(--lh-normal);
  -webkit-font-smoothing: antialiased;
}

/* ---------- BUTTONS ---------- */
.df-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  font-family: var(--font-ui);
  font-weight: var(--w-medium);
  font-size: 14px;
  line-height: 1;
  padding: 10px 16px;
  border-radius: var(--r-md);
  border: 1px solid transparent;
  cursor: pointer;
  white-space: nowrap;
  transition: background-color var(--dur-fast) var(--ease-standard),
              border-color var(--dur-fast) var(--ease-standard),
              color var(--dur-fast) var(--ease-standard);
  text-decoration: none;
}
.df-btn:focus-visible {
  outline: 2px solid var(--pigskin);
  outline-offset: 2px;
}
.df-btn[disabled],
.df-btn[aria-disabled="true"] {
  opacity: 0.45;
  pointer-events: none;
}
.df-btn-sm { padding: 6px 12px; font-size: 13px; }
.df-btn-lg { padding: 14px 22px; font-size: 16px; }

.df-btn-primary {
  background: var(--field);
  color: var(--fg-on-dark);
  border-color: var(--field);
}
.df-btn-primary:hover { background: var(--field-hover); border-color: var(--field-hover); }
.df-btn-primary:active { background: var(--field-press); border-color: var(--field-press); }

.df-btn-secondary {
  background: var(--bg-elevated);
  color: var(--fg);
  border-color: var(--border);
}
.df-btn-secondary:hover { border-color: var(--ink-4); }
.df-btn-secondary:active { background: var(--bg-sunken); }

.df-btn-link {
  background: transparent;
  color: var(--link);
  border-color: transparent;
  padding: 4px 0;
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
}
.df-btn-link:hover { color: var(--link-hover); }

/* ---------- CARDS ---------- */
.df-card {
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-sm);
  padding: var(--s-6);
}
.df-card-flush { padding: 0; }
.df-card-interactive {
  cursor: pointer;
  transition: border-color var(--dur-fast) var(--ease-standard),
              box-shadow var(--dur-fast) var(--ease-standard),
              transform var(--dur-fast) var(--ease-standard);
}
.df-card-interactive:hover {
  border-color: var(--pigskin);
  box-shadow: var(--shadow-md);
  transform: translateY(-1px);
}
.df-card-interactive:active { transform: translateY(0); box-shadow: var(--shadow-sm); }

/* ---------- PILLS / BADGES ---------- */
.df-pill {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-family: var(--font-ui);
  font-weight: var(--w-semibold);
  font-size: 12px;
  line-height: 1;
  padding: 4px 8px;
  border-radius: var(--r-pill);
  background: var(--bg-sunken);
  color: var(--fg-muted);
  border: 1px solid var(--border-soft);
  letter-spacing: 0.01em;
  white-space: nowrap;
}
.df-pill-pos  { background: var(--pos-soft);  color: var(--pos);  border-color: transparent; }
.df-pill-neg  { background: var(--neg-soft);  color: var(--neg);  border-color: transparent; }
.df-pill-warn { background: var(--warn-soft); color: var(--warn); border-color: transparent; }
.df-pill-info { background: var(--info-soft); color: var(--info); border-color: transparent; }
.df-pill-brand   { background: var(--field-soft);   color: var(--field);   border-color: transparent; }
.df-pill-pigskin { background: var(--pigskin-soft); color: var(--pigskin); border-color: transparent; }
/* Roster ROLE — opportunity status (depth-chart position), never injury.
   The alert family (neg/warn/info) is reserved for injury designations, which
   sit in the same row: before this role existed, a BACKUP chip rendered
   identically to the Questionable chip beside it. `-strong` is the filled
   weight for a harder roster statement; WELKER does not currently use it,
   because its only zero-availability state is designation-driven and painting
   that plum would invert the distinction this role exists to draw. */
.df-pill-role        { background: var(--role-soft); color: var(--role); border-color: transparent; }
.df-pill-role-strong { background: var(--role); color: var(--paper-2); border-color: transparent; }

/* ---------- FORM FIELDS ---------- */
.df-field { display: block; margin-bottom: var(--s-4); }
.df-field-label {
  display: block;
  font-family: var(--font-ui);
  font-weight: var(--w-medium);
  font-size: 13px;
  color: var(--fg-2);
  margin-bottom: 6px;
}
.df-input,
.df-select,
.df-textarea {
  width: 100%;
  font-family: var(--font-ui);
  font-size: 14px;
  line-height: 1.4;
  color: var(--fg);
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  padding: 10px 12px;
  transition: border-color var(--dur-fast) var(--ease-standard),
              box-shadow var(--dur-fast) var(--ease-standard);
}

/* Sized variants — same modifier system as .df-btn-sm/-lg.
   Use -sm for dense forms (week pickers, draft spinboxes), -xs for
   inline numeric inputs (FAAB bids, scoring grids). */
.df-input-sm, .df-select-sm, .df-textarea-sm {
  padding: 6px 10px; font-size: 13px;
}
.df-input-xs, .df-select-xs, .df-textarea-xs {
  padding: 4px 8px; font-size: 12px; border-radius: var(--r-sm);
}

/* Native checkbox + radio — restyled to match brand. Apply directly to
   the <input> element. Uses appearance:none to claim the box, then
   draws ink + check via SVG mask on :checked. */
.df-checkbox,
.df-radio {
  appearance: none;
  -webkit-appearance: none;
  width: 16px;
  height: 16px;
  margin: 0;
  flex-shrink: 0;
  background: var(--bg-elevated);
  border: 1.5px solid var(--border-strong);
  cursor: pointer;
  vertical-align: middle;
  transition: background-color var(--dur-fast) var(--ease-standard),
              border-color var(--dur-fast) var(--ease-standard);
  display: inline-block;
}
.df-checkbox { border-radius: var(--r-xs); }
.df-radio    { border-radius: var(--r-pill); }

.df-checkbox:hover,
.df-radio:hover { border-color: var(--ink-3); }

.df-checkbox:focus-visible,
.df-radio:focus-visible {
  outline: 2px solid var(--pigskin);
  outline-offset: 2px;
}

.df-checkbox:checked {
  background: var(--field);
  border-color: var(--field);
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none'><path d='M3.5 8.5l3 3 6-7' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/></svg>");
  background-size: 14px 14px;
  background-position: center;
  background-repeat: no-repeat;
}
.df-radio:checked {
  background: var(--bg-elevated);
  border-color: var(--field);
  border-width: 5px;  /* the dot is the inset border */
}
.df-checkbox[disabled],
.df-radio[disabled] { opacity: 0.45; pointer-events: none; }

/* Checkbox/radio + label row — pair the control with text */
.df-check-row {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  font-family: var(--font-ui);
  font-size: 14px;
  color: var(--fg);
  cursor: pointer;
}

/* Input group — input + suffix button as one connected control.
   Pattern: <div class="df-input-group"><input class="df-input"><button class="df-btn df-btn-primary">Go</button></div> */
.df-input-group {
  display: inline-flex;
  align-items: stretch;
  width: 100%;
}
.df-input-group > .df-input,
.df-input-group > .df-select {
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
  border-right: 0;
  flex: 1 1 auto;
  min-width: 0;
}
.df-input-group > .df-btn {
  border-top-left-radius: 0;
  border-bottom-left-radius: 0;
  flex: 0 0 auto;
}
.df-input-group:focus-within > .df-input,
.df-input-group:focus-within > .df-select {
  border-color: var(--pigskin);
  box-shadow: 0 0 0 3px var(--pigskin-softer);
  z-index: 1;
}
.df-input:focus,
.df-select:focus,
.df-textarea:focus {
  outline: none;
  border-color: var(--pigskin);
  box-shadow: 0 0 0 3px var(--pigskin-softer);
}
.df-field-error .df-input,
.df-field-error .df-select,
.df-field-error .df-textarea {
  border-color: var(--neg);
}
.df-field-error .df-input:focus { box-shadow: 0 0 0 3px var(--neg-soft); }
.df-field-help { font-size: 12px; color: var(--fg-muted); margin-top: 6px; }
.df-field-error-msg { font-size: 12px; color: var(--neg); margin-top: 6px; }

/* ---------- TABLES ---------- */
.df-table {
  width: 100%;
  border-collapse: collapse;
  font-family: var(--font-ui);
  font-size: 14px;
  color: var(--fg);
}
.df-table thead th {
  text-align: left;
  font-weight: var(--w-semibold);
  font-size: 12px;
  letter-spacing: var(--ls-caps);
  text-transform: uppercase;
  color: var(--fg-muted);
  padding: var(--s-3) var(--s-3);
  border-bottom: 1px solid var(--border);
  background: var(--bg-elevated);
}
.df-table tbody td {
  padding: var(--s-3) var(--s-3);
  border-bottom: 1px solid var(--border-soft);
  vertical-align: middle;
}
.df-table tbody tr:hover { background: var(--bg-sunken); }
.df-table .df-num {
  font-family: var(--font-mono);
  font-feature-settings: "tnum" 1, "zero" 1;
  text-align: right;
}

/* ---------- EYEBROW + STATS (already in colors_and_type.css; aliased here) ---------- */
.df-rule { height: 1px; background: var(--border); border: 0; margin: var(--s-7) 0; }
.df-rule-soft { height: 1px; background: var(--border-soft); border: 0; margin: var(--s-6) 0; }

/* ---------- LAYOUT HELPERS ---------- */
.df-container       { max-width: var(--container-app);   margin: 0 auto; padding: 0 var(--s-6); }
.df-container-text  { max-width: var(--container-text);  margin: 0 auto; padding: 0 var(--s-6); }
.df-container-prose { max-width: var(--container-prose); margin: 0 auto; padding: 0 var(--s-6); }

/* ---------- NAV ---------- */
.df-nav {
  position: sticky;
  top: 0;
  z-index: 50;
  background: var(--bg);
  border-bottom: 1px solid var(--border-soft);
  height: 64px;
  display: flex;
  align-items: center;
}
.df-nav-link {
  font-family: var(--font-ui);
  font-weight: var(--w-medium);
  font-size: 14px;
  color: var(--fg-2);
  text-decoration: none;
  padding: 6px 0;
  border-bottom: 1.5px solid transparent;
  transition: color var(--dur-fast) var(--ease-standard);
}
.df-nav-link:hover { color: var(--fg); }
.df-nav-link[aria-current="page"] {
  color: var(--fg);
  border-bottom-color: var(--pigskin);
}

/* ---------- BANNERS / INLINE STATES ---------- */
.df-banner {
  display: flex;
  gap: var(--s-3);
  align-items: flex-start;
  padding: var(--s-3) var(--s-4);
  border-radius: var(--r-md);
  font-size: 13px;
  line-height: 1.45;
}
.df-banner-warn    { background: var(--warn-soft);    color: var(--warn); }
.df-banner-neg     { background: var(--neg-soft);     color: var(--neg); }
.df-banner-info    { background: var(--info-soft);    color: var(--info); }
.df-banner-pos     { background: var(--pos-soft);     color: var(--pos); }
.df-banner-pigskin { background: var(--pigskin-soft); color: var(--pigskin); }

/* ---------- TABS / SEGMENTED CONTROL ----------
   Pattern: <div class="df-tabs" role="tablist">
              <a class="df-tab" role="tab" aria-selected="true" href="…">Live</a>
              <a class="df-tab" role="tab" href="…">Historical</a>
            </div>
   Or for nav-style pages, swap aria-selected for aria-current="page". */
.df-tabs {
  display: inline-flex;
  gap: 4px;
  padding: 4px;
  background: var(--bg-sunken);
  border-radius: var(--r-md);
  width: fit-content;
}
.df-tab {
  padding: 6px 14px;
  font-family: var(--font-ui);
  font-size: 13px;
  font-weight: var(--w-semibold);
  border-radius: var(--r-sm);
  text-decoration: none;
  color: var(--fg-muted);
  background: transparent;
  cursor: pointer;
  border: 0;
  transition: background-color var(--dur-fast) var(--ease-standard),
              color var(--dur-fast) var(--ease-standard);
}
.df-tab:hover { background: var(--bg-elevated); color: var(--fg); }
.df-tab[aria-selected="true"],
.df-tab[aria-current="page"] {
  background: var(--ink);
  color: var(--fg-on-dark);
}
.df-tab:focus-visible {
  outline: 2px solid var(--pigskin);
  outline-offset: 2px;
}

/* Underline-style tabs — flatter alternative for full-width nav rails
   (Schedule/Byes, document-style pages). Pattern same; use .df-tabs-underline. */
.df-tabs-underline {
  display: inline-flex;
  gap: var(--s-5);
  padding: 0;
  background: transparent;
  border-bottom: 1px solid var(--border);
  border-radius: 0;
  width: 100%;
  align-items: stretch;
}
.df-tabs-underline .df-tab {
  padding: 10px 0;
  border-radius: 0;
  border-bottom: 2px solid transparent;
  background: transparent;
  font-size: 14px;
  margin-bottom: -1px;
}
.df-tabs-underline .df-tab:hover {
  background: transparent;
  color: var(--fg);
}
.df-tabs-underline .df-tab[aria-selected="true"],
.df-tabs-underline .df-tab[aria-current="page"] {
  background: transparent;
  color: var(--fg);
  border-bottom-color: var(--pigskin);
}

/* ---------- EMPTY STATE ----------
   Pattern: <div class="df-card df-empty-state">
              <h3 class="df-empty-state-title">No leagues yet</h3>
              <p class="df-empty-state-text">Connect Sleeper or set one up by hand.</p>
              <a class="df-btn df-btn-primary">Add your first league</a>
            </div> */
.df-empty-state {
  text-align: center;
  padding: var(--s-9) var(--s-6);
}
.df-empty-state-title {
  font-family: var(--font-display);
  font-weight: var(--w-semibold);
  font-size: var(--t-h4);
  line-height: var(--lh-snug);
  color: var(--fg);
  margin: 0 0 var(--s-2) 0;
}
.df-empty-state-text {
  font-family: var(--font-ui);
  font-size: 14px;
  line-height: var(--lh-normal);
  color: var(--fg-muted);
  margin: 0 auto var(--s-4) auto;
  max-width: 28rem;
}

/* ---------- ERROR STATE ----------
   Page-level "something went wrong" pattern. Same shape as
   .df-empty-state but used for failed requests, dropped
   distributions, projection-set unavailable, etc.

   Pattern:
     <div class="df-card df-error-state">
       <svg class="df-error-state-art" …></svg>
       <h3 class="df-error-state-title">Couldn't load projections</h3>
       <p class="df-error-state-text">…specific message…</p>
       <code class="df-error-state-ref">req_8d3f4c1a · model v4.2</code>
       <div class="df-error-state-actions">
         <button class="df-btn df-btn-primary">Try again</button>
         <a class="df-btn df-btn-secondary">Go back</a>
       </div>
     </div>
   Reach for .df-banner-neg for inline form errors instead — this
   is for whole-screen failures only. */
.df-error-state {
  text-align: center;
  padding: var(--s-9) var(--s-6);
}
.df-error-state-art {
  display: block;
  margin: 0 auto var(--s-4);
  width: 56px;
  height: 56px;
  color: var(--neg);
  opacity: 0.85;
}
.df-error-state-title {
  font-family: var(--font-display);
  font-weight: var(--w-semibold);
  font-size: var(--t-h4);
  line-height: var(--lh-snug);
  color: var(--fg);
  margin: 0 0 var(--s-2) 0;
}
.df-error-state-text {
  font-family: var(--font-ui);
  font-size: 14px;
  line-height: var(--lh-normal);
  color: var(--fg-muted);
  margin: 0 auto var(--s-3) auto;
  max-width: 30rem;
}
.df-error-state-ref {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--fg-subtle);
  background: var(--bg-sunken);
  border: 1px solid var(--border-soft);
  border-radius: var(--r-sm);
  padding: 4px 8px;
  margin: 0 0 var(--s-4) 0;
}
.df-error-state-actions {
  display: flex;
  gap: var(--s-2);
  justify-content: center;
  flex-wrap: wrap;
}

/* ---------- LOADING SKELETON ---------- */
.df-skel {
  background: var(--bg-sunken);
  border-radius: var(--r-sm);
  display: inline-block;
  height: 1em;
  position: relative;
  overflow: hidden;
}
.df-skel-line { display: block; height: 14px; margin-bottom: 8px; }

/* Subtle shimmer animation. Disabled under prefers-reduced-motion. */
.df-skel::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg,
    transparent 0%,
    rgba(255, 255, 255, 0.42) 50%,
    transparent 100%);
  animation: df-skel-shimmer 1.4s ease-in-out infinite;
}
@keyframes df-skel-shimmer {
  0%   { transform: translateX(-100%); }
  100% { transform: translateX(100%); }
}
@media (prefers-reduced-motion: reduce) {
  .df-skel::after { animation: none; opacity: 0; }
}

/* ---------- BUTTON: NEGATIVE / DESTRUCTIVE ----------
   Used in confirmation modals for "Cancel subscription", "Delete account",
   "Drop player" — anything irreversible. Filled red so the destructive
   action reads as visually heavy; pair with iOS convention (destructive
   on the RIGHT) when the action is genuinely irreversible. */
.df-btn-neg {
  background: var(--neg);
  color: var(--fg-on-dark);
  border-color: var(--neg);
}
.df-btn-neg:hover { background: var(--neg-hover); border-color: var(--neg-hover); }
.df-btn-neg-outline {
  background: transparent;
  color: var(--neg);
  border-color: var(--neg);
}
.df-btn-neg-outline:hover { background: var(--neg-soft); }

/* ---------- TOGGLE / SWITCH ----------
   iOS-style on/off switch. Apply to a native <input type="checkbox">.
   Pattern:
     <label class="df-toggle-row">
       <input class="df-toggle" type="checkbox" checked>
       <span class="df-toggle-label">Lineup deadline reminder</span>
     </label>
   The checkbox is appearance:none and styled directly (no wrapper span).
   Track is 36×20, knob is 16×16, slides 16px on :checked. */
.df-toggle {
  appearance: none;
  -webkit-appearance: none;
  width: 36px;
  height: 20px;
  /* Raw --paper-4 on purpose: the toggle track is the only consumer of that step,
     and a semantic alias with one consumer is a rename, not an abstraction. If a
     second inset-control surface appears, promote it to --bg-track then. */
  background: var(--paper-4);
  border: 1px solid var(--border);
  border-radius: 999px;
  position: relative;
  cursor: pointer;
  transition: background-color .15s ease-out, border-color .15s ease-out;
  flex-shrink: 0;
  margin: 0;
}
.df-toggle::before {
  content: "";
  position: absolute;
  left: 1px;
  top: 1px;
  width: 16px;
  height: 16px;
  background: var(--bg-elevated);
  border-radius: 50%;
  box-shadow: 0 1px 2px rgba(13, 59, 31, 0.18);
  transition: transform .15s ease-out;
}
.df-toggle:checked {
  background: var(--field);
  border-color: var(--field);
}
.df-toggle:checked::before { transform: translateX(16px); }
.df-toggle:focus-visible {
  outline: 2px solid var(--ring);
  outline-offset: 2px;
}
.df-toggle:disabled { opacity: 0.5; cursor: not-allowed; }
@media (prefers-reduced-motion: reduce) {
  .df-toggle, .df-toggle::before { transition: none; }
}
/* Row: label and toggle, label takes the space, toggle pinned right. */
.df-toggle-row {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  padding: var(--s-3) 0;
  font-family: var(--font-ui);
  font-size: 14px;
  color: var(--fg);
  cursor: pointer;
}
.df-toggle-row .df-toggle-label { flex: 1 1 auto; }
.df-toggle-row .df-toggle-hint {
  display: block;
  font-size: 12px;
  color: var(--fg-subtle);
  margin-top: 2px;
}

/* ---------- TOAST / TRANSIENT NOTIFICATION ----------
   Pattern (HTMX or vanilla JS just adds/removes nodes):
     <div class="df-toast-stack" id="toasts" aria-live="polite" aria-atomic="false"></div>
     // append:
     <div class="df-toast df-toast-pos" role="status">
       <span class="df-toast-icon">✓</span>
       <span class="df-toast-msg">Lineup saved</span>
       <button class="df-toast-close" aria-label="Dismiss">✕</button>
     </div>
   Auto-dismiss after ~3s (script adds .df-toast-out class to fade, removes
   node 200ms later). Dismiss key: Esc. The stack pins to the bottom-right
   on desktop, top on mobile (closer to the system status area). */
.df-toast-stack {
  position: fixed;
  bottom: 16px;
  right: 16px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  z-index: 9000;
  max-width: calc(100vw - 32px);
  pointer-events: none; /* let toasts catch their own clicks */
}
.df-toast-stack > .df-toast { pointer-events: auto; }
@media (max-width: 720px) {
  .df-toast-stack {
    bottom: auto;
    top: max(8px, env(safe-area-inset-top, 8px));
    left: 8px;
    right: 8px;
  }
}

.df-toast {
  display: flex;
  align-items: flex-start;
  gap: var(--s-2);
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-left: 3px solid var(--ink-4);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-md);
  padding: 12px 12px 12px 14px;
  min-width: 260px;
  max-width: 380px;
  font-family: var(--font-ui);
  font-size: 14px;
  color: var(--fg);
  line-height: 1.4;
  /* Slide in from the right; on mobile (top), slide down. */
  animation: df-toast-in .22s cubic-bezier(.2, .8, .2, 1);
}
@media (max-width: 720px) {
  .df-toast { animation: df-toast-in-top .22s cubic-bezier(.2, .8, .2, 1); }
}
.df-toast-out {
  animation: df-toast-out .18s ease-out forwards;
}
@keyframes df-toast-in {
  from { opacity: 0; transform: translateX(16px); }
  to   { opacity: 1; transform: none; }
}
@keyframes df-toast-in-top {
  from { opacity: 0; transform: translateY(-12px); }
  to   { opacity: 1; transform: none; }
}
@keyframes df-toast-out {
  from { opacity: 1; transform: none; }
  to   { opacity: 0; transform: translateY(-6px); }
}
@media (prefers-reduced-motion: reduce) {
  .df-toast { animation: none; }
  .df-toast-out { animation: none; opacity: 0; }
}

.df-toast-icon {
  flex-shrink: 0;
  width: 20px;
  height: 20px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 600;
  border-radius: 50%;
  margin-top: 1px;
  background: var(--bg-sunken);
  color: var(--fg-muted);
}
.df-toast-msg { flex: 1 1 auto; }
.df-toast-close {
  flex-shrink: 0;
  background: transparent;
  border: 0;
  color: var(--fg-subtle);
  font-size: 14px;
  line-height: 1;
  cursor: pointer;
  padding: 2px 4px;
  margin: -2px -4px 0 0;
  border-radius: 4px;
}
.df-toast-close:hover { color: var(--fg); background: var(--bg-sunken); }

/* Variants */
.df-toast-pos     { border-left-color: var(--pos);     }
.df-toast-pos     .df-toast-icon { background: var(--pos-soft);     color: var(--pos); }
.df-toast-neg     { border-left-color: var(--neg);     }
.df-toast-neg     .df-toast-icon { background: var(--neg-soft);     color: var(--neg); }
.df-toast-warn    { border-left-color: var(--warn);    }
.df-toast-warn    .df-toast-icon { background: var(--warn-soft);    color: var(--warn); }
.df-toast-info    { border-left-color: var(--info);    }
.df-toast-info    .df-toast-icon { background: var(--info-soft);    color: var(--info); }
.df-toast-pigskin { border-left-color: var(--pigskin); }
.df-toast-pigskin .df-toast-icon { background: var(--pigskin-soft); color: var(--pigskin); }

/* ---------- CONFIRMATION MODAL ----------
   Built on native <dialog>. Open with .showModal() (or set [open]).
   Pattern:
     <dialog class="df-confirm-modal">
       <h3 class="df-confirm-title">Cancel your subscription?</h3>
       <p class="df-confirm-body">Your projections stay available through the end of your current billing period (Sep 14). After that, your account reverts to free tier.</p>
       <label class="df-confirm-gate">
         <input type="checkbox"> I understand my projections will stop on Sep 14.
       </label>
       <div class="df-confirm-actions">
         <button class="df-btn df-btn-secondary" autofocus>Keep subscription</button>
         <button class="df-btn df-btn-neg-outline">Cancel anyway</button>
       </div>
     </dialog>
   Destructive variant: use .df-btn-neg-outline (intentional friction —
   you have to mean it). Place destructive on the RIGHT (iOS convention)
   so the safe action sits under the resting thumb position. */
.df-confirm-modal {
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  padding: var(--s-5) var(--s-5) var(--s-4);
  max-width: 460px;
  width: calc(100vw - 32px);
  box-shadow: var(--shadow-lg);
  font-family: var(--font-ui);
  color: var(--fg);
}
.df-confirm-modal::backdrop {
  background: rgba(13, 59, 31, 0.45);
}
.df-confirm-title {
  font-family: var(--font-display);
  font-weight: var(--w-semibold);
  font-size: 20px;
  line-height: var(--lh-snug);
  margin: 0 0 var(--s-2) 0;
  color: var(--fg);
}
.df-confirm-body {
  font-family: var(--font-ui);
  font-size: 14px;
  line-height: var(--lh-normal);
  color: var(--fg-muted);
  margin: 0 0 var(--s-3) 0;
}
.df-confirm-gate {
  display: flex;
  align-items: flex-start;
  gap: var(--s-2);
  background: var(--bg-sunken);
  border: 1px solid var(--border-soft);
  border-radius: var(--r-sm);
  padding: 10px 12px;
  margin: 0 0 var(--s-4) 0;
  font-size: 13px;
  color: var(--fg-2);
  line-height: 1.4;
  cursor: pointer;
}
.df-confirm-gate input { flex-shrink: 0; margin-top: 2px; }
.df-confirm-actions {
  display: flex;
  gap: var(--s-2);
  justify-content: flex-end;
  flex-wrap: wrap;
}
@media (max-width: 480px) {
  .df-confirm-actions { flex-direction: column-reverse; }
  .df-confirm-actions > * { width: 100%; }
}

/* ---------- TREND FLAG ----------
   Inline indicator like "↑ 2 spots vs last week" or "↓ 4 since Sun".
   Pattern:
     <span class="df-trend df-trend-pos">↑ 2 <small>vs Wk 7</small></span>
   Three semantic variants (pos / neg / neutral). Sized to sit inline next
   to a player name without dominating the line. Mono digits for stable
   alignment in a column of trend flags. */
.df-trend {
  display: inline-flex;
  align-items: baseline;
  gap: 4px;
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 600;
  font-feature-settings: "tnum" 1;
  color: var(--fg-subtle);
  white-space: nowrap;
  letter-spacing: 0;
}
.df-trend small {
  font-family: var(--font-ui);
  font-size: 11px;
  font-weight: 400;
  color: var(--fg-subtle);
  letter-spacing: 0.04em;
}
.df-trend-pos     { color: var(--pos); }
.df-trend-pos small     { color: var(--pos); opacity: 0.7; }
.df-trend-neg     { color: var(--neg); }
.df-trend-neg small     { color: var(--neg); opacity: 0.7; }
.df-trend-neutral { color: var(--fg-subtle); }
.df-trend-pigskin { color: var(--pigskin); }
.df-trend-pigskin small { color: var(--pigskin); opacity: 0.7; }

/* ---------- DISTRIBUTION PILL (mini PI bar) ----------
   ~32–48px wide inline element conveying distribution shape. Three dots:
   P10 (left), median (center, larger), P90 (right). Track is a thin rule.
   Pattern:
     <span class="df-pi-mini" aria-label="P10 8.4, median 14.2, P90 22.6">
       <i class="df-pi-mini-track"></i>
       <i class="df-pi-mini-dot df-pi-mini-p10"  style="left: 12%"></i>
       <i class="df-pi-mini-dot df-pi-mini-med"  style="left: 48%"></i>
       <i class="df-pi-mini-dot df-pi-mini-p90"  style="left: 88%"></i>
     </span>
   Useful in tables/rankings where a full .df-pi-bar would crowd the row. */
.df-pi-mini {
  position: relative;
  display: inline-block;
  width: 36px;
  height: 12px;
  vertical-align: middle;
}
.df-pi-mini-track {
  position: absolute;
  left: 0; right: 0;
  top: 50%;
  height: 1px;
  background: var(--border);
  transform: translateY(-0.5px);
}
.df-pi-mini-dot {
  position: absolute;
  top: 50%;
  width: 3px;
  height: 3px;
  border-radius: 50%;
  background: var(--ink-4);
  transform: translate(-50%, -50%);
}
.df-pi-mini-med {
  width: 5px;
  height: 5px;
  background: var(--ink);
}
.df-pi-mini-p10, .df-pi-mini-p90 { background: var(--ink-4); }
/* Highlight variants — use when a column is sorted by ceiling or floor */
.df-pi-mini-emphasize-p90 .df-pi-mini-p90 { background: var(--pos); width: 4px; height: 4px; }
.df-pi-mini-emphasize-p10 .df-pi-mini-p10 { background: var(--neg); width: 4px; height: 4px; }

/* ---------- FIGURE + CAPTION ----------
   Long-form prose figure pattern (research posts, methodology page).
   Pattern:
     <figure class="df-figure">
       <svg>…</svg>
       <figcaption class="df-figure-caption">
         <strong>Figure 2.</strong> Model output vs realized outcome…
       </figcaption>
     </figure>
   Centers within the prose column, leaves room for caption below. */
.df-figure {
  margin: var(--s-6) 0;
  padding: var(--s-4);
  background: var(--bg-elevated);
  border: 1px solid var(--border-soft);
  border-radius: var(--r-sm);
}
.df-figure-caption {
  font-family: var(--font-ui);
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--fg-subtle);
  margin-top: var(--s-3);
  padding-top: var(--s-2);
  border-top: 1px solid var(--border-soft);
}
.df-figure-caption strong {
  color: var(--fg-muted);
  font-weight: var(--w-semibold);
  font-family: var(--font-mono);
  font-size: 11.5px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.df-figure-caption-clean {
  border: 0;
  padding-top: 0;
  text-align: center;
}

/* ---------- GLOSSARY INLINE TERM ----------
   Hover/tap-revealed definition for a jargon term in prose. Pattern:
     <span class="df-term" tabindex="0">
       median projection<span class="df-term-def" role="tooltip">The 50th
       percentile of our model's distribution — half the time the player
       finishes above this number, half below.</span>
     </span>
   Dotted underline signals "definable". Definition appears on :hover or
   :focus-within (keyboard accessible). On mobile, tap to focus.
   Use sparingly — every term defined inline is a term the reader didn't
   need to context-switch to look up. */
.df-term {
  position: relative;
  border-bottom: 1px dotted var(--ink-4);
  cursor: help;
  outline: none;
}
.df-term:focus-visible {
  outline: 2px solid var(--ring);
  outline-offset: 2px;
  border-radius: 2px;
}
.df-term-def {
  position: absolute;
  bottom: calc(100% + 6px);
  left: 50%;
  transform: translateX(-50%) translateY(4px);
  width: max-content;
  max-width: 280px;
  background: var(--ink);
  color: var(--fg-on-dark);
  font-family: var(--font-ui);
  font-size: 12.5px;
  font-weight: 400;
  line-height: 1.45;
  letter-spacing: 0;
  text-transform: none;
  border: 0;
  border-radius: var(--r-sm);
  padding: 8px 10px;
  box-shadow: var(--shadow-md);
  opacity: 0;
  pointer-events: none;
  transition: opacity .12s ease-out, transform .12s ease-out;
  z-index: 100;
}
.df-term-def::after {
  content: "";
  position: absolute;
  top: 100%;
  left: 50%;
  transform: translateX(-50%);
  border: 4px solid transparent;
  border-top-color: var(--ink);
}
.df-term:hover .df-term-def,
.df-term:focus-within .df-term-def {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}
@media (prefers-reduced-motion: reduce) {
  .df-term-def { transition: none; }
}

/* ---------- PULL QUOTE ----------
   Editorial pull-quote for long-form prose (research, methodology). */
/* Set in the READING voice, not the display voice: a pull-quote is lifted from
   serif body copy and sits inside it, so the sans would break voice mid-article.
   README §5 assigns Source Serif 4 to research-post bodies. */
.df-pullquote {
  font-family: var(--font-reading);
  font-style: italic;
  font-weight: var(--w-regular);
  font-size: var(--t-quote);
  line-height: 1.3;   /* between --lh-snug and --lh-normal; no token holds it */
  letter-spacing: var(--ls-snug);
  color: var(--fg);
  border-left: 2px solid var(--pigskin);
  padding: 0 0 0 var(--s-5);
  margin: var(--s-8) 0;
}
.df-pullquote-attr {
  display: block;
  margin-top: var(--s-3);
  font-family: var(--font-ui);
  font-style: normal;   /* undo the italic inherited from .df-pullquote */
  font-size: var(--t-sm);
  font-weight: var(--w-medium);
  color: var(--fg-subtle);
  letter-spacing: var(--ls-wide);
}

/* ---------- A11Y ---------- */
.df-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;
}

/* =============================================================
   EDITORIAL / LONG-FORM  (merged in from the former root df.css, v0.3)
   -------------------------------------------------------------
   Until v0.3 there were TWO files named df.css — a 17.3 KB root copy
   carrying these long-form classes, and a 30.5 KB handoff copy carrying
   the app-shell classes above. Neither was a superset, so whichever one
   a consumer linked, they silently lacked the other's components.

   They are now one file. 100 of the 106 shared selectors were already
   byte-identical. The 6 that differed split 4/2:

     handoff won  .df-skel (needs overflow/position or the shimmer can't
                  clip), .df-figure, .df-figure-caption and
                  .df-figure-caption strong (tokenized spacing where the
                  root copy hardcoded literals).
     root won     .df-pullquote and .df-pullquote-attr — the serif reading
                  voice was chosen over the display sans, since a pull-quote
                  is lifted from serif body copy and sits inside it. Root's
                  geometry was kept but rewritten with scale tokens; see the
                  .df-pullquote rule above.
   ============================================================= */
/* ---------- EDITORIAL PRIMITIVES ----------
   Used by long-form pages (Methodology, research posts). Opt in via .df-prose
   wrapper or by setting the classes directly. Sizes assume a ~720px column. */

/* Lede paragraph — first paragraph after the title. Bigger, lighter color. */
.df-lede {
  font-family: var(--font-reading);
  font-size: 19px;
  line-height: 1.55;
  color: var(--fg-2);
  margin: 0 0 var(--s-4);
}
.df-figure > svg,
.df-figure > img,
.df-figure > picture > img {
  display: block;
  width: 100%;
  height: auto;
}
/* .df-figure-body / .df-figure-flush were removed in v0.3. They came from the
   former root df.css and existed to undo *its* zero-padding figure base; against
   the merged base (which pads and rules) they double-padded and half-reset. The
   retained caption treatment needs neither. */
/* Inline callout box — sidebar-ish but lives inline in the column. */
.df-callout {
  background: var(--bg-sunken);
  border: 1px solid var(--border-soft);
  border-left: 3px solid var(--field);
  border-radius: var(--r-sm);
  padding: 14px 18px;
  margin: 24px 0;
  font-family: var(--font-ui);
  font-size: 14px;
  line-height: 1.55;
  color: var(--fg-2);
}
.df-callout-label {
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  color: var(--field);
  margin: 0 0 4px;
}
.df-callout-pigskin { border-left-color: var(--pigskin); }
.df-callout-pigskin .df-callout-label { color: var(--pigskin); }
/* Footnote reference (superscript number) + footnote list at end of post. */
.df-fn-ref {
  font-family: var(--font-mono);
  font-size: 0.7em;
  font-weight: 600;
  vertical-align: super;
  line-height: 0;
  color: var(--pigskin);
  text-decoration: none;
  padding: 0 1px 0 2px;
}
.df-fn-ref:hover { color: var(--field); }
.df-footnotes {
  margin-top: 56px;
  padding-top: 18px;
  border-top: 1px solid var(--border-soft);
}
.df-footnotes-label {
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  color: var(--fg-subtle);
  margin: 0 0 12px;
}
.df-footnotes ol {
  margin: 0;
  padding-left: 22px;
  font-family: var(--font-ui);
  font-size: 13px;
  line-height: 1.6;
  color: var(--fg-muted);
}
.df-footnotes li { margin-bottom: 10px; }
.df-footnotes li::marker { font-family: var(--font-mono); color: var(--fg-subtle); }
/* Section ornament — decorative break between major prose sections. */
.df-ornament {
  display: block;
  margin: 56px auto;
  width: 120px;
  opacity: 0.7;
}

/* ---------- BUTTON — GHOST (third neutral tier) ----------
   Transparent, no border, subtle hover. Sits between .df-btn-secondary and
   .df-btn-link: lower emphasis than secondary, but still a button-shaped hit
   target rather than inline text.

   Added v0.3.2. It was already a dependency, not a new idea:
   ui_kits/app/_account.css referenced .df-btn-ghost twice with nothing
   defining it, and two unrelated consumer templates independently invented
   .df-btn-tertiary for the same role. Three authors reaching for a tier that
   didn't exist is the definition of a gap.

   Use for: low-emphasis inline actions, and the UNSELECTED state of a
   two-state picker (pair with .df-btn-primary for selected). */
.df-btn-ghost {
  background: transparent;
  color: var(--fg-2);
  border-color: transparent;
}
.df-btn-ghost:hover  { background: var(--bg-sunken); color: var(--fg); }
.df-btn-ghost:active { background: var(--bg-sunken); }
.df-btn-ghost[aria-disabled="true"] { opacity: 0.45; pointer-events: none; }

/* ---------- WIZARD STEPPER ----------
   Numbered progress trail for multi-step flows. Belongs next to .df-tabs but
   is not a tab set: .df-wizard-step-active marks the current step AND every
   step behind it, so the trail reads as progress rather than a cursor.
   Contributed by a consumer (v0.3.2). */
.df-wizard-steps {
  display: flex; gap: var(--s-1); list-style: none;
  padding: 0; margin: 0 0 var(--s-7); flex-wrap: wrap;
}
.df-wizard-step {
  flex: 1; min-width: 96px;
  display: flex; flex-direction: column; align-items: center; gap: var(--s-1);
  font-family: var(--font-ui); font-size: var(--t-xs); color: var(--fg-subtle);
}
.df-wizard-step-dot {
  width: 22px; height: 22px; border-radius: var(--r-pill);
  display: flex; align-items: center; justify-content: center;
  font-family: var(--font-mono); font-size: 11px; font-weight: var(--w-semibold);
  background: var(--bg-sunken); color: var(--fg-subtle);
  border: 1px solid var(--border);
  /* .df-wizard-step-active is toggled on dots ALREADY in the DOM — the trail fills in
     behind the cursor rather than re-rendering — so all three colors change in place.
     Without this the step snaps. Reported by a consumer (v0.3.3). */
  transition: background-color var(--dur-fast) var(--ease-standard),
              border-color var(--dur-fast) var(--ease-standard),
              color var(--dur-fast) var(--ease-standard);
}
.df-wizard-step-active { color: var(--fg); }
.df-wizard-step-active .df-wizard-step-dot {
  background: var(--ink); color: var(--fg-on-dark); border-color: var(--ink);
}

/* ---------- PAGINATION ----------
   Prev/next + page indicator. Buttons need no disabled styling of their own —
   .df-btn[aria-disabled="true"] already dims to 0.45. Contributed by a
   consumer (v0.3.2). */
.df-pagination {
  display: flex; align-items: center; justify-content: center;
  gap: var(--s-2); margin-top: var(--s-3);
}
.df-pagination-status {
  font-family: var(--font-mono); font-size: var(--t-xs);
  color: var(--fg-muted); font-variant-numeric: tabular-nums;
}
