/* system.css — opt-in base layer + utilities for Develop surfaces.
 *
 * Wrapped in @layer lib.reset so a consumer's own base layer and
 * Tailwind's preflight deterministically WIN during the gradual
 * de-Tailwind overlap (a later @layer / unlayered rule beats this one).
 *
 * Deliberately MINIMAL: box-sizing, heading/p margin reset, the
 * custom-element placeholders, and a few layout utilities. It does NOT
 * touch overflow-x, scrollbar theming, or focus outline — those are
 * each consumer app's decision, not a shared concern.
 */

@layer lib.reset {
  *,
  *::before,
  *::after {
    box-sizing: border-box;
  }

  body {
    margin: 0;
    font-family: var(--font-sans);
    font-size: var(--text-body);
    line-height: var(--leading-body);
    background: var(--background);
    color: var(--foreground);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    text-rendering: optimizeLegibility;
  }

  /* Canonical heading sizes (in lib.reset so a consumer's own rule or Tailwind
     preflight still wins). They give bare h1-h6 a consistent default hierarchy
     for channels that don't size headings themselves. */
  h1, h2, h3, h4, h5, h6 {
    margin: 0;
    letter-spacing: -0.025em;
    line-height: var(--leading-heading);
  }
  h1 { font-size: var(--text-display); }  /* 22px */
  h2 { font-size: var(--text-lg); }       /* 18px */
  h3 { font-size: var(--text-heading); }  /* 16px */
  h4 { font-size: var(--text-title); }    /* 14px */
  h5 { font-size: var(--text-body); }     /* 12px */
  h6 { font-size: var(--text-micro); }    /* 11px */

  p {
    margin: 0;
    line-height: var(--leading-normal);
  }

  /* Graceful degradation + CLS fix: before components.js upgrades the
   * custom elements they are display:inline at 0px. Reserve their box
   * and paint a token-coloured surface so a cold first load (or a lib
   * outage on a consumer that hasn't kept its vendored copy) shows a
   * styled placeholder instead of a collapsed, invisible chrome.
   *
   * Heights track dev-site-header's declared 48px / 56px. The footer
   * value is a conservative reserve; confirm with getComputedStyle at
   * the A2/A3 pixel-verification step. */
  dev-site-header:not(:defined) {
    display: block;
    min-height: 48px;
    background: var(--background);
    border-bottom: 1px solid var(--border);
  }
  dev-site-footer:not(:defined) {
    display: block;
    min-height: 120px;
    background: var(--background);
    border-top: 1px solid var(--border);
  }
  /* A dialog is invisible until opened; once defined its closed native
     <dialog> is display:none anyway. Before the components bundle upgrades
     the element it is an unknown inline element whose light-DOM children
     (modal body + footer) would otherwise dump into the page flow — hide it. */
  dev-dialog:not(:defined) {
    display: none;
  }
  @media (min-width: 768px) {
    dev-site-header:not(:defined) {
      min-height: 56px;
    }
  }
}

@layer lib.utilities {
  /* Vertical rhythm — children stacked with a token gap. */
  .stack {
    display: flex;
    flex-direction: column;
    gap: var(--stack-gap, 1rem);
  }
  /* Horizontal grouping that wraps. */
  .cluster {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--cluster-gap, 0.5rem);
  }
  /* Centered, width-capped content column. */
  .center {
    margin-inline: auto;
    max-width: var(--center-max, 72rem);
    padding-inline: var(--center-pad, 1.5rem);
  }
  .text-balance {
    text-wrap: balance;
  }

  /* Brand gradient helpers — the platform's "克制" color accent. Apply
     .brand-gradient-text to a page H1 (gradient text) and .btn-brand to a
     primary button (gradient fill). Both read --brand-gradient /
     --brand-gradient-fg from tokens.css, so they flip light/dark for free. */
  .brand-gradient-text {
    background-image: var(--brand-gradient);
    background-size: 200% 100%;
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
  }
  .btn-brand {
    background-image: var(--brand-gradient);
    color: var(--brand-gradient-fg, oklch(0.99 0 0));
    border-color: transparent;
  }
  .btn-brand:hover {
    opacity: 0.92;
  }

  /* Canonical button system — ONE consistent size + shape across every
     surface, all from tokens. Use these instead of rolling per-app button CSS
     (which drifts in size and leaves the anti-aliased dark edge a transparent
     border puts on a gradient fill). A consumer's own unlayered .btn rules
     still win, so adopting this is opt-in and non-breaking.
       .btn            neutral default (secondary surface, 1px token border)
       .btn-primary    brand gradient fill (NO border -> no edge seam)
       .btn-secondary  same as the .btn default (explicit alias)
       .btn-ghost      transparent until hover
       .btn-danger     subtle destructive outline
       .btn-sm/.btn-lg size modifiers
     box-sizing:border-box + a shared min-height keep bordered and borderless
     variants the EXACT same height. */
  .btn {
    box-sizing: border-box;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    min-height: 2.25rem;
    padding: 0 0.875rem;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--secondary);
    color: var(--secondary-foreground);
    font-family: inherit;
    font-size: var(--text-sm);
    font-weight: 500;
    line-height: 1.2;
    text-decoration: none;
    cursor: pointer;
    transition: opacity 0.15s var(--ease-smooth), background-color 0.15s var(--ease-smooth), border-color 0.15s var(--ease-smooth);
  }
  .btn:hover {
    background: var(--accent);
  }
  .btn:focus-visible {
    outline: 2px solid var(--ring);
    outline-offset: 2px;
  }
  .btn:disabled {
    opacity: 0.5;
    cursor: not-allowed;
  }
  .btn-sm {
    min-height: 1.875rem;
    padding: 0 0.625rem;
    font-size: var(--text-xs);
  }
  .btn-lg {
    min-height: 2.75rem;
    padding: 0 1.25rem;
    font-size: var(--text-base);
  }
  .btn-primary {
    background-image: var(--brand-gradient);
    background-color: transparent;
    color: var(--brand-gradient-fg, oklch(0.99 0 0));
    border: none;
  }
  .btn-primary:hover {
    background: var(--brand-gradient);
    opacity: 0.92;
  }
  .btn-secondary {
    background: var(--secondary);
    color: var(--secondary-foreground);
    border: 1px solid var(--border);
  }
  .btn-ghost {
    background: transparent;
    border-color: transparent;
  }
  .btn-ghost:hover {
    background: var(--accent);
  }
  .btn-danger {
    background: transparent;
    color: var(--destructive);
    border-color: color-mix(in oklab, var(--destructive) 45%, transparent);
  }
  .btn-danger:hover {
    background: color-mix(in oklab, var(--destructive) 12%, transparent);
  }
}

/* Shared component skin — extracted from xshort's studio.css into lib's token
   vocabulary (12px type, brand gradient, light/dark tokens) so every channel
   links lib and uses these classes instead of vendoring its own copy. In
   @layer lib.components so a consumer's own unlayered rule still wins (opt-in,
   non-breaking). */
@layer lib.components {
  /* Tactile lift on hover — enriches the .btn system above for the refined feel. */
  .btn:not(:disabled):hover {
    border-color: var(--border-strong);
    box-shadow: var(--shadow-card);
    transform: translateY(-1px);
  }
  .btn:not(:disabled):active {
    transform: translateY(0);
    box-shadow: none;
  }
  .btn-icon {
    padding: 0;
    width: 2.25rem;
    aspect-ratio: 1;
  }

  /* Inputs — text fields, textareas, native selects. Aligned to .btn height. */
  .input,
  .textarea {
    box-sizing: border-box;
    width: 100%;
    padding: 0.5rem 0.75rem;
    font-family: inherit;
    font-size: var(--text-body);
    line-height: var(--leading-body);
    color: var(--foreground);
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    outline: none;
    transition: border-color 0.15s var(--ease-smooth), box-shadow 0.15s var(--ease-smooth);
  }
  .input {
    min-height: 2.25rem;
  }
  .input:hover,
  .textarea:hover {
    border-color: var(--border-strong);
  }
  .input:focus,
  .textarea:focus {
    border-color: var(--ring);
    box-shadow: 0 0 0 3px color-mix(in oklab, var(--ring) 22%, transparent);
  }
  .input::placeholder,
  .textarea::placeholder {
    color: var(--muted-foreground);
  }
  .textarea {
    resize: vertical;
  }
  select.input {
    appearance: none;
    cursor: pointer;
    padding-right: 2.25rem;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%2371717a' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 0.75rem center;
  }

  /* Tags / badges — pill, role-tinted. */
  .tag {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    padding: 0.1875rem 0.5rem;
    font-size: var(--text-micro);
    font-weight: 500;
    line-height: 1.4;
    border-radius: 999px;
    background: var(--secondary);
    color: var(--secondary-foreground);
    white-space: nowrap;
  }
  .tag-success { background: var(--success-bg); color: var(--success); }
  .tag-error   { background: var(--error-bg);   color: var(--error); }
  .tag-info    { background: var(--info-bg);    color: var(--info); }
  .tag-warning { background: var(--warning-bg); color: var(--warning); }

  /* Card — surface with token border + subtle shadow + hover affordance. */
  .card {
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    background: var(--card);
    color: var(--card-foreground);
    box-shadow: var(--shadow-card);
    transition: border-color 0.2s var(--ease-out), box-shadow 0.2s var(--ease-out);
  }
  .card-hover:hover {
    border-color: var(--border-strong);
    box-shadow: var(--shadow-float);
  }
  .card-active {
    border-color: var(--ring);
    box-shadow: 0 0 0 2px color-mix(in oklab, var(--ring) 20%, transparent);
  }

  /* Modal overlay — for channels not using <dev-dialog>. */
  .overlay {
    position: fixed;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background: oklch(0.2 0 0 / 0.34);
    -webkit-backdrop-filter: blur(6px);
    backdrop-filter: blur(6px);
    z-index: 100;
    animation: lib-fade-in 0.18s var(--ease-out);
  }

  /* Thin token-colored scrollbar — opt-in (not global, to avoid surprising a
     consumer that themes its own scrollbars). */
  .scroll-thin {
    scrollbar-width: thin;
    scrollbar-color: var(--border) transparent;
  }
  .scroll-thin::-webkit-scrollbar { width: 6px; height: 6px; }
  .scroll-thin::-webkit-scrollbar-track { background: transparent; }
  .scroll-thin::-webkit-scrollbar-thumb { background: var(--border); border-radius: 999px; }
  .scroll-thin::-webkit-scrollbar-thumb:hover { background: var(--border-strong); }

  /* Motion helpers. */
  .animate-spin { animation: lib-spin 0.9s linear infinite; }
  .page-enter { animation: lib-fade-up 0.35s var(--ease-out) both; }
  .stagger-1 { animation-delay: 0.05s; }
  .stagger-2 { animation-delay: 0.1s; }
  .stagger-3 { animation-delay: 0.15s; }
  .stagger-4 { animation-delay: 0.2s; }
}

/* Keyframes live outside @layer (animations aren't subject to the cascade). */
@keyframes lib-spin { to { transform: rotate(360deg); } }
@keyframes lib-fade-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes lib-fade-up {
  from { opacity: 0; transform: translateY(12px); }
  to { opacity: 1; transform: translateY(0); }
}
